summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt119
-rw-r--r--ConfigureChecks.cmake16
-rw-r--r--config.h.cmake13
-rw-r--r--kopete/CMakeLists.txt24
-rw-r--r--kopete/ConfigureChecks.cmake20
-rw-r--r--kopete/icons/CMakeLists.txt12
-rw-r--r--kopete/kopete/CMakeLists.txt65
-rw-r--r--kopete/kopete/addaccountwizard/CMakeLists.txt27
-rw-r--r--kopete/kopete/addcontactwizard/CMakeLists.txt27
-rw-r--r--kopete/kopete/chatwindow/CMakeLists.txt71
-rw-r--r--kopete/kopete/chatwindow/krichtexteditpart.cpp2
-rw-r--r--kopete/kopete/config/CMakeLists.txt17
-rw-r--r--kopete/kopete/config/accounts/CMakeLists.txt37
-rw-r--r--kopete/kopete/config/appearance/CMakeLists.txt43
-rw-r--r--kopete/kopete/config/avdevice/CMakeLists.txt39
-rw-r--r--kopete/kopete/config/behavior/CMakeLists.txt38
-rw-r--r--kopete/kopete/config/identity/CMakeLists.txt40
-rw-r--r--kopete/kopete/config/plugins/CMakeLists.txt24
-rw-r--r--kopete/kopete/contactlist/CMakeLists.txt40
-rw-r--r--kopete/kopete/contactlist/kopetegroupviewitem.cpp3
-rw-r--r--kopete/kopete/kconf_update/CMakeLists.txt64
-rw-r--r--kopete/libkopete/CMakeLists.txt91
-rw-r--r--kopete/libkopete/avdevice/CMakeLists.txt46
-rw-r--r--kopete/libkopete/kopetemessagemanager.h3
-rw-r--r--kopete/libkopete/kopetemessagemanagerfactory.h3
-rw-r--r--kopete/libkopete/kopetepasswordedaccount.h2
-rw-r--r--kopete/libkopete/private/CMakeLists.txt29
-rw-r--r--kopete/libkopete/ui/CMakeLists.txt56
-rw-r--r--kopete/plugins/CMakeLists.txt28
-rw-r--r--kopete/plugins/addbookmarks/CMakeLists.txt49
-rw-r--r--kopete/plugins/alias/CMakeLists.txt50
-rw-r--r--kopete/plugins/alias/aliasplugin.cpp2
-rw-r--r--kopete/plugins/autoreplace/CMakeLists.txt49
-rw-r--r--kopete/plugins/autoreplace/icons/CMakeLists.txt12
-rw-r--r--kopete/plugins/connectionstatus/CMakeLists.txt35
-rw-r--r--kopete/plugins/contactnotes/CMakeLists.txt36
-rw-r--r--kopete/plugins/cryptography/CMakeLists.txt53
-rw-r--r--kopete/plugins/cryptography/icons/CMakeLists.txt13
-rw-r--r--kopete/plugins/cryptography/kgpgselkey.h2
-rw-r--r--kopete/plugins/highlight/CMakeLists.txt52
-rw-r--r--kopete/plugins/highlight/icons/CMakeLists.txt12
-rw-r--r--kopete/plugins/history/CMakeLists.txt55
-rw-r--r--kopete/plugins/latex/CMakeLists.txt53
-rw-r--r--kopete/plugins/latex/icons/CMakeLists.txt12
-rw-r--r--kopete/plugins/motionautoaway/CMakeLists.txt51
-rw-r--r--kopete/plugins/netmeeting/CMakeLists.txt56
-rw-r--r--kopete/plugins/nowlistening/CMakeLists.txt54
-rw-r--r--kopete/plugins/smpppdcs/CMakeLists.txt59
-rw-r--r--kopete/plugins/smpppdcs/icons/CMakeLists.txt12
-rw-r--r--kopete/plugins/smpppdcs/libsmpppdclient/CMakeLists.txt23
-rw-r--r--kopete/plugins/statistics/CMakeLists.txt45
-rw-r--r--kopete/plugins/statistics/ConfigureChecks.cmake15
-rw-r--r--kopete/plugins/statistics/images/CMakeLists.txt14
-rw-r--r--kopete/plugins/statistics/sqlite/Makefile.am51
-rw-r--r--kopete/plugins/statistics/sqlite/attach.c329
-rw-r--r--kopete/plugins/statistics/sqlite/auth.c223
-rw-r--r--kopete/plugins/statistics/sqlite/btree.c4462
-rw-r--r--kopete/plugins/statistics/sqlite/btree.h124
-rw-r--r--kopete/plugins/statistics/sqlite/build.c2564
-rw-r--r--kopete/plugins/statistics/sqlite/date.c893
-rw-r--r--kopete/plugins/statistics/sqlite/delete.c419
-rw-r--r--kopete/plugins/statistics/sqlite/encode.c257
-rw-r--r--kopete/plugins/statistics/sqlite/expr.c1927
-rw-r--r--kopete/plugins/statistics/sqlite/func.c1018
-rw-r--r--kopete/plugins/statistics/sqlite/hash.c380
-rw-r--r--kopete/plugins/statistics/sqlite/hash.h109
-rw-r--r--kopete/plugins/statistics/sqlite/insert.c1018
-rw-r--r--kopete/plugins/statistics/sqlite/legacy.c138
-rw-r--r--kopete/plugins/statistics/sqlite/lempar.c687
-rw-r--r--kopete/plugins/statistics/sqlite/main.c1346
-rw-r--r--kopete/plugins/statistics/sqlite/opcodes.c128
-rw-r--r--kopete/plugins/statistics/sqlite/opcodes.h126
-rw-r--r--kopete/plugins/statistics/sqlite/os.h197
-rw-r--r--kopete/plugins/statistics/sqlite/os_common.h107
-rw-r--r--kopete/plugins/statistics/sqlite/os_mac.c738
-rw-r--r--kopete/plugins/statistics/sqlite/os_mac.h41
-rw-r--r--kopete/plugins/statistics/sqlite/os_unix.c1276
-rw-r--r--kopete/plugins/statistics/sqlite/os_unix.h89
-rw-r--r--kopete/plugins/statistics/sqlite/os_win.c747
-rw-r--r--kopete/plugins/statistics/sqlite/os_win.h40
-rw-r--r--kopete/plugins/statistics/sqlite/pager.c3205
-rw-r--r--kopete/plugins/statistics/sqlite/pager.h102
-rw-r--r--kopete/plugins/statistics/sqlite/parse.c3143
-rw-r--r--kopete/plugins/statistics/sqlite/parse.h129
-rw-r--r--kopete/plugins/statistics/sqlite/pragma.c754
-rw-r--r--kopete/plugins/statistics/sqlite/printf.c825
-rw-r--r--kopete/plugins/statistics/sqlite/random.c100
-rw-r--r--kopete/plugins/statistics/sqlite/select.c2628
-rw-r--r--kopete/plugins/statistics/sqlite/shell.c1786
-rw-r--r--kopete/plugins/statistics/sqlite/sqlite3.h1166
-rw-r--r--kopete/plugins/statistics/sqlite/sqliteInt.h1419
-rw-r--r--kopete/plugins/statistics/sqlite/table.c195
-rw-r--r--kopete/plugins/statistics/sqlite/tokenize.c707
-rw-r--r--kopete/plugins/statistics/sqlite/trigger.c804
-rw-r--r--kopete/plugins/statistics/sqlite/update.c450
-rw-r--r--kopete/plugins/statistics/sqlite/utf.c566
-rw-r--r--kopete/plugins/statistics/sqlite/util.c962
-rw-r--r--kopete/plugins/statistics/sqlite/vacuum.c262
-rw-r--r--kopete/plugins/statistics/sqlite/vdbe.c4450
-rw-r--r--kopete/plugins/statistics/sqlite/vdbe.h131
-rw-r--r--kopete/plugins/statistics/sqlite/vdbeInt.h408
-rw-r--r--kopete/plugins/statistics/sqlite/vdbeapi.c588
-rw-r--r--kopete/plugins/statistics/sqlite/vdbeaux.c1806
-rw-r--r--kopete/plugins/statistics/sqlite/vdbemem.c724
-rw-r--r--kopete/plugins/statistics/sqlite/where.c1210
-rw-r--r--kopete/plugins/statistics/statisticsdb.cpp2
-rw-r--r--kopete/plugins/texteffect/CMakeLists.txt51
-rw-r--r--kopete/plugins/texteffect/icons/CMakeLists.txt12
-rw-r--r--kopete/plugins/translator/CMakeLists.txt51
-rw-r--r--kopete/plugins/translator/translatorguiclient.cpp2
-rw-r--r--kopete/plugins/translator/translatorplugin.cpp2
-rw-r--r--kopete/plugins/webpresence/CMakeLists.txt59
-rw-r--r--kopete/protocols/CMakeLists.txt22
-rw-r--r--kopete/protocols/gadu/CMakeLists.txt50
-rw-r--r--kopete/protocols/gadu/ConfigureChecks.cmake15
-rw-r--r--kopete/protocols/gadu/gadueditcontact.h1
-rw-r--r--kopete/protocols/gadu/icons/CMakeLists.txt12
-rw-r--r--kopete/protocols/gadu/libgadu/COPYING504
-rw-r--r--kopete/protocols/gadu/libgadu/Makefile.am12
-rw-r--r--kopete/protocols/gadu/libgadu/common.c827
-rw-r--r--kopete/protocols/gadu/libgadu/compat.h29
-rw-r--r--kopete/protocols/gadu/libgadu/dcc.c1298
-rw-r--r--kopete/protocols/gadu/libgadu/events.c1580
-rw-r--r--kopete/protocols/gadu/libgadu/http.c522
-rw-r--r--kopete/protocols/gadu/libgadu/libgadu-config.h.in30
-rw-r--r--kopete/protocols/gadu/libgadu/libgadu.c1818
-rw-r--r--kopete/protocols/gadu/libgadu/libgadu.h1310
-rw-r--r--kopete/protocols/gadu/libgadu/pubdir.c689
-rw-r--r--kopete/protocols/gadu/libgadu/pubdir50.c467
-rw-r--r--kopete/protocols/gadu/ui/CMakeLists.txt28
-rw-r--r--kopete/protocols/groupwise/CMakeLists.txt50
-rw-r--r--kopete/protocols/groupwise/icons/CMakeLists.txt12
-rw-r--r--kopete/protocols/groupwise/libgroupwise/CMakeLists.txt53
-rw-r--r--kopete/protocols/groupwise/libgroupwise/qca/CMakeLists.txt12
-rw-r--r--kopete/protocols/groupwise/libgroupwise/qca/src/CMakeLists.txt22
-rw-r--r--kopete/protocols/groupwise/libgroupwise/tasks/CMakeLists.txt38
-rw-r--r--kopete/protocols/groupwise/ui/CMakeLists.txt35
-rw-r--r--kopete/protocols/irc/CMakeLists.txt54
-rw-r--r--kopete/protocols/irc/icons/CMakeLists.txt12
-rw-r--r--kopete/protocols/irc/libkirc/CMakeLists.txt30
-rw-r--r--kopete/protocols/irc/libkirc/kircentity.h2
-rw-r--r--kopete/protocols/irc/ui/CMakeLists.txt30
-rw-r--r--kopete/protocols/jabber/CMakeLists.txt85
-rw-r--r--kopete/protocols/jabber/icons/CMakeLists.txt12
-rw-r--r--kopete/protocols/jabber/jingle/CMakeLists.txt38
-rw-r--r--kopete/protocols/jabber/jingle/jinglevoicecaller.cpp2
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/CMakeLists.txt12
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/CMakeLists.txt19
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/ConfigureChecks.cmake48
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/CMakeLists.txt32
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc2
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc5
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/CMakeLists.txt13
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/CMakeLists.txt52
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver_main.cc1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.cc1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.cc1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver_main.cc1
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/CMakeLists.txt30
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/CMakeLists.txt12
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/CMakeLists.txt34
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc2
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc2
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/CMakeLists.txt13
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/CMakeLists.txt36
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.h2
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.c2
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.h2
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/CMakeLists.txt32
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/avprofile.c281
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/export.c25
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/export.h38
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/jitterctl.c141
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/jitterctl.h38
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp-config.h9
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp.c258
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp.h54
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/payloadtype.c268
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/payloadtype.h136
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/port_fct.c183
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/port_fct.h48
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/posixtimer.c167
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcp.c294
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcp.h167
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcpparse.c218
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtp.h90
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpmod.c122
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpmod.h31
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpparse.c159
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpport.h308
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsession.c1954
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsession.h287
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsignaltable.c98
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsignaltable.h47
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtptimer.c32
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtptimer.h52
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/scheduler.c235
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/scheduler.h70
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/sessionset.c187
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/sessionset.h102
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/str_utils.c297
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/str_utils.h118
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/telephonyevents.c338
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/telephonyevents.h98
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/utils.c44
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/utils.h43
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmllite/CMakeLists.txt28
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/CMakeLists.txt29
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h2
-rw-r--r--kopete/protocols/jabber/kioslave/CMakeLists.txt42
-rw-r--r--kopete/protocols/jabber/libiris/CMakeLists.txt14
-rw-r--r--kopete/protocols/jabber/libiris/cutestuff/CMakeLists.txt13
-rw-r--r--kopete/protocols/jabber/libiris/cutestuff/network/CMakeLists.txt27
-rw-r--r--kopete/protocols/jabber/libiris/cutestuff/util/CMakeLists.txt24
-rw-r--r--kopete/protocols/jabber/libiris/iris/CMakeLists.txt15
-rw-r--r--kopete/protocols/jabber/libiris/iris/include/CMakeLists.txt24
-rw-r--r--kopete/protocols/jabber/libiris/iris/jabber/CMakeLists.txt40
-rw-r--r--kopete/protocols/jabber/libiris/iris/xmpp-core/CMakeLists.txt38
-rw-r--r--kopete/protocols/jabber/libiris/iris/xmpp-im/CMakeLists.txt37
-rw-r--r--kopete/protocols/jabber/libiris/qca/CMakeLists.txt12
-rw-r--r--kopete/protocols/jabber/libiris/qca/src/CMakeLists.txt22
-rw-r--r--kopete/protocols/jabber/ui/CMakeLists.txt43
-rw-r--r--kopete/protocols/meanwhile/CMakeLists.txt47
-rw-r--r--kopete/protocols/meanwhile/ConfigureChecks.cmake15
-rw-r--r--kopete/protocols/meanwhile/icons/CMakeLists.txt12
-rw-r--r--kopete/protocols/meanwhile/ui/CMakeLists.txt27
-rw-r--r--kopete/protocols/msn/CMakeLists.txt71
-rw-r--r--kopete/protocols/msn/config/CMakeLists.txt38
-rw-r--r--kopete/protocols/msn/icons/CMakeLists.txt12
-rw-r--r--kopete/protocols/msn/ui/CMakeLists.txt29
-rw-r--r--kopete/protocols/msn/webcam/CMakeLists.txt28
-rw-r--r--kopete/protocols/msn/webcam/libmimic/CMakeLists.txt23
-rw-r--r--kopete/protocols/oscar/CMakeLists.txt42
-rw-r--r--kopete/protocols/oscar/aim/CMakeLists.txt47
-rw-r--r--kopete/protocols/oscar/aim/ui/CMakeLists.txt31
-rw-r--r--kopete/protocols/oscar/icons/CMakeLists.txt12
-rw-r--r--kopete/protocols/oscar/icq/CMakeLists.txt45
-rw-r--r--kopete/protocols/oscar/icq/ui/CMakeLists.txt34
-rw-r--r--kopete/protocols/oscar/liboscar/CMakeLists.txt46
-rw-r--r--kopete/protocols/sms/CMakeLists.txt48
-rw-r--r--kopete/protocols/sms/icons/CMakeLists.txt12
-rw-r--r--kopete/protocols/sms/services/CMakeLists.txt32
-rw-r--r--kopete/protocols/sms/services/ConfigureChecks.cmake30
-rw-r--r--kopete/protocols/sms/services/config.h.cmake1
-rw-r--r--kopete/protocols/sms/ui/CMakeLists.txt24
-rw-r--r--kopete/protocols/testbed/CMakeLists.txt44
-rw-r--r--kopete/protocols/testbed/icons/CMakeLists.txt12
-rw-r--r--kopete/protocols/testbed/testbedaccount.h2
-rw-r--r--kopete/protocols/testbed/ui/CMakeLists.txt25
-rw-r--r--kopete/protocols/winpopup/CMakeLists.txt51
-rw-r--r--kopete/protocols/winpopup/icons/CMakeLists.txt12
-rw-r--r--kopete/protocols/winpopup/libwinpopup/CMakeLists.txt24
-rw-r--r--kopete/protocols/winpopup/ui/CMakeLists.txt25
-rw-r--r--kopete/protocols/yahoo/CMakeLists.txt49
-rw-r--r--kopete/protocols/yahoo/icons/CMakeLists.txt12
-rw-r--r--kopete/protocols/yahoo/libkyahoo/CMakeLists.txt48
-rw-r--r--kopete/protocols/yahoo/libkyahoo/ConfigureChecks.cmake16
-rw-r--r--kopete/protocols/yahoo/ui/CMakeLists.txt30
-rw-r--r--kopete/sounds/CMakeLists.txt15
-rw-r--r--kopete/styles/CMakeLists.txt18
-rw-r--r--kopete/styles/Clean/CMakeLists.txt12
-rw-r--r--kopete/styles/Clean/Contents/CMakeLists.txt12
-rw-r--r--kopete/styles/Clean/Contents/Resources/CMakeLists.txt18
-rw-r--r--kopete/styles/Clean/Contents/Resources/Incoming/CMakeLists.txt14
-rw-r--r--kopete/styles/Clean/Contents/Resources/Outgoing/CMakeLists.txt14
-rw-r--r--kopete/styles/Clean/Contents/Resources/images/CMakeLists.txt14
-rw-r--r--kopete/styles/Clear/CMakeLists.txt12
-rw-r--r--kopete/styles/Clear/Contents/CMakeLists.txt12
-rw-r--r--kopete/styles/Clear/Contents/Resources/CMakeLists.txt19
-rw-r--r--kopete/styles/Clear/Contents/Resources/Incoming/CMakeLists.txt14
-rw-r--r--kopete/styles/Clear/Contents/Resources/Outgoing/CMakeLists.txt14
-rw-r--r--kopete/styles/Clear/Contents/Resources/Variants/CMakeLists.txt14
-rw-r--r--kopete/styles/Clear/Contents/Resources/images/CMakeLists.txt25
-rw-r--r--kopete/styles/Gaim/CMakeLists.txt12
-rw-r--r--kopete/styles/Gaim/Contents/CMakeLists.txt12
-rw-r--r--kopete/styles/Gaim/Contents/Resources/CMakeLists.txt18
-rw-r--r--kopete/styles/Gaim/Contents/Resources/Incoming/CMakeLists.txt14
-rw-r--r--kopete/styles/Gaim/Contents/Resources/Outgoing/CMakeLists.txt14
-rw-r--r--kopete/styles/Gaim/Contents/Resources/Variants/CMakeLists.txt14
-rw-r--r--kopete/styles/Hacker/CMakeLists.txt16
-rw-r--r--kopete/styles/Hacker/Contents/CMakeLists.txt14
-rw-r--r--kopete/styles/Hacker/Contents/Resources/CMakeLists.txt19
-rw-r--r--kopete/styles/Hacker/Contents/Resources/Incoming/CMakeLists.txt15
-rw-r--r--kopete/styles/Hacker/Contents/Resources/Outgoing/CMakeLists.txt15
-rw-r--r--kopete/styles/Hacker/Contents/Resources/Variants/CMakeLists.txt15
-rw-r--r--kopete/styles/Hacker/Contents/Resources/images/CMakeLists.txt14
-rw-r--r--kopete/styles/Konqi/CMakeLists.txt12
-rw-r--r--kopete/styles/Konqi/Contents/CMakeLists.txt12
-rw-r--r--kopete/styles/Konqi/Contents/Resources/CMakeLists.txt18
-rw-r--r--kopete/styles/Konqi/Contents/Resources/Incoming/CMakeLists.txt14
-rw-r--r--kopete/styles/Konqi/Contents/Resources/Outgoing/CMakeLists.txt14
-rw-r--r--kopete/styles/Konqi/Contents/Resources/Variants/CMakeLists.txt19
-rw-r--r--kopete/styles/Konqi/Contents/Resources/Variants/konqui/CMakeLists.txt16
-rw-r--r--kopete/styles/Kopete/CMakeLists.txt12
-rw-r--r--kopete/styles/Kopete/Contents/CMakeLists.txt12
-rw-r--r--kopete/styles/Kopete/Contents/Resources/CMakeLists.txt19
-rw-r--r--kopete/styles/Kopete/Contents/Resources/Incoming/CMakeLists.txt14
-rw-r--r--kopete/styles/Kopete/Contents/Resources/Outgoing/CMakeLists.txt14
-rw-r--r--kopete/styles/Kopete/Contents/Resources/Variants/CMakeLists.txt14
-rw-r--r--kopete/styles/Kopete/Contents/Resources/images/CMakeLists.txt14
-rw-r--r--kopete/styles/Retropete/CMakeLists.txt12
-rw-r--r--kopete/styles/Retropete/Contents/CMakeLists.txt12
-rw-r--r--kopete/styles/Retropete/Contents/Resources/CMakeLists.txt17
-rw-r--r--kopete/styles/Retropete/Contents/Resources/Incoming/CMakeLists.txt14
-rw-r--r--kopete/styles/Retropete/Contents/Resources/Outgoing/CMakeLists.txt14
309 files changed, 12134 insertions, 57066 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..e2fc1fd4
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,119 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+cmake_minimum_required( VERSION 2.8 )
+
+
+##### general package setup #####################
+
+project( kdenetwork )
+
+set( PACKAGE kdenetwork )
+set( VERSION "3.5.13" )
+
+
+##### include essential cmake modules ###########
+
+include( FindPkgConfig )
+include( CheckIncludeFile )
+include( CheckIncludeFileCXX )
+include( CheckCXXSourceCompiles )
+include( CheckLibraryExists )
+
+
+##### include our cmake modules #################
+
+set( CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules" )
+include( TDEMacros )
+
+
+##### setup install paths #######################
+
+include( TDESetupPaths )
+tde_setup_paths( )
+
+
+##### optional stuff ############################
+
+option( WITH_JINGLE "Enable jingle support (kopete)" OFF )
+option( WITH_SPEEX "Enable speex support (for jingle)" OFF )
+option( WITH_WEBCAM "Enable webcam support (kopete/msn)" OFF )
+option( WITH_GSM "Enable GSM SMS support (kopete/sms)" OFF )
+
+
+##### kopete protocols ##########################
+
+option( BUILD_KOPETE_PROTOCOL_ALL "Build all kopete protocols" OFF )
+option( BUILD_KOPETE_PROTOCOL_TESTBED "Build kopete protocol testbed" ${BUILD_KOPETE_PROTOCOL_ALL} )
+option( BUILD_KOPETE_PROTOCOL_GROUPWISE "Build kopete protocol groupwise" ${BUILD_KOPETE_PROTOCOL_ALL} )
+option( BUILD_KOPETE_PROTOCOL_MSN "Build kopete protocol msn" ${BUILD_KOPETE_PROTOCOL_ALL} )
+option( BUILD_KOPETE_PROTOCOL_IRC "Build kopete protocol irc" ${BUILD_KOPETE_PROTOCOL_ALL} )
+option( BUILD_KOPETE_PROTOCOL_OSCAR "Build kopete protocol oscar" ${BUILD_KOPETE_PROTOCOL_ALL} )
+option( BUILD_KOPETE_PROTOCOL_YAHOO "Build kopete protocol yahoo" ${BUILD_KOPETE_PROTOCOL_ALL} )
+option( BUILD_KOPETE_PROTOCOL_WINPOPUP "Build kopete protocol winpopup" ${BUILD_KOPETE_PROTOCOL_ALL} )
+option( BUILD_KOPETE_PROTOCOL_SMS "Build kopete protocol sms" ${BUILD_KOPETE_PROTOCOL_ALL} )
+option( BUILD_KOPETE_PROTOCOL_JABBER "Build kopete protocol jabber" ${BUILD_KOPETE_PROTOCOL_ALL} )
+option( BUILD_KOPETE_PROTOCOL_GADU "Build kopete protocol gadu" ${BUILD_KOPETE_PROTOCOL_ALL} )
+option( BUILD_KOPETE_PROTOCOL_MEANWHILE "Build kopete protocol meanwhile" ${BUILD_KOPETE_PROTOCOL_ALL} )
+
+
+##### kopete plugins ############################
+
+option( BUILD_KOPETE_PLUGIN_ALL "Build all kopete plugins" OFF )
+option( BUILD_KOPETE_PLUGIN_LATEX "Build latex kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_AUTOREPLACE "Build autoreplace kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_HISTORY "Build history kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_CONTACTNOTES "Build contactnotes kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_CRYPTOGRAPHY "Build cryptography kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_CONNECTIONSTATUS "Build connectionstatus kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_TRANSLATOR "Build translator kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_NOWLISTENING "Build nowlistening kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_WEBPRESENCE "Build webpresence kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_TEXTEFFECT "Build texteffect kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_HIGHLIGHT "Build highlight kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_ALIAS "Build alias kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_MOTIONAUTOAWAY "Build motionautoaway kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_NETMEETING "Build netmeeting kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_ADDBOOKMARKS "Build addbookmarks kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_STATISTICS "Build statistics kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+option( BUILD_KOPETE_PLUGIN_SMPPPDCS "Build smpppdcs kopete plugin" ${BUILD_KOPETE_PLUGIN_ALL} )
+
+
+##### user requested modules ####################
+
+option( BUILD_ALL "Build all" OFF )
+option( BUILD_KOPETE "Build kopete" ${BUILD_ALL} )
+
+
+##### configure checks ##########################
+
+include( ConfigureChecks.cmake )
+
+
+###### global compiler settings #################
+
+add_definitions(
+ -DHAVE_CONFIG_H
+)
+
+set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TQT_CXX_FLAGS}" )
+set( CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined" )
+set( CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined" )
+
+
+##### kdenetwork directories ####################
+
+tde_conditional_add_subdirectory( BUILD_KOPETE kopete )
+
+
+##### write configure files #####################
+
+configure_file( config.h.cmake config.h @ONLY )
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
new file mode 100644
index 00000000..df5b169f
--- /dev/null
+++ b/ConfigureChecks.cmake
@@ -0,0 +1,16 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+
+
+# required stuff
+find_package( TQt )
+find_package( TDE )
diff --git a/config.h.cmake b/config.h.cmake
new file mode 100644
index 00000000..7bf17882
--- /dev/null
+++ b/config.h.cmake
@@ -0,0 +1,13 @@
+// NOTE:
+// this definition is safe for modern Linux systems
+// for other OSes can be necessary to check
+#define STDC_HEADERS 1
+
+// kopete/protocols/yahoo
+#cmakedefine HAVE_STRING_H 1
+#cmakedefine HAVE_STRINGS_H 1
+
+// kopete/protocols/jabber
+#cmakedefine SUPPORT_JINGLE 1
+#cmakedefine HAVE_GLIB 1
+#cmakedefine HAVE_SPEEX 1
diff --git a/kopete/CMakeLists.txt b/kopete/CMakeLists.txt
new file mode 100644
index 00000000..f04465a7
--- /dev/null
+++ b/kopete/CMakeLists.txt
@@ -0,0 +1,24 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+# NOTE some files was renamed:
+# kopetemessagemanager.h -> kopetechatsession.h
+# kopetemessagemanagerfactory.h -> kopetechatsessionmanager.h
+
+include( ConfigureChecks.cmake )
+
+add_subdirectory( libkopete )
+add_subdirectory( kopete )
+add_subdirectory( protocols )
+add_subdirectory( plugins )
+add_subdirectory( icons )
+add_subdirectory( sounds )
+add_subdirectory( styles )
diff --git a/kopete/ConfigureChecks.cmake b/kopete/ConfigureChecks.cmake
new file mode 100644
index 00000000..6a78d91f
--- /dev/null
+++ b/kopete/ConfigureChecks.cmake
@@ -0,0 +1,20 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+# glib-2.0 (jabber, msn)
+if( (BUILD_KOPETE_PROTOCOL_JABBER AND WITH_JINGLE) OR (BUILD_KOPETE_PROTOCOL_MSN AND WITH_WEBCAM) )
+ pkg_search_module( GLIB2 glib-2.0 )
+ if( GLIB2_FOUND )
+ set( HAVE_GLIB 1 CACHE INTERNAL "" FORCE )
+ else( )
+ tde_message_fatal( "glib-2.0 is required, but was not found on your system" )
+ endif( )
+endif( )
diff --git a/kopete/icons/CMakeLists.txt b/kopete/icons/CMakeLists.txt
new file mode 100644
index 00000000..189a3a20
--- /dev/null
+++ b/kopete/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons()
diff --git a/kopete/kopete/CMakeLists.txt b/kopete/kopete/CMakeLists.txt
new file mode 100644
index 00000000..b88714c2
--- /dev/null
+++ b/kopete/kopete/CMakeLists.txt
@@ -0,0 +1,65 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( addaccountwizard )
+add_subdirectory( addcontactwizard )
+add_subdirectory( contactlist )
+add_subdirectory( chatwindow )
+add_subdirectory( config )
+add_subdirectory( kconf_update )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_BINARY_DIR}/kopete/libkopete
+ ${CMAKE_BINARY_DIR}/kopete/kopete/addcontactwizard
+ ${CMAKE_BINARY_DIR}/kopete/kopete/contactlist
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/private
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/avdevice
+ ${CMAKE_SOURCE_DIR}/kopete/kopete/addaccountwizard
+ ${CMAKE_SOURCE_DIR}/kopete/kopete/addcontactwizard
+ ${CMAKE_SOURCE_DIR}/kopete/kopete/contactlist
+ ${CMAKE_SOURCE_DIR}/kopete/kopete/config/plugins
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+tde_install_icons( )
+install( FILES kopete.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
+install( FILES kopeteui.rc eventsrc DESTINATION ${DATA_INSTALL_DIR}/kopete )
+install( FILES x-kopete-emoticons.desktop DESTINATION ${MIME_INSTALL_DIR}/application )
+
+
+##### kopete (executable) #######################
+
+tde_add_executable( kopete AUTOMOC
+ SOURCES
+ main.cpp kopeteapplication.cpp kopeteiface.cpp
+ kopeteiface.skel systemtray.cpp kopeteballoon.cpp
+ kopetewindow.cpp kopeteaccountstatusbaricon.cpp
+ kimifaceimpl.cpp kimiface.skel groupkabcselectorwidget.ui
+ kopeteeditglobalidentitywidget.cpp
+ LINK
+ kopetecontactlist-static kopeteaddaccountwizard-static
+ kopeteaddcontactwizard-static kopeteui-static
+ kopetepluginconfig-static kopete-shared
+ DESTINATION ${BIN_INSTALL_DIR}
+)
diff --git a/kopete/kopete/addaccountwizard/CMakeLists.txt b/kopete/kopete/addaccountwizard/CMakeLists.txt
new file mode 100644
index 00000000..4c25f42a
--- /dev/null
+++ b/kopete/kopete/addaccountwizard/CMakeLists.txt
@@ -0,0 +1,27 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopeteaddaccountwizard (static) ###########
+
+tde_add_library( kopeteaddaccountwizard STATIC_PIC AUTOMOC
+ SOURCES
+ addaccountwizardpage1.ui addaccountwizardpage2.ui
+ addaccountwizardpage3.ui addaccountwizard.cpp
+)
diff --git a/kopete/kopete/addcontactwizard/CMakeLists.txt b/kopete/kopete/addcontactwizard/CMakeLists.txt
new file mode 100644
index 00000000..ce2c317c
--- /dev/null
+++ b/kopete/kopete/addcontactwizard/CMakeLists.txt
@@ -0,0 +1,27 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopeteaddcontactwizard (static) ###########
+
+tde_add_library( kopeteaddcontactwizard STATIC_PIC AUTOMOC
+ SOURCES
+ addcontactwizard_base.ui addcontactwizard.cpp
+)
diff --git a/kopete/kopete/chatwindow/CMakeLists.txt b/kopete/kopete/chatwindow/CMakeLists.txt
new file mode 100644
index 00000000..c88678d6
--- /dev/null
+++ b/kopete/kopete/chatwindow/CMakeLists.txt
@@ -0,0 +1,71 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/private
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/kopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopeterichtexteditpartfull.rc DESTINATION ${DATA_INSTALL_DIR}/kopeterichtexteditpart )
+install( FILES kopetechatwindow.rc kopeteemailwindow.rc DESTINATION ${DATA_INSTALL_DIR}/kopete )
+install( FILES chatwindow.desktop emailwindow.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### libkrichtexteditpart (module) #############
+
+tde_add_kpart( libkrichtexteditpart AUTOMOC
+ SOURCES krichtexteditpart.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kopete_chatwindow (module) ################
+
+tde_add_kpart( kopete_chatwindow AUTOMOC
+ SOURCES
+ chatview.cpp kopetechatwindow.cpp chatmemberslistwidget.cpp
+ LINK kopeteui-static kopetechatwindow-static kopete-shared khtml-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kopete_emailwindow (module) ###############
+
+tde_add_kpart( kopete_emailwindow AUTOMOC
+ SOURCES
+ kopeteemailwindow.cpp
+ LINK kopeteui-static kopetechatwindow-static kopete-shared khtml-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kopetechatwindow (static) #################
+
+tde_add_library( kopetechatwindow STATIC_PIC AUTOMOC
+ SOURCES
+ chatmessagepart.cpp emoticonselector.cpp kopeteemoticonaction.cpp
+ chattexteditpart.cpp krichtexteditpart.cpp kopetechatwindowstyle.cpp
+ kopetechatwindowstylemanager.cpp
+)
diff --git a/kopete/kopete/chatwindow/krichtexteditpart.cpp b/kopete/kopete/chatwindow/krichtexteditpart.cpp
index a08fa7e3..392e187a 100644
--- a/kopete/kopete/chatwindow/krichtexteditpart.cpp
+++ b/kopete/kopete/chatwindow/krichtexteditpart.cpp
@@ -38,7 +38,7 @@ public:
KopeteRichTextEditPart::KopeteRichTextEditPart( TQWidget *wparent, const char *wname, TQObject*, const char*, const TQStringList& )
: KParts::ReadOnlyPart( wparent, wname ? wname : "rich_text_part" )
{
- KopeteRichTextEditPart::KopeteRichTextEditPart( wparent, wname, false );
+ KopeteRichTextEditPart( wparent, wname, false );
}
KopeteRichTextEditPart::KopeteRichTextEditPart( TQWidget *parent, const char *name, int capabilities )
diff --git a/kopete/kopete/config/CMakeLists.txt b/kopete/kopete/config/CMakeLists.txt
new file mode 100644
index 00000000..88e5efd9
--- /dev/null
+++ b/kopete/kopete/config/CMakeLists.txt
@@ -0,0 +1,17 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( plugins )
+add_subdirectory( accounts )
+add_subdirectory( behavior )
+add_subdirectory( appearance )
+add_subdirectory( identity )
+add_subdirectory( avdevice )
diff --git a/kopete/kopete/config/accounts/CMakeLists.txt b/kopete/kopete/config/accounts/CMakeLists.txt
new file mode 100644
index 00000000..53741c13
--- /dev/null
+++ b/kopete/kopete/config/accounts/CMakeLists.txt
@@ -0,0 +1,37 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/kopete/addaccountwizard
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_accountconfig.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kcm_kopete_accountconfig (module) #########
+
+tde_add_kpart( kcm_kopete_accountconfig AUTOMOC
+ SOURCES kopeteaccountconfigbase.ui kopeteaccountconfig.cpp
+ LINK kopeteaddaccountwizard-static kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/kopete/config/appearance/CMakeLists.txt b/kopete/kopete/config/appearance/CMakeLists.txt
new file mode 100644
index 00000000..f24d022b
--- /dev/null
+++ b/kopete/kopete/config/appearance/CMakeLists.txt
@@ -0,0 +1,43 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/private
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/kopete/chatwindow
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_appearanceconfig.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kcm_kopete_appearanceconfig (module) ######
+
+tde_add_kpart( kcm_kopete_appearanceconfig AUTOMOC
+ SOURCES
+ appearanceconfig.cpp appearanceconfig_chatwindow.ui
+ appearanceconfig_colors.ui appearanceconfig_contactlist.ui
+ appearanceconfig_emoticons.ui emoticonseditdialog.cpp
+ emoticonseditwidget.ui tooltipeditdialog.cpp
+ tooltipeditwidget.ui
+ LINK kopetechatwindow-static kopete-shared khtml-shared knewstuff-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/kopete/config/avdevice/CMakeLists.txt b/kopete/kopete/config/avdevice/CMakeLists.txt
new file mode 100644
index 00000000..7fe58f0e
--- /dev/null
+++ b/kopete/kopete/config/avdevice/CMakeLists.txt
@@ -0,0 +1,39 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/avdevice
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
+install( FILES kopete_avdeviceconfig.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kcm_kopete_avdeviceconfig (module) ########
+
+tde_add_kpart( kcm_kopete_avdeviceconfig AUTOMOC
+ SOURCES
+ avdeviceconfig.cpp avdeviceconfig_videoconfig.ui
+ LINK kopete_videodevice-shared kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/kopete/config/behavior/CMakeLists.txt b/kopete/kopete/config/behavior/CMakeLists.txt
new file mode 100644
index 00000000..669878c0
--- /dev/null
+++ b/kopete/kopete/config/behavior/CMakeLists.txt
@@ -0,0 +1,38 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_behaviorconfig.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kcm_kopete_behaviorconfig (module) ########
+
+tde_add_kpart( kcm_kopete_behaviorconfig AUTOMOC
+ SOURCES
+ kopeteawayconfigbase.ui behaviorconfig_chat.ui
+ behaviorconfig_general.ui behaviorconfig_events.ui
+ behaviorconfig.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/kopete/config/identity/CMakeLists.txt b/kopete/kopete/config/identity/CMakeLists.txt
new file mode 100644
index 00000000..2495b388
--- /dev/null
+++ b/kopete/kopete/config/identity/CMakeLists.txt
@@ -0,0 +1,40 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_identityconfig.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopeteidentityconfigpreferences.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
+
+
+##### kcm_kopete_identityconfig (module) ########
+
+tde_add_kpart( kcm_kopete_identityconfig AUTOMOC
+ SOURCES
+ kopeteidentityconfigbase.ui kopeteidentityconfig.cpp
+ globalidentitiesmanager.cpp kopeteidentityconfigpreferences.kcfgc
+ LINK kopeteui-static kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/kopete/config/plugins/CMakeLists.txt b/kopete/kopete/config/plugins/CMakeLists.txt
new file mode 100644
index 00000000..58fbefc3
--- /dev/null
+++ b/kopete/kopete/config/plugins/CMakeLists.txt
@@ -0,0 +1,24 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopetepluginconfig (static) ###############
+
+tde_add_library( kopetepluginconfig STATIC_PIC AUTOMOC
+ SOURCES kopetepluginconfig.cpp
+)
diff --git a/kopete/kopete/contactlist/CMakeLists.txt b/kopete/kopete/contactlist/CMakeLists.txt
new file mode 100644
index 00000000..741d3e0f
--- /dev/null
+++ b/kopete/kopete/contactlist/CMakeLists.txt
@@ -0,0 +1,40 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+# FIXME no XRENDER support yet
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_BINARY_DIR}/kopete/kopete/addcontactwizard
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/private
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/kopete
+ ${CMAKE_SOURCE_DIR}/kopete/kopete/addcontactwizard
+ ${CMAKE_SOURCE_DIR}/kopete/kopete/chatwindow
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopetecontactlist (static) ################
+
+tde_add_library( kopetecontactlist STATIC_PIC AUTOMOC
+ SOURCES
+ kopetemetacontactlvi.cpp kopetestatusgroupviewitem.cpp
+ kopetegroupviewitem.cpp kopetecontactlistview.cpp
+ kopetegvipropswidget.ui kopetemetalvipropswidget.ui
+ kopetelviprops.cpp kopeteaddrbookexport.cpp
+ kopeteaddrbookexportui.ui customnotifications.ui
+ customnotificationprops.cpp kopetegrouplistaction.cpp
+ kabcexport.cpp kabcexport_base.ui
+)
diff --git a/kopete/kopete/contactlist/kopetegroupviewitem.cpp b/kopete/kopete/contactlist/kopetegroupviewitem.cpp
index ab375540..b28b7cb3 100644
--- a/kopete/kopete/contactlist/kopetegroupviewitem.cpp
+++ b/kopete/kopete/contactlist/kopetegroupviewitem.cpp
@@ -174,8 +174,7 @@ void KopeteGroupViewItem::refreshDisplayName()
// Sorting in this slot is extremely expensive as it's called dozens of times and
// the sorting itself is rather slow. Therefore we call delayedSort, which tries
// to group multiple sort requests into one.
- using namespace Kopete::UI::ListView;
- if ( ListView::ListView *lv = dynamic_cast<ListView::ListView *>( listView() ) )
+ if ( Kopete::UI::ListView::ListView *lv = dynamic_cast<Kopete::UI::ListView::ListView *>( listView() ) )
lv->delayedSort();
else
listView()->sort();
diff --git a/kopete/kopete/kconf_update/CMakeLists.txt b/kopete/kopete/kconf_update/CMakeLists.txt
new file mode 100644
index 00000000..1317d824
--- /dev/null
+++ b/kopete/kopete/kconf_update/CMakeLists.txt
@@ -0,0 +1,64 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions( -DKDE_NO_COMPAT )
+
+include_directories(
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES
+ kopete-pluginloader.upd kopete-account-kconf_update.upd
+ kopete-pluginloader2.upd kopete-jabberproxytype-kconf_update.upd
+ kopete-jabberpriorityaddition-kconf_update.upd
+ kopete-nameTracking.upd
+ DESTINATION ${KCONF_UPDATE_INSTALL_DIR} )
+
+install( PROGRAMS
+ kopete-pluginloader.pl kopete-jabberpriorityaddition-kconf_update.sh
+ kopete-pluginloader2.sh kopete-jabberproxytype-kconf_update.sh
+ kopete-account-0.10.pl kopete-account-kconf_update.sh
+ DESTINATION ${KCONF_UPDATE_INSTALL_DIR} )
+
+
+##### kopete_account_kconf_update (executable) ##
+
+tde_add_executable( kopete_account_kconf_update
+ SOURCES kopete-account-kconf_update.cpp
+ LINK ${TQT_LIBRARIES}
+ DESTINATION ${LIB_INSTALL_DIR}/kconf_update_bin
+)
+
+
+##### kopete_pluginloader2_kconf_update (executable)
+
+tde_add_executable( kopete_pluginloader2_kconf_update
+ SOURCES kopete-pluginloader2.cpp
+ LINK ${TQT_LIBRARIES}
+ DESTINATION ${LIB_INSTALL_DIR}/kconf_update_bin
+)
+
+
+##### kopete_nameTracking_kconf_update (executable)
+
+tde_add_executable( kopete_nameTracking_kconf_update
+ SOURCES kopete-nameTracking.cpp
+ LINK kdecore-shared
+ DESTINATION ${LIB_INSTALL_DIR}/kconf_update_bin
+)
diff --git a/kopete/libkopete/CMakeLists.txt b/kopete/libkopete/CMakeLists.txt
new file mode 100644
index 00000000..bbed2548
--- /dev/null
+++ b/kopete/libkopete/CMakeLists.txt
@@ -0,0 +1,91 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+# FIXME no support for XSS and XRENDER yet
+
+add_subdirectory( private )
+add_subdirectory( ui )
+add_subdirectory( avdevice )
+
+add_definitions( -DKDE_NO_COMPAT )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/private
+ ${CMAKE_CURRENT_SOURCE_DIR}/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### headers ###################################
+
+install( FILES
+ kopeteaccount.h kopeteaccountmanager.h kopeteawayaction.h
+ kopeteawaydialog.h kopeteaway.h kopetecommandhandler.h
+ kopetecontact.h kopetecontactlistelement.h kopetecontactlist.h
+ kopetecontactproperty.h kopeteeventpresentation.h
+ kopete_export.h kopeteglobal.h kopetegroup.h kopetemessageevent.h
+ kopetemessage.h kopetemessagehandlerchain.h kopetemessagehandler.h
+ kopetechatsession.h kopetechatsessionmanager.h kopetemetacontact.h
+ kopetemimetypehandler.h kopeteonlinestatus.h kopeteonlinestatusmanager.h
+ kopetepasswordedaccount.h kopetepassword.h kopeteplugin.h
+ kopeteprotocol.h kopetesimplemessagehandler.h kopetetask.h
+ kopetetransfermanager.h kopeteuiglobal.h kabcpersistence.h
+ managedconnectionaccount.h kopetenotifydataobject.h
+ kopeteversion.h kopeteprefs.h kopetepicture.h webcamwidget.h
+ kopetepluginmanager.h
+ DESTINATION ${INCLUDE_INSTALL_DIR}/kopete )
+
+
+##### other data ################################
+
+install( FILES kopete.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
+install( FILES kopetecommandui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete )
+install( FILES kopeteplugin.desktop kopeteprotocol.desktop kopeteui.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} )
+
+
+##### kopete (shared) ###########################
+
+tde_include_tqt( kopetemimetypehandler.cpp )
+
+tde_add_library( kopete SHARED AUTOMOC
+ SOURCES
+ knotification.cpp connectionmanager.cpp kopeteonlinestatus.cpp
+ kopeteonlinestatusmanager.cpp kopeteprotocol.cpp
+ kopetecontact.cpp kopetepluginmanager.cpp kopeteplugin.cpp
+ kopetemessage.cpp kopetechatsession.cpp kopetechatsessionmanager.cpp
+ kopetecontactlist.cpp kopetemetacontact.cpp kopeteawaydialog.cpp
+ kopetetransfermanager.cpp kopetegroup.cpp kcautoconfigmodule.cpp
+ kopeteaccountmanager.cpp kopeteaccount.cpp kopetecontactlistelement.cpp
+ kopetecommandhandler.cpp kopeteaway.cpp kopeteawayaction.cpp
+ kautoconfig.cpp kopetewalletmanager.cpp kopetecontactproperty.cpp
+ kopetepassword.cpp kopeteglobal.cpp kopeteuiglobal.cpp
+ kopetepasswordedaccount.cpp kopetemimetypehandler.cpp
+ kopetetask.cpp kopetemimesourcefactory.cpp kopeteeventpresentation.cpp
+ kopetenotifyevent.cpp kopetenotifydataobject.cpp kopeteblacklister.cpp
+ kopetemessageevent.cpp kopetemessagehandler.cpp kopetemessagehandlerchain.cpp
+ kopetesimplemessagehandler.cpp kopeteproperties.cpp kabcpersistence.cpp
+ connectionmanager.skel clientiface.stub managedconnectionaccount.cpp
+ networkstatuscommon.h kopeteconfig.kcfgc kopeteutils.cpp
+ kopeteprefs.cpp kopetepicture.cpp webcamwidget.cpp
+ VERSION 1.0.0
+ EMBED kopeteui-static
+ LINK kopeteprivate-static kabc-shared kutils-shared khtml-shared
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/kopete/libkopete/avdevice/CMakeLists.txt b/kopete/libkopete/avdevice/CMakeLists.txt
new file mode 100644
index 00000000..8e37773f
--- /dev/null
+++ b/kopete/libkopete/avdevice/CMakeLists.txt
@@ -0,0 +1,46 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+# FIXME no support for GLLIB yet
+
+add_definitions( -DKDE_NO_COMPAT )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### kvideoio (static) #########################
+
+tde_add_library( kvideoio STATIC_PIC AUTOMOC
+ SOURCES kxv.cpp qvideo.cpp qvideostream.cpp
+)
+
+
+##### kopete_videodevice (shared) ###############
+
+tde_add_library( kopete_videodevice SHARED AUTOMOC
+ SOURCES
+ videocontrol.cpp videodevice.cpp videodevicemodelpool.cpp
+ videodevicepool.cpp videoinput.cpp bayer.cpp
+ sonix_compress.cpp
+ VERSION 1.0.0
+ LINK kdecore-shared
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/kopete/libkopete/kopetemessagemanager.h b/kopete/libkopete/kopetemessagemanager.h
deleted file mode 100644
index a07fb6f9..00000000
--- a/kopete/libkopete/kopetemessagemanager.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#warning kopetemessagemanager.h has been renamed to kopetechatsession.h
-#include "kopetechatsession.h"
-
diff --git a/kopete/libkopete/kopetemessagemanagerfactory.h b/kopete/libkopete/kopetemessagemanagerfactory.h
deleted file mode 100644
index 9ebdaa98..00000000
--- a/kopete/libkopete/kopetemessagemanagerfactory.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#warning kopetemessagemanagerfactory.h has been renamed to kopetechatsessionmanager.h
-#include "kopetechatsessionmanager.h"
-
diff --git a/kopete/libkopete/kopetepasswordedaccount.h b/kopete/libkopete/kopetepasswordedaccount.h
index d008bae4..dbec92db 100644
--- a/kopete/libkopete/kopetepasswordedaccount.h
+++ b/kopete/libkopete/kopetepasswordedaccount.h
@@ -21,8 +21,6 @@
#include "kopete_export.h"
-class Kopete::OnlineStatus;
-
namespace Kopete
{
diff --git a/kopete/libkopete/private/CMakeLists.txt b/kopete/libkopete/private/CMakeLists.txt
new file mode 100644
index 00000000..9ed6d643
--- /dev/null
+++ b/kopete/libkopete/private/CMakeLists.txt
@@ -0,0 +1,29 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions( -DKDE_NO_COMPAT )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopeteprivate (static) ####################
+
+tde_add_library( kopeteprivate STATIC_PIC AUTOMOC
+ SOURCES
+ kopeteemoticons.cpp kopetecommand.cpp
+ kopeteviewmanager.cpp kopeteutils_private.cpp
+)
diff --git a/kopete/libkopete/ui/CMakeLists.txt b/kopete/libkopete/ui/CMakeLists.txt
new file mode 100644
index 00000000..cb224847
--- /dev/null
+++ b/kopete/libkopete/ui/CMakeLists.txt
@@ -0,0 +1,56 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions( -DKDE_NO_COMPAT )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/private
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES
+ addressbooklinkwidget.h kopetefileconfirmdialog.h
+ kopetepasswordwidget.h kopeteview.h addcontactpage.h
+ kopeteviewplugin.h editaccountwidget.h kopetecontactaction.h
+ kopetestdaction.h userinfodialog.h addressbookselectordialog.h
+ addressbookselectorwidget.h kopetelistview.h accountselector.h
+ kopetelistviewitem.h kopetelistviewsearchline.h
+ ${CMAKE_CURRENT_BINARY_DIR}/fileconfirmbase.h
+ ${CMAKE_CURRENT_BINARY_DIR}/kopeteawaydialogbase.h
+ ${CMAKE_CURRENT_BINARY_DIR}/kopetepasswordwidgetbase.h
+ ${CMAKE_CURRENT_BINARY_DIR}/kopetepassworddialog.h
+ DESTINATION ${INCLUDE_INSTALL_DIR}/kopete/ui )
+
+
+##### kopeteui (static) #########################
+
+tde_add_library( kopeteui STATIC_PIC AUTOMOC
+ SOURCES
+ kopetecontactaction.cpp addcontactpage.cpp editaccountwidget.cpp
+ kopetepassworddialog.ui kopetestdaction.cpp kopeteawaydialogbase.ui
+ kopetefileconfirmdialog.cpp fileconfirmbase.ui
+ userinfodialog.cpp kopeteview.cpp kopetepasswordwidgetbase.ui
+ kopetepasswordwidget.cpp accountselector.cpp kopeteviewplugin.cpp
+ addresseeitem.cpp addressbookselectorwidget_base.ui
+ addressbookselectordialog.cpp addressbookselectorwidget.cpp
+ metacontactselectorwidget_base.ui metacontactselectorwidget.cpp
+ kopetelistview.cpp kopetelistviewitem.cpp kopetelistviewsearchline.cpp
+ contactaddednotifywidget.ui contactaddednotifydialog.cpp
+ addressbooklinkwidget_base.ui addressbooklinkwidget.cpp
+)
diff --git a/kopete/plugins/CMakeLists.txt b/kopete/plugins/CMakeLists.txt
new file mode 100644
index 00000000..a5c6b08c
--- /dev/null
+++ b/kopete/plugins/CMakeLists.txt
@@ -0,0 +1,28 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_LATEX latex )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_AUTOREPLACE autoreplace )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_HISTORY history )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_CONTACTNOTES contactnotes )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_CRYPTOGRAPHY cryptography )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_CONNECTIONSTATUS connectionstatus )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_TRANSLATOR translator )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_NOWLISTENING nowlistening )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_WEBPRESENCE webpresence )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_TEXTEFFECT texteffect )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_HIGHLIGHT highlight )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_ALIAS alias )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_MOTIONAUTOAWAY motionautoaway )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_NETMEETING netmeeting )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_ADDBOOKMARKS addbookmarks )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_STATISTICS statistics )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PLUGIN_SMPPPDCS smpppdcs )
diff --git a/kopete/plugins/addbookmarks/CMakeLists.txt b/kopete/plugins/addbookmarks/CMakeLists.txt
new file mode 100644
index 00000000..4d1df111
--- /dev/null
+++ b/kopete/plugins/addbookmarks/CMakeLists.txt
@@ -0,0 +1,49 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_addbookmarks.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_addbookmarks_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+
+
+##### kopete_addbookmarks (module) ##############
+
+tde_add_kpart( kopete_addbookmarks AUTOMOC
+ SOURCES
+ addbookmarksplugin.cpp addbookmarksprefssettings.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_addbookmarks (module) ##########
+
+tde_add_kpart( kcm_kopete_addbookmarks AUTOMOC
+ SOURCES
+ addbookmarkspreferences.cpp addbookmarksprefsui.ui
+ addbookmarksprefssettings.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/alias/CMakeLists.txt b/kopete/plugins/alias/CMakeLists.txt
new file mode 100644
index 00000000..d8ca2088
--- /dev/null
+++ b/kopete/plugins/alias/CMakeLists.txt
@@ -0,0 +1,50 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_alias.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_alias_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+
+
+##### kopete_alias (module) #####################
+
+tde_add_kpart( kopete_alias AUTOMOC
+ SOURCES
+ aliasplugin.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_alias (module) #################
+
+tde_add_kpart( kcm_kopete_alias AUTOMOC
+ SOURCES
+ aliaspreferences.cpp aliasdialogbase.ui
+ aliasdialog.ui editaliasdialog.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/alias/aliasplugin.cpp b/kopete/plugins/alias/aliasplugin.cpp
index 52a8511b..4824e2fb 100644
--- a/kopete/plugins/alias/aliasplugin.cpp
+++ b/kopete/plugins/alias/aliasplugin.cpp
@@ -9,7 +9,7 @@
#include <kgenericfactory.h>
-#include "kopetemessagemanagerfactory.h"
+#include "kopetechatsessionmanager.h"
#include "aliasplugin.h"
diff --git a/kopete/plugins/autoreplace/CMakeLists.txt b/kopete/plugins/autoreplace/CMakeLists.txt
new file mode 100644
index 00000000..9a39da64
--- /dev/null
+++ b/kopete/plugins/autoreplace/CMakeLists.txt
@@ -0,0 +1,49 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( icons )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_autoreplace.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_autoreplace_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+
+
+##### kopete_autoreplace (module) ###############
+
+tde_add_kpart( kopete_autoreplace AUTOMOC
+ SOURCES
+ autoreplaceplugin.cpp autoreplaceconfig.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_autoreplace (module) ###########
+
+tde_add_kpart( kcm_kopete_autoreplace AUTOMOC
+ SOURCES
+ autoreplacepreferences.cpp autoreplaceconfig.cpp autoreplaceprefs.ui
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/autoreplace/icons/CMakeLists.txt b/kopete/plugins/autoreplace/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/plugins/autoreplace/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/plugins/connectionstatus/CMakeLists.txt b/kopete/plugins/connectionstatus/CMakeLists.txt
new file mode 100644
index 00000000..207349c5
--- /dev/null
+++ b/kopete/plugins/connectionstatus/CMakeLists.txt
@@ -0,0 +1,35 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_connectionstatus.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kopete_connectionstatus (module) ##########
+
+tde_add_kpart( kopete_connectionstatus AUTOMOC
+ SOURCES connectionstatusplugin.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/contactnotes/CMakeLists.txt b/kopete/plugins/contactnotes/CMakeLists.txt
new file mode 100644
index 00000000..284e59bd
--- /dev/null
+++ b/kopete/plugins/contactnotes/CMakeLists.txt
@@ -0,0 +1,36 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_contactnotes.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES contactnotesui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_contactnotes )
+
+
+##### kopete_contactnotes (module) ##############
+
+tde_add_kpart( kopete_contactnotes AUTOMOC
+ SOURCES contactnotesplugin.cpp contactnotesedit.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/cryptography/CMakeLists.txt b/kopete/plugins/cryptography/CMakeLists.txt
new file mode 100644
index 00000000..4952d8e2
--- /dev/null
+++ b/kopete/plugins/cryptography/CMakeLists.txt
@@ -0,0 +1,53 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( icons )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_cryptography.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_cryptography_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+install( FILES cryptographyui.rc cryptographychatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_cryptography )
+
+
+##### kopete_cryptography (module) ##############
+
+tde_add_kpart( kopete_cryptography AUTOMOC
+ SOURCES
+ cryptographyplugin.cpp kgpginterface.cpp
+ cryptographyguiclient.cpp cryptographyselectuserkey.cpp
+ cryptographyuserkey_ui.ui popuppublic.cpp kgpgselkey.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_cryptography (module) ##########
+
+tde_add_kpart( kcm_kopete_cryptography AUTOMOC
+ SOURCES
+ cryptographypreferences.cpp cryptographyprefsbase.ui
+ kgpgselkey.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/cryptography/icons/CMakeLists.txt b/kopete/plugins/cryptography/icons/CMakeLists.txt
new file mode 100644
index 00000000..a3136b6f
--- /dev/null
+++ b/kopete/plugins/cryptography/icons/CMakeLists.txt
@@ -0,0 +1,13 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/plugins/cryptography/kgpgselkey.h b/kopete/plugins/cryptography/kgpgselkey.h
index 20b3dfd2..1e357482 100644
--- a/kopete/plugins/cryptography/kgpgselkey.h
+++ b/kopete/plugins/cryptography/kgpgselkey.h
@@ -26,7 +26,7 @@
class KListView;
class TQCheckBox;
-typedef struct gpgKey{
+struct gpgKey {
TQString gpgkeymail;
TQString gpgkeyname;
TQString gpgkeyid;
diff --git a/kopete/plugins/highlight/CMakeLists.txt b/kopete/plugins/highlight/CMakeLists.txt
new file mode 100644
index 00000000..312252bf
--- /dev/null
+++ b/kopete/plugins/highlight/CMakeLists.txt
@@ -0,0 +1,52 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( icons )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_highlight.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_highlight_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+
+
+##### kopete_highlight (module) #################
+
+tde_add_kpart( kopete_highlight AUTOMOC
+ SOURCES
+ highlightplugin.cpp highlightconfig.cpp filter.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_highlight (module) #############
+
+tde_add_kpart( kcm_kopete_highlight AUTOMOC
+ SOURCES
+ highlightprefsbase.ui highlightpreferences.cpp
+ filter.cpp highlightconfig.cpp
+ LINK kutils-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/highlight/icons/CMakeLists.txt b/kopete/plugins/highlight/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/plugins/highlight/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/plugins/history/CMakeLists.txt b/kopete/plugins/history/CMakeLists.txt
new file mode 100644
index 00000000..4d118d91
--- /dev/null
+++ b/kopete/plugins/history/CMakeLists.txt
@@ -0,0 +1,55 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions( ${KDE_PLUGIN} )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_history.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES historyui.rc historychatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_history )
+install( FILES kopete_history_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+install( FILES historyconfig.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
+
+
+##### kopete_history (module) ###################
+
+tde_add_kpart( kopete_history AUTOMOC
+ SOURCES
+ historyplugin.cpp historydialog.cpp historyviewer.ui
+ historylogger.cpp converter.cpp historyguiclient.cpp
+ historyconfig.kcfgc
+ LINK kopete-shared khtml-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_history (module) ###############
+
+tde_add_kpart( kcm_kopete_history AUTOMOC
+ SOURCES
+ historyprefsui.ui historypreferences.cpp
+ historyconfig.kcfgc
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/latex/CMakeLists.txt b/kopete/plugins/latex/CMakeLists.txt
new file mode 100644
index 00000000..18433acd
--- /dev/null
+++ b/kopete/plugins/latex/CMakeLists.txt
@@ -0,0 +1,53 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( icons )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_latex.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_latex_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+install( FILES kopete_latexconvert.sh DESTINATION ${BIN_INSTALL_DIR} )
+install( FILES latexconfig.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
+install( FILES latexchatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_latex )
+
+
+##### kopete_latex (module) #####################
+
+tde_add_kpart( kopete_latex AUTOMOC
+ SOURCES
+ latexplugin.cpp latexconfig.kcfgc latexguiclient.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_latex (module) #######################
+
+tde_add_kpart( kcm_kopete_latex AUTOMOC
+ SOURCES
+ latexprefsbase.ui latexpreferences.cpp latexconfig.kcfgc
+ LINK kutils-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/latex/icons/CMakeLists.txt b/kopete/plugins/latex/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/plugins/latex/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/plugins/motionautoaway/CMakeLists.txt b/kopete/plugins/motionautoaway/CMakeLists.txt
new file mode 100644
index 00000000..bc750e89
--- /dev/null
+++ b/kopete/plugins/motionautoaway/CMakeLists.txt
@@ -0,0 +1,51 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_motionaway.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_motionaway_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+install( FILES motionawayconfig.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
+
+
+##### kopete_motionaway (module) ################
+
+tde_add_kpart( kopete_motionaway AUTOMOC
+ SOURCES
+ motionawayplugin.cpp motionawayconfig.kcfgc
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_motionaway (module) ############
+
+tde_add_kpart( kcm_kopete_motionaway AUTOMOC
+ SOURCES
+ motionawayprefs.ui motionawaypreferences.cpp
+ motionawayconfig.kcfgc
+ LINK kutils-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/netmeeting/CMakeLists.txt b/kopete/plugins/netmeeting/CMakeLists.txt
new file mode 100644
index 00000000..b6cc0313
--- /dev/null
+++ b/kopete/plugins/netmeeting/CMakeLists.txt
@@ -0,0 +1,56 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+if( NOT BUILD_KOPETE_PROTOCOL_MSN )
+ tde_message_error( "netmeeting plugin needs msn protocol.\n Add -DBUILD_KOPETE_PROTOCOL_MSN=ON to cmake flags." )
+endif( )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/protocols/msn
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_netmeeting.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_netmeeting_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+install( FILES netmeetingchatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_netmeeting )
+
+
+##### kopete_netmeeting (module) ################
+
+tde_add_kpart( kopete_netmeeting AUTOMOC
+ SOURCES
+ netmeetingplugin.cpp netmeetinginvitation.cpp
+ netmeetingguiclient.cpp
+ LINK kopete_msn_shared-shared kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_netmeeting (module) ############
+
+tde_add_kpart( kcm_kopete_netmeeting AUTOMOC
+ SOURCES
+ netmeetingprefs_ui.ui netmeetingpreferences.cpp
+ LINK kutils-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/nowlistening/CMakeLists.txt b/kopete/plugins/nowlistening/CMakeLists.txt
new file mode 100644
index 00000000..b1b6b198
--- /dev/null
+++ b/kopete/plugins/nowlistening/CMakeLists.txt
@@ -0,0 +1,54 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_nowlistening.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_nowlistening_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+install( FILES nowlisteningconfig.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
+install( FILES nowlisteningui.rc nowlisteningchatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete )
+
+
+##### kopete_nowlistening (module) ##############
+
+tde_add_kpart( kopete_nowlistening AUTOMOC
+ SOURCES
+ nowlisteningconfig.kcfgc nowlisteningplugin.cpp nlkscd.cpp
+ nlnoatun.cpp nlxmms.cpp nowlisteningguiclient.cpp nljuk.cpp
+ nlamarok.cpp nlkaffeine.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_nowlistening (module) ##########
+
+tde_add_kpart( kcm_kopete_nowlistening AUTOMOC
+ SOURCES
+ nowlisteningprefs.ui nowlisteningpreferences.cpp
+ nowlisteningconfig.kcfgc
+ LINK kutils-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/smpppdcs/CMakeLists.txt b/kopete/plugins/smpppdcs/CMakeLists.txt
new file mode 100644
index 00000000..cac131f9
--- /dev/null
+++ b/kopete/plugins/smpppdcs/CMakeLists.txt
@@ -0,0 +1,59 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( icons )
+add_subdirectory( libsmpppdclient )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/libsmpppdclient
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_smpppdcs.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_smpppdcs_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+install( FILES smpppdcs.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
+
+
+##### kopete_smpppdcs (module) ##################
+
+tde_add_kpart( kopete_smpppdcs AUTOMOC
+ SOURCES
+ kinternetiface.stub smpppdcsplugin.cpp onlineinquiry.cpp
+ smpppdcsiface.skel detectordcop.cpp detectorsmpppd.cpp
+ detectornetstat.cpp detectornetworkstatus.cpp smpppdcsconfig.kcfgc
+ LINK smpppdclient-static kopete-shared crypto
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_smpppdcs (module) ##############
+
+tde_add_kpart( kcm_kopete_smpppdcs AUTOMOC
+ SOURCES
+ smpppdcsprefs.ui smpppdcspreferences.cpp smpppdsearcher.cpp
+ smpppdcsprefsimpl.cpp smpppdlocationui.ui smpppdlocationwidget.cpp
+ smpppdcsconfig.kcfgc
+ LINK smpppdclient-static kopete-shared crypto
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/smpppdcs/icons/CMakeLists.txt b/kopete/plugins/smpppdcs/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/plugins/smpppdcs/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/plugins/smpppdcs/libsmpppdclient/CMakeLists.txt b/kopete/plugins/smpppdcs/libsmpppdclient/CMakeLists.txt
new file mode 100644
index 00000000..e56ea8d4
--- /dev/null
+++ b/kopete/plugins/smpppdcs/libsmpppdclient/CMakeLists.txt
@@ -0,0 +1,23 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### smpppdclient (static) #####################
+
+tde_add_library( smpppdclient STATIC_PIC
+ SOURCES
+ smpppdclient.cpp smpppdstate.cpp smpppdready.cpp smpppdunsettled.cpp
+)
diff --git a/kopete/plugins/statistics/CMakeLists.txt b/kopete/plugins/statistics/CMakeLists.txt
new file mode 100644
index 00000000..629aa9c7
--- /dev/null
+++ b/kopete/plugins/statistics/CMakeLists.txt
@@ -0,0 +1,45 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include( ConfigureChecks.cmake )
+
+add_subdirectory( images )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+ ${SQLITE_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_statistics.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES statisticsui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_statistics )
+
+
+##### kopete_statistics (module) ################
+
+tde_add_kpart( kopete_statistics AUTOMOC
+ SOURCES
+ statisticsplugin.cpp statisticsdb.cpp statisticsdialog.cpp
+ statisticswidget.ui statisticscontact.cpp statisticsdcopiface.skel
+ LINK kopete-shared khtml-shared ${SQLITE_LIBRARIES}
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/statistics/ConfigureChecks.cmake b/kopete/plugins/statistics/ConfigureChecks.cmake
new file mode 100644
index 00000000..429214ee
--- /dev/null
+++ b/kopete/plugins/statistics/ConfigureChecks.cmake
@@ -0,0 +1,15 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+pkg_search_module( SQLITE sqlite3 )
+if( NOT SQLITE_FOUND )
+ tde_message_fatal( "sqlite3 is required, but was not found on your system" )
+endif( )
diff --git a/kopete/plugins/statistics/images/CMakeLists.txt b/kopete/plugins/statistics/images/CMakeLists.txt
new file mode 100644
index 00000000..e411a9af
--- /dev/null
+++ b/kopete/plugins/statistics/images/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ blue.png navy.png black.png gray.png
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/pics/statistics )
diff --git a/kopete/plugins/statistics/sqlite/Makefile.am b/kopete/plugins/statistics/sqlite/Makefile.am
deleted file mode 100644
index f647c6d5..00000000
--- a/kopete/plugins/statistics/sqlite/Makefile.am
+++ /dev/null
@@ -1,51 +0,0 @@
-noinst_LTLIBRARIES = \
- libsqlite.la
-
-KDE_CFLAGS = \
- -w
-
-libsqlite_la_CFLAGS = \
- $(all_includes) \
- -DTHREADSAFE=1
-
-libsqlite_la_LDFLAGS = \
- $(LIBPTHREAD)
-
-libsqlite_la_SOURCES = \
- attach.c \
- auth.c \
- btree.c \
- build.c \
- date.c \
- delete.c \
- encode.c \
- expr.c \
- func.c \
- hash.c \
- insert.c \
- legacy.c \
- main.c \
- opcodes.c \
- os_mac.c \
- os_unix.c \
- os_win.c \
- pager.c \
- parse.c \
- pragma.c \
- printf.c \
- random.c \
- select.c \
- shell.c \
- table.c \
- tokenize.c \
- trigger.c \
- update.c \
- utf.c \
- util.c \
- vacuum.c \
- vdbe.c \
- vdbeapi.c \
- vdbeaux.c \
- vdbemem.c \
- where.c
-
diff --git a/kopete/plugins/statistics/sqlite/attach.c b/kopete/plugins/statistics/sqlite/attach.c
deleted file mode 100644
index 2f089986..00000000
--- a/kopete/plugins/statistics/sqlite/attach.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
-** 2003 April 6
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains code used to implement the ATTACH and DETACH commands.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-
-/*
-** This routine is called by the parser to process an ATTACH statement:
-**
-** ATTACH DATABASE filename AS dbname
-**
-** The pFilename and pDbname arguments are the tokens that define the
-** filename and dbname in the ATTACH statement.
-*/
-void sqlite3Attach(
- Parse *pParse, /* The parser context */
- Token *pFilename, /* Name of database file */
- Token *pDbname, /* Name of the database to use internally */
- int keyType, /* 0: no key. 1: TEXT, 2: BLOB */
- Token *pKey /* Text of the key for keytype 1 and 2 */
-){
- Db *aNew;
- int rc, i;
- char *zFile, *zName;
- sqlite3 *db;
- Vdbe *v;
-
- v = sqlite3GetVdbe(pParse);
- if( !v ) return;
- sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
- if( pParse->explain ) return;
- db = pParse->db;
- if( db->nDb>=MAX_ATTACHED+2 ){
- sqlite3ErrorMsg(pParse, "too many attached databases - max %d",
- MAX_ATTACHED);
- pParse->rc = SQLITE_ERROR;
- return;
- }
-
- if( !db->autoCommit ){
- sqlite3ErrorMsg(pParse, "cannot ATTACH database within transaction");
- pParse->rc = SQLITE_ERROR;
- return;
- }
-
- zFile = sqlite3NameFromToken(pFilename);;
- if( zFile==0 ) return;
-#ifndef SQLITE_OMIT_AUTHORIZATION
- if( sqlite3AuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){
- sqliteFree(zFile);
- return;
- }
-#endif /* SQLITE_OMIT_AUTHORIZATION */
-
- zName = sqlite3NameFromToken(pDbname);
- if( zName==0 ) return;
- for(i=0; i<db->nDb; i++){
- char *z = db->aDb[i].zName;
- if( z && sqlite3StrICmp(z, zName)==0 ){
- sqlite3ErrorMsg(pParse, "database %z is already in use", zName);
- pParse->rc = SQLITE_ERROR;
- sqliteFree(zFile);
- return;
- }
- }
-
- if( db->aDb==db->aDbStatic ){
- aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
- if( aNew==0 ) return;
- memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
- }else{
- aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
- if( aNew==0 ) return;
- }
- db->aDb = aNew;
- aNew = &db->aDb[db->nDb++];
- memset(aNew, 0, sizeof(*aNew));
- sqlite3HashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
- aNew->zName = zName;
- aNew->safety_level = 3;
- rc = sqlite3BtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
- if( rc ){
- sqlite3ErrorMsg(pParse, "unable to open database: %s", zFile);
- }
-#if SQLITE_HAS_CODEC
- {
- extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
- char *zKey;
- int nKey;
- if( keyType==0 ){
- /* No key specified. Use the key from the main database */
- extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
- sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
- }else if( keyType==1 ){
- /* Key specified as text */
- zKey = sqlite3NameFromToken(pKey);
- nKey = strlen(zKey);
- }else{
- /* Key specified as a BLOB */
- char *zTemp;
- assert( keyType==2 );
- pKey->z++;
- pKey->n--;
- zTemp = sqlite3NameFromToken(pKey);
- zKey = sqlite3HexToBlob(zTemp);
- sqliteFree(zTemp);
- }
- sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
- if( keyType ){
- sqliteFree(zKey);
- }
- }
-#endif
- sqliteFree(zFile);
- db->flags &= ~SQLITE_Initialized;
- if( pParse->nErr==0 && rc==SQLITE_OK ){
- rc = sqlite3ReadSchema(pParse);
- }
- if( rc ){
- int i = db->nDb - 1;
- assert( i>=2 );
- if( db->aDb[i].pBt ){
- sqlite3BtreeClose(db->aDb[i].pBt);
- db->aDb[i].pBt = 0;
- }
- sqlite3ResetInternalSchema(db, 0);
- if( 0==pParse->nErr ){
- pParse->nErr++;
- pParse->rc = SQLITE_ERROR;
- }
- }
-}
-
-/*
-** This routine is called by the parser to process a DETACH statement:
-**
-** DETACH DATABASE dbname
-**
-** The pDbname argument is the name of the database in the DETACH statement.
-*/
-void sqlite3Detach(Parse *pParse, Token *pDbname){
- int i;
- sqlite3 *db;
- Vdbe *v;
- Db *pDb = 0;
-
- v = sqlite3GetVdbe(pParse);
- if( !v ) return;
- sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
- if( pParse->explain ) return;
- db = pParse->db;
- for(i=0; i<db->nDb; i++){
- pDb = &db->aDb[i];
- if( pDb->pBt==0 || pDb->zName==0 ) continue;
- if( strlen(pDb->zName)!=pDbname->n ) continue;
- if( sqlite3StrNICmp(pDb->zName, pDbname->z, pDbname->n)==0 ) break;
- }
- if( i>=db->nDb ){
- sqlite3ErrorMsg(pParse, "no such database: %T", pDbname);
- return;
- }
- if( i<2 ){
- sqlite3ErrorMsg(pParse, "cannot detach database %T", pDbname);
- return;
- }
- if( !db->autoCommit ){
- sqlite3ErrorMsg(pParse, "cannot DETACH database within transaction");
- pParse->rc = SQLITE_ERROR;
- return;
- }
-#ifndef SQLITE_OMIT_AUTHORIZATION
- if( sqlite3AuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){
- return;
- }
-#endif /* SQLITE_OMIT_AUTHORIZATION */
- sqlite3BtreeClose(pDb->pBt);
- pDb->pBt = 0;
- sqlite3ResetInternalSchema(db, 0);
-}
-
-/*
-** Initialize a DbFixer structure. This routine must be called prior
-** to passing the structure to one of the sqliteFixAAAA() routines below.
-**
-** The return value indicates whether or not fixation is required. TRUE
-** means we do need to fix the database references, FALSE means we do not.
-*/
-int sqlite3FixInit(
- DbFixer *pFix, /* The fixer to be initialized */
- Parse *pParse, /* Error messages will be written here */
- int iDb, /* This is the database that must be used */
- const char *zType, /* "view", "trigger", or "index" */
- const Token *pName /* Name of the view, trigger, or index */
-){
- sqlite3 *db;
-
- if( iDb<0 || iDb==1 ) return 0;
- db = pParse->db;
- assert( db->nDb>iDb );
- pFix->pParse = pParse;
- pFix->zDb = db->aDb[iDb].zName;
- pFix->zType = zType;
- pFix->pName = pName;
- return 1;
-}
-
-/*
-** The following set of routines walk through the parse tree and assign
-** a specific database to all table references where the database name
-** was left unspecified in the original SQL statement. The pFix structure
-** must have been initialized by a prior call to sqlite3FixInit().
-**
-** These routines are used to make sure that an index, trigger, or
-** view in one database does not refer to objects in a different database.
-** (Exception: indices, triggers, and views in the TEMP database are
-** allowed to refer to anything.) If a reference is explicitly made
-** to an object in a different database, an error message is added to
-** pParse->zErrMsg and these routines return non-zero. If everything
-** checks out, these routines return 0.
-*/
-int sqlite3FixSrcList(
- DbFixer *pFix, /* Context of the fixation */
- SrcList *pList /* The Source list to check and modify */
-){
- int i;
- const char *zDb;
- struct SrcList_item *pItem;
-
- if( pList==0 ) return 0;
- zDb = pFix->zDb;
- for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
- if( pItem->zDatabase==0 ){
- pItem->zDatabase = sqliteStrDup(zDb);
- }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
- sqlite3ErrorMsg(pFix->pParse,
- "%s %T cannot reference objects in database %s",
- pFix->zType, pFix->pName, pItem->zDatabase);
- return 1;
- }
- if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
- if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
- }
- return 0;
-}
-int sqlite3FixSelect(
- DbFixer *pFix, /* Context of the fixation */
- Select *pSelect /* The SELECT statement to be fixed to one database */
-){
- while( pSelect ){
- if( sqlite3FixExprList(pFix, pSelect->pEList) ){
- return 1;
- }
- if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
- return 1;
- }
- if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
- return 1;
- }
- if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
- return 1;
- }
- pSelect = pSelect->pPrior;
- }
- return 0;
-}
-int sqlite3FixExpr(
- DbFixer *pFix, /* Context of the fixation */
- Expr *pExpr /* The expression to be fixed to one database */
-){
- while( pExpr ){
- if( sqlite3FixSelect(pFix, pExpr->pSelect) ){
- return 1;
- }
- if( sqlite3FixExprList(pFix, pExpr->pList) ){
- return 1;
- }
- if( sqlite3FixExpr(pFix, pExpr->pRight) ){
- return 1;
- }
- pExpr = pExpr->pLeft;
- }
- return 0;
-}
-int sqlite3FixExprList(
- DbFixer *pFix, /* Context of the fixation */
- ExprList *pList /* The expression to be fixed to one database */
-){
- int i;
- struct ExprList_item *pItem;
- if( pList==0 ) return 0;
- for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){
- if( sqlite3FixExpr(pFix, pItem->pExpr) ){
- return 1;
- }
- }
- return 0;
-}
-int sqlite3FixTriggerStep(
- DbFixer *pFix, /* Context of the fixation */
- TriggerStep *pStep /* The trigger step be fixed to one database */
-){
- while( pStep ){
- if( sqlite3FixSelect(pFix, pStep->pSelect) ){
- return 1;
- }
- if( sqlite3FixExpr(pFix, pStep->pWhere) ){
- return 1;
- }
- if( sqlite3FixExprList(pFix, pStep->pExprList) ){
- return 1;
- }
- pStep = pStep->pNext;
- }
- return 0;
-}
diff --git a/kopete/plugins/statistics/sqlite/auth.c b/kopete/plugins/statistics/sqlite/auth.c
deleted file mode 100644
index b251eacf..00000000
--- a/kopete/plugins/statistics/sqlite/auth.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
-** 2003 January 11
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains code used to implement the sqlite3_set_authorizer()
-** API. This facility is an optional feature of the library. Embedded
-** systems that do not need this facility may omit it by recompiling
-** the library with -DSQLITE_OMIT_AUTHORIZATION=1
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-
-/*
-** All of the code in this file may be omitted by defining a single
-** macro.
-*/
-#ifndef SQLITE_OMIT_AUTHORIZATION
-
-/*
-** Set or clear the access authorization function.
-**
-** The access authorization function is be called during the compilation
-** phase to verify that the user has read and/or write access permission on
-** various fields of the database. The first argument to the auth function
-** is a copy of the 3rd argument to this routine. The second argument
-** to the auth function is one of these constants:
-**
-** SQLITE_CREATE_INDEX
-** SQLITE_CREATE_TABLE
-** SQLITE_CREATE_TEMP_INDEX
-** SQLITE_CREATE_TEMP_TABLE
-** SQLITE_CREATE_TEMP_TRIGGER
-** SQLITE_CREATE_TEMP_VIEW
-** SQLITE_CREATE_TRIGGER
-** SQLITE_CREATE_VIEW
-** SQLITE_DELETE
-** SQLITE_DROP_INDEX
-** SQLITE_DROP_TABLE
-** SQLITE_DROP_TEMP_INDEX
-** SQLITE_DROP_TEMP_TABLE
-** SQLITE_DROP_TEMP_TRIGGER
-** SQLITE_DROP_TEMP_VIEW
-** SQLITE_DROP_TRIGGER
-** SQLITE_DROP_VIEW
-** SQLITE_INSERT
-** SQLITE_PRAGMA
-** SQLITE_READ
-** SQLITE_SELECT
-** SQLITE_TRANSACTION
-** SQLITE_UPDATE
-**
-** The third and fourth arguments to the auth function are the name of
-** the table and the column that are being accessed. The auth function
-** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. If
-** SQLITE_OK is returned, it means that access is allowed. SQLITE_DENY
-** means that the SQL statement will never-run - the sqlite3_exec() call
-** will return with an error. SQLITE_IGNORE means that the SQL statement
-** should run but attempts to read the specified column will return NULL
-** and attempts to write the column will be ignored.
-**
-** Setting the auth function to NULL disables this hook. The default
-** setting of the auth function is NULL.
-*/
-int sqlite3_set_authorizer(
- sqlite3 *db,
- int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
- void *pArg
-){
- db->xAuth = xAuth;
- db->pAuthArg = pArg;
- return SQLITE_OK;
-}
-
-/*
-** Write an error message into pParse->zErrMsg that explains that the
-** user-supplied authorization function returned an illegal value.
-*/
-static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
- sqlite3ErrorMsg(pParse, "illegal return value (%d) from the "
- "authorization function - should be SQLITE_OK, SQLITE_IGNORE, "
- "or SQLITE_DENY", rc);
- pParse->rc = SQLITE_ERROR;
-}
-
-/*
-** The pExpr should be a TK_COLUMN expression. The table referred to
-** is in pTabList or else it is the NEW or OLD table of a trigger.
-** Check to see if it is OK to read this particular column.
-**
-** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
-** instruction into a TK_NULL. If the auth function returns SQLITE_DENY,
-** then generate an error.
-*/
-void sqlite3AuthRead(
- Parse *pParse, /* The parser context */
- Expr *pExpr, /* The expression to check authorization on */
- SrcList *pTabList /* All table that pExpr might refer to */
-){
- sqlite3 *db = pParse->db;
- int rc;
- Table *pTab; /* The table being read */
- const char *zCol; /* Name of the column of the table */
- int iSrc; /* Index in pTabList->a[] of table being read */
- const char *zDBase; /* Name of database being accessed */
- TriggerStack *pStack; /* The stack of current triggers */
-
- if( db->xAuth==0 ) return;
- assert( pExpr->op==TK_COLUMN );
- for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
- if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
- }
- if( iSrc>=0 && iSrc<pTabList->nSrc ){
- pTab = pTabList->a[iSrc].pTab;
- }else if( (pStack = pParse->trigStack)!=0 ){
- /* This must be an attempt to read the NEW or OLD pseudo-tables
- ** of a trigger.
- */
- assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx );
- pTab = pStack->pTab;
- }else{
- return;
- }
- if( pTab==0 ) return;
- if( pExpr->iColumn>=0 ){
- assert( pExpr->iColumn<pTab->nCol );
- zCol = pTab->aCol[pExpr->iColumn].zName;
- }else if( pTab->iPKey>=0 ){
- assert( pTab->iPKey<pTab->nCol );
- zCol = pTab->aCol[pTab->iPKey].zName;
- }else{
- zCol = "ROWID";
- }
- assert( pExpr->iDb<db->nDb );
- zDBase = db->aDb[pExpr->iDb].zName;
- rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase,
- pParse->zAuthContext);
- if( rc==SQLITE_IGNORE ){
- pExpr->op = TK_NULL;
- }else if( rc==SQLITE_DENY ){
- if( db->nDb>2 || pExpr->iDb!=0 ){
- sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",
- zDBase, pTab->zName, zCol);
- }else{
- sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited",pTab->zName,zCol);
- }
- pParse->rc = SQLITE_AUTH;
- }else if( rc!=SQLITE_OK ){
- sqliteAuthBadReturnCode(pParse, rc);
- }
-}
-
-/*
-** Do an authorization check using the code and arguments given. Return
-** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY
-** is returned, then the error count and error message in pParse are
-** modified appropriately.
-*/
-int sqlite3AuthCheck(
- Parse *pParse,
- int code,
- const char *zArg1,
- const char *zArg2,
- const char *zArg3
-){
- sqlite3 *db = pParse->db;
- int rc;
-
- /* Don't do any authorization checks if the database is initialising. */
- if( db->init.busy ){
- return SQLITE_OK;
- }
-
- if( db->xAuth==0 ){
- return SQLITE_OK;
- }
- rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext);
- if( rc==SQLITE_DENY ){
- sqlite3ErrorMsg(pParse, "not authorized");
- pParse->rc = SQLITE_AUTH;
- }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
- rc = SQLITE_DENY;
- sqliteAuthBadReturnCode(pParse, rc);
- }
- return rc;
-}
-
-/*
-** Push an authorization context. After this routine is called, the
-** zArg3 argument to authorization callbacks will be zContext until
-** popped. Or if pParse==0, this routine is a no-op.
-*/
-void sqlite3AuthContextPush(
- Parse *pParse,
- AuthContext *pContext,
- const char *zContext
-){
- pContext->pParse = pParse;
- if( pParse ){
- pContext->zAuthContext = pParse->zAuthContext;
- pParse->zAuthContext = zContext;
- }
-}
-
-/*
-** Pop an authorization context that was previously pushed
-** by sqlite3AuthContextPush
-*/
-void sqlite3AuthContextPop(AuthContext *pContext){
- if( pContext->pParse ){
- pContext->pParse->zAuthContext = pContext->zAuthContext;
- pContext->pParse = 0;
- }
-}
-
-#endif /* SQLITE_OMIT_AUTHORIZATION */
diff --git a/kopete/plugins/statistics/sqlite/btree.c b/kopete/plugins/statistics/sqlite/btree.c
deleted file mode 100644
index fe8754e0..00000000
--- a/kopete/plugins/statistics/sqlite/btree.c
+++ /dev/null
@@ -1,4462 +0,0 @@
-/*
-** 2004 April 6
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** $Id$
-**
-** This file implements a external (disk-based) database using BTrees.
-** For a detailed discussion of BTrees, refer to
-**
-** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
-** "Sorting And Searching", pages 473-480. Addison-Wesley
-** Publishing Company, Reading, Massachusetts.
-**
-** The basic idea is that each page of the file contains N database
-** entries and N+1 pointers to subpages.
-**
-** ----------------------------------------------------------------
-** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N) | Ptr(N+1) |
-** ----------------------------------------------------------------
-**
-** All of the keys on the page that Ptr(0) points to have values less
-** than Key(0). All of the keys on page Ptr(1) and its subpages have
-** values greater than Key(0) and less than Key(1). All of the keys
-** on Ptr(N+1) and its subpages have values greater than Key(N). And
-** so forth.
-**
-** Finding a particular key requires reading O(log(M)) pages from the
-** disk where M is the number of entries in the tree.
-**
-** In this implementation, a single file can hold one or more separate
-** BTrees. Each BTree is identified by the index of its root page. The
-** key and data for any entry are combined to form the "payload". A
-** fixed amount of payload can be carried directly on the database
-** page. If the payload is larger than the preset amount then surplus
-** bytes are stored on overflow pages. The payload for an entry
-** and the preceding pointer are combined to form a "Cell". Each
-** page has a small header which contains the Ptr(N+1) pointer and other
-** information such as the size of key and data.
-**
-** FORMAT DETAILS
-**
-** The file is divided into pages. The first page is called page 1,
-** the second is page 2, and so forth. A page number of zero indicates
-** "no such page". The page size can be anything between 512 and 65536.
-** Each page can be either a btree page, a freelist page or an overflow
-** page.
-**
-** The first page is always a btree page. The first 100 bytes of the first
-** page contain a special header (the "file header") that describes the file.
-** The format of the file header is as follows:
-**
-** OFFSET SIZE DESCRIPTION
-** 0 16 Header string: "SQLite format 3\000"
-** 16 2 Page size in bytes.
-** 18 1 File format write version
-** 19 1 File format read version
-** 20 1 Bytes of unused space at the end of each page
-** 21 1 Max embedded payload fraction
-** 22 1 Min embedded payload fraction
-** 23 1 Min leaf payload fraction
-** 24 4 File change counter
-** 28 4 Reserved for future use
-** 32 4 First freelist page
-** 36 4 Number of freelist pages in the file
-** 40 60 15 4-byte meta values passed to higher layers
-**
-** All of the integer values are big-endian (most significant byte first).
-**
-** The file change counter is incremented when the database is changed more
-** than once within the same second. This counter, together with the
-** modification time of the file, allows other processes to know
-** when the file has changed and thus when they need to flush their
-** cache.
-**
-** The max embedded payload fraction is the amount of the total usable
-** space in a page that can be consumed by a single cell for standard
-** B-tree (non-LEAFDATA) tables. A value of 255 means 100%. The default
-** is to limit the maximum cell size so that at least 4 cells will fit
-** on one page. Thus the default max embedded payload fraction is 64.
-**
-** If the payload for a cell is larger than the max payload, then extra
-** payload is spilled to overflow pages. Once an overflow page is allocated,
-** as many bytes as possible are moved into the overflow pages without letting
-** the cell size drop below the min embedded payload fraction.
-**
-** The min leaf payload fraction is like the min embedded payload fraction
-** except that it applies to leaf nodes in a LEAFDATA tree. The maximum
-** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
-** not specified in the header.
-**
-** Each btree pages is divided into three sections: The header, the
-** cell pointer array, and the cell area area. Page 1 also has a 100-byte
-** file header that occurs before the page header.
-**
-** |----------------|
-** | file header | 100 bytes. Page 1 only.
-** |----------------|
-** | page header | 8 bytes for leaves. 12 bytes for interior nodes
-** |----------------|
-** | cell pointer | | 2 bytes per cell. Sorted order.
-** | array | | Grows downward
-** | | v
-** |----------------|
-** | unallocated |
-** | space |
-** |----------------| ^ Grows upwards
-** | cell content | | Arbitrary order interspersed with freeblocks.
-** | area | | and free space fragments.
-** |----------------|
-**
-** The page headers looks like this:
-**
-** OFFSET SIZE DESCRIPTION
-** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
-** 1 2 byte offset to the first freeblock
-** 3 2 number of cells on this page
-** 5 2 first byte of the cell content area
-** 7 1 number of fragmented free bytes
-** 8 4 Right child (the Ptr(N+1) value). Omitted on leaves.
-**
-** The flags define the format of this btree page. The leaf flag means that
-** this page has no children. The zerodata flag means that this page carries
-** only keys and no data. The intkey flag means that the key is a integer
-** which is stored in the key size entry of the cell header rather than in
-** the payload area.
-**
-** The cell pointer array begins on the first byte after the page header.
-** The cell pointer array contains zero or more 2-byte numbers which are
-** offsets from the beginning of the page to the cell content in the cell
-** content area. The cell pointers occur in sorted order. The system strives
-** to keep free space after the last cell pointer so that new cells can
-** be easily added without having to defragment the page.
-**
-** Cell content is stored at the very end of the page and grows toward the
-** beginning of the page.
-**
-** Unused space within the cell content area is collected into a linked list of
-** freeblocks. Each freeblock is at least 4 bytes in size. The byte offset
-** to the first freeblock is given in the header. Freeblocks occur in
-** increasing order. Because a freeblock must be at least 4 bytes in size,
-** any group of 3 or fewer unused bytes in the cell content area cannot
-** exist on the freeblock chain. A group of 3 or fewer free bytes is called
-** a fragment. The total number of bytes in all fragments is recorded.
-** in the page header at offset 7.
-**
-** SIZE DESCRIPTION
-** 2 Byte offset of the next freeblock
-** 2 Bytes in this freeblock
-**
-** Cells are of variable length. Cells are stored in the cell content area at
-** the end of the page. Pointers to the cells are in the cell pointer array
-** that immediately follows the page header. Cells is not necessarily
-** contiguous or in order, but cell pointers are contiguous and in order.
-**
-** Cell content makes use of variable length integers. A variable
-** length integer is 1 to 9 bytes where the lower 7 bits of each
-** byte are used. The integer consists of all bytes that have bit 8 set and
-** the first byte with bit 8 clear. The most significant byte of the integer
-** appears first. A variable-length integer may not be more than 9 bytes long.
-** As a special case, all 8 bytes of the 9th byte are used as data. This
-** allows a 64-bit integer to be encoded in 9 bytes.
-**
-** 0x00 becomes 0x00000000
-** 0x7f becomes 0x0000007f
-** 0x81 0x00 becomes 0x00000080
-** 0x82 0x00 becomes 0x00000100
-** 0x80 0x7f becomes 0x0000007f
-** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
-** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
-**
-** Variable length integers are used for rowids and to hold the number of
-** bytes of key and data in a btree cell.
-**
-** The content of a cell looks like this:
-**
-** SIZE DESCRIPTION
-** 4 Page number of the left child. Omitted if leaf flag is set.
-** var Number of bytes of data. Omitted if the zerodata flag is set.
-** var Number of bytes of key. Or the key itself if intkey flag is set.
-** * Payload
-** 4 First page of the overflow chain. Omitted if no overflow
-**
-** Overflow pages form a linked list. Each page except the last is completely
-** filled with data (pagesize - 4 bytes). The last page can have as little
-** as 1 byte of data.
-**
-** SIZE DESCRIPTION
-** 4 Page number of next overflow page
-** * Data
-**
-** Freelist pages come in two subtypes: trunk pages and leaf pages. The
-** file header points to first in a linked list of trunk page. Each trunk
-** page points to multiple leaf pages. The content of a leaf page is
-** unspecified. A trunk page looks like this:
-**
-** SIZE DESCRIPTION
-** 4 Page number of next trunk page
-** 4 Number of leaf pointers on this page
-** * zero or more pages numbers of leaves
-*/
-#include "sqliteInt.h"
-#include "pager.h"
-#include "btree.h"
-#include "os.h"
-#include <assert.h>
-
-
-/* The following value is the maximum cell size assuming a maximum page
-** size give above.
-*/
-#define MX_CELL_SIZE(pBt) (pBt->pageSize-8)
-
-/* The maximum number of cells on a single page of the database. This
-** assumes a minimum cell size of 3 bytes. Such small cells will be
-** exceedingly rare, but they are possible.
-*/
-#define MX_CELL(pBt) ((pBt->pageSize-8)/3)
-
-/* Forward declarations */
-typedef struct MemPage MemPage;
-
-/*
-** This is a magic string that appears at the beginning of every
-** SQLite database in order to identify the file as a real database.
-** 123456789 123456 */
-static const char zMagicHeader[] = "SQLite format 3";
-
-/*
-** Page type flags. An ORed combination of these flags appear as the
-** first byte of every BTree page.
-*/
-#define PTF_INTKEY 0x01
-#define PTF_ZERODATA 0x02
-#define PTF_LEAFDATA 0x04
-#define PTF_LEAF 0x08
-
-/*
-** As each page of the file is loaded into memory, an instance of the following
-** structure is appended and initialized to zero. This structure stores
-** information about the page that is decoded from the raw file page.
-**
-** The pParent field points back to the parent page. This allows us to
-** walk up the BTree from any leaf to the root. Care must be taken to
-** unref() the parent page pointer when this page is no longer referenced.
-** The pageDestructor() routine handles that chore.
-*/
-struct MemPage {
- u8 isInit; /* True if previously initialized. MUST BE FIRST! */
- u8 idxShift; /* True if Cell indices have changed */
- u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
- u8 intKey; /* True if intkey flag is set */
- u8 leaf; /* True if leaf flag is set */
- u8 zeroData; /* True if table stores keys only */
- u8 leafData; /* True if tables stores data on leaves only */
- u8 hasData; /* True if this page stores data */
- u8 hdrOffset; /* 100 for page 1. 0 otherwise */
- u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
- u16 maxLocal; /* Copy of Btree.maxLocal or Btree.maxLeaf */
- u16 minLocal; /* Copy of Btree.minLocal or Btree.minLeaf */
- u16 cellOffset; /* Index in aData of first cell pointer */
- u16 idxParent; /* Index in parent of this node */
- u16 nFree; /* Number of free bytes on the page */
- u16 nCell; /* Number of cells on this page, local and ovfl */
- struct _OvflCell { /* Cells that will not fit on aData[] */
- u8 *pCell; /* Pointers to the body of the overflow cell */
- u16 idx; /* Insert this cell before idx-th non-overflow cell */
- } aOvfl[5];
- struct Btree *pBt; /* Pointer back to BTree structure */
- u8 *aData; /* Pointer back to the start of the page */
- Pgno pgno; /* Page number for this page */
- MemPage *pParent; /* The parent of this page. NULL for root */
-};
-
-/*
-** The in-memory image of a disk page has the auxiliary information appended
-** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
-** that extra information.
-*/
-#define EXTRA_SIZE sizeof(MemPage)
-
-/*
-** Everything we need to know about an open database
-*/
-struct Btree {
- Pager *pPager; /* The page cache */
- BtCursor *pCursor; /* A list of all open cursors */
- MemPage *pPage1; /* First page of the database */
- u8 inTrans; /* True if a transaction is in progress */
- u8 inStmt; /* True if we are in a statement subtransaction */
- u8 readOnly; /* True if the underlying file is readonly */
- u8 maxEmbedFrac; /* Maximum payload as % of total page size */
- u8 minEmbedFrac; /* Minimum payload as % of total page size */
- u8 minLeafFrac; /* Minimum leaf payload as % of total page size */
- u8 pageSizeFixed; /* True if the page size can no longer be changed */
- u16 pageSize; /* Total number of bytes on a page */
- u16 usableSize; /* Number of usable bytes on each page */
- int maxLocal; /* Maximum local payload in non-LEAFDATA tables */
- int minLocal; /* Minimum local payload in non-LEAFDATA tables */
- int maxLeaf; /* Maximum local payload in a LEAFDATA table */
- int minLeaf; /* Minimum local payload in a LEAFDATA table */
-};
-typedef Btree Bt;
-
-/*
-** Btree.inTrans may take one of the following values.
-*/
-#define TRANS_NONE 0
-#define TRANS_READ 1
-#define TRANS_WRITE 2
-
-/*
-** An instance of the following structure is used to hold information
-** about a cell. The parseCellPtr() function fills in this structure
-** based on information extract from the raw disk page.
-*/
-typedef struct CellInfo CellInfo;
-struct CellInfo {
- u8 *pCell; /* Pointer to the start of cell content */
- i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
- u32 nData; /* Number of bytes of data */
- u16 nHeader; /* Size of the cell content header in bytes */
- u16 nLocal; /* Amount of payload held locally */
- u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
- u16 nSize; /* Size of the cell content on the main b-tree page */
-};
-
-/*
-** A cursor is a pointer to a particular entry in the BTree.
-** The entry is identified by its MemPage and the index in
-** MemPage.aCell[] of the entry.
-*/
-struct BtCursor {
- Btree *pBt; /* The Btree to which this cursor belongs */
- BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
- int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */
- void *pArg; /* First arg to xCompare() */
- Pgno pgnoRoot; /* The root page of this tree */
- MemPage *pPage; /* Page that contains the entry */
- int idx; /* Index of the entry in pPage->aCell[] */
- CellInfo info; /* A parse of the cell we are pointing at */
- u8 wrFlag; /* True if writable */
- u8 isValid; /* TRUE if points to a valid entry */
- u8 status; /* Set to SQLITE_ABORT if cursors is invalidated */
-};
-
-/*
-** Forward declaration
-*/
-static int checkReadLocks(Btree*,Pgno,BtCursor*);
-
-
-/*
-** Read or write a two- and four-byte big-endian integer values.
-*/
-static u32 get2byte(unsigned char *p){
- return (p[0]<<8) | p[1];
-}
-static u32 get4byte(unsigned char *p){
- return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
-}
-static void put2byte(unsigned char *p, u32 v){
- p[0] = v>>8;
- p[1] = v;
-}
-static void put4byte(unsigned char *p, u32 v){
- p[0] = v>>24;
- p[1] = v>>16;
- p[2] = v>>8;
- p[3] = v;
-}
-
-/*
-** Routines to read and write variable-length integers. These used to
-** be defined locally, but now we use the varint routines in the util.c
-** file.
-*/
-#define getVarint sqlite3GetVarint
-#define getVarint32 sqlite3GetVarint32
-#define putVarint sqlite3PutVarint
-
-/*
-** Given a btree page and a cell index (0 means the first cell on
-** the page, 1 means the second cell, and so forth) return a pointer
-** to the cell content.
-**
-** This routine works only for pages that do not contain overflow cells.
-*/
-static u8 *findCell(MemPage *pPage, int iCell){
- u8 *data = pPage->aData;
- assert( iCell>=0 );
- assert( iCell<get2byte(&data[pPage->hdrOffset+3]) );
- return data + get2byte(&data[pPage->cellOffset+2*iCell]);
-}
-
-/*
-** This a more complex version of findCell() that works for
-** pages that do contain overflow cells. See insert
-*/
-static u8 *findOverflowCell(MemPage *pPage, int iCell){
- int i;
- for(i=pPage->nOverflow-1; i>=0; i--){
- int k;
- struct _OvflCell *pOvfl;
- pOvfl = &pPage->aOvfl[i];
- k = pOvfl->idx;
- if( k<=iCell ){
- if( k==iCell ){
- return pOvfl->pCell;
- }
- iCell--;
- }
- }
- return findCell(pPage, iCell);
-}
-
-/*
-** Parse a cell content block and fill in the CellInfo structure. There
-** are two versions of this function. parseCell() takes a cell index
-** as the second argument and parseCellPtr() takes a pointer to the
-** body of the cell as its second argument.
-*/
-static void parseCellPtr(
- MemPage *pPage, /* Page containing the cell */
- u8 *pCell, /* Pointer to the cell text. */
- CellInfo *pInfo /* Fill in this structure */
-){
- int n; /* Number bytes in cell content header */
- u32 nPayload; /* Number of bytes of cell payload */
-
- pInfo->pCell = pCell;
- assert( pPage->leaf==0 || pPage->leaf==1 );
- n = pPage->childPtrSize;
- assert( n==4-4*pPage->leaf );
- if( pPage->hasData ){
- n += getVarint32(&pCell[n], &nPayload);
- }else{
- nPayload = 0;
- }
- n += getVarint(&pCell[n], (u64 *)&pInfo->nKey);
- pInfo->nHeader = n;
- pInfo->nData = nPayload;
- if( !pPage->intKey ){
- nPayload += pInfo->nKey;
- }
- if( nPayload<=pPage->maxLocal ){
- /* This is the (easy) common case where the entire payload fits
- ** on the local page. No overflow is required.
- */
- int nSize; /* Total size of cell content in bytes */
- pInfo->nLocal = nPayload;
- pInfo->iOverflow = 0;
- nSize = nPayload + n;
- if( nSize<4 ){
- nSize = 4; /* Minimum cell size is 4 */
- }
- pInfo->nSize = nSize;
- }else{
- /* If the payload will not fit completely on the local page, we have
- ** to decide how much to store locally and how much to spill onto
- ** overflow pages. The strategy is to minimize the amount of unused
- ** space on overflow pages while keeping the amount of local storage
- ** in between minLocal and maxLocal.
- **
- ** Warning: changing the way overflow payload is distributed in any
- ** way will result in an incompatible file format.
- */
- int minLocal; /* Minimum amount of payload held locally */
- int maxLocal; /* Maximum amount of payload held locally */
- int surplus; /* Overflow payload available for local storage */
-
- minLocal = pPage->minLocal;
- maxLocal = pPage->maxLocal;
- surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize - 4);
- if( surplus <= maxLocal ){
- pInfo->nLocal = surplus;
- }else{
- pInfo->nLocal = minLocal;
- }
- pInfo->iOverflow = pInfo->nLocal + n;
- pInfo->nSize = pInfo->iOverflow + 4;
- }
-}
-static void parseCell(
- MemPage *pPage, /* Page containing the cell */
- int iCell, /* The cell index. First cell is 0 */
- CellInfo *pInfo /* Fill in this structure */
-){
- parseCellPtr(pPage, findCell(pPage, iCell), pInfo);
-}
-
-/*
-** Compute the total number of bytes that a Cell needs in the cell
-** data area of the btree-page. The return number includes the cell
-** data header and the local payload, but not any overflow page or
-** the space used by the cell pointer.
-*/
-#ifndef NDEBUG
-static int cellSize(MemPage *pPage, int iCell){
- CellInfo info;
- parseCell(pPage, iCell, &info);
- return info.nSize;
-}
-#endif
-static int cellSizePtr(MemPage *pPage, u8 *pCell){
- CellInfo info;
- parseCellPtr(pPage, pCell, &info);
- return info.nSize;
-}
-
-/*
-** Do sanity checking on a page. Throw an exception if anything is
-** not right.
-**
-** This routine is used for internal error checking only. It is omitted
-** from most builds.
-*/
-#if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0
-static void _pageIntegrity(MemPage *pPage){
- int usableSize;
- u8 *data;
- int i, j, idx, c, pc, hdr, nFree;
- int cellOffset;
- int nCell, cellLimit;
- u8 *used;
-
- used = sqliteMallocRaw( pPage->pBt->pageSize );
- if( used==0 ) return;
- usableSize = pPage->pBt->usableSize;
- assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] );
- hdr = pPage->hdrOffset;
- assert( hdr==(pPage->pgno==1 ? 100 : 0) );
- assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
- c = pPage->aData[hdr];
- if( pPage->isInit ){
- assert( pPage->leaf == ((c & PTF_LEAF)!=0) );
- assert( pPage->zeroData == ((c & PTF_ZERODATA)!=0) );
- assert( pPage->leafData == ((c & PTF_LEAFDATA)!=0) );
- assert( pPage->intKey == ((c & (PTF_INTKEY|PTF_LEAFDATA))!=0) );
- assert( pPage->hasData ==
- !(pPage->zeroData || (!pPage->leaf && pPage->leafData)) );
- assert( pPage->cellOffset==pPage->hdrOffset+12-4*pPage->leaf );
- assert( pPage->nCell = get2byte(&pPage->aData[hdr+3]) );
- }
- data = pPage->aData;
- memset(used, 0, usableSize);
- for(i=0; i<hdr+10-pPage->leaf*4; i++) used[i] = 1;
- nFree = 0;
- pc = get2byte(&data[hdr+1]);
- while( pc ){
- int size;
- assert( pc>0 && pc<usableSize-4 );
- size = get2byte(&data[pc+2]);
- assert( pc+size<=usableSize );
- nFree += size;
- for(i=pc; i<pc+size; i++){
- assert( used[i]==0 );
- used[i] = 1;
- }
- pc = get2byte(&data[pc]);
- }
- idx = 0;
- nCell = get2byte(&data[hdr+3]);
- cellLimit = get2byte(&data[hdr+5]);
- assert( pPage->isInit==0
- || pPage->nFree==nFree+data[hdr+7]+cellLimit-(cellOffset+2*nCell) );
- cellOffset = pPage->cellOffset;
- for(i=0; i<nCell; i++){
- int size;
- pc = get2byte(&data[cellOffset+2*i]);
- assert( pc>0 && pc<usableSize-4 );
- size = cellSize(pPage, &data[pc]);
- assert( pc+size<=usableSize );
- for(j=pc; j<pc+size; j++){
- assert( used[j]==0 );
- used[j] = 1;
- }
- }
- for(i=cellOffset+2*nCell; i<cellimit; i++){
- assert( used[i]==0 );
- used[i] = 1;
- }
- nFree = 0;
- for(i=0; i<usableSize; i++){
- assert( used[i]<=1 );
- if( used[i]==0 ) nFree++;
- }
- assert( nFree==data[hdr+7] );
- sqliteFree(used);
-}
-#define pageIntegrity(X) _pageIntegrity(X)
-#else
-# define pageIntegrity(X)
-#endif
-
-/*
-** Defragment the page given. All Cells are moved to the
-** beginning of the page and all free space is collected
-** into one big FreeBlk at the end of the page.
-*/
-static int defragmentPage(MemPage *pPage){
- int i; /* Loop counter */
- int pc; /* Address of a i-th cell */
- int addr; /* Offset of first byte after cell pointer array */
- int hdr; /* Offset to the page header */
- int size; /* Size of a cell */
- int usableSize; /* Number of usable bytes on a page */
- int cellOffset; /* Offset to the cell pointer array */
- int brk; /* Offset to the cell content area */
- int nCell; /* Number of cells on the page */
- unsigned char *data; /* The page data */
- unsigned char *temp; /* Temp area for cell content */
-
- assert( sqlite3pager_iswriteable(pPage->aData) );
- assert( pPage->pBt!=0 );
- assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
- assert( pPage->nOverflow==0 );
- temp = sqliteMalloc( pPage->pBt->pageSize );
- if( temp==0 ) return SQLITE_NOMEM;
- data = pPage->aData;
- hdr = pPage->hdrOffset;
- cellOffset = pPage->cellOffset;
- nCell = pPage->nCell;
- assert( nCell==get2byte(&data[hdr+3]) );
- usableSize = pPage->pBt->usableSize;
- brk = get2byte(&data[hdr+5]);
- memcpy(&temp[brk], &data[brk], usableSize - brk);
- brk = usableSize;
- for(i=0; i<nCell; i++){
- u8 *pAddr; /* The i-th cell pointer */
- pAddr = &data[cellOffset + i*2];
- pc = get2byte(pAddr);
- assert( pc<pPage->pBt->usableSize );
- size = cellSizePtr(pPage, &temp[pc]);
- brk -= size;
- memcpy(&data[brk], &temp[pc], size);
- put2byte(pAddr, brk);
- }
- assert( brk>=cellOffset+2*nCell );
- put2byte(&data[hdr+5], brk);
- data[hdr+1] = 0;
- data[hdr+2] = 0;
- data[hdr+7] = 0;
- addr = cellOffset+2*nCell;
- memset(&data[addr], 0, brk-addr);
- sqliteFree(temp);
- return SQLITE_OK;
-}
-
-/*
-** Allocate nByte bytes of space on a page.
-**
-** Return the index into pPage->aData[] of the first byte of
-** the new allocation. Or return 0 if there is not enough free
-** space on the page to satisfy the allocation request.
-**
-** If the page contains nBytes of free space but does not contain
-** nBytes of contiguous free space, then this routine automatically
-** calls defragementPage() to consolidate all free space before
-** allocating the new chunk.
-*/
-static int allocateSpace(MemPage *pPage, int nByte){
- int addr, pc, hdr;
- int size;
- int nFrag;
- int top;
- int nCell;
- int cellOffset;
- unsigned char *data;
-
- data = pPage->aData;
- assert( sqlite3pager_iswriteable(data) );
- assert( pPage->pBt );
- if( nByte<4 ) nByte = 4;
- if( pPage->nFree<nByte || pPage->nOverflow>0 ) return 0;
- pPage->nFree -= nByte;
- hdr = pPage->hdrOffset;
-
- nFrag = data[hdr+7];
- if( nFrag<60 ){
- /* Search the freelist looking for a slot big enough to satisfy the
- ** space request. */
- addr = hdr+1;
- while( (pc = get2byte(&data[addr]))>0 ){
- size = get2byte(&data[pc+2]);
- if( size>=nByte ){
- if( size<nByte+4 ){
- memcpy(&data[addr], &data[pc], 2);
- data[hdr+7] = nFrag + size - nByte;
- return pc;
- }else{
- put2byte(&data[pc+2], size-nByte);
- return pc + size - nByte;
- }
- }
- addr = pc;
- }
- }
-
- /* Allocate memory from the gap in between the cell pointer array
- ** and the cell content area.
- */
- top = get2byte(&data[hdr+5]);
- nCell = get2byte(&data[hdr+3]);
- cellOffset = pPage->cellOffset;
- if( nFrag>=60 || cellOffset + 2*nCell > top - nByte ){
- if( defragmentPage(pPage) ) return 0;
- top = get2byte(&data[hdr+5]);
- }
- top -= nByte;
- assert( cellOffset + 2*nCell <= top );
- put2byte(&data[hdr+5], top);
- return top;
-}
-
-/*
-** Return a section of the pPage->aData to the freelist.
-** The first byte of the new free block is pPage->aDisk[start]
-** and the size of the block is "size" bytes.
-**
-** Most of the effort here is involved in coalesing adjacent
-** free blocks into a single big free block.
-*/
-static void freeSpace(MemPage *pPage, int start, int size){
- int addr, pbegin, hdr;
- unsigned char *data = pPage->aData;
-
- assert( pPage->pBt!=0 );
- assert( sqlite3pager_iswriteable(data) );
- assert( start>=pPage->hdrOffset+6+(pPage->leaf?0:4) );
- assert( (start + size)<=pPage->pBt->usableSize );
- if( size<4 ) size = 4;
-
- /* Add the space back into the linked list of freeblocks */
- hdr = pPage->hdrOffset;
- addr = hdr + 1;
- while( (pbegin = get2byte(&data[addr]))<start && pbegin>0 ){
- assert( pbegin<=pPage->pBt->usableSize-4 );
- assert( pbegin>addr );
- addr = pbegin;
- }
- assert( pbegin<=pPage->pBt->usableSize-4 );
- assert( pbegin>addr || pbegin==0 );
- put2byte(&data[addr], start);
- put2byte(&data[start], pbegin);
- put2byte(&data[start+2], size);
- pPage->nFree += size;
-
- /* Coalesce adjacent free blocks */
- addr = pPage->hdrOffset + 1;
- while( (pbegin = get2byte(&data[addr]))>0 ){
- int pnext, psize;
- assert( pbegin>addr );
- assert( pbegin<=pPage->pBt->usableSize-4 );
- pnext = get2byte(&data[pbegin]);
- psize = get2byte(&data[pbegin+2]);
- if( pbegin + psize + 3 >= pnext && pnext>0 ){
- int frag = pnext - (pbegin+psize);
- assert( frag<=data[pPage->hdrOffset+7] );
- data[pPage->hdrOffset+7] -= frag;
- put2byte(&data[pbegin], get2byte(&data[pnext]));
- put2byte(&data[pbegin+2], pnext+get2byte(&data[pnext+2])-pbegin);
- }else{
- addr = pbegin;
- }
- }
-
- /* If the cell content area begins with a freeblock, remove it. */
- if( data[hdr+1]==data[hdr+5] && data[hdr+2]==data[hdr+6] ){
- int top;
- pbegin = get2byte(&data[hdr+1]);
- memcpy(&data[hdr+1], &data[pbegin], 2);
- top = get2byte(&data[hdr+5]);
- put2byte(&data[hdr+5], top + get2byte(&data[pbegin+2]));
- }
-}
-
-/*
-** Decode the flags byte (the first byte of the header) for a page
-** and initialize fields of the MemPage structure accordingly.
-*/
-static void decodeFlags(MemPage *pPage, int flagByte){
- Btree *pBt; /* A copy of pPage->pBt */
-
- assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
- pPage->intKey = (flagByte & (PTF_INTKEY|PTF_LEAFDATA))!=0;
- pPage->zeroData = (flagByte & PTF_ZERODATA)!=0;
- pPage->leaf = (flagByte & PTF_LEAF)!=0;
- pPage->childPtrSize = 4*(pPage->leaf==0);
- pBt = pPage->pBt;
- if( flagByte & PTF_LEAFDATA ){
- pPage->leafData = 1;
- pPage->maxLocal = pBt->maxLeaf;
- pPage->minLocal = pBt->minLeaf;
- }else{
- pPage->leafData = 0;
- pPage->maxLocal = pBt->maxLocal;
- pPage->minLocal = pBt->minLocal;
- }
- pPage->hasData = !(pPage->zeroData || (!pPage->leaf && pPage->leafData));
-}
-
-/*
-** Initialize the auxiliary information for a disk block.
-**
-** The pParent parameter must be a pointer to the MemPage which
-** is the parent of the page being initialized. The root of a
-** BTree has no parent and so for that page, pParent==NULL.
-**
-** Return SQLITE_OK on success. If we see that the page does
-** not contain a well-formed database page, then return
-** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not
-** guarantee that the page is well-formed. It only shows that
-** we failed to detect any corruption.
-*/
-static int initPage(
- MemPage *pPage, /* The page to be initialized */
- MemPage *pParent /* The parent. Might be NULL */
-){
- int pc; /* Address of a freeblock within pPage->aData[] */
- int i; /* Loop counter */
- int hdr; /* Offset to beginning of page header */
- u8 *data; /* Equal to pPage->aData */
- Btree *pBt; /* The main btree structure */
- int usableSize; /* Amount of usable space on each page */
- int cellOffset; /* Offset from start of page to first cell pointer */
- int nFree; /* Number of unused bytes on the page */
- int top; /* First byte of the cell content area */
-
- pBt = pPage->pBt;
- assert( pBt!=0 );
- assert( pParent==0 || pParent->pBt==pBt );
- assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
- assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );
- if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
- /* The parent page should never change unless the file is corrupt */
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
- if( pPage->isInit ) return SQLITE_OK;
- if( pPage->pParent==0 && pParent!=0 ){
- pPage->pParent = pParent;
- sqlite3pager_ref(pParent->aData);
- }
- hdr = pPage->hdrOffset;
- data = pPage->aData;
- decodeFlags(pPage, data[hdr]);
- pPage->nOverflow = 0;
- pPage->idxShift = 0;
- usableSize = pBt->usableSize;
- pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;
- top = get2byte(&data[hdr+5]);
- pPage->nCell = get2byte(&data[hdr+3]);
- if( pPage->nCell>MX_CELL(pBt) ){
- /* To many cells for a single page. The page must be corrupt */
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
- if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){
- /* All pages must have at least one cell, except for root pages */
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
-
- /* Compute the total free space on the page */
- pc = get2byte(&data[hdr+1]);
- nFree = data[hdr+7] + top - (cellOffset + 2*pPage->nCell);
- i = 0;
- while( pc>0 ){
- int next, size;
- if( pc>usableSize-4 ){
- /* Free block is off the page */
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
- if( i++>SQLITE_MAX_PAGE_SIZE/4 ){
- /* The free block list forms an infinite loop */
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
- next = get2byte(&data[pc]);
- size = get2byte(&data[pc+2]);
- if( next>0 && next<=pc+size+3 ){
- /* Free blocks must be in accending order */
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
- nFree += size;
- pc = next;
- }
- pPage->nFree = nFree;
- if( nFree>=usableSize ){
- /* Free space cannot exceed total page size */
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
-
- pPage->isInit = 1;
- pageIntegrity(pPage);
- return SQLITE_OK;
-}
-
-/*
-** Set up a raw page so that it looks like a database page holding
-** no entries.
-*/
-static void zeroPage(MemPage *pPage, int flags){
- unsigned char *data = pPage->aData;
- Btree *pBt = pPage->pBt;
- int hdr = pPage->hdrOffset;
- int first;
-
- assert( sqlite3pager_pagenumber(data)==pPage->pgno );
- assert( &data[pBt->pageSize] == (unsigned char*)pPage );
- assert( sqlite3pager_iswriteable(data) );
- memset(&data[hdr], 0, pBt->usableSize - hdr);
- data[hdr] = flags;
- first = hdr + 8 + 4*((flags&PTF_LEAF)==0);
- memset(&data[hdr+1], 0, 4);
- data[hdr+7] = 0;
- put2byte(&data[hdr+5], pBt->usableSize);
- pPage->nFree = pBt->usableSize - first;
- decodeFlags(pPage, flags);
- pPage->hdrOffset = hdr;
- pPage->cellOffset = first;
- pPage->nOverflow = 0;
- pPage->idxShift = 0;
- pPage->nCell = 0;
- pPage->isInit = 1;
- pageIntegrity(pPage);
-}
-
-/*
-** Get a page from the pager. Initialize the MemPage.pBt and
-** MemPage.aData elements if needed.
-*/
-static int getPage(Btree *pBt, Pgno pgno, MemPage **ppPage){
- int rc;
- unsigned char *aData;
- MemPage *pPage;
- rc = sqlite3pager_get(pBt->pPager, pgno, (void**)&aData);
- if( rc ) return rc;
- pPage = (MemPage*)&aData[pBt->pageSize];
- pPage->aData = aData;
- pPage->pBt = pBt;
- pPage->pgno = pgno;
- pPage->hdrOffset = pPage->pgno==1 ? 100 : 0;
- *ppPage = pPage;
- return SQLITE_OK;
-}
-
-/*
-** Get a page from the pager and initialize it. This routine
-** is just a convenience wrapper around separate calls to
-** getPage() and initPage().
-*/
-static int getAndInitPage(
- Btree *pBt, /* The database file */
- Pgno pgno, /* Number of the page to get */
- MemPage **ppPage, /* Write the page pointer here */
- MemPage *pParent /* Parent of the page */
-){
- int rc;
- if( pgno==0 ){
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
- rc = getPage(pBt, pgno, ppPage);
- if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
- rc = initPage(*ppPage, pParent);
- }
- return rc;
-}
-
-/*
-** Release a MemPage. This should be called once for each prior
-** call to getPage.
-*/
-static void releasePage(MemPage *pPage){
- if( pPage ){
- assert( pPage->aData );
- assert( pPage->pBt );
- assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage );
- sqlite3pager_unref(pPage->aData);
- }
-}
-
-/*
-** This routine is called when the reference count for a page
-** reaches zero. We need to unref the pParent pointer when that
-** happens.
-*/
-static void pageDestructor(void *pData, int pageSize){
- MemPage *pPage = (MemPage*)&((char*)pData)[pageSize];
- if( pPage->pParent ){
- MemPage *pParent = pPage->pParent;
- pPage->pParent = 0;
- releasePage(pParent);
- }
- pPage->isInit = 0;
-}
-
-/*
-** During a rollback, when the pager reloads information into the cache
-** so that the cache is restored to its original state at the start of
-** the transaction, for each page restored this routine is called.
-**
-** This routine needs to reset the extra data section at the end of the
-** page to agree with the restored data.
-*/
-static void pageReinit(void *pData, int pageSize){
- MemPage *pPage = (MemPage*)&((char*)pData)[pageSize];
- if( pPage->isInit ){
- pPage->isInit = 0;
- initPage(pPage, pPage->pParent);
- }
-}
-
-/*
-** Open a database file.
-**
-** zFilename is the name of the database file. If zFilename is NULL
-** a new database with a random name is created. This randomly named
-** database file will be deleted when sqlite3BtreeClose() is called.
-*/
-int sqlite3BtreeOpen(
- const char *zFilename, /* Name of the file containing the BTree database */
- Btree **ppBtree, /* Pointer to new Btree object written here */
- int flags /* Options */
-){
- Btree *pBt;
- int rc;
- int nReserve;
- unsigned char zDbHeader[100];
-
- /*
- ** The following asserts make sure that structures used by the btree are
- ** the right size. This is to guard against size changes that result
- ** when compiling on a different architecture.
- */
- assert( sizeof(i64)==8 );
- assert( sizeof(u64)==8 );
- assert( sizeof(u32)==4 );
- assert( sizeof(u16)==2 );
- assert( sizeof(Pgno)==4 );
- assert( sizeof(ptr)==sizeof(char*) );
- assert( sizeof(uptr)==sizeof(ptr) );
-
- pBt = sqliteMalloc( sizeof(*pBt) );
- if( pBt==0 ){
- *ppBtree = 0;
- return SQLITE_NOMEM;
- }
- rc = sqlite3pager_open(&pBt->pPager, zFilename, EXTRA_SIZE,
- (flags & BTREE_OMIT_JOURNAL)==0);
- if( rc!=SQLITE_OK ){
- if( pBt->pPager ) sqlite3pager_close(pBt->pPager);
- sqliteFree(pBt);
- *ppBtree = 0;
- return rc;
- }
- sqlite3pager_set_destructor(pBt->pPager, pageDestructor);
- sqlite3pager_set_reiniter(pBt->pPager, pageReinit);
- pBt->pCursor = 0;
- pBt->pPage1 = 0;
- pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager);
- sqlite3pager_read_fileheader(pBt->pPager, sizeof(zDbHeader), zDbHeader);
- pBt->pageSize = get2byte(&zDbHeader[16]);
- if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE ){
- pBt->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
- pBt->maxEmbedFrac = 64; /* 25% */
- pBt->minEmbedFrac = 32; /* 12.5% */
- pBt->minLeafFrac = 32; /* 12.5% */
- nReserve = 0;
- }else{
- nReserve = zDbHeader[20];
- pBt->maxEmbedFrac = zDbHeader[21];
- pBt->minEmbedFrac = zDbHeader[22];
- pBt->minLeafFrac = zDbHeader[23];
- pBt->pageSizeFixed = 1;
- }
- pBt->usableSize = pBt->pageSize - nReserve;
- sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize);
- *ppBtree = pBt;
- return SQLITE_OK;
-}
-
-/*
-** Close an open database and invalidate all cursors.
-*/
-int sqlite3BtreeClose(Btree *pBt){
- while( pBt->pCursor ){
- sqlite3BtreeCloseCursor(pBt->pCursor);
- }
- sqlite3pager_close(pBt->pPager);
- sqliteFree(pBt);
- return SQLITE_OK;
-}
-
-/*
-** Change the busy handler callback function.
-*/
-int sqlite3BtreeSetBusyHandler(Btree *pBt, BusyHandler *pHandler){
- sqlite3pager_set_busyhandler(pBt->pPager, pHandler);
- return SQLITE_OK;
-}
-
-/*
-** Change the limit on the number of pages allowed in the cache.
-**
-** The maximum number of cache pages is set to the absolute
-** value of mxPage. If mxPage is negative, the pager will
-** operate asynchronously - it will not stop to do fsync()s
-** to insure data is written to the disk surface before
-** continuing. Transactions still work if synchronous is off,
-** and the database cannot be corrupted if this program
-** crashes. But if the operating system crashes or there is
-** an abrupt power failure when synchronous is off, the database
-** could be left in an inconsistent and unrecoverable state.
-** Synchronous is on by default so database corruption is not
-** normally a worry.
-*/
-int sqlite3BtreeSetCacheSize(Btree *pBt, int mxPage){
- sqlite3pager_set_cachesize(pBt->pPager, mxPage);
- return SQLITE_OK;
-}
-
-/*
-** Change the way data is synced to disk in order to increase or decrease
-** how well the database resists damage due to OS crashes and power
-** failures. Level 1 is the same as asynchronous (no syncs() occur and
-** there is a high probability of damage) Level 2 is the default. There
-** is a very low but non-zero probability of damage. Level 3 reduces the
-** probability of damage to near zero but with a write performance reduction.
-*/
-int sqlite3BtreeSetSafetyLevel(Btree *pBt, int level){
- sqlite3pager_set_safety_level(pBt->pPager, level);
- return SQLITE_OK;
-}
-
-/*
-** Change the default pages size and the number of reserved bytes per page.
-*/
-int sqlite3BtreeSetPageSize(Btree *pBt, int pageSize, int nReserve){
- if( pBt->pageSizeFixed ){
- return SQLITE_READONLY;
- }
- if( nReserve<0 ){
- nReserve = pBt->pageSize - pBt->usableSize;
- }
- if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE ){
- pBt->pageSize = pageSize;
- sqlite3pager_set_pagesize(pBt->pPager, pageSize);
- }
- pBt->usableSize = pBt->pageSize - nReserve;
- return SQLITE_OK;
-}
-
-/*
-** Return the currently defined page size
-*/
-int sqlite3BtreeGetPageSize(Btree *pBt){
- return pBt->pageSize;
-}
-int sqlite3BtreeGetReserve(Btree *pBt){
- return pBt->pageSize - pBt->usableSize;
-}
-
-/*
-** Get a reference to pPage1 of the database file. This will
-** also acquire a readlock on that file.
-**
-** SQLITE_OK is returned on success. If the file is not a
-** well-formed database file, then SQLITE_CORRUPT is returned.
-** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM
-** is returned if we run out of memory. SQLITE_PROTOCOL is returned
-** if there is a locking protocol violation.
-*/
-static int lockBtree(Btree *pBt){
- int rc;
- MemPage *pPage1;
- if( pBt->pPage1 ) return SQLITE_OK;
- rc = getPage(pBt, 1, &pPage1);
- if( rc!=SQLITE_OK ) return rc;
-
-
- /* Do some checking to help insure the file we opened really is
- ** a valid database file.
- */
- rc = SQLITE_NOTADB;
- if( sqlite3pager_pagecount(pBt->pPager)>0 ){
- u8 *page1 = pPage1->aData;
- if( memcmp(page1, zMagicHeader, 16)!=0 ){
- goto page1_init_failed;
- }
- if( page1[18]>1 || page1[19]>1 ){
- goto page1_init_failed;
- }
- pBt->pageSize = get2byte(&page1[16]);
- pBt->usableSize = pBt->pageSize - page1[20];
- if( pBt->usableSize<500 ){
- goto page1_init_failed;
- }
- pBt->maxEmbedFrac = page1[21];
- pBt->minEmbedFrac = page1[22];
- pBt->minLeafFrac = page1[23];
- }
-
- /* maxLocal is the maximum amount of payload to store locally for
- ** a cell. Make sure it is small enough so that at least minFanout
- ** cells can will fit on one page. We assume a 10-byte page header.
- ** Besides the payload, the cell must store:
- ** 2-byte pointer to the cell
- ** 4-byte child pointer
- ** 9-byte nKey value
- ** 4-byte nData value
- ** 4-byte overflow page pointer
- ** So a cell consists of a 2-byte poiner, a header which is as much as
- ** 17 bytes long, 0 to N bytes of payload, and an optional 4 byte overflow
- ** page pointer.
- */
- pBt->maxLocal = (pBt->usableSize-12)*pBt->maxEmbedFrac/255 - 23;
- pBt->minLocal = (pBt->usableSize-12)*pBt->minEmbedFrac/255 - 23;
- pBt->maxLeaf = pBt->usableSize - 35;
- pBt->minLeaf = (pBt->usableSize-12)*pBt->minLeafFrac/255 - 23;
- if( pBt->minLocal>pBt->maxLocal || pBt->maxLocal<0 ){
- goto page1_init_failed;
- }
- assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
- pBt->pPage1 = pPage1;
- return SQLITE_OK;
-
-page1_init_failed:
- releasePage(pPage1);
- pBt->pPage1 = 0;
- return rc;
-}
-
-/*
-** If there are no outstanding cursors and we are not in the middle
-** of a transaction but there is a read lock on the database, then
-** this routine unrefs the first page of the database file which
-** has the effect of releasing the read lock.
-**
-** If there are any outstanding cursors, this routine is a no-op.
-**
-** If there is a transaction in progress, this routine is a no-op.
-*/
-static void unlockBtreeIfUnused(Btree *pBt){
- if( pBt->inTrans==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
- if( pBt->pPage1->aData==0 ){
- MemPage *pPage = pBt->pPage1;
- pPage->aData = &((char*)pPage)[-pBt->pageSize];
- pPage->pBt = pBt;
- pPage->pgno = 1;
- }
- releasePage(pBt->pPage1);
- pBt->pPage1 = 0;
- pBt->inStmt = 0;
- }
-}
-
-/*
-** Create a new database by initializing the first page of the
-** file.
-*/
-static int newDatabase(Btree *pBt){
- MemPage *pP1;
- unsigned char *data;
- int rc;
- if( sqlite3pager_pagecount(pBt->pPager)>0 ) return SQLITE_OK;
- pP1 = pBt->pPage1;
- assert( pP1!=0 );
- data = pP1->aData;
- rc = sqlite3pager_write(data);
- if( rc ) return rc;
- memcpy(data, zMagicHeader, sizeof(zMagicHeader));
- assert( sizeof(zMagicHeader)==16 );
- put2byte(&data[16], pBt->pageSize);
- data[18] = 1;
- data[19] = 1;
- data[20] = pBt->pageSize - pBt->usableSize;
- data[21] = pBt->maxEmbedFrac;
- data[22] = pBt->minEmbedFrac;
- data[23] = pBt->minLeafFrac;
- memset(&data[24], 0, 100-24);
- zeroPage(pP1, PTF_INTKEY|PTF_LEAF|PTF_LEAFDATA );
- pBt->pageSizeFixed = 1;
- return SQLITE_OK;
-}
-
-/*
-** Attempt to start a new transaction. A write-transaction
-** is started if the second argument is nonzero, otherwise a read-
-** transaction. If the second argument is 2 or more and exclusive
-** transaction is started, meaning that no other process is allowed
-** to access the database. A preexisting transaction may not be
-** upgrade to exclusive by calling this routine a second time - the
-** exclusivity flag only works for a new transaction.
-**
-** A write-transaction must be started before attempting any
-** changes to the database. None of the following routines
-** will work unless a transaction is started first:
-**
-** sqlite3BtreeCreateTable()
-** sqlite3BtreeCreateIndex()
-** sqlite3BtreeClearTable()
-** sqlite3BtreeDropTable()
-** sqlite3BtreeInsert()
-** sqlite3BtreeDelete()
-** sqlite3BtreeUpdateMeta()
-**
-** If wrflag is true, then nMaster specifies the maximum length of
-** a master journal file name supplied later via sqlite3BtreeSync().
-** This is so that appropriate space can be allocated in the journal file
-** when it is created..
-*/
-int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){
- int rc = SQLITE_OK;
-
- /* If the btree is already in a write-transaction, or it
- ** is already in a read-transaction and a read-transaction
- ** is requested, this is a no-op.
- */
- if( pBt->inTrans==TRANS_WRITE ||
- (pBt->inTrans==TRANS_READ && !wrflag) ){
- return SQLITE_OK;
- }
- if( pBt->readOnly && wrflag ){
- return SQLITE_READONLY;
- }
-
- if( pBt->pPage1==0 ){
- rc = lockBtree(pBt);
- }
-
- if( rc==SQLITE_OK && wrflag ){
- rc = sqlite3pager_begin(pBt->pPage1->aData, wrflag>1);
- if( rc==SQLITE_OK ){
- rc = newDatabase(pBt);
- }
- }
-
- if( rc==SQLITE_OK ){
- pBt->inTrans = (wrflag?TRANS_WRITE:TRANS_READ);
- if( wrflag ) pBt->inStmt = 0;
- }else{
- unlockBtreeIfUnused(pBt);
- }
- return rc;
-}
-
-/*
-** Commit the transaction currently in progress.
-**
-** This will release the write lock on the database file. If there
-** are no active cursors, it also releases the read lock.
-*/
-int sqlite3BtreeCommit(Btree *pBt){
- int rc = SQLITE_OK;
- if( pBt->inTrans==TRANS_WRITE ){
- rc = sqlite3pager_commit(pBt->pPager);
- }
- pBt->inTrans = TRANS_NONE;
- pBt->inStmt = 0;
- unlockBtreeIfUnused(pBt);
- return rc;
-}
-
-#ifndef NDEBUG
-/*
-** Return the number of write-cursors open on this handle. This is for use
-** in assert() expressions, so it is only compiled if NDEBUG is not
-** defined.
-*/
-static int countWriteCursors(Btree *pBt){
- BtCursor *pCur;
- int r = 0;
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- if( pCur->wrFlag ) r++;
- }
- return r;
-}
-#endif
-
-#if 0
-/*
-** Invalidate all cursors
-*/
-static void invalidateCursors(Btree *pBt){
- BtCursor *pCur;
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- MemPage *pPage = pCur->pPage;
- if( pPage /* && !pPage->isInit */ ){
- pageIntegrity(pPage);
- releasePage(pPage);
- pCur->pPage = 0;
- pCur->isValid = 0;
- pCur->status = SQLITE_ABORT;
- }
- }
-}
-#endif
-
-#ifdef SQLITE_TEST
-/*
-** Print debugging information about all cursors to standard output.
-*/
-void sqlite3BtreeCursorList(Btree *pBt){
- BtCursor *pCur;
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- MemPage *pPage = pCur->pPage;
- char *zMode = pCur->wrFlag ? "rw" : "ro";
- sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n",
- pCur, pCur->pgnoRoot, zMode,
- pPage ? pPage->pgno : 0, pCur->idx,
- pCur->isValid ? "" : " eof"
- );
- }
-}
-#endif
-
-/*
-** Rollback the transaction in progress. All cursors will be
-** invalided by this operation. Any attempt to use a cursor
-** that was open at the beginning of this operation will result
-** in an error.
-**
-** This will release the write lock on the database file. If there
-** are no active cursors, it also releases the read lock.
-*/
-int sqlite3BtreeRollback(Btree *pBt){
- int rc = SQLITE_OK;
- MemPage *pPage1;
- if( pBt->inTrans==TRANS_WRITE ){
- rc = sqlite3pager_rollback(pBt->pPager);
- /* The rollback may have destroyed the pPage1->aData value. So
- ** call getPage() on page 1 again to make sure pPage1->aData is
- ** set correctly. */
- if( getPage(pBt, 1, &pPage1)==SQLITE_OK ){
- releasePage(pPage1);
- }
- assert( countWriteCursors(pBt)==0 );
- }
- pBt->inTrans = TRANS_NONE;
- pBt->inStmt = 0;
- unlockBtreeIfUnused(pBt);
- return rc;
-}
-
-/*
-** Start a statement subtransaction. The subtransaction can
-** can be rolled back independently of the main transaction.
-** You must start a transaction before starting a subtransaction.
-** The subtransaction is ended automatically if the main transaction
-** commits or rolls back.
-**
-** Only one subtransaction may be active at a time. It is an error to try
-** to start a new subtransaction if another subtransaction is already active.
-**
-** Statement subtransactions are used around individual SQL statements
-** that are contained within a BEGIN...COMMIT block. If a constraint
-** error occurs within the statement, the effect of that one statement
-** can be rolled back without having to rollback the entire transaction.
-*/
-int sqlite3BtreeBeginStmt(Btree *pBt){
- int rc;
- if( (pBt->inTrans!=TRANS_WRITE) || pBt->inStmt ){
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
- }
- rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_stmt_begin(pBt->pPager);
- pBt->inStmt = 1;
- return rc;
-}
-
-
-/*
-** Commit the statment subtransaction currently in progress. If no
-** subtransaction is active, this is a no-op.
-*/
-int sqlite3BtreeCommitStmt(Btree *pBt){
- int rc;
- if( pBt->inStmt && !pBt->readOnly ){
- rc = sqlite3pager_stmt_commit(pBt->pPager);
- }else{
- rc = SQLITE_OK;
- }
- pBt->inStmt = 0;
- return rc;
-}
-
-/*
-** Rollback the active statement subtransaction. If no subtransaction
-** is active this routine is a no-op.
-**
-** All cursors will be invalidated by this operation. Any attempt
-** to use a cursor that was open at the beginning of this operation
-** will result in an error.
-*/
-int sqlite3BtreeRollbackStmt(Btree *pBt){
- int rc;
- if( pBt->inStmt==0 || pBt->readOnly ) return SQLITE_OK;
- rc = sqlite3pager_stmt_rollback(pBt->pPager);
- assert( countWriteCursors(pBt)==0 );
- pBt->inStmt = 0;
- return rc;
-}
-
-/*
-** Default key comparison function to be used if no comparison function
-** is specified on the sqlite3BtreeCursor() call.
-*/
-static int dfltCompare(
- void *NotUsed, /* User data is not used */
- int n1, const void *p1, /* First key to compare */
- int n2, const void *p2 /* Second key to compare */
-){
- int c;
- c = memcmp(p1, p2, n1<n2 ? n1 : n2);
- if( c==0 ){
- c = n1 - n2;
- }
- return c;
-}
-
-/*
-** Create a new cursor for the BTree whose root is on the page
-** iTable. The act of acquiring a cursor gets a read lock on
-** the database file.
-**
-** If wrFlag==0, then the cursor can only be used for reading.
-** If wrFlag==1, then the cursor can be used for reading or for
-** writing if other conditions for writing are also met. These
-** are the conditions that must be met in order for writing to
-** be allowed:
-**
-** 1: The cursor must have been opened with wrFlag==1
-**
-** 2: No other cursors may be open with wrFlag==0 on the same table
-**
-** 3: The database must be writable (not on read-only media)
-**
-** 4: There must be an active transaction.
-**
-** Condition 2 warrants further discussion. If any cursor is opened
-** on a table with wrFlag==0, that prevents all other cursors from
-** writing to that table. This is a kind of "read-lock". When a cursor
-** is opened with wrFlag==0 it is guaranteed that the table will not
-** change as long as the cursor is open. This allows the cursor to
-** do a sequential scan of the table without having to worry about
-** entries being inserted or deleted during the scan. Cursors should
-** be opened with wrFlag==0 only if this read-lock property is needed.
-** That is to say, cursors should be opened with wrFlag==0 only if they
-** intend to use the sqlite3BtreeNext() system call. All other cursors
-** should be opened with wrFlag==1 even if they never really intend
-** to write.
-**
-** No checking is done to make sure that page iTable really is the
-** root page of a b-tree. If it is not, then the cursor acquired
-** will not work correctly.
-**
-** The comparison function must be logically the same for every cursor
-** on a particular table. Changing the comparison function will result
-** in incorrect operations. If the comparison function is NULL, a
-** default comparison function is used. The comparison function is
-** always ignored for INTKEY tables.
-*/
-int sqlite3BtreeCursor(
- Btree *pBt, /* The btree */
- int iTable, /* Root page of table to open */
- int wrFlag, /* 1 to write. 0 read-only */
- int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */
- void *pArg, /* First arg to xCompare() */
- BtCursor **ppCur /* Write new cursor here */
-){
- int rc;
- BtCursor *pCur;
-
- *ppCur = 0;
- if( wrFlag ){
- if( pBt->readOnly ){
- return SQLITE_READONLY;
- }
- if( checkReadLocks(pBt, iTable, 0) ){
- return SQLITE_LOCKED;
- }
- }
- if( pBt->pPage1==0 ){
- rc = lockBtree(pBt);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- }
- pCur = sqliteMallocRaw( sizeof(*pCur) );
- if( pCur==0 ){
- rc = SQLITE_NOMEM;
- goto create_cursor_exception;
- }
- pCur->pgnoRoot = (Pgno)iTable;
- if( iTable==1 && sqlite3pager_pagecount(pBt->pPager)==0 ){
- rc = SQLITE_EMPTY;
- pCur->pPage = 0;
- goto create_cursor_exception;
- }
- pCur->pPage = 0; /* For exit-handler, in case getAndInitPage() fails. */
- rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->pPage, 0);
- if( rc!=SQLITE_OK ){
- goto create_cursor_exception;
- }
- pCur->xCompare = xCmp ? xCmp : dfltCompare;
- pCur->pArg = pArg;
- pCur->pBt = pBt;
- pCur->wrFlag = wrFlag;
- pCur->idx = 0;
- memset(&pCur->info, 0, sizeof(pCur->info));
- pCur->pNext = pBt->pCursor;
- if( pCur->pNext ){
- pCur->pNext->pPrev = pCur;
- }
- pCur->pPrev = 0;
- pBt->pCursor = pCur;
- pCur->isValid = 0;
- pCur->status = SQLITE_OK;
- *ppCur = pCur;
- return SQLITE_OK;
-
-create_cursor_exception:
- if( pCur ){
- releasePage(pCur->pPage);
- sqliteFree(pCur);
- }
- unlockBtreeIfUnused(pBt);
- return rc;
-}
-
-#if 0 /* Not Used */
-/*
-** Change the value of the comparison function used by a cursor.
-*/
-void sqlite3BtreeSetCompare(
- BtCursor *pCur, /* The cursor to whose comparison function is changed */
- int(*xCmp)(void*,int,const void*,int,const void*), /* New comparison func */
- void *pArg /* First argument to xCmp() */
-){
- pCur->xCompare = xCmp ? xCmp : dfltCompare;
- pCur->pArg = pArg;
-}
-#endif
-
-/*
-** Close a cursor. The read lock on the database file is released
-** when the last cursor is closed.
-*/
-int sqlite3BtreeCloseCursor(BtCursor *pCur){
- Btree *pBt = pCur->pBt;
- if( pCur->pPrev ){
- pCur->pPrev->pNext = pCur->pNext;
- }else{
- pBt->pCursor = pCur->pNext;
- }
- if( pCur->pNext ){
- pCur->pNext->pPrev = pCur->pPrev;
- }
- releasePage(pCur->pPage);
- unlockBtreeIfUnused(pBt);
- sqliteFree(pCur);
- return SQLITE_OK;
-}
-
-/*
-** Make a temporary cursor by filling in the fields of pTempCur.
-** The temporary cursor is not on the cursor list for the Btree.
-*/
-static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){
- memcpy(pTempCur, pCur, sizeof(*pCur));
- pTempCur->pNext = 0;
- pTempCur->pPrev = 0;
- if( pTempCur->pPage ){
- sqlite3pager_ref(pTempCur->pPage->aData);
- }
-}
-
-/*
-** Delete a temporary cursor such as was made by the CreateTemporaryCursor()
-** function above.
-*/
-static void releaseTempCursor(BtCursor *pCur){
- if( pCur->pPage ){
- sqlite3pager_unref(pCur->pPage->aData);
- }
-}
-
-/*
-** Make sure the BtCursor.info field of the given cursor is valid.
-** If it is not already valid, call parseCell() to fill it in.
-**
-** BtCursor.info is a cache of the information in the current cell.
-** Using this cache reduces the number of calls to parseCell().
-*/
-static void getCellInfo(BtCursor *pCur){
- if( pCur->info.nSize==0 ){
- parseCell(pCur->pPage, pCur->idx, &pCur->info);
- }else{
-#ifndef NDEBUG
- CellInfo info;
- memset(&info, 0, sizeof(info));
- parseCell(pCur->pPage, pCur->idx, &info);
- assert( memcmp(&info, &pCur->info, sizeof(info))==0 );
-#endif
- }
-}
-
-/*
-** Set *pSize to the size of the buffer needed to hold the value of
-** the key for the current entry. If the cursor is not pointing
-** to a valid entry, *pSize is set to 0.
-**
-** For a table with the INTKEY flag set, this routine returns the key
-** itself, not the number of bytes in the key.
-*/
-int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
- if( !pCur->isValid ){
- *pSize = 0;
- }else{
- getCellInfo(pCur);
- *pSize = pCur->info.nKey;
- }
- return SQLITE_OK;
-}
-
-/*
-** Set *pSize to the number of bytes of data in the entry the
-** cursor currently points to. Always return SQLITE_OK.
-** Failure is not possible. If the cursor is not currently
-** pointing to an entry (which can happen, for example, if
-** the database is empty) then *pSize is set to 0.
-*/
-int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
- if( !pCur->isValid ){
- /* Not pointing at a valid entry - set *pSize to 0. */
- *pSize = 0;
- }else{
- getCellInfo(pCur);
- *pSize = pCur->info.nData;
- }
- return SQLITE_OK;
-}
-
-/*
-** Read payload information from the entry that the pCur cursor is
-** pointing to. Begin reading the payload at "offset" and read
-** a total of "amt" bytes. Put the result in zBuf.
-**
-** This routine does not make a distinction between key and data.
-** It just reads bytes from the payload area. Data might appear
-** on the main page or be scattered out on multiple overflow pages.
-*/
-static int getPayload(
- BtCursor *pCur, /* Cursor pointing to entry to read from */
- int offset, /* Begin reading this far into payload */
- int amt, /* Read this many bytes */
- unsigned char *pBuf, /* Write the bytes into this buffer */
- int skipKey /* offset begins at data if this is true */
-){
- unsigned char *aPayload;
- Pgno nextPage;
- int rc;
- MemPage *pPage;
- Btree *pBt;
- int ovflSize;
- u32 nKey;
-
- assert( pCur!=0 && pCur->pPage!=0 );
- assert( pCur->isValid );
- pBt = pCur->pBt;
- pPage = pCur->pPage;
- pageIntegrity(pPage);
- assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
- getCellInfo(pCur);
- aPayload = pCur->info.pCell;
- aPayload += pCur->info.nHeader;
- if( pPage->intKey ){
- nKey = 0;
- }else{
- nKey = pCur->info.nKey;
- }
- assert( offset>=0 );
- if( skipKey ){
- offset += nKey;
- }
- if( offset+amt > nKey+pCur->info.nData ){
- return SQLITE_ERROR;
- }
- if( offset<pCur->info.nLocal ){
- int a = amt;
- if( a+offset>pCur->info.nLocal ){
- a = pCur->info.nLocal - offset;
- }
- memcpy(pBuf, &aPayload[offset], a);
- if( a==amt ){
- return SQLITE_OK;
- }
- offset = 0;
- pBuf += a;
- amt -= a;
- }else{
- offset -= pCur->info.nLocal;
- }
- ovflSize = pBt->usableSize - 4;
- if( amt>0 ){
- nextPage = get4byte(&aPayload[pCur->info.nLocal]);
- while( amt>0 && nextPage ){
- rc = sqlite3pager_get(pBt->pPager, nextPage, (void**)&aPayload);
- if( rc!=0 ){
- return rc;
- }
- nextPage = get4byte(aPayload);
- if( offset<ovflSize ){
- int a = amt;
- if( a + offset > ovflSize ){
- a = ovflSize - offset;
- }
- memcpy(pBuf, &aPayload[offset+4], a);
- offset = 0;
- amt -= a;
- pBuf += a;
- }else{
- offset -= ovflSize;
- }
- sqlite3pager_unref(aPayload);
- }
- }
-
- if( amt>0 ){
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
- return SQLITE_OK;
-}
-
-/*
-** Read part of the key associated with cursor pCur. Exactly
-** "amt" bytes will be transfered into pBuf[]. The transfer
-** begins at "offset".
-**
-** Return SQLITE_OK on success or an error code if anything goes
-** wrong. An error is returned if "offset+amt" is larger than
-** the available payload.
-*/
-int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- if( pCur->isValid==0 ){
- return pCur->status;
- }
- assert( pCur->pPage!=0 );
- assert( pCur->pPage->intKey==0 );
- assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
- return getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
-}
-
-/*
-** Read part of the data associated with cursor pCur. Exactly
-** "amt" bytes will be transfered into pBuf[]. The transfer
-** begins at "offset".
-**
-** Return SQLITE_OK on success or an error code if anything goes
-** wrong. An error is returned if "offset+amt" is larger than
-** the available payload.
-*/
-int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- if( !pCur->isValid ){
- return pCur->status ? pCur->status : SQLITE_INTERNAL;
- }
- assert( pCur->pPage!=0 );
- assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
- return getPayload(pCur, offset, amt, pBuf, 1);
-}
-
-/*
-** Return a pointer to payload information from the entry that the
-** pCur cursor is pointing to. The pointer is to the beginning of
-** the key if skipKey==0 and it points to the beginning of data if
-** skipKey==1. The number of bytes of available key/data is written
-** into *pAmt. If *pAmt==0, then the value returned will not be
-** a valid pointer.
-**
-** This routine is an optimization. It is common for the entire key
-** and data to fit on the local page and for there to be no overflow
-** pages. When that is so, this routine can be used to access the
-** key and data without making a copy. If the key and/or data spills
-** onto overflow pages, then getPayload() must be used to reassembly
-** the key/data and copy it into a preallocated buffer.
-**
-** The pointer returned by this routine looks directly into the cached
-** page of the database. The data might change or move the next time
-** any btree routine is called.
-*/
-static const unsigned char *fetchPayload(
- BtCursor *pCur, /* Cursor pointing to entry to read from */
- int *pAmt, /* Write the number of available bytes here */
- int skipKey /* read beginning at data if this is true */
-){
- unsigned char *aPayload;
- MemPage *pPage;
- Btree *pBt;
- u32 nKey;
- int nLocal;
-
- assert( pCur!=0 && pCur->pPage!=0 );
- assert( pCur->isValid );
- pBt = pCur->pBt;
- pPage = pCur->pPage;
- pageIntegrity(pPage);
- assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
- getCellInfo(pCur);
- aPayload = pCur->info.pCell;
- aPayload += pCur->info.nHeader;
- if( pPage->intKey ){
- nKey = 0;
- }else{
- nKey = pCur->info.nKey;
- }
- if( skipKey ){
- aPayload += nKey;
- nLocal = pCur->info.nLocal - nKey;
- }else{
- nLocal = pCur->info.nLocal;
- if( nLocal>nKey ){
- nLocal = nKey;
- }
- }
- *pAmt = nLocal;
- return aPayload;
-}
-
-
-/*
-** For the entry that cursor pCur is point to, return as
-** many bytes of the key or data as are available on the local
-** b-tree page. Write the number of available bytes into *pAmt.
-**
-** The pointer returned is ephemeral. The key/data may move
-** or be destroyed on the next call to any Btree routine.
-**
-** These routines is used to get quick access to key and data
-** in the common case where no overflow pages are used.
-*/
-const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){
- return (const void*)fetchPayload(pCur, pAmt, 0);
-}
-const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){
- return (const void*)fetchPayload(pCur, pAmt, 1);
-}
-
-
-/*
-** Move the cursor down to a new child page. The newPgno argument is the
-** page number of the child page to move to.
-*/
-static int moveToChild(BtCursor *pCur, u32 newPgno){
- int rc;
- MemPage *pNewPage;
- MemPage *pOldPage;
- Btree *pBt = pCur->pBt;
-
- assert( pCur->isValid );
- rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
- if( rc ) return rc;
- pageIntegrity(pNewPage);
- pNewPage->idxParent = pCur->idx;
- pOldPage = pCur->pPage;
- pOldPage->idxShift = 0;
- releasePage(pOldPage);
- pCur->pPage = pNewPage;
- pCur->idx = 0;
- pCur->info.nSize = 0;
- if( pNewPage->nCell<1 ){
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
- return SQLITE_OK;
-}
-
-/*
-** Return true if the page is the virtual root of its table.
-**
-** The virtual root page is the root page for most tables. But
-** for the table rooted on page 1, sometime the real root page
-** is empty except for the right-pointer. In such cases the
-** virtual root page is the page that the right-pointer of page
-** 1 is pointing to.
-*/
-static int isRootPage(MemPage *pPage){
- MemPage *pParent = pPage->pParent;
- if( pParent==0 ) return 1;
- if( pParent->pgno>1 ) return 0;
- if( get2byte(&pParent->aData[pParent->hdrOffset+3])==0 ) return 1;
- return 0;
-}
-
-/*
-** Move the cursor up to the parent page.
-**
-** pCur->idx is set to the cell index that contains the pointer
-** to the page we are coming from. If we are coming from the
-** right-most child page then pCur->idx is set to one more than
-** the largest cell index.
-*/
-static void moveToParent(BtCursor *pCur){
- Pgno oldPgno;
- MemPage *pParent;
- MemPage *pPage;
- int idxParent;
-
- assert( pCur->isValid );
- pPage = pCur->pPage;
- assert( pPage!=0 );
- assert( !isRootPage(pPage) );
- pageIntegrity(pPage);
- pParent = pPage->pParent;
- assert( pParent!=0 );
- pageIntegrity(pParent);
- idxParent = pPage->idxParent;
- sqlite3pager_ref(pParent->aData);
- oldPgno = pPage->pgno;
- releasePage(pPage);
- pCur->pPage = pParent;
- pCur->info.nSize = 0;
- assert( pParent->idxShift==0 );
- pCur->idx = idxParent;
-}
-
-/*
-** Move the cursor to the root page
-*/
-static int moveToRoot(BtCursor *pCur){
- MemPage *pRoot;
- int rc;
- Btree *pBt = pCur->pBt;
-
- rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0);
- if( rc ){
- pCur->isValid = 0;
- return rc;
- }
- releasePage(pCur->pPage);
- pageIntegrity(pRoot);
- pCur->pPage = pRoot;
- pCur->idx = 0;
- pCur->info.nSize = 0;
- if( pRoot->nCell==0 && !pRoot->leaf ){
- Pgno subpage;
- assert( pRoot->pgno==1 );
- subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]);
- assert( subpage>0 );
- pCur->isValid = 1;
- rc = moveToChild(pCur, subpage);
- }
- pCur->isValid = pCur->pPage->nCell>0;
- return rc;
-}
-
-/*
-** Move the cursor down to the left-most leaf entry beneath the
-** entry to which it is currently pointing.
-*/
-static int moveToLeftmost(BtCursor *pCur){
- Pgno pgno;
- int rc;
- MemPage *pPage;
-
- assert( pCur->isValid );
- while( !(pPage = pCur->pPage)->leaf ){
- assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
- pgno = get4byte(findCell(pPage, pCur->idx));
- rc = moveToChild(pCur, pgno);
- if( rc ) return rc;
- }
- return SQLITE_OK;
-}
-
-/*
-** Move the cursor down to the right-most leaf entry beneath the
-** page to which it is currently pointing. Notice the difference
-** between moveToLeftmost() and moveToRightmost(). moveToLeftmost()
-** finds the left-most entry beneath the *entry* whereas moveToRightmost()
-** finds the right-most entry beneath the *page*.
-*/
-static int moveToRightmost(BtCursor *pCur){
- Pgno pgno;
- int rc;
- MemPage *pPage;
-
- assert( pCur->isValid );
- while( !(pPage = pCur->pPage)->leaf ){
- pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- pCur->idx = pPage->nCell;
- rc = moveToChild(pCur, pgno);
- if( rc ) return rc;
- }
- pCur->idx = pPage->nCell - 1;
- pCur->info.nSize = 0;
- return SQLITE_OK;
-}
-
-/* Move the cursor to the first entry in the table. Return SQLITE_OK
-** on success. Set *pRes to 0 if the cursor actually points to something
-** or set *pRes to 1 if the table is empty.
-*/
-int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
- int rc;
- if( pCur->status ){
- return pCur->status;
- }
- rc = moveToRoot(pCur);
- if( rc ) return rc;
- if( pCur->isValid==0 ){
- assert( pCur->pPage->nCell==0 );
- *pRes = 1;
- return SQLITE_OK;
- }
- assert( pCur->pPage->nCell>0 );
- *pRes = 0;
- rc = moveToLeftmost(pCur);
- return rc;
-}
-
-/* Move the cursor to the last entry in the table. Return SQLITE_OK
-** on success. Set *pRes to 0 if the cursor actually points to something
-** or set *pRes to 1 if the table is empty.
-*/
-int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
- int rc;
- if( pCur->status ){
- return pCur->status;
- }
- rc = moveToRoot(pCur);
- if( rc ) return rc;
- if( pCur->isValid==0 ){
- assert( pCur->pPage->nCell==0 );
- *pRes = 1;
- return SQLITE_OK;
- }
- assert( pCur->isValid );
- *pRes = 0;
- rc = moveToRightmost(pCur);
- return rc;
-}
-
-/* Move the cursor so that it points to an entry near pKey/nKey.
-** Return a success code.
-**
-** For INTKEY tables, only the nKey parameter is used. pKey is
-** ignored. For other tables, nKey is the number of bytes of data
-** in nKey. The comparison function specified when the cursor was
-** created is used to compare keys.
-**
-** If an exact match is not found, then the cursor is always
-** left pointing at a leaf page which would hold the entry if it
-** were present. The cursor might point to an entry that comes
-** before or after the key.
-**
-** The result of comparing the key with the entry to which the
-** cursor is written to *pRes if pRes!=NULL. The meaning of
-** this value is as follows:
-**
-** *pRes<0 The cursor is left pointing at an entry that
-** is smaller than pKey or if the table is empty
-** and the cursor is therefore left point to nothing.
-**
-** *pRes==0 The cursor is left pointing at an entry that
-** exactly matches pKey.
-**
-** *pRes>0 The cursor is left pointing at an entry that
-** is larger than pKey.
-*/
-int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
- int rc;
-
- if( pCur->status ){
- return pCur->status;
- }
- rc = moveToRoot(pCur);
- if( rc ) return rc;
- assert( pCur->pPage );
- assert( pCur->pPage->isInit );
- if( pCur->isValid==0 ){
- *pRes = -1;
- assert( pCur->pPage->nCell==0 );
- return SQLITE_OK;
- }
- for(;;){
- int lwr, upr;
- Pgno chldPg;
- MemPage *pPage = pCur->pPage;
- int c = -1; /* pRes return if table is empty must be -1 */
- lwr = 0;
- upr = pPage->nCell-1;
- pageIntegrity(pPage);
- while( lwr<=upr ){
- void *pCellKey;
- i64 nCellKey;
- pCur->idx = (lwr+upr)/2;
- pCur->info.nSize = 0;
- sqlite3BtreeKeySize(pCur, &nCellKey);
- if( pPage->intKey ){
- if( nCellKey<nKey ){
- c = -1;
- }else if( nCellKey>nKey ){
- c = +1;
- }else{
- c = 0;
- }
- }else{
- int available;
- pCellKey = (void *)fetchPayload(pCur, &available, 0);
- if( available>=nCellKey ){
- c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
- }else{
- pCellKey = sqliteMallocRaw( nCellKey );
- if( pCellKey==0 ) return SQLITE_NOMEM;
- rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey);
- c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
- sqliteFree(pCellKey);
- if( rc ) return rc;
- }
- }
- if( c==0 ){
- if( pPage->leafData && !pPage->leaf ){
- lwr = pCur->idx;
- upr = lwr - 1;
- break;
- }else{
- if( pRes ) *pRes = 0;
- return SQLITE_OK;
- }
- }
- if( c<0 ){
- lwr = pCur->idx+1;
- }else{
- upr = pCur->idx-1;
- }
- }
- assert( lwr==upr+1 );
- assert( pPage->isInit );
- if( pPage->leaf ){
- chldPg = 0;
- }else if( lwr>=pPage->nCell ){
- chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- }else{
- chldPg = get4byte(findCell(pPage, lwr));
- }
- if( chldPg==0 ){
- assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
- if( pRes ) *pRes = c;
- return SQLITE_OK;
- }
- pCur->idx = lwr;
- pCur->info.nSize = 0;
- rc = moveToChild(pCur, chldPg);
- if( rc ){
- return rc;
- }
- }
- /* NOT REACHED */
-}
-
-/*
-** Return TRUE if the cursor is not pointing at an entry of the table.
-**
-** TRUE will be returned after a call to sqlite3BtreeNext() moves
-** past the last entry in the table or sqlite3BtreePrev() moves past
-** the first entry. TRUE is also returned if the table is empty.
-*/
-int sqlite3BtreeEof(BtCursor *pCur){
- return pCur->isValid==0;
-}
-
-/*
-** Advance the cursor to the next entry in the database. If
-** successful then set *pRes=0. If the cursor
-** was already pointing to the last entry in the database before
-** this routine was called, then set *pRes=1.
-*/
-int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
- int rc;
- MemPage *pPage = pCur->pPage;
-
- assert( pRes!=0 );
- if( pCur->isValid==0 ){
- *pRes = 1;
- return SQLITE_OK;
- }
- assert( pPage->isInit );
- assert( pCur->idx<pPage->nCell );
- pCur->idx++;
- pCur->info.nSize = 0;
- if( pCur->idx>=pPage->nCell ){
- if( !pPage->leaf ){
- rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
- if( rc ) return rc;
- rc = moveToLeftmost(pCur);
- *pRes = 0;
- return rc;
- }
- do{
- if( isRootPage(pPage) ){
- *pRes = 1;
- pCur->isValid = 0;
- return SQLITE_OK;
- }
- moveToParent(pCur);
- pPage = pCur->pPage;
- }while( pCur->idx>=pPage->nCell );
- *pRes = 0;
- if( pPage->leafData ){
- rc = sqlite3BtreeNext(pCur, pRes);
- }else{
- rc = SQLITE_OK;
- }
- return rc;
- }
- *pRes = 0;
- if( pPage->leaf ){
- return SQLITE_OK;
- }
- rc = moveToLeftmost(pCur);
- return rc;
-}
-
-/*
-** Step the cursor to the back to the previous entry in the database. If
-** successful then set *pRes=0. If the cursor
-** was already pointing to the first entry in the database before
-** this routine was called, then set *pRes=1.
-*/
-int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
- int rc;
- Pgno pgno;
- MemPage *pPage;
- if( pCur->isValid==0 ){
- *pRes = 1;
- return SQLITE_OK;
- }
- pPage = pCur->pPage;
- assert( pPage->isInit );
- assert( pCur->idx>=0 );
- if( !pPage->leaf ){
- pgno = get4byte( findCell(pPage, pCur->idx) );
- rc = moveToChild(pCur, pgno);
- if( rc ) return rc;
- rc = moveToRightmost(pCur);
- }else{
- while( pCur->idx==0 ){
- if( isRootPage(pPage) ){
- pCur->isValid = 0;
- *pRes = 1;
- return SQLITE_OK;
- }
- moveToParent(pCur);
- pPage = pCur->pPage;
- }
- pCur->idx--;
- pCur->info.nSize = 0;
- if( pPage->leafData ){
- rc = sqlite3BtreePrevious(pCur, pRes);
- }else{
- rc = SQLITE_OK;
- }
- }
- *pRes = 0;
- return rc;
-}
-
-/*
-** The TRACE macro will print high-level status information about the
-** btree operation when the global variable sqlite3_btree_trace is
-** enabled.
-*/
-#if SQLITE_TEST
-# define TRACE(X) if( sqlite3_btree_trace )\
- { sqlite3DebugPrintf X; fflush(stdout); }
-#else
-# define TRACE(X)
-#endif
-int sqlite3_btree_trace=0; /* True to enable tracing */
-
-/*
-** Allocate a new page from the database file.
-**
-** The new page is marked as dirty. (In other words, sqlite3pager_write()
-** has already been called on the new page.) The new page has also
-** been referenced and the calling routine is responsible for calling
-** sqlite3pager_unref() on the new page when it is done.
-**
-** SQLITE_OK is returned on success. Any other return value indicates
-** an error. *ppPage and *pPgno are undefined in the event of an error.
-** Do not invoke sqlite3pager_unref() on *ppPage if an error is returned.
-**
-** If the "nearby" parameter is not 0, then a (feeble) effort is made to
-** locate a page close to the page number "nearby". This can be used in an
-** attempt to keep related pages close to each other in the database file,
-** which in turn can make database access faster.
-*/
-static int allocatePage(Btree *pBt, MemPage **ppPage, Pgno *pPgno, Pgno nearby){
- MemPage *pPage1;
- int rc;
- int n; /* Number of pages on the freelist */
- int k; /* Number of leaves on the trunk of the freelist */
-
- pPage1 = pBt->pPage1;
- n = get4byte(&pPage1->aData[36]);
- if( n>0 ){
- /* There are pages on the freelist. Reuse one of those pages. */
- MemPage *pTrunk;
- rc = sqlite3pager_write(pPage1->aData);
- if( rc ) return rc;
- put4byte(&pPage1->aData[36], n-1);
- rc = getPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk);
- if( rc ) return rc;
- rc = sqlite3pager_write(pTrunk->aData);
- if( rc ){
- releasePage(pTrunk);
- return rc;
- }
- k = get4byte(&pTrunk->aData[4]);
- if( k==0 ){
- /* The trunk has no leaves. So extract the trunk page itself and
- ** use it as the newly allocated page */
- *pPgno = get4byte(&pPage1->aData[32]);
- memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
- *ppPage = pTrunk;
- TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
- }else if( k>pBt->usableSize/4 - 8 ){
- /* Value of k is out of range. Database corruption */
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }else{
- /* Extract a leaf from the trunk */
- int closest;
- unsigned char *aData = pTrunk->aData;
- if( nearby>0 ){
- int i, dist;
- closest = 0;
- dist = get4byte(&aData[8]) - nearby;
- if( dist<0 ) dist = -dist;
- for(i=1; i<k; i++){
- int d2 = get4byte(&aData[8+i*4]) - nearby;
- if( d2<0 ) d2 = -d2;
- if( d2<dist ) closest = i;
- }
- }else{
- closest = 0;
- }
- *pPgno = get4byte(&aData[8+closest*4]);
- if( *pPgno>sqlite3pager_pagecount(pBt->pPager) ){
- /* Free page off the end of the file */
- return SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
- TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d: %d more free pages\n",
- *pPgno, closest+1, k, pTrunk->pgno, n-1));
- if( closest<k-1 ){
- memcpy(&aData[8+closest*4], &aData[4+k*4], 4);
- }
- put4byte(&aData[4], k-1);
- rc = getPage(pBt, *pPgno, ppPage);
- releasePage(pTrunk);
- if( rc==SQLITE_OK ){
- sqlite3pager_dont_rollback((*ppPage)->aData);
- rc = sqlite3pager_write((*ppPage)->aData);
- }
- }
- }else{
- /* There are no pages on the freelist, so create a new page at the
- ** end of the file */
- *pPgno = sqlite3pager_pagecount(pBt->pPager) + 1;
- rc = getPage(pBt, *pPgno, ppPage);
- if( rc ) return rc;
- rc = sqlite3pager_write((*ppPage)->aData);
- TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
- }
- return rc;
-}
-
-/*
-** Add a page of the database file to the freelist.
-**
-** sqlite3pager_unref() is NOT called for pPage.
-*/
-static int freePage(MemPage *pPage){
- Btree *pBt = pPage->pBt;
- MemPage *pPage1 = pBt->pPage1;
- int rc, n, k;
-
- /* Prepare the page for freeing */
- assert( pPage->pgno>1 );
- pPage->isInit = 0;
- releasePage(pPage->pParent);
- pPage->pParent = 0;
-
- /* Increment the free page count on pPage1 */
- rc = sqlite3pager_write(pPage1->aData);
- if( rc ) return rc;
- n = get4byte(&pPage1->aData[36]);
- put4byte(&pPage1->aData[36], n+1);
-
- if( n==0 ){
- /* This is the first free page */
- rc = sqlite3pager_write(pPage->aData);
- if( rc ) return rc;
- memset(pPage->aData, 0, 8);
- put4byte(&pPage1->aData[32], pPage->pgno);
- TRACE(("FREE-PAGE: %d first\n", pPage->pgno));
- }else{
- /* Other free pages already exist. Retrive the first trunk page
- ** of the freelist and find out how many leaves it has. */
- MemPage *pTrunk;
- rc = getPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk);
- if( rc ) return rc;
- k = get4byte(&pTrunk->aData[4]);
- if( k>=pBt->usableSize/4 - 8 ){
- /* The trunk is full. Turn the page being freed into a new
- ** trunk page with no leaves. */
- rc = sqlite3pager_write(pPage->aData);
- if( rc ) return rc;
- put4byte(pPage->aData, pTrunk->pgno);
- put4byte(&pPage->aData[4], 0);
- put4byte(&pPage1->aData[32], pPage->pgno);
- TRACE(("FREE-PAGE: %d new trunk page replacing %d\n",
- pPage->pgno, pTrunk->pgno));
- }else{
- /* Add the newly freed page as a leaf on the current trunk */
- rc = sqlite3pager_write(pTrunk->aData);
- if( rc ) return rc;
- put4byte(&pTrunk->aData[4], k+1);
- put4byte(&pTrunk->aData[8+k*4], pPage->pgno);
- sqlite3pager_dont_write(pBt->pPager, pPage->pgno);
- TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
- }
- releasePage(pTrunk);
- }
- return rc;
-}
-
-/*
-** Free any overflow pages associated with the given Cell.
-*/
-static int clearCell(MemPage *pPage, unsigned char *pCell){
- Btree *pBt = pPage->pBt;
- CellInfo info;
- Pgno ovflPgno;
- int rc;
-
- parseCellPtr(pPage, pCell, &info);
- if( info.iOverflow==0 ){
- return SQLITE_OK; /* No overflow pages. Return without doing anything */
- }
- ovflPgno = get4byte(&pCell[info.iOverflow]);
- while( ovflPgno!=0 ){
- MemPage *pOvfl;
- rc = getPage(pBt, ovflPgno, &pOvfl);
- if( rc ) return rc;
- ovflPgno = get4byte(pOvfl->aData);
- rc = freePage(pOvfl);
- if( rc ) return rc;
- sqlite3pager_unref(pOvfl->aData);
- }
- return SQLITE_OK;
-}
-
-/*
-** Create the byte sequence used to represent a cell on page pPage
-** and write that byte sequence into pCell[]. Overflow pages are
-** allocated and filled in as necessary. The calling procedure
-** is responsible for making sure sufficient space has been allocated
-** for pCell[].
-**
-** Note that pCell does not necessary need to point to the pPage->aData
-** area. pCell might point to some temporary storage. The cell will
-** be constructed in this temporary area then copied into pPage->aData
-** later.
-*/
-static int fillInCell(
- MemPage *pPage, /* The page that contains the cell */
- unsigned char *pCell, /* Complete text of the cell */
- const void *pKey, i64 nKey, /* The key */
- const void *pData,int nData, /* The data */
- int *pnSize /* Write cell size here */
-){
- int nPayload;
- const u8 *pSrc;
- int nSrc, n, rc;
- int spaceLeft;
- MemPage *pOvfl = 0;
- MemPage *pToRelease = 0;
- unsigned char *pPrior;
- unsigned char *pPayload;
- Btree *pBt = pPage->pBt;
- Pgno pgnoOvfl = 0;
- int nHeader;
- CellInfo info;
-
- /* Fill in the header. */
- nHeader = 0;
- if( !pPage->leaf ){
- nHeader += 4;
- }
- if( pPage->hasData ){
- nHeader += putVarint(&pCell[nHeader], nData);
- }else{
- nData = 0;
- }
- nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey);
- parseCellPtr(pPage, pCell, &info);
- assert( info.nHeader==nHeader );
- assert( info.nKey==nKey );
- assert( info.nData==nData );
-
- /* Fill in the payload */
- nPayload = nData;
- if( pPage->intKey ){
- pSrc = pData;
- nSrc = nData;
- nData = 0;
- }else{
- nPayload += nKey;
- pSrc = pKey;
- nSrc = nKey;
- }
- *pnSize = info.nSize;
- spaceLeft = info.nLocal;
- pPayload = &pCell[nHeader];
- pPrior = &pCell[info.iOverflow];
-
- while( nPayload>0 ){
- if( spaceLeft==0 ){
- rc = allocatePage(pBt, &pOvfl, &pgnoOvfl, pgnoOvfl);
- if( rc ){
- releasePage(pToRelease);
- clearCell(pPage, pCell);
- return rc;
- }
- put4byte(pPrior, pgnoOvfl);
- releasePage(pToRelease);
- pToRelease = pOvfl;
- pPrior = pOvfl->aData;
- put4byte(pPrior, 0);
- pPayload = &pOvfl->aData[4];
- spaceLeft = pBt->usableSize - 4;
- }
- n = nPayload;
- if( n>spaceLeft ) n = spaceLeft;
- if( n>nSrc ) n = nSrc;
- memcpy(pPayload, pSrc, n);
- nPayload -= n;
- pPayload += n;
- pSrc += n;
- nSrc -= n;
- spaceLeft -= n;
- if( nSrc==0 ){
- nSrc = nData;
- pSrc = pData;
- }
- }
- releasePage(pToRelease);
- return SQLITE_OK;
-}
-
-/*
-** Change the MemPage.pParent pointer on the page whose number is
-** given in the second argument so that MemPage.pParent holds the
-** pointer in the third argument.
-*/
-static void reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){
- MemPage *pThis;
- unsigned char *aData;
-
- if( pgno==0 ) return;
- assert( pBt->pPager!=0 );
- aData = sqlite3pager_lookup(pBt->pPager, pgno);
- if( aData ){
- pThis = (MemPage*)&aData[pBt->pageSize];
- assert( pThis->aData==aData );
- if( pThis->isInit ){
- if( pThis->pParent!=pNewParent ){
- if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
- pThis->pParent = pNewParent;
- if( pNewParent ) sqlite3pager_ref(pNewParent->aData);
- }
- pThis->idxParent = idx;
- }
- sqlite3pager_unref(aData);
- }
-}
-
-/*
-** Change the pParent pointer of all children of pPage to point back
-** to pPage.
-**
-** In other words, for every child of pPage, invoke reparentPage()
-** to make sure that each child knows that pPage is its parent.
-**
-** This routine gets called after you memcpy() one page into
-** another.
-*/
-static void reparentChildPages(MemPage *pPage){
- int i;
- Btree *pBt;
-
- if( pPage->leaf ) return;
- pBt = pPage->pBt;
- for(i=0; i<pPage->nCell; i++){
- reparentPage(pBt, get4byte(findCell(pPage,i)), pPage, i);
- }
- reparentPage(pBt, get4byte(&pPage->aData[pPage->hdrOffset+8]), pPage, i);
- pPage->idxShift = 0;
-}
-
-/*
-** Remove the i-th cell from pPage. This routine effects pPage only.
-** The cell content is not freed or deallocated. It is assumed that
-** the cell content has been copied someplace else. This routine just
-** removes the reference to the cell from pPage.
-**
-** "sz" must be the number of bytes in the cell.
-*/
-static void dropCell(MemPage *pPage, int idx, int sz){
- int i; /* Loop counter */
- int pc; /* Offset to cell content of cell being deleted */
- u8 *data; /* pPage->aData */
- u8 *ptr; /* Used to move bytes around within data[] */
-
- assert( idx>=0 && idx<pPage->nCell );
- assert( sz==cellSize(pPage, idx) );
- assert( sqlite3pager_iswriteable(pPage->aData) );
- data = pPage->aData;
- ptr = &data[pPage->cellOffset + 2*idx];
- pc = get2byte(ptr);
- assert( pc>10 && pc+sz<=pPage->pBt->usableSize );
- freeSpace(pPage, pc, sz);
- for(i=idx+1; i<pPage->nCell; i++, ptr+=2){
- ptr[0] = ptr[2];
- ptr[1] = ptr[3];
- }
- pPage->nCell--;
- put2byte(&data[pPage->hdrOffset+3], pPage->nCell);
- pPage->nFree += 2;
- pPage->idxShift = 1;
-}
-
-/*
-** Insert a new cell on pPage at cell index "i". pCell points to the
-** content of the cell.
-**
-** If the cell content will fit on the page, then put it there. If it
-** will not fit, then make a copy of the cell content into pTemp if
-** pTemp is not null. Regardless of pTemp, allocate a new entry
-** in pPage->aOvfl[] and make it point to the cell content (either
-** in pTemp or the original pCell) and also record its index.
-** Allocating a new entry in pPage->aCell[] implies that
-** pPage->nOverflow is incremented.
-*/
-static void insertCell(
- MemPage *pPage, /* Page into which we are copying */
- int i, /* New cell becomes the i-th cell of the page */
- u8 *pCell, /* Content of the new cell */
- int sz, /* Bytes of content in pCell */
- u8 *pTemp /* Temp storage space for pCell, if needed */
-){
- int idx; /* Where to write new cell content in data[] */
- int j; /* Loop counter */
- int top; /* First byte of content for any cell in data[] */
- int end; /* First byte past the last cell pointer in data[] */
- int ins; /* Index in data[] where new cell pointer is inserted */
- int hdr; /* Offset into data[] of the page header */
- int cellOffset; /* Address of first cell pointer in data[] */
- u8 *data; /* The content of the whole page */
- u8 *ptr; /* Used for moving information around in data[] */
-
- assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
- assert( sz==cellSizePtr(pPage, pCell) );
- assert( sqlite3pager_iswriteable(pPage->aData) );
- if( pPage->nOverflow || sz+2>pPage->nFree ){
- if( pTemp ){
- memcpy(pTemp, pCell, sz);
- pCell = pTemp;
- }
- j = pPage->nOverflow++;
- assert( j<sizeof(pPage->aOvfl)/sizeof(pPage->aOvfl[0]) );
- pPage->aOvfl[j].pCell = pCell;
- pPage->aOvfl[j].idx = i;
- pPage->nFree = 0;
- }else{
- data = pPage->aData;
- hdr = pPage->hdrOffset;
- top = get2byte(&data[hdr+5]);
- cellOffset = pPage->cellOffset;
- end = cellOffset + 2*pPage->nCell + 2;
- ins = cellOffset + 2*i;
- if( end > top - sz ){
- defragmentPage(pPage);
- top = get2byte(&data[hdr+5]);
- assert( end + sz <= top );
- }
- idx = allocateSpace(pPage, sz);
- assert( idx>0 );
- assert( end <= get2byte(&data[hdr+5]) );
- pPage->nCell++;
- pPage->nFree -= 2;
- memcpy(&data[idx], pCell, sz);
- for(j=end-2, ptr=&data[j]; j>ins; j-=2, ptr-=2){
- ptr[0] = ptr[-2];
- ptr[1] = ptr[-1];
- }
- put2byte(&data[ins], idx);
- put2byte(&data[hdr+3], pPage->nCell);
- pPage->idxShift = 1;
- pageIntegrity(pPage);
- }
-}
-
-/*
-** Add a list of cells to a page. The page should be initially empty.
-** The cells are guaranteed to fit on the page.
-*/
-static void assemblePage(
- MemPage *pPage, /* The page to be assemblied */
- int nCell, /* The number of cells to add to this page */
- u8 **apCell, /* Pointers to cell bodies */
- int *aSize /* Sizes of the cells */
-){
- int i; /* Loop counter */
- int totalSize; /* Total size of all cells */
- int hdr; /* Index of page header */
- int cellptr; /* Address of next cell pointer */
- int cellbody; /* Address of next cell body */
- u8 *data; /* Data for the page */
-
- assert( pPage->nOverflow==0 );
- totalSize = 0;
- for(i=0; i<nCell; i++){
- totalSize += aSize[i];
- }
- assert( totalSize+2*nCell<=pPage->nFree );
- assert( pPage->nCell==0 );
- cellptr = pPage->cellOffset;
- data = pPage->aData;
- hdr = pPage->hdrOffset;
- put2byte(&data[hdr+3], nCell);
- cellbody = allocateSpace(pPage, totalSize);
- assert( cellbody>0 );
- assert( pPage->nFree >= 2*nCell );
- pPage->nFree -= 2*nCell;
- for(i=0; i<nCell; i++){
- put2byte(&data[cellptr], cellbody);
- memcpy(&data[cellbody], apCell[i], aSize[i]);
- cellptr += 2;
- cellbody += aSize[i];
- }
- assert( cellbody==pPage->pBt->usableSize );
- pPage->nCell = nCell;
-}
-
-/*
-** GCC does not define the offsetof() macro so we'll have to do it
-** ourselves.
-*/
-#ifndef offsetof
-#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD))
-#endif
-
-/*
-** The following parameters determine how many adjacent pages get involved
-** in a balancing operation. NN is the number of neighbors on either side
-** of the page that participate in the balancing operation. NB is the
-** total number of pages that participate, including the target page and
-** NN neighbors on either side.
-**
-** The minimum value of NN is 1 (of course). Increasing NN above 1
-** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance
-** in exchange for a larger degradation in INSERT and UPDATE performance.
-** The value of NN appears to give the best results overall.
-*/
-#define NN 1 /* Number of neighbors on either side of pPage */
-#define NB (NN*2+1) /* Total pages involved in the balance */
-
-/* Forward reference */
-static int balance(MemPage*);
-
-/*
-** This routine redistributes Cells on pPage and up to NN*2 siblings
-** of pPage so that all pages have about the same amount of free space.
-** Usually NN siblings on either side of pPage is used in the balancing,
-** though more siblings might come from one side if pPage is the first
-** or last child of its parent. If pPage has fewer than 2*NN siblings
-** (something which can only happen if pPage is the root page or a
-** child of root) then all available siblings participate in the balancing.
-**
-** The number of siblings of pPage might be increased or decreased by one or
-** two in an effort to keep pages nearly full but not over full. The root page
-** is special and is allowed to be nearly empty. If pPage is
-** the root page, then the depth of the tree might be increased
-** or decreased by one, as necessary, to keep the root page from being
-** overfull or completely empty.
-**
-** Note that when this routine is called, some of the Cells on pPage
-** might not actually be stored in pPage->aData[]. This can happen
-** if the page is overfull. Part of the job of this routine is to
-** make sure all Cells for pPage once again fit in pPage->aData[].
-**
-** In the course of balancing the siblings of pPage, the parent of pPage
-** might become overfull or underfull. If that happens, then this routine
-** is called recursively on the parent.
-**
-** If this routine fails for any reason, it might leave the database
-** in a corrupted state. So if this routine fails, the database should
-** be rolled back.
-*/
-static int balance_nonroot(MemPage *pPage){
- MemPage *pParent; /* The parent of pPage */
- Btree *pBt; /* The whole database */
- int nCell = 0; /* Number of cells in aCell[] */
- int nOld; /* Number of pages in apOld[] */
- int nNew; /* Number of pages in apNew[] */
- int nDiv; /* Number of cells in apDiv[] */
- int i, j, k; /* Loop counters */
- int idx; /* Index of pPage in pParent->aCell[] */
- int nxDiv; /* Next divider slot in pParent->aCell[] */
- int rc; /* The return code */
- int leafCorrection; /* 4 if pPage is a leaf. 0 if not */
- int leafData; /* True if pPage is a leaf of a LEAFDATA tree */
- int usableSpace; /* Bytes in pPage beyond the header */
- int pageFlags; /* Value of pPage->aData[0] */
- int subtotal; /* Subtotal of bytes in cells on one page */
- int iSpace = 0; /* First unused byte of aSpace[] */
- int mxCellPerPage; /* Maximum number of cells in one page */
- MemPage *apOld[NB]; /* pPage and up to two siblings */
- Pgno pgnoOld[NB]; /* Page numbers for each page in apOld[] */
- MemPage *apCopy[NB]; /* Private copies of apOld[] pages */
- MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */
- Pgno pgnoNew[NB+2]; /* Page numbers for each page in apNew[] */
- int idxDiv[NB]; /* Indices of divider cells in pParent */
- u8 *apDiv[NB]; /* Divider cells in pParent */
- int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */
- int szNew[NB+2]; /* Combined size of cells place on i-th page */
- u8 **apCell; /* All cells begin balanced */
- int *szCell; /* Local size of all cells in apCell[] */
- u8 *aCopy[NB]; /* Space for holding data of apCopy[] */
- u8 *aSpace; /* Space to hold copies of dividers cells */
-
- /*
- ** Find the parent page.
- */
- assert( pPage->isInit );
- assert( sqlite3pager_iswriteable(pPage->aData) );
- pBt = pPage->pBt;
- pParent = pPage->pParent;
- sqlite3pager_write(pParent->aData);
- assert( pParent );
- TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno));
-
- /*
- ** Allocate space for memory structures
- */
- mxCellPerPage = MX_CELL(pBt);
- apCell = sqliteMallocRaw(
- (mxCellPerPage+2)*NB*(sizeof(u8*)+sizeof(int))
- + sizeof(MemPage)*NB
- + pBt->pageSize*(5+NB)
- );
- if( apCell==0 ){
- return SQLITE_NOMEM;
- }
- szCell = (int*)&apCell[(mxCellPerPage+2)*NB];
- aCopy[0] = (u8*)&szCell[(mxCellPerPage+2)*NB];
- for(i=1; i<NB; i++){
- aCopy[i] = &aCopy[i-1][pBt->pageSize+sizeof(MemPage)];
- }
- aSpace = &aCopy[NB-1][pBt->pageSize+sizeof(MemPage)];
-
- /*
- ** Find the cell in the parent page whose left child points back
- ** to pPage. The "idx" variable is the index of that cell. If pPage
- ** is the rightmost child of pParent then set idx to pParent->nCell
- */
- if( pParent->idxShift ){
- Pgno pgno;
- pgno = pPage->pgno;
- assert( pgno==sqlite3pager_pagenumber(pPage->aData) );
- for(idx=0; idx<pParent->nCell; idx++){
- if( get4byte(findCell(pParent, idx))==pgno ){
- break;
- }
- }
- assert( idx<pParent->nCell
- || get4byte(&pParent->aData[pParent->hdrOffset+8])==pgno );
- }else{
- idx = pPage->idxParent;
- }
-
- /*
- ** Initialize variables so that it will be safe to jump
- ** directly to balance_cleanup at any moment.
- */
- nOld = nNew = 0;
- sqlite3pager_ref(pParent->aData);
-
- /*
- ** Find sibling pages to pPage and the cells in pParent that divide
- ** the siblings. An attempt is made to find NN siblings on either
- ** side of pPage. More siblings are taken from one side, however, if
- ** pPage there are fewer than NN siblings on the other side. If pParent
- ** has NB or fewer children then all children of pParent are taken.
- */
- nxDiv = idx - NN;
- if( nxDiv + NB > pParent->nCell ){
- nxDiv = pParent->nCell - NB + 1;
- }
- if( nxDiv<0 ){
- nxDiv = 0;
- }
- nDiv = 0;
- for(i=0, k=nxDiv; i<NB; i++, k++){
- if( k<pParent->nCell ){
- idxDiv[i] = k;
- apDiv[i] = findCell(pParent, k);
- nDiv++;
- assert( !pParent->leaf );
- pgnoOld[i] = get4byte(apDiv[i]);
- }else if( k==pParent->nCell ){
- pgnoOld[i] = get4byte(&pParent->aData[pParent->hdrOffset+8]);
- }else{
- break;
- }
- rc = getAndInitPage(pBt, pgnoOld[i], &apOld[i], pParent);
- if( rc ) goto balance_cleanup;
- apOld[i]->idxParent = k;
- apCopy[i] = 0;
- assert( i==nOld );
- nOld++;
- }
-
- /*
- ** Make copies of the content of pPage and its siblings into aOld[].
- ** The rest of this function will use data from the copies rather
- ** that the original pages since the original pages will be in the
- ** process of being overwritten.
- */
- for(i=0; i<nOld; i++){
- MemPage *p = apCopy[i] = (MemPage*)&aCopy[i][pBt->pageSize];
- p->aData = &((u8*)p)[-pBt->pageSize];
- memcpy(p->aData, apOld[i]->aData, pBt->pageSize + sizeof(MemPage));
- p->aData = &((u8*)p)[-pBt->pageSize];
- }
-
- /*
- ** Load pointers to all cells on sibling pages and the divider cells
- ** into the local apCell[] array. Make copies of the divider cells
- ** into space obtained form aSpace[] and remove the the divider Cells
- ** from pParent.
- **
- ** If the siblings are on leaf pages, then the child pointers of the
- ** divider cells are stripped from the cells before they are copied
- ** into aSpace[]. In this way, all cells in apCell[] are without
- ** child pointers. If siblings are not leaves, then all cell in
- ** apCell[] include child pointers. Either way, all cells in apCell[]
- ** are alike.
- **
- ** leafCorrection: 4 if pPage is a leaf. 0 if pPage is not a leaf.
- ** leafData: 1 if pPage holds key+data and pParent holds only keys.
- */
- nCell = 0;
- leafCorrection = pPage->leaf*4;
- leafData = pPage->leafData && pPage->leaf;
- for(i=0; i<nOld; i++){
- MemPage *pOld = apCopy[i];
- int limit = pOld->nCell+pOld->nOverflow;
- for(j=0; j<limit; j++){
- apCell[nCell] = findOverflowCell(pOld, j);
- szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
- nCell++;
- }
- if( i<nOld-1 ){
- int sz = cellSizePtr(pParent, apDiv[i]);
- if( leafData ){
- /* With the LEAFDATA flag, pParent cells hold only INTKEYs that
- ** are duplicates of keys on the child pages. We need to remove
- ** the divider cells from pParent, but the dividers cells are not
- ** added to apCell[] because they are duplicates of child cells.
- */
- dropCell(pParent, nxDiv, sz);
- }else{
- u8 *pTemp;
- szCell[nCell] = sz;
- pTemp = &aSpace[iSpace];
- iSpace += sz;
- assert( iSpace<=pBt->pageSize*5 );
- memcpy(pTemp, apDiv[i], sz);
- apCell[nCell] = pTemp+leafCorrection;
- dropCell(pParent, nxDiv, sz);
- szCell[nCell] -= leafCorrection;
- assert( get4byte(pTemp)==pgnoOld[i] );
- if( !pOld->leaf ){
- assert( leafCorrection==0 );
- /* The right pointer of the child page pOld becomes the left
- ** pointer of the divider cell */
- memcpy(apCell[nCell], &pOld->aData[pOld->hdrOffset+8], 4);
- }else{
- assert( leafCorrection==4 );
- }
- nCell++;
- }
- }
- }
-
- /*
- ** Figure out the number of pages needed to hold all nCell cells.
- ** Store this number in "k". Also compute szNew[] which is the total
- ** size of all cells on the i-th page and cntNew[] which is the index
- ** in apCell[] of the cell that divides page i from page i+1.
- ** cntNew[k] should equal nCell.
- **
- ** Values computed by this block:
- **
- ** k: The total number of sibling pages
- ** szNew[i]: Spaced used on the i-th sibling page.
- ** cntNew[i]: Index in apCell[] and szCell[] for the first cell to
- ** the right of the i-th sibling page.
- ** usableSpace: Number of bytes of space available on each sibling.
- **
- */
- usableSpace = pBt->usableSize - 12 + leafCorrection;
- for(subtotal=k=i=0; i<nCell; i++){
- subtotal += szCell[i] + 2;
- if( subtotal > usableSpace ){
- szNew[k] = subtotal - szCell[i];
- cntNew[k] = i;
- if( leafData ){ i--; }
- subtotal = 0;
- k++;
- }
- }
- szNew[k] = subtotal;
- cntNew[k] = nCell;
- k++;
-
- /*
- ** The packing computed by the previous block is biased toward the siblings
- ** on the left side. The left siblings are always nearly full, while the
- ** right-most sibling might be nearly empty. This block of code attempts
- ** to adjust the packing of siblings to get a better balance.
- **
- ** This adjustment is more than an optimization. The packing above might
- ** be so out of balance as to be illegal. For example, the right-most
- ** sibling might be completely empty. This adjustment is not optional.
- */
- for(i=k-1; i>0; i--){
- int szRight = szNew[i]; /* Size of sibling on the right */
- int szLeft = szNew[i-1]; /* Size of sibling on the left */
- int r; /* Index of right-most cell in left sibling */
- int d; /* Index of first cell to the left of right sibling */
-
- r = cntNew[i-1] - 1;
- d = r + 1 - leafData;
- while( szRight==0 || szRight+szCell[d]+2<=szLeft-(szCell[r]+2) ){
- szRight += szCell[d] + 2;
- szLeft -= szCell[r] + 2;
- cntNew[i-1]--;
- r = cntNew[i-1] - 1;
- d = r + 1 - leafData;
- }
- szNew[i] = szRight;
- szNew[i-1] = szLeft;
- }
- assert( cntNew[0]>0 );
-
- /*
- ** Allocate k new pages. Reuse old pages where possible.
- */
- assert( pPage->pgno>1 );
- pageFlags = pPage->aData[0];
- for(i=0; i<k; i++){
- MemPage *pNew;
- if( i<nOld ){
- pNew = apNew[i] = apOld[i];
- pgnoNew[i] = pgnoOld[i];
- apOld[i] = 0;
- sqlite3pager_write(pNew->aData);
- }else{
- rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1]);
- if( rc ) goto balance_cleanup;
- apNew[i] = pNew;
- }
- nNew++;
- zeroPage(pNew, pageFlags);
- }
-
- /* Free any old pages that were not reused as new pages.
- */
- while( i<nOld ){
- rc = freePage(apOld[i]);
- if( rc ) goto balance_cleanup;
- releasePage(apOld[i]);
- apOld[i] = 0;
- i++;
- }
-
- /*
- ** Put the new pages in accending order. This helps to
- ** keep entries in the disk file in order so that a scan
- ** of the table is a linear scan through the file. That
- ** in turn helps the operating system to deliver pages
- ** from the disk more rapidly.
- **
- ** An O(n^2) insertion sort algorithm is used, but since
- ** n is never more than NB (a small constant), that should
- ** not be a problem.
- **
- ** When NB==3, this one optimization makes the database
- ** about 25% faster for large insertions and deletions.
- */
- for(i=0; i<k-1; i++){
- int minV = pgnoNew[i];
- int minI = i;
- for(j=i+1; j<k; j++){
- if( pgnoNew[j]<(unsigned)minV ){
- minI = j;
- minV = pgnoNew[j];
- }
- }
- if( minI>i ){
- int t;
- MemPage *pT;
- t = pgnoNew[i];
- pT = apNew[i];
- pgnoNew[i] = pgnoNew[minI];
- apNew[i] = apNew[minI];
- pgnoNew[minI] = t;
- apNew[minI] = pT;
- }
- }
- TRACE(("BALANCE: old: %d %d %d new: %d(%d) %d(%d) %d(%d) %d(%d) %d(%d)\n",
- pgnoOld[0],
- nOld>=2 ? pgnoOld[1] : 0,
- nOld>=3 ? pgnoOld[2] : 0,
- pgnoNew[0], szNew[0],
- nNew>=2 ? pgnoNew[1] : 0, nNew>=2 ? szNew[1] : 0,
- nNew>=3 ? pgnoNew[2] : 0, nNew>=3 ? szNew[2] : 0,
- nNew>=4 ? pgnoNew[3] : 0, nNew>=4 ? szNew[3] : 0,
- nNew>=5 ? pgnoNew[4] : 0, nNew>=5 ? szNew[4] : 0));
-
-
- /*
- ** Evenly distribute the data in apCell[] across the new pages.
- ** Insert divider cells into pParent as necessary.
- */
- j = 0;
- for(i=0; i<nNew; i++){
- MemPage *pNew = apNew[i];
- assert( pNew->pgno==pgnoNew[i] );
- assemblePage(pNew, cntNew[i]-j, &apCell[j], &szCell[j]);
- j = cntNew[i];
- assert( pNew->nCell>0 );
- assert( pNew->nOverflow==0 );
- if( i<nNew-1 && j<nCell ){
- u8 *pCell;
- u8 *pTemp;
- int sz;
- pCell = apCell[j];
- sz = szCell[j] + leafCorrection;
- if( !pNew->leaf ){
- memcpy(&pNew->aData[8], pCell, 4);
- pTemp = 0;
- }else if( leafData ){
- CellInfo info;
- j--;
- parseCellPtr(pNew, apCell[j], &info);
- pCell = &aSpace[iSpace];
- fillInCell(pParent, pCell, 0, info.nKey, 0, 0, &sz);
- iSpace += sz;
- assert( iSpace<=pBt->pageSize*5 );
- pTemp = 0;
- }else{
- pCell -= 4;
- pTemp = &aSpace[iSpace];
- iSpace += sz;
- assert( iSpace<=pBt->pageSize*5 );
- }
- insertCell(pParent, nxDiv, pCell, sz, pTemp);
- put4byte(findOverflowCell(pParent,nxDiv), pNew->pgno);
- j++;
- nxDiv++;
- }
- }
- assert( j==nCell );
- if( (pageFlags & PTF_LEAF)==0 ){
- memcpy(&apNew[nNew-1]->aData[8], &apCopy[nOld-1]->aData[8], 4);
- }
- if( nxDiv==pParent->nCell+pParent->nOverflow ){
- /* Right-most sibling is the right-most child of pParent */
- put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew[nNew-1]);
- }else{
- /* Right-most sibling is the left child of the first entry in pParent
- ** past the right-most divider entry */
- put4byte(findOverflowCell(pParent, nxDiv), pgnoNew[nNew-1]);
- }
-
- /*
- ** Reparent children of all cells.
- */
- for(i=0; i<nNew; i++){
- reparentChildPages(apNew[i]);
- }
- reparentChildPages(pParent);
-
- /*
- ** Balance the parent page. Note that the current page (pPage) might
- ** have been added to the freelist is it might no longer be initialized.
- ** But the parent page will always be initialized.
- */
- assert( pParent->isInit );
- /* assert( pPage->isInit ); // No! pPage might have been added to freelist */
- /* pageIntegrity(pPage); // No! pPage might have been added to freelist */
- rc = balance(pParent);
-
- /*
- ** Cleanup before returning.
- */
-balance_cleanup:
- sqliteFree(apCell);
- for(i=0; i<nOld; i++){
- releasePage(apOld[i]);
- }
- for(i=0; i<nNew; i++){
- releasePage(apNew[i]);
- }
- releasePage(pParent);
- TRACE(("BALANCE: finished with %d: old=%d new=%d cells=%d\n",
- pPage->pgno, nOld, nNew, nCell));
- return rc;
-}
-
-/*
-** This routine is called for the root page of a btree when the root
-** page contains no cells. This is an opportunity to make the tree
-** shallower by one level.
-*/
-static int balance_shallower(MemPage *pPage){
- MemPage *pChild; /* The only child page of pPage */
- Pgno pgnoChild; /* Page number for pChild */
- int rc = SQLITE_OK; /* Return code from subprocedures */
- Btree *pBt; /* The main BTree structure */
- int mxCellPerPage; /* Maximum number of cells per page */
- u8 **apCell; /* All cells from pages being balanced */
- int *szCell; /* Local size of all cells */
-
- assert( pPage->pParent==0 );
- assert( pPage->nCell==0 );
- pBt = pPage->pBt;
- mxCellPerPage = MX_CELL(pBt);
- apCell = sqliteMallocRaw( mxCellPerPage*(sizeof(u8*)+sizeof(int)) );
- if( apCell==0 ) return SQLITE_NOMEM;
- szCell = (int*)&apCell[mxCellPerPage];
- if( pPage->leaf ){
- /* The table is completely empty */
- TRACE(("BALANCE: empty table %d\n", pPage->pgno));
- }else{
- /* The root page is empty but has one child. Transfer the
- ** information from that one child into the root page if it
- ** will fit. This reduces the depth of the tree by one.
- **
- ** If the root page is page 1, it has less space available than
- ** its child (due to the 100 byte header that occurs at the beginning
- ** of the database fle), so it might not be able to hold all of the
- ** information currently contained in the child. If this is the
- ** case, then do not do the transfer. Leave page 1 empty except
- ** for the right-pointer to the child page. The child page becomes
- ** the virtual root of the tree.
- */
- pgnoChild = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- assert( pgnoChild>0 );
- assert( pgnoChild<=sqlite3pager_pagecount(pPage->pBt->pPager) );
- rc = getPage(pPage->pBt, pgnoChild, &pChild);
- if( rc ) goto end_shallow_balance;
- if( pPage->pgno==1 ){
- rc = initPage(pChild, pPage);
- if( rc ) goto end_shallow_balance;
- assert( pChild->nOverflow==0 );
- if( pChild->nFree>=100 ){
- /* The child information will fit on the root page, so do the
- ** copy */
- int i;
- zeroPage(pPage, pChild->aData[0]);
- for(i=0; i<pChild->nCell; i++){
- apCell[i] = findCell(pChild,i);
- szCell[i] = cellSizePtr(pChild, apCell[i]);
- }
- assemblePage(pPage, pChild->nCell, apCell, szCell);
- freePage(pChild);
- TRACE(("BALANCE: child %d transfer to page 1\n", pChild->pgno));
- }else{
- /* The child has more information that will fit on the root.
- ** The tree is already balanced. Do nothing. */
- TRACE(("BALANCE: child %d will not fit on page 1\n", pChild->pgno));
- }
- }else{
- memcpy(pPage->aData, pChild->aData, pPage->pBt->usableSize);
- pPage->isInit = 0;
- pPage->pParent = 0;
- rc = initPage(pPage, 0);
- assert( rc==SQLITE_OK );
- freePage(pChild);
- TRACE(("BALANCE: transfer child %d into root %d\n",
- pChild->pgno, pPage->pgno));
- }
- reparentChildPages(pPage);
- releasePage(pChild);
- }
-end_shallow_balance:
- sqliteFree(apCell);
- return rc;
-}
-
-
-/*
-** The root page is overfull
-**
-** When this happens, Create a new child page and copy the
-** contents of the root into the child. Then make the root
-** page an empty page with rightChild pointing to the new
-** child. Finally, call balance_internal() on the new child
-** to cause it to split.
-*/
-static int balance_deeper(MemPage *pPage){
- int rc; /* Return value from subprocedures */
- MemPage *pChild; /* Pointer to a new child page */
- Pgno pgnoChild; /* Page number of the new child page */
- Btree *pBt; /* The BTree */
- int usableSize; /* Total usable size of a page */
- u8 *data; /* Content of the parent page */
- u8 *cdata; /* Content of the child page */
- int hdr; /* Offset to page header in parent */
- int brk; /* Offset to content of first cell in parent */
-
- assert( pPage->pParent==0 );
- assert( pPage->nOverflow>0 );
- pBt = pPage->pBt;
- rc = allocatePage(pBt, &pChild, &pgnoChild, pPage->pgno);
- if( rc ) return rc;
- assert( sqlite3pager_iswriteable(pChild->aData) );
- usableSize = pBt->usableSize;
- data = pPage->aData;
- hdr = pPage->hdrOffset;
- brk = get2byte(&data[hdr+5]);
- cdata = pChild->aData;
- memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr);
- memcpy(&cdata[brk], &data[brk], usableSize-brk);
- rc = initPage(pChild, pPage);
- if( rc ) return rc;
- memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0]));
- pChild->nOverflow = pPage->nOverflow;
- if( pChild->nOverflow ){
- pChild->nFree = 0;
- }
- assert( pChild->nCell==pPage->nCell );
- zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF);
- put4byte(&pPage->aData[pPage->hdrOffset+8], pgnoChild);
- TRACE(("BALANCE: copy root %d into %d\n", pPage->pgno, pChild->pgno));
- rc = balance_nonroot(pChild);
- releasePage(pChild);
- return rc;
-}
-
-/*
-** Decide if the page pPage needs to be balanced. If balancing is
-** required, call the appropriate balancing routine.
-*/
-static int balance(MemPage *pPage){
- int rc = SQLITE_OK;
- if( pPage->pParent==0 ){
- if( pPage->nOverflow>0 ){
- rc = balance_deeper(pPage);
- }
- if( pPage->nCell==0 ){
- rc = balance_shallower(pPage);
- }
- }else{
- if( pPage->nOverflow>0 || pPage->nFree>pPage->pBt->usableSize*2/3 ){
- rc = balance_nonroot(pPage);
- }
- }
- return rc;
-}
-
-/*
-** This routine checks all cursors that point to table pgnoRoot.
-** If any of those cursors other than pExclude were opened with
-** wrFlag==0 then this routine returns SQLITE_LOCKED. If all
-** cursors that point to pgnoRoot were opened with wrFlag==1
-** then this routine returns SQLITE_OK.
-**
-** In addition to checking for read-locks (where a read-lock
-** means a cursor opened with wrFlag==0) this routine also moves
-** all cursors other than pExclude so that they are pointing to the
-** first Cell on root page. This is necessary because an insert
-** or delete might change the number of cells on a page or delete
-** a page entirely and we do not want to leave any cursors
-** pointing to non-existant pages or cells.
-*/
-static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){
- BtCursor *p;
- for(p=pBt->pCursor; p; p=p->pNext){
- if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue;
- if( p->wrFlag==0 ) return SQLITE_LOCKED;
- if( p->pPage->pgno!=p->pgnoRoot ){
- moveToRoot(p);
- }
- }
- return SQLITE_OK;
-}
-
-/*
-** Insert a new record into the BTree. The key is given by (pKey,nKey)
-** and the data is given by (pData,nData). The cursor is used only to
-** define what table the record should be inserted into. The cursor
-** is left pointing at a random location.
-**
-** For an INTKEY table, only the nKey value of the key is used. pKey is
-** ignored. For a ZERODATA table, the pData and nData are both ignored.
-*/
-int sqlite3BtreeInsert(
- BtCursor *pCur, /* Insert data into the table of this cursor */
- const void *pKey, i64 nKey, /* The key of the new record */
- const void *pData, int nData /* The data of the new record */
-){
- int rc;
- int loc;
- int szNew;
- MemPage *pPage;
- Btree *pBt = pCur->pBt;
- unsigned char *oldCell;
- unsigned char *newCell = 0;
-
- if( pCur->status ){
- return pCur->status; /* A rollback destroyed this cursor */
- }
- if( pBt->inTrans!=TRANS_WRITE ){
- /* Must start a transaction before doing an insert */
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
- }
- assert( !pBt->readOnly );
- if( !pCur->wrFlag ){
- return SQLITE_PERM; /* Cursor not open for writing */
- }
- if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
- return SQLITE_LOCKED; /* The table pCur points to has a read lock */
- }
- rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc);
- if( rc ) return rc;
- pPage = pCur->pPage;
- assert( pPage->intKey || nKey>=0 );
- assert( pPage->leaf || !pPage->leafData );
- TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
- pCur->pgnoRoot, nKey, nData, pPage->pgno,
- loc==0 ? "overwrite" : "new entry"));
- assert( pPage->isInit );
- rc = sqlite3pager_write(pPage->aData);
- if( rc ) return rc;
- newCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
- if( newCell==0 ) return SQLITE_NOMEM;
- rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, &szNew);
- if( rc ) goto end_insert;
- assert( szNew==cellSizePtr(pPage, newCell) );
- assert( szNew<=MX_CELL_SIZE(pBt) );
- if( loc==0 && pCur->isValid ){
- int szOld;
- assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
- oldCell = findCell(pPage, pCur->idx);
- if( !pPage->leaf ){
- memcpy(newCell, oldCell, 4);
- }
- szOld = cellSizePtr(pPage, oldCell);
- rc = clearCell(pPage, oldCell);
- if( rc ) goto end_insert;
- dropCell(pPage, pCur->idx, szOld);
- }else if( loc<0 && pPage->nCell>0 ){
- assert( pPage->leaf );
- pCur->idx++;
- pCur->info.nSize = 0;
- }else{
- assert( pPage->leaf );
- }
- insertCell(pPage, pCur->idx, newCell, szNew, 0);
- rc = balance(pPage);
- /* sqlite3BtreePageDump(pCur->pBt, pCur->pgnoRoot, 1); */
- /* fflush(stdout); */
- moveToRoot(pCur);
-end_insert:
- sqliteFree(newCell);
- return rc;
-}
-
-/*
-** Delete the entry that the cursor is pointing to. The cursor
-** is left pointing at a random location.
-*/
-int sqlite3BtreeDelete(BtCursor *pCur){
- MemPage *pPage = pCur->pPage;
- unsigned char *pCell;
- int rc;
- Pgno pgnoChild = 0;
- Btree *pBt = pCur->pBt;
-
- assert( pPage->isInit );
- if( pCur->status ){
- return pCur->status; /* A rollback destroyed this cursor */
- }
- if( pBt->inTrans!=TRANS_WRITE ){
- /* Must start a transaction before doing a delete */
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
- }
- assert( !pBt->readOnly );
- if( pCur->idx >= pPage->nCell ){
- return SQLITE_ERROR; /* The cursor is not pointing to anything */
- }
- if( !pCur->wrFlag ){
- return SQLITE_PERM; /* Did not open this cursor for writing */
- }
- if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
- return SQLITE_LOCKED; /* The table pCur points to has a read lock */
- }
- rc = sqlite3pager_write(pPage->aData);
- if( rc ) return rc;
- pCell = findCell(pPage, pCur->idx);
- if( !pPage->leaf ){
- pgnoChild = get4byte(pCell);
- }
- clearCell(pPage, pCell);
- if( !pPage->leaf ){
- /*
- ** The entry we are about to delete is not a leaf so if we do not
- ** do something we will leave a hole on an internal page.
- ** We have to fill the hole by moving in a cell from a leaf. The
- ** next Cell after the one to be deleted is guaranteed to exist and
- ** to be a leaf so we can use it.
- */
- BtCursor leafCur;
- unsigned char *pNext;
- int szNext;
- int notUsed;
- unsigned char *tempCell;
- assert( !pPage->leafData );
- getTempCursor(pCur, &leafCur);
- rc = sqlite3BtreeNext(&leafCur, &notUsed);
- if( rc!=SQLITE_OK ){
- if( rc!=SQLITE_NOMEM ){
- rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }
- return rc;
- }
- rc = sqlite3pager_write(leafCur.pPage->aData);
- if( rc ) return rc;
- TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n",
- pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno));
- dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell));
- pNext = findCell(leafCur.pPage, leafCur.idx);
- szNext = cellSizePtr(leafCur.pPage, pNext);
- assert( MX_CELL_SIZE(pBt)>=szNext+4 );
- tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
- if( tempCell==0 ) return SQLITE_NOMEM;
- insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell);
- put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild);
- rc = balance(pPage);
- sqliteFree(tempCell);
- if( rc ) return rc;
- dropCell(leafCur.pPage, leafCur.idx, szNext);
- rc = balance(leafCur.pPage);
- releaseTempCursor(&leafCur);
- }else{
- TRACE(("DELETE: table=%d delete from leaf %d\n",
- pCur->pgnoRoot, pPage->pgno));
- dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell));
- rc = balance(pPage);
- }
- moveToRoot(pCur);
- return rc;
-}
-
-/*
-** Create a new BTree table. Write into *piTable the page
-** number for the root page of the new table.
-**
-** The type of type is determined by the flags parameter. Only the
-** following values of flags are currently in use. Other values for
-** flags might not work:
-**
-** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
-** BTREE_ZERODATA Used for SQL indices
-*/
-int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){
- MemPage *pRoot;
- Pgno pgnoRoot;
- int rc;
- if( pBt->inTrans!=TRANS_WRITE ){
- /* Must start a transaction first */
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
- }
- if( pBt->readOnly ){
- return SQLITE_READONLY;
- }
- rc = allocatePage(pBt, &pRoot, &pgnoRoot, 1);
- if( rc ) return rc;
- assert( sqlite3pager_iswriteable(pRoot->aData) );
- zeroPage(pRoot, flags | PTF_LEAF);
- sqlite3pager_unref(pRoot->aData);
- *piTable = (int)pgnoRoot;
- return SQLITE_OK;
-}
-
-/*
-** Erase the given database page and all its children. Return
-** the page to the freelist.
-*/
-static int clearDatabasePage(
- Btree *pBt, /* The BTree that contains the table */
- Pgno pgno, /* Page number to clear */
- MemPage *pParent, /* Parent page. NULL for the root */
- int freePageFlag /* Deallocate page if true */
-){
- MemPage *pPage;
- int rc;
- unsigned char *pCell;
- int i;
-
- rc = getAndInitPage(pBt, pgno, &pPage, pParent);
- if( rc ) return rc;
- rc = sqlite3pager_write(pPage->aData);
- if( rc ) return rc;
- for(i=0; i<pPage->nCell; i++){
- pCell = findCell(pPage, i);
- if( !pPage->leaf ){
- rc = clearDatabasePage(pBt, get4byte(pCell), pPage->pParent, 1);
- if( rc ) return rc;
- }
- rc = clearCell(pPage, pCell);
- if( rc ) return rc;
- }
- if( !pPage->leaf ){
- rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), pPage->pParent, 1);
- if( rc ) return rc;
- }
- if( freePageFlag ){
- rc = freePage(pPage);
- }else{
- zeroPage(pPage, pPage->aData[0] | PTF_LEAF);
- }
- releasePage(pPage);
- return rc;
-}
-
-/*
-** Delete all information from a single table in the database. iTable is
-** the page number of the root of the table. After this routine returns,
-** the root page is empty, but still exists.
-**
-** This routine will fail with SQLITE_LOCKED if there are any open
-** read cursors on the table. Open write cursors are moved to the
-** root of the table.
-*/
-int sqlite3BtreeClearTable(Btree *pBt, int iTable){
- int rc;
- BtCursor *pCur;
- if( pBt->inTrans!=TRANS_WRITE ){
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
- }
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- if( pCur->pgnoRoot==(Pgno)iTable ){
- if( pCur->wrFlag==0 ) return SQLITE_LOCKED;
- moveToRoot(pCur);
- }
- }
- rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0);
- if( rc ){
- sqlite3BtreeRollback(pBt);
- }
- return rc;
-}
-
-/*
-** Erase all information in a table and add the root of the table to
-** the freelist. Except, the root of the principle table (the one on
-** page 1) is never added to the freelist.
-**
-** This routine will fail with SQLITE_LOCKED if there are any open
-** cursors on the table.
-*/
-int sqlite3BtreeDropTable(Btree *pBt, int iTable){
- int rc;
- MemPage *pPage;
- BtCursor *pCur;
- if( pBt->inTrans!=TRANS_WRITE ){
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
- }
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- if( pCur->pgnoRoot==(Pgno)iTable ){
- return SQLITE_LOCKED; /* Cannot drop a table that has a cursor */
- }
- }
- rc = getPage(pBt, (Pgno)iTable, &pPage);
- if( rc ) return rc;
- rc = sqlite3BtreeClearTable(pBt, iTable);
- if( rc ) return rc;
- if( iTable>1 ){
- rc = freePage(pPage);
- }else{
- zeroPage(pPage, PTF_INTKEY|PTF_LEAF );
- }
- releasePage(pPage);
- return rc;
-}
-
-
-/*
-** Read the meta-information out of a database file. Meta[0]
-** is the number of free pages currently in the database. Meta[1]
-** through meta[15] are available for use by higher layers. Meta[0]
-** is read-only, the others are read/write.
-**
-** The schema layer numbers meta values differently. At the schema
-** layer (and the SetCookie and ReadCookie opcodes) the number of
-** free pages is not visible. So Cookie[0] is the same as Meta[1].
-*/
-int sqlite3BtreeGetMeta(Btree *pBt, int idx, u32 *pMeta){
- int rc;
- unsigned char *pP1;
-
- assert( idx>=0 && idx<=15 );
- rc = sqlite3pager_get(pBt->pPager, 1, (void**)&pP1);
- if( rc ) return rc;
- *pMeta = get4byte(&pP1[36 + idx*4]);
- sqlite3pager_unref(pP1);
-
- /* The current implementation is unable to handle writes to an autovacuumed
- ** database. So make such a database readonly. */
- if( idx==4 && *pMeta>0 ) pBt->readOnly = 1;
-
- return SQLITE_OK;
-}
-
-/*
-** Write meta-information back into the database. Meta[0] is
-** read-only and may not be written.
-*/
-int sqlite3BtreeUpdateMeta(Btree *pBt, int idx, u32 iMeta){
- unsigned char *pP1;
- int rc;
- assert( idx>=1 && idx<=15 );
- if( pBt->inTrans!=TRANS_WRITE ){
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
- }
- assert( pBt->pPage1!=0 );
- pP1 = pBt->pPage1->aData;
- rc = sqlite3pager_write(pP1);
- if( rc ) return rc;
- put4byte(&pP1[36 + idx*4], iMeta);
- return SQLITE_OK;
-}
-
-/*
-** Return the flag byte at the beginning of the page that the cursor
-** is currently pointing to.
-*/
-int sqlite3BtreeFlags(BtCursor *pCur){
- MemPage *pPage = pCur->pPage;
- return pPage ? pPage->aData[pPage->hdrOffset] : 0;
-}
-
-/*
-** Print a disassembly of the given page on standard output. This routine
-** is used for debugging and testing only.
-*/
-#ifdef SQLITE_TEST
-int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
- int rc;
- MemPage *pPage;
- int i, j, c;
- int nFree;
- u16 idx;
- int hdr;
- int nCell;
- int isInit;
- unsigned char *data;
- char range[20];
- unsigned char payload[20];
-
- rc = getPage(pBt, (Pgno)pgno, &pPage);
- isInit = pPage->isInit;
- if( pPage->isInit==0 ){
- initPage(pPage, 0);
- }
- if( rc ){
- return rc;
- }
- hdr = pPage->hdrOffset;
- data = pPage->aData;
- c = data[hdr];
- pPage->intKey = (c & (PTF_INTKEY|PTF_LEAFDATA))!=0;
- pPage->zeroData = (c & PTF_ZERODATA)!=0;
- pPage->leafData = (c & PTF_LEAFDATA)!=0;
- pPage->leaf = (c & PTF_LEAF)!=0;
- pPage->hasData = !(pPage->zeroData || (!pPage->leaf && pPage->leafData));
- nCell = get2byte(&data[hdr+3]);
- sqlite3DebugPrintf("PAGE %d: flags=0x%02x frag=%d parent=%d\n", pgno,
- data[hdr], data[hdr+7],
- (pPage->isInit && pPage->pParent) ? pPage->pParent->pgno : 0);
- assert( hdr == (pgno==1 ? 100 : 0) );
- idx = hdr + 12 - pPage->leaf*4;
- for(i=0; i<nCell; i++){
- CellInfo info;
- Pgno child;
- unsigned char *pCell;
- int sz;
- int addr;
-
- addr = get2byte(&data[idx + 2*i]);
- pCell = &data[addr];
- parseCellPtr(pPage, pCell, &info);
- sz = info.nSize;
- sprintf(range,"%d..%d", addr, addr+sz-1);
- if( pPage->leaf ){
- child = 0;
- }else{
- child = get4byte(pCell);
- }
- sz = info.nData;
- if( !pPage->intKey ) sz += info.nKey;
- if( sz>sizeof(payload)-1 ) sz = sizeof(payload)-1;
- memcpy(payload, &pCell[info.nHeader], sz);
- for(j=0; j<sz; j++){
- if( payload[j]<0x20 || payload[j]>0x7f ) payload[j] = '.';
- }
- payload[sz] = 0;
- sqlite3DebugPrintf(
- "cell %2d: i=%-10s chld=%-4d nk=%-4lld nd=%-4d payload=%s\n",
- i, range, child, info.nKey, info.nData, payload
- );
- }
- if( !pPage->leaf ){
- sqlite3DebugPrintf("right_child: %d\n", get4byte(&data[hdr+8]));
- }
- nFree = 0;
- i = 0;
- idx = get2byte(&data[hdr+1]);
- while( idx>0 && idx<pPage->pBt->usableSize ){
- int sz = get2byte(&data[idx+2]);
- sprintf(range,"%d..%d", idx, idx+sz-1);
- nFree += sz;
- sqlite3DebugPrintf("freeblock %2d: i=%-10s size=%-4d total=%d\n",
- i, range, sz, nFree);
- idx = get2byte(&data[idx]);
- i++;
- }
- if( idx!=0 ){
- sqlite3DebugPrintf("ERROR: next freeblock index out of range: %d\n", idx);
- }
- if( recursive && !pPage->leaf ){
- for(i=0; i<nCell; i++){
- unsigned char *pCell = findCell(pPage, i);
- sqlite3BtreePageDump(pBt, get4byte(pCell), 1);
- idx = get2byte(pCell);
- }
- sqlite3BtreePageDump(pBt, get4byte(&data[hdr+8]), 1);
- }
- pPage->isInit = isInit;
- sqlite3pager_unref(data);
- fflush(stdout);
- return SQLITE_OK;
-}
-#endif
-
-#ifdef SQLITE_TEST
-/*
-** Fill aResult[] with information about the entry and page that the
-** cursor is pointing to.
-**
-** aResult[0] = The page number
-** aResult[1] = The entry number
-** aResult[2] = Total number of entries on this page
-** aResult[3] = Cell size (local payload + header)
-** aResult[4] = Number of free bytes on this page
-** aResult[5] = Number of free blocks on the page
-** aResult[6] = Total payload size (local + overflow)
-** aResult[7] = Header size in bytes
-** aResult[8] = Local payload size
-** aResult[9] = Parent page number
-**
-** This routine is used for testing and debugging only.
-*/
-int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
- int cnt, idx;
- MemPage *pPage = pCur->pPage;
- BtCursor tmpCur;
-
- pageIntegrity(pPage);
- assert( pPage->isInit );
- getTempCursor(pCur, &tmpCur);
- while( upCnt-- ){
- moveToParent(&tmpCur);
- }
- pPage = tmpCur.pPage;
- pageIntegrity(pPage);
- aResult[0] = sqlite3pager_pagenumber(pPage->aData);
- assert( aResult[0]==pPage->pgno );
- aResult[1] = tmpCur.idx;
- aResult[2] = pPage->nCell;
- if( tmpCur.idx>=0 && tmpCur.idx<pPage->nCell ){
- getCellInfo(&tmpCur);
- aResult[3] = tmpCur.info.nSize;
- aResult[6] = tmpCur.info.nData;
- aResult[7] = tmpCur.info.nHeader;
- aResult[8] = tmpCur.info.nLocal;
- }else{
- aResult[3] = 0;
- aResult[6] = 0;
- aResult[7] = 0;
- aResult[8] = 0;
- }
- aResult[4] = pPage->nFree;
- cnt = 0;
- idx = get2byte(&pPage->aData[pPage->hdrOffset+1]);
- while( idx>0 && idx<pPage->pBt->usableSize ){
- cnt++;
- idx = get2byte(&pPage->aData[idx]);
- }
- aResult[5] = cnt;
- if( pPage->pParent==0 || isRootPage(pPage) ){
- aResult[9] = 0;
- }else{
- aResult[9] = pPage->pParent->pgno;
- }
- releaseTempCursor(&tmpCur);
- return SQLITE_OK;
-}
-#endif
-
-/*
-** Return the pager associated with a BTree. This routine is used for
-** testing and debugging only.
-*/
-Pager *sqlite3BtreePager(Btree *pBt){
- return pBt->pPager;
-}
-
-/*
-** This structure is passed around through all the sanity checking routines
-** in order to keep track of some global state information.
-*/
-typedef struct IntegrityCk IntegrityCk;
-struct IntegrityCk {
- Btree *pBt; /* The tree being checked out */
- Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
- int nPage; /* Number of pages in the database */
- int *anRef; /* Number of times each page is referenced */
- char *zErrMsg; /* An error message. NULL of no errors seen. */
-};
-
-/*
-** Append a message to the error message string.
-*/
-static void checkAppendMsg(
- IntegrityCk *pCheck,
- char *zMsg1,
- const char *zFormat,
- ...
-){
- va_list ap;
- char *zMsg2;
- va_start(ap, zFormat);
- zMsg2 = sqlite3VMPrintf(zFormat, ap);
- va_end(ap);
- if( zMsg1==0 ) zMsg1 = "";
- if( pCheck->zErrMsg ){
- char *zOld = pCheck->zErrMsg;
- pCheck->zErrMsg = 0;
- sqlite3SetString(&pCheck->zErrMsg, zOld, "\n", zMsg1, zMsg2, (char*)0);
- sqliteFree(zOld);
- }else{
- sqlite3SetString(&pCheck->zErrMsg, zMsg1, zMsg2, (char*)0);
- }
- sqliteFree(zMsg2);
-}
-
-/*
-** Add 1 to the reference count for page iPage. If this is the second
-** reference to the page, add an error message to pCheck->zErrMsg.
-** Return 1 if there are 2 ore more references to the page and 0 if
-** if this is the first reference to the page.
-**
-** Also check that the page number is in bounds.
-*/
-static int checkRef(IntegrityCk *pCheck, int iPage, char *zContext){
- if( iPage==0 ) return 1;
- if( iPage>pCheck->nPage || iPage<0 ){
- checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage);
- return 1;
- }
- if( pCheck->anRef[iPage]==1 ){
- checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage);
- return 1;
- }
- return (pCheck->anRef[iPage]++)>1;
-}
-
-/*
-** Check the integrity of the freelist or of an overflow page list.
-** Verify that the number of pages on the list is N.
-*/
-static void checkList(
- IntegrityCk *pCheck, /* Integrity checking context */
- int isFreeList, /* True for a freelist. False for overflow page list */
- int iPage, /* Page number for first page in the list */
- int N, /* Expected number of pages in the list */
- char *zContext /* Context for error messages */
-){
- int i;
- int expected = N;
- int iFirst = iPage;
- while( N-- > 0 ){
- unsigned char *pOvfl;
- if( iPage<1 ){
- checkAppendMsg(pCheck, zContext,
- "%d of %d pages missing from overflow list starting at %d",
- N+1, expected, iFirst);
- break;
- }
- if( checkRef(pCheck, iPage, zContext) ) break;
- if( sqlite3pager_get(pCheck->pPager, (Pgno)iPage, (void**)&pOvfl) ){
- checkAppendMsg(pCheck, zContext, "failed to get page %d", iPage);
- break;
- }
- if( isFreeList ){
- int n = get4byte(&pOvfl[4]);
- if( n>pCheck->pBt->usableSize/4-8 ){
- checkAppendMsg(pCheck, zContext,
- "freelist leaf count too big on page %d", iPage);
- N--;
- }else{
- for(i=0; i<n; i++){
- checkRef(pCheck, get4byte(&pOvfl[8+i*4]), zContext);
- }
- N -= n;
- }
- }
- iPage = get4byte(pOvfl);
- sqlite3pager_unref(pOvfl);
- }
-}
-
-/*
-** Do various sanity checks on a single page of a tree. Return
-** the tree depth. Root pages return 0. Parents of root pages
-** return 1, and so forth.
-**
-** These checks are done:
-**
-** 1. Make sure that cells and freeblocks do not overlap
-** but combine to completely cover the page.
-** NO 2. Make sure cell keys are in order.
-** NO 3. Make sure no key is less than or equal to zLowerBound.
-** NO 4. Make sure no key is greater than or equal to zUpperBound.
-** 5. Check the integrity of overflow pages.
-** 6. Recursively call checkTreePage on all children.
-** 7. Verify that the depth of all children is the same.
-** 8. Make sure this page is at least 33% full or else it is
-** the root of the tree.
-*/
-static int checkTreePage(
- IntegrityCk *pCheck, /* Context for the sanity check */
- int iPage, /* Page number of the page to check */
- MemPage *pParent, /* Parent page */
- char *zParentContext, /* Parent context */
- char *zLowerBound, /* All keys should be greater than this, if not NULL */
- int nLower, /* Number of characters in zLowerBound */
- char *zUpperBound, /* All keys should be less than this, if not NULL */
- int nUpper /* Number of characters in zUpperBound */
-){
- MemPage *pPage;
- int i, rc, depth, d2, pgno, cnt;
- int hdr, cellStart;
- int nCell;
- u8 *data;
- BtCursor cur;
- Btree *pBt;
- int maxLocal, usableSize;
- char zContext[100];
- char *hit;
-
- /* Check that the page exists
- */
- cur.pBt = pBt = pCheck->pBt;
- usableSize = pBt->usableSize;
- if( iPage==0 ) return 0;
- if( checkRef(pCheck, iPage, zParentContext) ) return 0;
- if( (rc = getPage(pBt, (Pgno)iPage, &pPage))!=0 ){
- checkAppendMsg(pCheck, zContext,
- "unable to get the page. error code=%d", rc);
- return 0;
- }
- maxLocal = pPage->leafData ? pBt->maxLeaf : pBt->maxLocal;
- if( (rc = initPage(pPage, pParent))!=0 ){
- checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc);
- releasePage(pPage);
- return 0;
- }
-
- /* Check out all the cells.
- */
- depth = 0;
- cur.pPage = pPage;
- for(i=0; i<pPage->nCell; i++){
- u8 *pCell;
- int sz;
- CellInfo info;
-
- /* Check payload overflow pages
- */
- sprintf(zContext, "On tree page %d cell %d: ", iPage, i);
- pCell = findCell(pPage,i);
- parseCellPtr(pPage, pCell, &info);
- sz = info.nData;
- if( !pPage->intKey ) sz += info.nKey;
- if( sz>info.nLocal ){
- int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4);
- checkList(pCheck, 0, get4byte(&pCell[info.iOverflow]),nPage,zContext);
- }
-
- /* Check sanity of left child page.
- */
- if( !pPage->leaf ){
- pgno = get4byte(pCell);
- d2 = checkTreePage(pCheck,pgno,pPage,zContext,0,0,0,0);
- if( i>0 && d2!=depth ){
- checkAppendMsg(pCheck, zContext, "Child page depth differs");
- }
- depth = d2;
- }
- }
- if( !pPage->leaf ){
- pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- sprintf(zContext, "On page %d at right child: ", iPage);
- checkTreePage(pCheck, pgno, pPage, zContext,0,0,0,0);
- }
-
- /* Check for complete coverage of the page
- */
- data = pPage->aData;
- hdr = pPage->hdrOffset;
- hit = sqliteMalloc( usableSize );
- if( hit ){
- memset(hit, 1, get2byte(&data[hdr+5]));
- nCell = get2byte(&data[hdr+3]);
- cellStart = hdr + 12 - 4*pPage->leaf;
- for(i=0; i<nCell; i++){
- int pc = get2byte(&data[cellStart+i*2]);
- int size = cellSizePtr(pPage, &data[pc]);
- int j;
- for(j=pc+size-1; j>=pc; j--) hit[j]++;
- }
- for(cnt=0, i=get2byte(&data[hdr+1]); i>0 && i<usableSize && cnt<10000;
- cnt++){
- int size = get2byte(&data[i+2]);
- int j;
- for(j=i+size-1; j>=i; j--) hit[j]++;
- i = get2byte(&data[i]);
- }
- for(i=cnt=0; i<usableSize; i++){
- if( hit[i]==0 ){
- cnt++;
- }else if( hit[i]>1 ){
- checkAppendMsg(pCheck, 0,
- "Multiple uses for byte %d of page %d", i, iPage);
- break;
- }
- }
- if( cnt!=data[hdr+7] ){
- checkAppendMsg(pCheck, 0,
- "Fragmented space is %d byte reported as %d on page %d",
- cnt, data[hdr+7], iPage);
- }
- }
- sqliteFree(hit);
-
- releasePage(pPage);
- return depth+1;
-}
-
-/*
-** This routine does a complete check of the given BTree file. aRoot[] is
-** an array of pages numbers were each page number is the root page of
-** a table. nRoot is the number of entries in aRoot.
-**
-** If everything checks out, this routine returns NULL. If something is
-** amiss, an error message is written into memory obtained from malloc()
-** and a pointer to that error message is returned. The calling function
-** is responsible for freeing the error message when it is done.
-*/
-char *sqlite3BtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){
- int i;
- int nRef;
- IntegrityCk sCheck;
-
- nRef = *sqlite3pager_stats(pBt->pPager);
- if( lockBtree(pBt)!=SQLITE_OK ){
- return sqliteStrDup("Unable to acquire a read lock on the database");
- }
- sCheck.pBt = pBt;
- sCheck.pPager = pBt->pPager;
- sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager);
- if( sCheck.nPage==0 ){
- unlockBtreeIfUnused(pBt);
- return 0;
- }
- sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
- for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; }
- i = PENDING_BYTE/pBt->pageSize + 1;
- if( i<=sCheck.nPage ){
- sCheck.anRef[i] = 1;
- }
- sCheck.zErrMsg = 0;
-
- /* Check the integrity of the freelist
- */
- checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
- get4byte(&pBt->pPage1->aData[36]), "Main freelist: ");
-
- /* Check all the tables.
- */
- for(i=0; i<nRoot; i++){
- if( aRoot[i]==0 ) continue;
- checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ", 0,0,0,0);
- }
-
- /* Make sure every page in the file is referenced
- */
- for(i=1; i<=sCheck.nPage; i++){
- if( sCheck.anRef[i]==0 ){
- checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
- }
- }
-
- /* Make sure this analysis did not leave any unref() pages
- */
- unlockBtreeIfUnused(pBt);
- if( nRef != *sqlite3pager_stats(pBt->pPager) ){
- checkAppendMsg(&sCheck, 0,
- "Outstanding page count goes from %d to %d during this analysis",
- nRef, *sqlite3pager_stats(pBt->pPager)
- );
- }
-
- /* Clean up and report errors.
- */
- sqliteFree(sCheck.anRef);
- return sCheck.zErrMsg;
-}
-
-/*
-** Return the full pathname of the underlying database file.
-*/
-const char *sqlite3BtreeGetFilename(Btree *pBt){
- assert( pBt->pPager!=0 );
- return sqlite3pager_filename(pBt->pPager);
-}
-
-/*
-** Return the pathname of the directory that contains the database file.
-*/
-const char *sqlite3BtreeGetDirname(Btree *pBt){
- assert( pBt->pPager!=0 );
- return sqlite3pager_dirname(pBt->pPager);
-}
-
-/*
-** Return the pathname of the journal file for this database. The return
-** value of this routine is the same regardless of whether the journal file
-** has been created or not.
-*/
-const char *sqlite3BtreeGetJournalname(Btree *pBt){
- assert( pBt->pPager!=0 );
- return sqlite3pager_journalname(pBt->pPager);
-}
-
-/*
-** Copy the complete content of pBtFrom into pBtTo. A transaction
-** must be active for both files.
-**
-** The size of file pBtFrom may be reduced by this operation.
-** If anything goes wrong, the transaction on pBtFrom is rolled back.
-*/
-int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
- int rc = SQLITE_OK;
- Pgno i, nPage, nToPage;
-
- if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){
- return SQLITE_ERROR;
- }
- if( pBtTo->pCursor ) return SQLITE_BUSY;
- nToPage = sqlite3pager_pagecount(pBtTo->pPager);
- nPage = sqlite3pager_pagecount(pBtFrom->pPager);
- for(i=1; rc==SQLITE_OK && i<=nPage; i++){
- void *pPage;
- rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage);
- if( rc ) break;
- rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage);
- if( rc ) break;
- sqlite3pager_unref(pPage);
- }
- for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
- void *pPage;
- rc = sqlite3pager_get(pBtTo->pPager, i, &pPage);
- if( rc ) break;
- rc = sqlite3pager_write(pPage);
- sqlite3pager_unref(pPage);
- sqlite3pager_dont_write(pBtTo->pPager, i);
- }
- if( !rc && nPage<nToPage ){
- rc = sqlite3pager_truncate(pBtTo->pPager, nPage);
- }
- if( rc ){
- sqlite3BtreeRollback(pBtTo);
- }
- return rc;
-}
-
-/*
-** Return non-zero if a transaction is active.
-*/
-int sqlite3BtreeIsInTrans(Btree *pBt){
- return (pBt && (pBt->inTrans==TRANS_WRITE));
-}
-
-/*
-** Return non-zero if a statement transaction is active.
-*/
-int sqlite3BtreeIsInStmt(Btree *pBt){
- return (pBt && pBt->inStmt);
-}
-
-/*
-** This call is a no-op if no write-transaction is currently active on pBt.
-**
-** Otherwise, sync the database file for the btree pBt. zMaster points to
-** the name of a master journal file that should be written into the
-** individual journal file, or is NULL, indicating no master journal file
-** (single database transaction).
-**
-** When this is called, the master journal should already have been
-** created, populated with this journal pointer and synced to disk.
-**
-** Once this is routine has returned, the only thing required to commit
-** the write-transaction for this database file is to delete the journal.
-*/
-int sqlite3BtreeSync(Btree *pBt, const char *zMaster){
- if( pBt->inTrans==TRANS_WRITE ){
- return sqlite3pager_sync(pBt->pPager, zMaster);
- }
- return SQLITE_OK;
-}
diff --git a/kopete/plugins/statistics/sqlite/btree.h b/kopete/plugins/statistics/sqlite/btree.h
deleted file mode 100644
index 48524aef..00000000
--- a/kopete/plugins/statistics/sqlite/btree.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This header file defines the interface that the sqlite B-Tree file
-** subsystem. See comments in the source code for a detailed description
-** of what each interface routine does.
-**
-** @(#) $Id$
-*/
-#ifndef _BTREE_H_
-#define _BTREE_H_
-
-/* TODO: This definition is just included so other modules compile. It
-** needs to be revisited.
-*/
-#define SQLITE_N_BTREE_META 10
-
-/*
-** Forward declarations of structure
-*/
-typedef struct Btree Btree;
-typedef struct BtCursor BtCursor;
-
-
-int sqlite3BtreeOpen(
- const char *zFilename, /* Name of database file to open */
- Btree **, /* Return open Btree* here */
- int flags /* Flags */
-);
-
-/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the
-** following values.
-*/
-#define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */
-#define BTREE_MEMORY 2 /* In-memory DB. No argument */
-
-int sqlite3BtreeClose(Btree*);
-int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
-int sqlite3BtreeSetCacheSize(Btree*,int);
-int sqlite3BtreeSetSafetyLevel(Btree*,int);
-int sqlite3BtreeSetPageSize(Btree*,int,int);
-int sqlite3BtreeGetPageSize(Btree*);
-int sqlite3BtreeGetReserve(Btree*);
-int sqlite3BtreeBeginTrans(Btree*,int);
-int sqlite3BtreeCommit(Btree*);
-int sqlite3BtreeRollback(Btree*);
-int sqlite3BtreeBeginStmt(Btree*);
-int sqlite3BtreeCommitStmt(Btree*);
-int sqlite3BtreeRollbackStmt(Btree*);
-int sqlite3BtreeCreateTable(Btree*, int*, int flags);
-int sqlite3BtreeIsInTrans(Btree*);
-int sqlite3BtreeIsInStmt(Btree*);
-int sqlite3BtreeSync(Btree*, const char *zMaster);
-
-const char *sqlite3BtreeGetFilename(Btree *);
-const char *sqlite3BtreeGetDirname(Btree *);
-const char *sqlite3BtreeGetJournalname(Btree *);
-int sqlite3BtreeCopyFile(Btree *, Btree *);
-
-/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
-** of the following flags:
-*/
-#define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
-#define BTREE_ZERODATA 2 /* Table has keys only - no data */
-#define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */
-
-int sqlite3BtreeDropTable(Btree*, int);
-int sqlite3BtreeClearTable(Btree*, int);
-int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
-int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
-
-int sqlite3BtreeCursor(
- Btree*, /* BTree containing table to open */
- int iTable, /* Index of root page */
- int wrFlag, /* 1 for writing. 0 for read-only */
- int(*)(void*,int,const void*,int,const void*), /* Key comparison function */
- void*, /* First argument to compare function */
- BtCursor **ppCursor /* Returned cursor */
-);
-
-void sqlite3BtreeSetCompare(
- BtCursor *,
- int(*)(void*,int,const void*,int,const void*),
- void*
-);
-
-int sqlite3BtreeCloseCursor(BtCursor*);
-int sqlite3BtreeMoveto(BtCursor*, const void *pKey, i64 nKey, int *pRes);
-int sqlite3BtreeDelete(BtCursor*);
-int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
- const void *pData, int nData);
-int sqlite3BtreeFirst(BtCursor*, int *pRes);
-int sqlite3BtreeLast(BtCursor*, int *pRes);
-int sqlite3BtreeNext(BtCursor*, int *pRes);
-int sqlite3BtreeEof(BtCursor*);
-int sqlite3BtreeFlags(BtCursor*);
-int sqlite3BtreePrevious(BtCursor*, int *pRes);
-int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
-int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
-const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
-const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
-int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
-int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
-
-char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot);
-struct Pager *sqlite3BtreePager(Btree*);
-
-
-#ifdef SQLITE_TEST
-int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
-void sqlite3BtreeCursorList(Btree*);
-int sqlite3BtreePageDump(Btree*, int, int recursive);
-#endif
-
-
-#endif /* _BTREE_H_ */
diff --git a/kopete/plugins/statistics/sqlite/build.c b/kopete/plugins/statistics/sqlite/build.c
deleted file mode 100644
index 3e5e08a5..00000000
--- a/kopete/plugins/statistics/sqlite/build.c
+++ /dev/null
@@ -1,2564 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains C code routines that are called by the SQLite parser
-** when syntax rules are reduced. The routines in this file handle the
-** following kinds of SQL syntax:
-**
-** CREATE TABLE
-** DROP TABLE
-** CREATE INDEX
-** DROP INDEX
-** creating ID lists
-** BEGIN TRANSACTION
-** COMMIT
-** ROLLBACK
-** PRAGMA
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-#include <ctype.h>
-
-/*
-** This routine is called when a new SQL statement is beginning to
-** be parsed. Check to see if the schema for the database needs
-** to be read from the SQLITE_MASTER and SQLITE_TEMP_MASTER tables.
-** If it does, then read it.
-*/
-void sqlite3BeginParse(Parse *pParse, int explainFlag){
- pParse->explain = explainFlag;
- pParse->nVar = 0;
-}
-
-/*
-** This routine is called after a single SQL statement has been
-** parsed and a VDBE program to execute that statement has been
-** prepared. This routine puts the finishing touches on the
-** VDBE program and resets the pParse structure for the next
-** parse.
-**
-** Note that if an error occurred, it might be the case that
-** no VDBE code was generated.
-*/
-void sqlite3FinishCoding(Parse *pParse){
- sqlite3 *db;
- Vdbe *v;
-
- if( sqlite3_malloc_failed ) return;
-
- /* Begin by generating some termination code at the end of the
- ** vdbe program
- */
- db = pParse->db;
- v = sqlite3GetVdbe(pParse);
- if( v ){
- sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
-
- /* The cookie mask contains one bit for each database file open.
- ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
- ** set for each database that is used. Generate code to start a
- ** transaction on each used database and to verify the schema cookie
- ** on each used database.
- */
- if( pParse->cookieGoto>0 ){
- u32 mask;
- int iDb;
- sqlite3VdbeChangeP2(v, pParse->cookieGoto-1, sqlite3VdbeCurrentAddr(v));
- for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
- if( (mask & pParse->cookieMask)==0 ) continue;
- sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
- sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
- }
- sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
- }
-
- /* Add a No-op that contains the complete text of the compiled SQL
- ** statement as its P3 argument. This does not change the functionality
- ** of the program.
- **
- ** This is used to implement sqlite3_trace() functionality.
- */
- sqlite3VdbeOp3(v, OP_Noop, 0, 0, pParse->zSql, pParse->zTail-pParse->zSql);
- }
-
-
- /* Get the VDBE program ready for execution
- */
- if( v && pParse->nErr==0 ){
- FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
- sqlite3VdbeTrace(v, trace);
- sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
- pParse->nTab+3, pParse->explain);
- pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
- pParse->colNamesSet = 0;
- }else if( pParse->rc==SQLITE_OK ){
- pParse->rc = SQLITE_ERROR;
- }
- pParse->nTab = 0;
- pParse->nMem = 0;
- pParse->nSet = 0;
- pParse->nAgg = 0;
- pParse->nVar = 0;
- pParse->cookieMask = 0;
- pParse->cookieGoto = 0;
-}
-
-/*
-** Locate the in-memory structure that describes a particular database
-** table given the name of that table and (optionally) the name of the
-** database containing the table. Return NULL if not found.
-**
-** If zDatabase is 0, all databases are searched for the table and the
-** first matching table is returned. (No checking for duplicate table
-** names is done.) The search order is TEMP first, then MAIN, then any
-** auxiliary databases added using the ATTACH command.
-**
-** See also sqlite3LocateTable().
-*/
-Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
- Table *p = 0;
- int i;
- assert( zName!=0 );
- assert( (db->flags & SQLITE_Initialized) || db->init.busy );
- for(i=0; i<db->nDb; i++){
- int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
- if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
- p = sqlite3HashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1);
- if( p ) break;
- }
- return p;
-}
-
-/*
-** Locate the in-memory structure that describes a particular database
-** table given the name of that table and (optionally) the name of the
-** database containing the table. Return NULL if not found. Also leave an
-** error message in pParse->zErrMsg.
-**
-** The difference between this routine and sqlite3FindTable() is that this
-** routine leaves an error message in pParse->zErrMsg where
-** sqlite3FindTable() does not.
-*/
-Table *sqlite3LocateTable(Parse *pParse, const char *zName, const char *zDbase){
- Table *p;
-
- /* Read the database schema. If an error occurs, leave an error message
- ** and code in pParse and return NULL. */
- if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
- return 0;
- }
-
- p = sqlite3FindTable(pParse->db, zName, zDbase);
- if( p==0 ){
- if( zDbase ){
- sqlite3ErrorMsg(pParse, "no such table: %s.%s", zDbase, zName);
- }else if( sqlite3FindTable(pParse->db, zName, 0)!=0 ){
- sqlite3ErrorMsg(pParse, "table \"%s\" is not in database \"%s\"",
- zName, zDbase);
- }else{
- sqlite3ErrorMsg(pParse, "no such table: %s", zName);
- }
- pParse->checkSchema = 1;
- }
- return p;
-}
-
-/*
-** Locate the in-memory structure that describes
-** a particular index given the name of that index
-** and the name of the database that contains the index.
-** Return NULL if not found.
-**
-** If zDatabase is 0, all databases are searched for the
-** table and the first matching index is returned. (No checking
-** for duplicate index names is done.) The search order is
-** TEMP first, then MAIN, then any auxiliary databases added
-** using the ATTACH command.
-*/
-Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
- Index *p = 0;
- int i;
- assert( (db->flags & SQLITE_Initialized) || db->init.busy );
- for(i=0; i<db->nDb; i++){
- int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
- if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
- p = sqlite3HashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1);
- if( p ) break;
- }
- return p;
-}
-
-/*
-** Reclaim the memory used by an index
-*/
-static void freeIndex(Index *p){
- sqliteFree(p->zColAff);
- sqliteFree(p);
-}
-
-/*
-** Remove the given index from the index hash table, and free
-** its memory structures.
-**
-** The index is removed from the database hash tables but
-** it is not unlinked from the Table that it indexes.
-** Unlinking from the Table must be done by the calling function.
-*/
-static void sqliteDeleteIndex(sqlite3 *db, Index *p){
- Index *pOld;
-
- assert( db!=0 && p->zName!=0 );
- pOld = sqlite3HashInsert(&db->aDb[p->iDb].idxHash, p->zName,
- strlen(p->zName)+1, 0);
- if( pOld!=0 && pOld!=p ){
- sqlite3HashInsert(&db->aDb[p->iDb].idxHash, pOld->zName,
- strlen(pOld->zName)+1, pOld);
- }
- freeIndex(p);
-}
-
-/*
-** Unlink the given index from its table, then remove
-** the index from the index hash table and free its memory
-** structures.
-*/
-void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
- Index *pIndex;
- int len;
-
- len = strlen(zIdxName);
- pIndex = sqlite3HashInsert(&db->aDb[iDb].idxHash, zIdxName, len+1, 0);
- if( pIndex ){
- if( pIndex->pTable->pIndex==pIndex ){
- pIndex->pTable->pIndex = pIndex->pNext;
- }else{
- Index *p;
- for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){}
- if( p && p->pNext==pIndex ){
- p->pNext = pIndex->pNext;
- }
- }
- freeIndex(pIndex);
- }
- db->flags |= SQLITE_InternChanges;
-}
-
-/*
-** Erase all schema information from the in-memory hash tables of
-** a single database. This routine is called to reclaim memory
-** before the database closes. It is also called during a rollback
-** if there were schema changes during the transaction or if a
-** schema-cookie mismatch occurs.
-**
-** If iDb<=0 then reset the internal schema tables for all database
-** files. If iDb>=2 then reset the internal schema for only the
-** single file indicated.
-*/
-void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
- HashElem *pElem;
- Hash temp1;
- Hash temp2;
- int i, j;
-
- assert( iDb>=0 && iDb<db->nDb );
- db->flags &= ~SQLITE_Initialized;
- for(i=iDb; i<db->nDb; i++){
- Db *pDb = &db->aDb[i];
- temp1 = pDb->tblHash;
- temp2 = pDb->trigHash;
- sqlite3HashInit(&pDb->trigHash, SQLITE_HASH_STRING, 0);
- sqlite3HashClear(&pDb->aFKey);
- sqlite3HashClear(&pDb->idxHash);
- for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
- Trigger *pTrigger = sqliteHashData(pElem);
- sqlite3DeleteTrigger(pTrigger);
- }
- sqlite3HashClear(&temp2);
- sqlite3HashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0);
- for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
- Table *pTab = sqliteHashData(pElem);
- sqlite3DeleteTable(db, pTab);
- }
- sqlite3HashClear(&temp1);
- DbClearProperty(db, i, DB_SchemaLoaded);
- if( iDb>0 ) return;
- }
- assert( iDb==0 );
- db->flags &= ~SQLITE_InternChanges;
-
- /* If one or more of the auxiliary database files has been closed,
- ** then remove then from the auxiliary database list. We take the
- ** opportunity to do this here since we have just deleted all of the
- ** schema hash tables and therefore do not have to make any changes
- ** to any of those tables.
- */
- for(i=0; i<db->nDb; i++){
- struct Db *pDb = &db->aDb[i];
- if( pDb->pBt==0 ){
- if( pDb->pAux && pDb->xFreeAux ) pDb->xFreeAux(pDb->pAux);
- pDb->pAux = 0;
- }
- }
- for(i=j=2; i<db->nDb; i++){
- struct Db *pDb = &db->aDb[i];
- if( pDb->pBt==0 ){
- sqliteFree(pDb->zName);
- pDb->zName = 0;
- continue;
- }
- if( j<i ){
- db->aDb[j] = db->aDb[i];
- }
- j++;
- }
- memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
- db->nDb = j;
- if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
- memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
- sqliteFree(db->aDb);
- db->aDb = db->aDbStatic;
- }
-}
-
-/*
-** This routine is called whenever a rollback occurs. If there were
-** schema changes during the transaction, then we have to reset the
-** internal hash tables and reload them from disk.
-*/
-void sqlite3RollbackInternalChanges(sqlite3 *db){
- if( db->flags & SQLITE_InternChanges ){
- sqlite3ResetInternalSchema(db, 0);
- }
-}
-
-/*
-** This routine is called when a commit occurs.
-*/
-void sqlite3CommitInternalChanges(sqlite3 *db){
- db->flags &= ~SQLITE_InternChanges;
-}
-
-/*
-** Clear the column names from a table or view.
-*/
-static void sqliteResetColumnNames(Table *pTable){
- int i;
- Column *pCol;
- assert( pTable!=0 );
- for(i=0, pCol=pTable->aCol; i<pTable->nCol; i++, pCol++){
- sqliteFree(pCol->zName);
- sqliteFree(pCol->zDflt);
- sqliteFree(pCol->zType);
- }
- sqliteFree(pTable->aCol);
- pTable->aCol = 0;
- pTable->nCol = 0;
-}
-
-/*
-** Remove the memory data structures associated with the given
-** Table. No changes are made to disk by this routine.
-**
-** This routine just deletes the data structure. It does not unlink
-** the table data structure from the hash table. Nor does it remove
-** foreign keys from the sqlite.aFKey hash table. But it does destroy
-** memory structures of the indices and foreign keys associated with
-** the table.
-**
-** Indices associated with the table are unlinked from the "db"
-** data structure if db!=NULL. If db==NULL, indices attached to
-** the table are deleted, but it is assumed they have already been
-** unlinked.
-*/
-void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
- Index *pIndex, *pNext;
- FKey *pFKey, *pNextFKey;
-
- if( pTable==0 ) return;
-
- /* Delete all indices associated with this table
- */
- for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
- pNext = pIndex->pNext;
- assert( pIndex->iDb==pTable->iDb || (pTable->iDb==0 && pIndex->iDb==1) );
- sqliteDeleteIndex(db, pIndex);
- }
-
- /* Delete all foreign keys associated with this table. The keys
- ** should have already been unlinked from the db->aFKey hash table
- */
- for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
- pNextFKey = pFKey->pNextFrom;
- assert( pTable->iDb<db->nDb );
- assert( sqlite3HashFind(&db->aDb[pTable->iDb].aFKey,
- pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey );
- sqliteFree(pFKey);
- }
-
- /* Delete the Table structure itself.
- */
- sqliteResetColumnNames(pTable);
- sqliteFree(pTable->zName);
- sqliteFree(pTable->zColAff);
- sqlite3SelectDelete(pTable->pSelect);
- sqliteFree(pTable);
-}
-
-/*
-** Unlink the given table from the hash tables and the delete the
-** table structure with all its indices and foreign keys.
-*/
-void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
- Table *p;
- FKey *pF1, *pF2;
- Db *pDb;
-
- assert( db!=0 );
- assert( iDb>=0 && iDb<db->nDb );
- assert( zTabName && zTabName[0] );
- pDb = &db->aDb[iDb];
- p = sqlite3HashInsert(&pDb->tblHash, zTabName, strlen(zTabName)+1, 0);
- if( p ){
- for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){
- int nTo = strlen(pF1->zTo) + 1;
- pF2 = sqlite3HashFind(&pDb->aFKey, pF1->zTo, nTo);
- if( pF2==pF1 ){
- sqlite3HashInsert(&pDb->aFKey, pF1->zTo, nTo, pF1->pNextTo);
- }else{
- while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; }
- if( pF2 ){
- pF2->pNextTo = pF1->pNextTo;
- }
- }
- }
- sqlite3DeleteTable(db, p);
- }
- db->flags |= SQLITE_InternChanges;
-}
-
-/*
-** Given a token, return a string that consists of the text of that
-** token with any quotations removed. Space to hold the returned string
-** is obtained from sqliteMalloc() and must be freed by the calling
-** function.
-**
-** Tokens are really just pointers into the original SQL text and so
-** are not \000 terminated and are not persistent. The returned string
-** is \000 terminated and is persistent.
-*/
-char *sqlite3NameFromToken(Token *pName){
- char *zName;
- if( pName ){
- zName = sqliteStrNDup(pName->z, pName->n);
- sqlite3Dequote(zName);
- }else{
- zName = 0;
- }
- return zName;
-}
-
-/*
-** Open the sqlite_master table stored in database number iDb for
-** writing. The table is opened using cursor 0.
-*/
-void sqlite3OpenMasterTable(Vdbe *v, int iDb){
- sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
- sqlite3VdbeAddOp(v, OP_OpenWrite, 0, MASTER_ROOT);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, 0, 5); /* sqlite_master has 5 columns */
-}
-
-/*
-** The token *pName contains the name of a database (either "main" or
-** "temp" or the name of an attached db). This routine returns the
-** index of the named database in db->aDb[], or -1 if the named db
-** does not exist.
-*/
-int findDb(sqlite3 *db, Token *pName){
- int i;
- Db *pDb;
- for(pDb=db->aDb, i=0; i<db->nDb; i++, pDb++){
- if( pName->n==strlen(pDb->zName) &&
- 0==sqlite3StrNICmp(pDb->zName, pName->z, pName->n) ){
- return i;
- }
- }
- return -1;
-}
-
-/* The table or view or trigger name is passed to this routine via tokens
-** pName1 and pName2. If the table name was fully qualified, for example:
-**
-** CREATE TABLE xxx.yyy (...);
-**
-** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
-** the table name is not fully qualified, i.e.:
-**
-** CREATE TABLE yyy(...);
-**
-** Then pName1 is set to "yyy" and pName2 is "".
-**
-** This routine sets the *ppUnqual pointer to point at the token (pName1 or
-** pName2) that stores the unqualified table name. The index of the
-** database "xxx" is returned.
-*/
-int sqlite3TwoPartName(
- Parse *pParse, /* Parsing and code generating context */
- Token *pName1, /* The "xxx" in the name "xxx.yyy" or "xxx" */
- Token *pName2, /* The "yyy" in the name "xxx.yyy" */
- Token **pUnqual /* Write the unqualified object name here */
-){
- int iDb; /* Database holding the object */
- sqlite3 *db = pParse->db;
-
- if( pName2 && pName2->n>0 ){
- assert( !db->init.busy );
- *pUnqual = pName2;
- iDb = findDb(db, pName1);
- if( iDb<0 ){
- sqlite3ErrorMsg(pParse, "unknown database %T", pName1);
- pParse->nErr++;
- return -1;
- }
- }else{
- assert( db->init.iDb==0 || db->init.busy );
- iDb = db->init.iDb;
- *pUnqual = pName1;
- }
- return iDb;
-}
-
-/*
-** This routine is used to check if the UTF-8 string zName is a legal
-** unqualified name for a new schema object (table, index, view or
-** trigger). All names are legal except those that begin with the string
-** "sqlite_" (in upper, lower or mixed case). This portion of the namespace
-** is reserved for internal use.
-*/
-int sqlite3CheckObjectName(Parse *pParse, const char *zName){
- if( !pParse->db->init.busy && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
- sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName);
- return SQLITE_ERROR;
- }
- return SQLITE_OK;
-}
-
-/*
-** Begin constructing a new table representation in memory. This is
-** the first of several action routines that get called in response
-** to a CREATE TABLE statement. In particular, this routine is called
-** after seeing tokens "CREATE" and "TABLE" and the table name. The
-** pStart token is the CREATE and pName is the table name. The isTemp
-** flag is true if the table should be stored in the auxiliary database
-** file instead of in the main database file. This is normally the case
-** when the "TEMP" or "TEMPORARY" keyword occurs in between
-** CREATE and TABLE.
-**
-** The new table record is initialized and put in pParse->pNewTable.
-** As more of the CREATE TABLE statement is parsed, additional action
-** routines will be called to add more information to this record.
-** At the end of the CREATE TABLE statement, the sqlite3EndTable() routine
-** is called to complete the construction of the new table record.
-*/
-void sqlite3StartTable(
- Parse *pParse, /* Parser context */
- Token *pStart, /* The "CREATE" token */
- Token *pName1, /* First part of the name of the table or view */
- Token *pName2, /* Second part of the name of the table or view */
- int isTemp, /* True if this is a TEMP table */
- int isView /* True if this is a VIEW */
-){
- Table *pTable;
- Index *pIdx;
- char *zName;
- sqlite3 *db = pParse->db;
- Vdbe *v;
- int iDb; /* Database number to create the table in */
- Token *pName; /* Unqualified name of the table to create */
-
- /* The table or view name to create is passed to this routine via tokens
- ** pName1 and pName2. If the table name was fully qualified, for example:
- **
- ** CREATE TABLE xxx.yyy (...);
- **
- ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
- ** the table name is not fully qualified, i.e.:
- **
- ** CREATE TABLE yyy(...);
- **
- ** Then pName1 is set to "yyy" and pName2 is "".
- **
- ** The call below sets the pName pointer to point at the token (pName1 or
- ** pName2) that stores the unqualified table name. The variable iDb is
- ** set to the index of the database that the table or view is to be
- ** created in.
- */
- iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
- if( iDb<0 ) return;
- if( isTemp && iDb>1 ){
- /* If creating a temp table, the name may not be qualified */
- sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
- pParse->nErr++;
- return;
- }
- if( isTemp ) iDb = 1;
-
- pParse->sNameToken = *pName;
- zName = sqlite3NameFromToken(pName);
- if( zName==0 ) return;
- if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
- sqliteFree(zName);
- return;
- }
- if( db->init.iDb==1 ) isTemp = 1;
-#ifndef SQLITE_OMIT_AUTHORIZATION
- assert( (isTemp & 1)==isTemp );
- {
- int code;
- char *zDb = db->aDb[iDb].zName;
- if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
- sqliteFree(zName);
- return;
- }
- if( isView ){
- if( isTemp ){
- code = SQLITE_CREATE_TEMP_VIEW;
- }else{
- code = SQLITE_CREATE_VIEW;
- }
- }else{
- if( isTemp ){
- code = SQLITE_CREATE_TEMP_TABLE;
- }else{
- code = SQLITE_CREATE_TABLE;
- }
- }
- if( sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
- sqliteFree(zName);
- return;
- }
- }
-#endif
-
- /* Make sure the new table name does not collide with an existing
- ** index or table name in the same database. Issue an error message if
- ** it does.
- */
- if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) return;
- pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
- if( pTable ){
- sqlite3ErrorMsg(pParse, "table %T already exists", pName);
- sqliteFree(zName);
- return;
- }
- if( (pIdx = sqlite3FindIndex(db, zName, 0))!=0 &&
- ( iDb==0 || !db->init.busy) ){
- sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
- sqliteFree(zName);
- return;
- }
- pTable = sqliteMalloc( sizeof(Table) );
- if( pTable==0 ){
- pParse->rc = SQLITE_NOMEM;
- pParse->nErr++;
- sqliteFree(zName);
- return;
- }
- pTable->zName = zName;
- pTable->nCol = 0;
- pTable->aCol = 0;
- pTable->iPKey = -1;
- pTable->pIndex = 0;
- pTable->iDb = iDb;
- if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable);
- pParse->pNewTable = pTable;
-
- /* Begin generating the code that will insert the table record into
- ** the SQLITE_MASTER table. Note in particular that we must go ahead
- ** and allocate the record number for the table entry now. Before any
- ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause
- ** indices to be created and the table record must come before the
- ** indices. Hence, the record number for the table must be allocated
- ** now.
- */
- if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
- sqlite3BeginWriteOperation(pParse, 0, iDb);
- /* Every time a new table is created the file-format
- ** and encoding meta-values are set in the database, in
- ** case this is the first table created.
- */
- sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0);
- sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
- sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0);
- sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4);
-
- sqlite3OpenMasterTable(v, iDb);
- sqlite3VdbeAddOp(v, OP_NewRecno, 0, 0);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
- }
-}
-
-/*
-** Add a new column to the table currently being constructed.
-**
-** The parser calls this routine once for each column declaration
-** in a CREATE TABLE statement. sqlite3StartTable() gets called
-** first to get things going. Then this routine is called for each
-** column.
-*/
-void sqlite3AddColumn(Parse *pParse, Token *pName){
- Table *p;
- int i;
- char *z;
- Column *pCol;
- if( (p = pParse->pNewTable)==0 ) return;
- z = sqlite3NameFromToken(pName);
- if( z==0 ) return;
- for(i=0; i<p->nCol; i++){
- if( sqlite3StrICmp(z, p->aCol[i].zName)==0 ){
- sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
- sqliteFree(z);
- return;
- }
- }
- if( (p->nCol & 0x7)==0 ){
- Column *aNew;
- aNew = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0]));
- if( aNew==0 ) return;
- p->aCol = aNew;
- }
- pCol = &p->aCol[p->nCol];
- memset(pCol, 0, sizeof(p->aCol[0]));
- pCol->zName = z;
-
- /* If there is no type specified, columns have the default affinity
- ** 'NONE'. If there is a type specified, then sqlite3AddColumnType() will
- ** be called next to set pCol->affinity correctly.
- */
- pCol->affinity = SQLITE_AFF_NONE;
- pCol->pColl = pParse->db->pDfltColl;
- p->nCol++;
-}
-
-/*
-** This routine is called by the parser while in the middle of
-** parsing a CREATE TABLE statement. A "NOT NULL" constraint has
-** been seen on a column. This routine sets the notNull flag on
-** the column currently under construction.
-*/
-void sqlite3AddNotNull(Parse *pParse, int onError){
- Table *p;
- int i;
- if( (p = pParse->pNewTable)==0 ) return;
- i = p->nCol-1;
- if( i>=0 ) p->aCol[i].notNull = onError;
-}
-
-/*
-** This routine is called by the parser while in the middle of
-** parsing a CREATE TABLE statement. The pFirst token is the first
-** token in the sequence of tokens that describe the type of the
-** column currently under construction. pLast is the last token
-** in the sequence. Use this information to construct a string
-** that contains the typename of the column and store that string
-** in zType.
-*/
-void sqlite3AddColumnType(Parse *pParse, Token *pFirst, Token *pLast){
- Table *p;
- int i, j;
- int n;
- char *z, **pz;
- Column *pCol;
- if( (p = pParse->pNewTable)==0 ) return;
- i = p->nCol-1;
- if( i<0 ) return;
- pCol = &p->aCol[i];
- pz = &pCol->zType;
- n = pLast->n + (pLast->z - pFirst->z);
- assert( pCol->zType==0 );
- z = pCol->zType = sqlite3MPrintf("%.*s", n, pFirst->z);
- if( z==0 ) return;
- for(i=j=0; z[i]; i++){
- int c = z[i];
- if( isspace(c) ) continue;
- z[j++] = c;
- }
- z[j] = 0;
- pCol->affinity = sqlite3AffinityType(z, n);
-}
-
-/*
-** The given token is the default value for the last column added to
-** the table currently under construction. If "minusFlag" is true, it
-** means the value token was preceded by a minus sign.
-**
-** This routine is called by the parser while in the middle of
-** parsing a CREATE TABLE statement.
-*/
-void sqlite3AddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){
- Table *p;
- int i;
- char *z;
- if( (p = pParse->pNewTable)==0 ) return;
- i = p->nCol-1;
- if( i<0 ) return;
- assert( p->aCol[i].zDflt==0 );
- z = p->aCol[i].zDflt = sqlite3MPrintf("%s%T", minusFlag ? "-" : "", pVal);
- sqlite3Dequote(z);
-}
-
-/*
-** Designate the PRIMARY KEY for the table. pList is a list of names
-** of columns that form the primary key. If pList is NULL, then the
-** most recently added column of the table is the primary key.
-**
-** A table can have at most one primary key. If the table already has
-** a primary key (and this is the second primary key) then create an
-** error.
-**
-** If the PRIMARY KEY is on a single column whose datatype is INTEGER,
-** then we will try to use that column as the row id. (Exception:
-** For backwards compatibility with older databases, do not do this
-** if the file format version number is less than 1.) Set the Table.iPKey
-** field of the table under construction to be the index of the
-** INTEGER PRIMARY KEY column. Table.iPKey is set to -1 if there is
-** no INTEGER PRIMARY KEY.
-**
-** If the key is not an INTEGER PRIMARY KEY, then create a unique
-** index for the key. No index is created for INTEGER PRIMARY KEYs.
-*/
-void sqlite3AddPrimaryKey(Parse *pParse, ExprList *pList, int onError){
- Table *pTab = pParse->pNewTable;
- char *zType = 0;
- int iCol = -1, i;
- if( pTab==0 ) goto primary_key_exit;
- if( pTab->hasPrimKey ){
- sqlite3ErrorMsg(pParse,
- "table \"%s\" has more than one primary key", pTab->zName);
- goto primary_key_exit;
- }
- pTab->hasPrimKey = 1;
- if( pList==0 ){
- iCol = pTab->nCol - 1;
- pTab->aCol[iCol].isPrimKey = 1;
- }else{
- for(i=0; i<pList->nExpr; i++){
- for(iCol=0; iCol<pTab->nCol; iCol++){
- if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){
- break;
- }
- }
- if( iCol<pTab->nCol ) pTab->aCol[iCol].isPrimKey = 1;
- }
- if( pList->nExpr>1 ) iCol = -1;
- }
- if( iCol>=0 && iCol<pTab->nCol ){
- zType = pTab->aCol[iCol].zType;
- }
- if( zType && sqlite3StrICmp(zType, "INTEGER")==0 ){
- pTab->iPKey = iCol;
- pTab->keyConf = onError;
- }else{
- sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0);
- pList = 0;
- }
-
-primary_key_exit:
- sqlite3ExprListDelete(pList);
- return;
-}
-
-/*
-** Set the collation function of the most recently parsed table column
-** to the CollSeq given.
-*/
-void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
- Table *p;
- Index *pIdx;
- CollSeq *pColl;
- int i;
-
- if( (p = pParse->pNewTable)==0 ) return;
- i = p->nCol-1;
-
- pColl = sqlite3LocateCollSeq(pParse, zType, nType);
- p->aCol[i].pColl = pColl;
-
- /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
- ** then an index may have been created on this column before the
- ** collation type was added. Correct this if it is the case.
- */
- for(pIdx = p->pIndex; pIdx; pIdx=pIdx->pNext){
- assert( pIdx->nColumn==1 );
- if( pIdx->aiColumn[0]==i ) pIdx->keyInfo.aColl[0] = pColl;
- }
-}
-
-/*
-** Locate and return an entry from the db.aCollSeq hash table. If the entry
-** specified by zName and nName is not found and parameter 'create' is
-** true, then create a new entry. Otherwise return NULL.
-**
-** Each pointer stored in the sqlite3.aCollSeq hash table contains an
-** array of three CollSeq structures. The first is the collation sequence
-** prefferred for UTF-8, the second UTF-16le, and the third UTF-16be.
-**
-** Stored immediately after the three collation sequences is a copy of
-** the collation sequence name. A pointer to this string is stored in
-** each collation sequence structure.
-*/
-static CollSeq * findCollSeqEntry(
- sqlite3 *db,
- const char *zName,
- int nName,
- int create
-){
- CollSeq *pColl;
- if( nName<0 ) nName = strlen(zName);
- pColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
-
- if( 0==pColl && create ){
- pColl = sqliteMalloc( 3*sizeof(*pColl) + nName + 1 );
- if( pColl ){
- pColl[0].zName = (char*)&pColl[3];
- pColl[0].enc = SQLITE_UTF8;
- pColl[1].zName = (char*)&pColl[3];
- pColl[1].enc = SQLITE_UTF16LE;
- pColl[2].zName = (char*)&pColl[3];
- pColl[2].enc = SQLITE_UTF16BE;
- memcpy(pColl[0].zName, zName, nName);
- pColl[0].zName[nName] = 0;
- sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl);
- }
- }
- return pColl;
-}
-
-/*
-** Parameter zName points to a UTF-8 encoded string nName bytes long.
-** Return the CollSeq* pointer for the collation sequence named zName
-** for the encoding 'enc' from the database 'db'.
-**
-** If the entry specified is not found and 'create' is true, then create a
-** new entry. Otherwise return NULL.
-*/
-CollSeq *sqlite3FindCollSeq(
- sqlite3 *db,
- u8 enc,
- const char *zName,
- int nName,
- int create
-){
- CollSeq *pColl = findCollSeqEntry(db, zName, nName, create);
- assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
- assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
- if( pColl ) pColl += enc-1;
- return pColl;
-}
-
-/*
-** Invoke the 'collation needed' callback to request a collation sequence
-** in the database text encoding of name zName, length nName.
-** If the collation sequence
-*/
-static void callCollNeeded(sqlite3 *db, const char *zName, int nName){
- assert( !db->xCollNeeded || !db->xCollNeeded16 );
- if( nName<0 ) nName = strlen(zName);
- if( db->xCollNeeded ){
- char *zExternal = sqliteStrNDup(zName, nName);
- if( !zExternal ) return;
- db->xCollNeeded(db->pCollNeededArg, db, (int)db->enc, zExternal);
- sqliteFree(zExternal);
- }
- if( db->xCollNeeded16 ){
- char const *zExternal;
- sqlite3_value *pTmp = sqlite3GetTransientValue(db);
- sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC);
- zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE);
- if( !zExternal ) return;
- db->xCollNeeded16(db->pCollNeededArg, db, (int)db->enc, zExternal);
- }
-}
-
-/*
-** This routine is called if the collation factory fails to deliver a
-** collation function in the best encoding but there may be other versions
-** of this collation function (for other text encodings) available. Use one
-** of these instead if they exist. Avoid a UTF-8 <-> UTF-16 conversion if
-** possible.
-*/
-static int synthCollSeq(Parse *pParse, CollSeq *pColl){
- CollSeq *pColl2;
- char *z = pColl->zName;
- int n = strlen(z);
- sqlite3 *db = pParse->db;
- int i;
- static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 };
- for(i=0; i<3; i++){
- pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, n, 0);
- if( pColl2->xCmp!=0 ){
- memcpy(pColl, pColl2, sizeof(CollSeq));
- return SQLITE_OK;
- }
- }
- if( pParse->nErr==0 ){
- sqlite3ErrorMsg(pParse, "no such collation sequence: %.*s", n, z);
- }
- pParse->nErr++;
- return SQLITE_ERROR;
-}
-
-/*
-** This routine is called on a collation sequence before it is used to
-** check that it is defined. An undefined collation sequence exists when
-** a database is loaded that contains references to collation sequences
-** that have not been defined by sqlite3_create_collation() etc.
-**
-** If required, this routine calls the 'collation needed' callback to
-** request a definition of the collating sequence. If this doesn't work,
-** an equivalent collating sequence that uses a text encoding different
-** from the main database is substituted, if one is available.
-*/
-int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
- if( pColl && !pColl->xCmp ){
- /* No collation sequence of this type for this encoding is registered.
- ** Call the collation factory to see if it can supply us with one.
- */
- callCollNeeded(pParse->db, pColl->zName, strlen(pColl->zName));
- if( !pColl->xCmp && synthCollSeq(pParse, pColl) ){
- return SQLITE_ERROR;
- }
- }
- return SQLITE_OK;
-}
-
-/*
-** Call sqlite3CheckCollSeq() for all collating sequences in an index,
-** in order to verify that all the necessary collating sequences are
-** loaded.
-*/
-int sqlite3CheckIndexCollSeq(Parse *pParse, Index *pIdx){
- if( pIdx ){
- int i;
- for(i=0; i<pIdx->nColumn; i++){
- if( sqlite3CheckCollSeq(pParse, pIdx->keyInfo.aColl[i]) ){
- return SQLITE_ERROR;
- }
- }
- }
- return SQLITE_OK;
-}
-
-/*
-** This function returns the collation sequence for database native text
-** encoding identified by the string zName, length nName.
-**
-** If the requested collation sequence is not available, or not available
-** in the database native encoding, the collation factory is invoked to
-** request it. If the collation factory does not supply such a sequence,
-** and the sequence is available in another text encoding, then that is
-** returned instead.
-**
-** If no versions of the requested collations sequence are available, or
-** another error occurs, NULL is returned and an error message written into
-** pParse.
-*/
-CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
- u8 enc = pParse->db->enc;
- u8 initbusy = pParse->db->init.busy;
- CollSeq *pColl = sqlite3FindCollSeq(pParse->db, enc, zName, nName, initbusy);
- if( nName<0 ) nName = strlen(zName);
- if( !initbusy && (!pColl || !pColl->xCmp) ){
- /* No collation sequence of this type for this encoding is registered.
- ** Call the collation factory to see if it can supply us with one.
- */
- callCollNeeded(pParse->db, zName, nName);
- pColl = sqlite3FindCollSeq(pParse->db, enc, zName, nName, 0);
- if( pColl && !pColl->xCmp ){
- /* There may be a version of the collation sequence that requires
- ** translation between encodings. Search for it with synthCollSeq().
- */
- if( synthCollSeq(pParse, pColl) ){
- return 0;
- }
- }
- }
-
- /* If nothing has been found, write the error message into pParse */
- if( !initbusy && (!pColl || !pColl->xCmp) ){
- if( pParse->nErr==0 ){
- sqlite3ErrorMsg(pParse, "no such collation sequence: %.*s", nName, zName);
- }
- pColl = 0;
- }
- return pColl;
-}
-
-
-
-/*
-** Scan the column type name zType (length nType) and return the
-** associated affinity type.
-*/
-char sqlite3AffinityType(const char *zType, int nType){
- int n, i;
- static const struct {
- const char *zSub; /* Keywords substring to search for */
- char nSub; /* length of zSub */
- char affinity; /* Affinity to return if it matches */
- } substrings[] = {
- {"INT", 3, SQLITE_AFF_INTEGER},
- {"CHAR", 4, SQLITE_AFF_TEXT},
- {"CLOB", 4, SQLITE_AFF_TEXT},
- {"TEXT", 4, SQLITE_AFF_TEXT},
- {"BLOB", 4, SQLITE_AFF_NONE},
- };
-
- if( nType==0 ){
- return SQLITE_AFF_NONE;
- }
- for(i=0; i<sizeof(substrings)/sizeof(substrings[0]); i++){
- int c1 = substrings[i].zSub[0];
- int c2 = tolower(c1);
- int limit = nType - substrings[i].nSub;
- const char *z = substrings[i].zSub;
- for(n=0; n<=limit; n++){
- int c = zType[n];
- if( (c==c1 || c==c2)
- && 0==sqlite3StrNICmp(&zType[n], z, substrings[i].nSub) ){
- return substrings[i].affinity;
- }
- }
- }
- return SQLITE_AFF_NUMERIC;
-}
-
-/*
-** Generate code that will increment the schema cookie.
-**
-** The schema cookie is used to determine when the schema for the
-** database changes. After each schema change, the cookie value
-** changes. When a process first reads the schema it records the
-** cookie. Thereafter, whenever it goes to access the database,
-** it checks the cookie to make sure the schema has not changed
-** since it was last read.
-**
-** This plan is not completely bullet-proof. It is possible for
-** the schema to change multiple times and for the cookie to be
-** set back to prior value. But schema changes are infrequent
-** and the probability of hitting the same cookie value is only
-** 1 chance in 2^32. So we're safe enough.
-*/
-void sqlite3ChangeCookie(sqlite3 *db, Vdbe *v, int iDb){
- sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].schema_cookie+1, 0);
- sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
-}
-
-/*
-** Measure the number of characters needed to output the given
-** identifier. The number returned includes any quotes used
-** but does not include the null terminator.
-**
-** The estimate is conservative. It might be larger that what is
-** really needed.
-*/
-static int identLength(const char *z){
- int n;
- for(n=0; *z; n++, z++){
- if( *z=='"' ){ n++; }
- }
- return n + 2;
-}
-
-/*
-** Write an identifier onto the end of the given string. Add
-** quote characters as needed.
-*/
-static void identPut(char *z, int *pIdx, char *zSignedIdent){
- unsigned char *zIdent = (unsigned char*)zSignedIdent;
- int i, j, needQuote;
- i = *pIdx;
- for(j=0; zIdent[j]; j++){
- if( !isalnum(zIdent[j]) && zIdent[j]!='_' ) break;
- }
- needQuote = zIdent[j]!=0 || isdigit(zIdent[0])
- || sqlite3KeywordCode(zIdent, j)!=TK_ID;
- if( needQuote ) z[i++] = '"';
- for(j=0; zIdent[j]; j++){
- z[i++] = zIdent[j];
- if( zIdent[j]=='"' ) z[i++] = '"';
- }
- if( needQuote ) z[i++] = '"';
- z[i] = 0;
- *pIdx = i;
-}
-
-/*
-** Generate a CREATE TABLE statement appropriate for the given
-** table. Memory to hold the text of the statement is obtained
-** from sqliteMalloc() and must be freed by the calling function.
-*/
-static char *createTableStmt(Table *p){
- int i, k, n;
- char *zStmt;
- char *zSep, *zSep2, *zEnd, *z;
- Column *pCol;
- n = 0;
- for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){
- n += identLength(pCol->zName);
- z = pCol->zType;
- if( z ){
- n += (strlen(z) + 1);
- }
- }
- n += identLength(p->zName);
- if( n<50 ){
- zSep = "";
- zSep2 = ",";
- zEnd = ")";
- }else{
- zSep = "\n ";
- zSep2 = ",\n ";
- zEnd = "\n)";
- }
- n += 35 + 6*p->nCol;
- zStmt = sqliteMallocRaw( n );
- if( zStmt==0 ) return 0;
- strcpy(zStmt, p->iDb==1 ? "CREATE TEMP TABLE " : "CREATE TABLE ");
- k = strlen(zStmt);
- identPut(zStmt, &k, p->zName);
- zStmt[k++] = '(';
- for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
- strcpy(&zStmt[k], zSep);
- k += strlen(&zStmt[k]);
- zSep = zSep2;
- identPut(zStmt, &k, pCol->zName);
- if( (z = pCol->zType)!=0 ){
- zStmt[k++] = ' ';
- strcpy(&zStmt[k], z);
- k += strlen(z);
- }
- }
- strcpy(&zStmt[k], zEnd);
- return zStmt;
-}
-
-/*
-** This routine is called to report the final ")" that terminates
-** a CREATE TABLE statement.
-**
-** The table structure that other action routines have been building
-** is added to the internal hash tables, assuming no errors have
-** occurred.
-**
-** An entry for the table is made in the master table on disk, unless
-** this is a temporary table or db->init.busy==1. When db->init.busy==1
-** it means we are reading the sqlite_master table because we just
-** connected to the database or because the sqlite_master table has
-** recently changes, so the entry for this table already exists in
-** the sqlite_master table. We do not want to create it again.
-**
-** If the pSelect argument is not NULL, it means that this routine
-** was called to create a table generated from a
-** "CREATE TABLE ... AS SELECT ..." statement. The column names of
-** the new table will match the result set of the SELECT.
-*/
-void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){
- Table *p;
- sqlite3 *db = pParse->db;
-
- if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3_malloc_failed ) return;
- p = pParse->pNewTable;
- if( p==0 ) return;
-
- assert( !db->init.busy || !pSelect );
-
- /* If the db->init.busy is 1 it means we are reading the SQL off the
- ** "sqlite_master" or "sqlite_temp_master" table on the disk.
- ** So do not write to the disk again. Extract the root page number
- ** for the table from the db->init.newTnum field. (The page number
- ** should have been put there by the sqliteOpenCb routine.)
- */
- if( db->init.busy ){
- p->tnum = db->init.newTnum;
- }
-
- /* If not initializing, then create a record for the new table
- ** in the SQLITE_MASTER table of the database. The record number
- ** for the new table entry should already be on the stack.
- **
- ** If this is a TEMPORARY table, write the entry into the auxiliary
- ** file instead of into the main database file.
- */
- if( !db->init.busy ){
- int n;
- Vdbe *v;
-
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) return;
-
- if( p->pSelect==0 ){
- /* A regular table */
- sqlite3VdbeAddOp(v, OP_CreateTable, p->iDb, 0);
- }else{
- /* A view */
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
- }
-
- sqlite3VdbeAddOp(v, OP_Close, 0, 0);
-
- /* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT
- ** statement to populate the new table. The root-page number for the
- ** new table is on the top of the vdbe stack.
- **
- ** Once the SELECT has been coded by sqlite3Select(), it is in a
- ** suitable state to query for the column names and types to be used
- ** by the new table.
- */
- if( pSelect ){
- Table *pSelTab;
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0);
- sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
- pParse->nTab = 2;
- sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0);
- sqlite3VdbeAddOp(v, OP_Close, 1, 0);
- if( pParse->nErr==0 ){
- pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSelect);
- if( pSelTab==0 ) return;
- assert( p->aCol==0 );
- p->nCol = pSelTab->nCol;
- p->aCol = pSelTab->aCol;
- pSelTab->nCol = 0;
- pSelTab->aCol = 0;
- sqlite3DeleteTable(0, pSelTab);
- }
- }
-
- sqlite3OpenMasterTable(v, p->iDb);
-
- sqlite3VdbeOp3(v, OP_String8, 0, 0, p->pSelect==0?"table":"view",P3_STATIC);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, p->zName, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, p->zName, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 3, 0);
-
- if( pSelect ){
- char *z = createTableStmt(p);
- n = z ? strlen(z) : 0;
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- sqlite3VdbeChangeP3(v, -1, z, n);
- sqliteFree(z);
- }else{
- if( p->pSelect ){
- sqlite3VdbeOp3(v, OP_String8, 0, 0, "CREATE VIEW ", P3_STATIC);
- }else{
- sqlite3VdbeOp3(v, OP_String8, 0, 0, "CREATE TABLE ", P3_STATIC);
- }
- assert( pEnd!=0 );
- n = Addr(pEnd->z) - Addr(pParse->sNameToken.z) + 1;
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- sqlite3VdbeChangeP3(v, -1, pParse->sNameToken.z, n);
- sqlite3VdbeAddOp(v, OP_Concat, 0, 0);
- }
- sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
- sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
- sqlite3ChangeCookie(db, v, p->iDb);
- sqlite3VdbeAddOp(v, OP_Close, 0, 0);
- sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0,
- sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC);
- }
-
- /* Add the table to the in-memory representation of the database.
- */
- if( db->init.busy && pParse->nErr==0 ){
- Table *pOld;
- FKey *pFKey;
- Db *pDb = &db->aDb[p->iDb];
- pOld = sqlite3HashInsert(&pDb->tblHash, p->zName, strlen(p->zName)+1, p);
- if( pOld ){
- assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
- return;
- }
- for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){
- int nTo = strlen(pFKey->zTo) + 1;
- pFKey->pNextTo = sqlite3HashFind(&pDb->aFKey, pFKey->zTo, nTo);
- sqlite3HashInsert(&pDb->aFKey, pFKey->zTo, nTo, pFKey);
- }
- pParse->pNewTable = 0;
- db->nTable++;
- db->flags |= SQLITE_InternChanges;
- }
-}
-
-/*
-** The parser calls this routine in order to create a new VIEW
-*/
-void sqlite3CreateView(
- Parse *pParse, /* The parsing context */
- Token *pBegin, /* The CREATE token that begins the statement */
- Token *pName1, /* The token that holds the name of the view */
- Token *pName2, /* The token that holds the name of the view */
- Select *pSelect, /* A SELECT statement that will become the new view */
- int isTemp /* TRUE for a TEMPORARY view */
-){
- Table *p;
- int n;
- const unsigned char *z;
- Token sEnd;
- DbFixer sFix;
- Token *pName;
-
- sqlite3StartTable(pParse, pBegin, pName1, pName2, isTemp, 1);
- p = pParse->pNewTable;
- if( p==0 || pParse->nErr ){
- sqlite3SelectDelete(pSelect);
- return;
- }
- sqlite3TwoPartName(pParse, pName1, pName2, &pName);
- if( sqlite3FixInit(&sFix, pParse, p->iDb, "view", pName)
- && sqlite3FixSelect(&sFix, pSelect)
- ){
- sqlite3SelectDelete(pSelect);
- return;
- }
-
- /* Make a copy of the entire SELECT statement that defines the view.
- ** This will force all the Expr.token.z values to be dynamically
- ** allocated rather than point to the input string - which means that
- ** they will persist after the current sqlite3_exec() call returns.
- */
- p->pSelect = sqlite3SelectDup(pSelect);
- sqlite3SelectDelete(pSelect);
- if( !pParse->db->init.busy ){
- sqlite3ViewGetColumnNames(pParse, p);
- }
-
- /* Locate the end of the CREATE VIEW statement. Make sEnd point to
- ** the end.
- */
- sEnd = pParse->sLastToken;
- if( sEnd.z[0]!=0 && sEnd.z[0]!=';' ){
- sEnd.z += sEnd.n;
- }
- sEnd.n = 0;
- n = sEnd.z - pBegin->z;
- z = (const unsigned char*)pBegin->z;
- while( n>0 && (z[n-1]==';' || isspace(z[n-1])) ){ n--; }
- sEnd.z = &z[n-1];
- sEnd.n = 1;
-
- /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */
- sqlite3EndTable(pParse, &sEnd, 0);
- return;
-}
-
-/*
-** The Table structure pTable is really a VIEW. Fill in the names of
-** the columns of the view in the pTable structure. Return the number
-** of errors. If an error is seen leave an error message in pParse->zErrMsg.
-*/
-int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
- ExprList *pEList;
- Select *pSel;
- Table *pSelTab;
- int nErr = 0;
-
- assert( pTable );
-
- /* A positive nCol means the columns names for this view are
- ** already known.
- */
- if( pTable->nCol>0 ) return 0;
-
- /* A negative nCol is a special marker meaning that we are currently
- ** trying to compute the column names. If we enter this routine with
- ** a negative nCol, it means two or more views form a loop, like this:
- **
- ** CREATE VIEW one AS SELECT * FROM two;
- ** CREATE VIEW two AS SELECT * FROM one;
- **
- ** Actually, this error is caught previously and so the following test
- ** should always fail. But we will leave it in place just to be safe.
- */
- if( pTable->nCol<0 ){
- sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName);
- return 1;
- }
-
- /* If we get this far, it means we need to compute the table names.
- */
- assert( pTable->pSelect ); /* If nCol==0, then pTable must be a VIEW */
- pSel = pTable->pSelect;
-
- /* Note that the call to sqlite3ResultSetOfSelect() will expand any
- ** "*" elements in this list. But we will need to restore the list
- ** back to its original configuration afterwards, so we save a copy of
- ** the original in pEList.
- */
- pEList = pSel->pEList;
- pSel->pEList = sqlite3ExprListDup(pEList);
- if( pSel->pEList==0 ){
- pSel->pEList = pEList;
- return 1; /* Malloc failed */
- }
- pTable->nCol = -1;
- pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel);
- if( pSelTab ){
- assert( pTable->aCol==0 );
- pTable->nCol = pSelTab->nCol;
- pTable->aCol = pSelTab->aCol;
- pSelTab->nCol = 0;
- pSelTab->aCol = 0;
- sqlite3DeleteTable(0, pSelTab);
- DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews);
- }else{
- pTable->nCol = 0;
- nErr++;
- }
- sqlite3SelectUnbind(pSel);
- sqlite3ExprListDelete(pSel->pEList);
- pSel->pEList = pEList;
- return nErr;
-}
-
-/*
-** Clear the column names from every VIEW in database idx.
-*/
-static void sqliteViewResetAll(sqlite3 *db, int idx){
- HashElem *i;
- if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;
- for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){
- Table *pTab = sqliteHashData(i);
- if( pTab->pSelect ){
- sqliteResetColumnNames(pTab);
- }
- }
- DbClearProperty(db, idx, DB_UnresetViews);
-}
-
-/*
-** This routine is called to do the work of a DROP TABLE statement.
-** pName is the name of the table to be dropped.
-*/
-void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
- Table *pTab;
- Vdbe *v;
- int base;
- sqlite3 *db = pParse->db;
- int iDb;
-
- if( pParse->nErr || sqlite3_malloc_failed ) goto exit_drop_table;
- assert( pName->nSrc==1 );
- pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase);
-
- if( pTab==0 ) goto exit_drop_table;
- iDb = pTab->iDb;
- assert( iDb>=0 && iDb<db->nDb );
-#ifndef SQLITE_OMIT_AUTHORIZATION
- {
- int code;
- const char *zTab = SCHEMA_TABLE(pTab->iDb);
- const char *zDb = db->aDb[pTab->iDb].zName;
- if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
- goto exit_drop_table;
- }
- if( isView ){
- if( iDb==1 ){
- code = SQLITE_DROP_TEMP_VIEW;
- }else{
- code = SQLITE_DROP_VIEW;
- }
- }else{
- if( iDb==1 ){
- code = SQLITE_DROP_TEMP_TABLE;
- }else{
- code = SQLITE_DROP_TABLE;
- }
- }
- if( sqlite3AuthCheck(pParse, code, pTab->zName, 0, zDb) ){
- goto exit_drop_table;
- }
- if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
- goto exit_drop_table;
- }
- }
-#endif
- if( pTab->readOnly ){
- sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
- pParse->nErr++;
- goto exit_drop_table;
- }
- if( isView && pTab->pSelect==0 ){
- sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName);
- goto exit_drop_table;
- }
- if( !isView && pTab->pSelect ){
- sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName);
- goto exit_drop_table;
- }
-
- /* Generate code to remove the table from the master table
- ** on disk.
- */
- v = sqlite3GetVdbe(pParse);
- if( v ){
- static const VdbeOpList dropTable[] = {
- { OP_Rewind, 0, ADDR(13), 0},
- { OP_String8, 0, 0, 0}, /* 1 */
- { OP_MemStore, 1, 1, 0},
- { OP_MemLoad, 1, 0, 0}, /* 3 */
- { OP_Column, 0, 2, 0}, /* sqlite_master.tbl_name */
- { OP_Ne, 0, ADDR(12), 0},
- { OP_String8, 0, 0, "trigger"},
- { OP_Column, 0, 2, 0}, /* sqlite_master.type */
- { OP_Eq, 0, ADDR(12), 0},
- { OP_Delete, 0, 0, 0},
- { OP_Rewind, 0, ADDR(13), 0},
- { OP_Goto, 0, ADDR(3), 0},
- { OP_Next, 0, ADDR(3), 0}, /* 12 */
- };
- Index *pIdx;
- Trigger *pTrigger;
- sqlite3BeginWriteOperation(pParse, 0, pTab->iDb);
-
- /* Drop all triggers associated with the table being dropped. Code
- ** is generated to remove entries from sqlite_master and/or
- ** sqlite_temp_master if required.
- */
- pTrigger = pTab->pTrigger;
- while( pTrigger ){
- assert( pTrigger->iDb==pTab->iDb || pTrigger->iDb==1 );
- sqlite3DropTriggerPtr(pParse, pTrigger, 1);
- pTrigger = pTrigger->pNext;
- }
-
- /* Drop all SQLITE_MASTER table and index entries that refer to the
- ** table. The program name loops through the master table and deletes
- ** every row that refers to a table of the same name as the one being
- ** dropped. Triggers are handled seperately because a trigger can be
- ** created in the temp database that refers to a table in another
- ** database.
- */
- sqlite3OpenMasterTable(v, pTab->iDb);
- base = sqlite3VdbeAddOpList(v, ArraySize(dropTable), dropTable);
- sqlite3VdbeChangeP3(v, base+1, pTab->zName, 0);
- sqlite3ChangeCookie(db, v, pTab->iDb);
- sqlite3VdbeAddOp(v, OP_Close, 0, 0);
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Destroy, pTab->tnum, pTab->iDb);
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- sqlite3VdbeAddOp(v, OP_Destroy, pIdx->tnum, pIdx->iDb);
- }
- }
- sqlite3VdbeOp3(v, OP_DropTable, pTab->iDb, 0, pTab->zName, 0);
- }
- sqliteViewResetAll(db, iDb);
-
-exit_drop_table:
- sqlite3SrcListDelete(pName);
-}
-
-/*
-** This routine is called to create a new foreign key on the table
-** currently under construction. pFromCol determines which columns
-** in the current table point to the foreign key. If pFromCol==0 then
-** connect the key to the last column inserted. pTo is the name of
-** the table referred to. pToCol is a list of tables in the other
-** pTo table that the foreign key points to. flags contains all
-** information about the conflict resolution algorithms specified
-** in the ON DELETE, ON UPDATE and ON INSERT clauses.
-**
-** An FKey structure is created and added to the table currently
-** under construction in the pParse->pNewTable field. The new FKey
-** is not linked into db->aFKey at this point - that does not happen
-** until sqlite3EndTable().
-**
-** The foreign key is set for IMMEDIATE processing. A subsequent call
-** to sqlite3DeferForeignKey() might change this to DEFERRED.
-*/
-void sqlite3CreateForeignKey(
- Parse *pParse, /* Parsing context */
- ExprList *pFromCol, /* Columns in this table that point to other table */
- Token *pTo, /* Name of the other table */
- ExprList *pToCol, /* Columns in the other table */
- int flags /* Conflict resolution algorithms. */
-){
- Table *p = pParse->pNewTable;
- int nByte;
- int i;
- int nCol;
- char *z;
- FKey *pFKey = 0;
-
- assert( pTo!=0 );
- if( p==0 || pParse->nErr ) goto fk_end;
- if( pFromCol==0 ){
- int iCol = p->nCol-1;
- if( iCol<0 ) goto fk_end;
- if( pToCol && pToCol->nExpr!=1 ){
- sqlite3ErrorMsg(pParse, "foreign key on %s"
- " should reference only one column of table %T",
- p->aCol[iCol].zName, pTo);
- goto fk_end;
- }
- nCol = 1;
- }else if( pToCol && pToCol->nExpr!=pFromCol->nExpr ){
- sqlite3ErrorMsg(pParse,
- "number of columns in foreign key does not match the number of "
- "columns in the referenced table");
- goto fk_end;
- }else{
- nCol = pFromCol->nExpr;
- }
- nByte = sizeof(*pFKey) + nCol*sizeof(pFKey->aCol[0]) + pTo->n + 1;
- if( pToCol ){
- for(i=0; i<pToCol->nExpr; i++){
- nByte += strlen(pToCol->a[i].zName) + 1;
- }
- }
- pFKey = sqliteMalloc( nByte );
- if( pFKey==0 ) goto fk_end;
- pFKey->pFrom = p;
- pFKey->pNextFrom = p->pFKey;
- z = (char*)&pFKey[1];
- pFKey->aCol = (struct sColMap*)z;
- z += sizeof(struct sColMap)*nCol;
- pFKey->zTo = z;
- memcpy(z, pTo->z, pTo->n);
- z[pTo->n] = 0;
- z += pTo->n+1;
- pFKey->pNextTo = 0;
- pFKey->nCol = nCol;
- if( pFromCol==0 ){
- pFKey->aCol[0].iFrom = p->nCol-1;
- }else{
- for(i=0; i<nCol; i++){
- int j;
- for(j=0; j<p->nCol; j++){
- if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){
- pFKey->aCol[i].iFrom = j;
- break;
- }
- }
- if( j>=p->nCol ){
- sqlite3ErrorMsg(pParse,
- "unknown column \"%s\" in foreign key definition",
- pFromCol->a[i].zName);
- goto fk_end;
- }
- }
- }
- if( pToCol ){
- for(i=0; i<nCol; i++){
- int n = strlen(pToCol->a[i].zName);
- pFKey->aCol[i].zCol = z;
- memcpy(z, pToCol->a[i].zName, n);
- z[n] = 0;
- z += n+1;
- }
- }
- pFKey->isDeferred = 0;
- pFKey->deleteConf = flags & 0xff;
- pFKey->updateConf = (flags >> 8 ) & 0xff;
- pFKey->insertConf = (flags >> 16 ) & 0xff;
-
- /* Link the foreign key to the table as the last step.
- */
- p->pFKey = pFKey;
- pFKey = 0;
-
-fk_end:
- sqliteFree(pFKey);
- sqlite3ExprListDelete(pFromCol);
- sqlite3ExprListDelete(pToCol);
-}
-
-/*
-** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED
-** clause is seen as part of a foreign key definition. The isDeferred
-** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE.
-** The behavior of the most recently created foreign key is adjusted
-** accordingly.
-*/
-void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){
- Table *pTab;
- FKey *pFKey;
- if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return;
- pFKey->isDeferred = isDeferred;
-}
-
-/*
-** Create a new index for an SQL table. pIndex is the name of the index
-** and pTable is the name of the table that is to be indexed. Both will
-** be NULL for a primary key or an index that is created to satisfy a
-** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable
-** as the table to be indexed. pParse->pNewTable is a table that is
-** currently being constructed by a CREATE TABLE statement.
-**
-** pList is a list of columns to be indexed. pList will be NULL if this
-** is a primary key or unique-constraint on the most recent column added
-** to the table currently under construction.
-*/
-void sqlite3CreateIndex(
- Parse *pParse, /* All information about this parse */
- Token *pName1, /* First part of index name. May be NULL */
- Token *pName2, /* Second part of index name. May be NULL */
- SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */
- ExprList *pList, /* A list of columns to be indexed */
- int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
- Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */
- Token *pEnd /* The ")" that closes the CREATE INDEX statement */
-){
- Table *pTab = 0; /* Table to be indexed */
- Index *pIndex = 0; /* The index to be created */
- char *zName = 0;
- int i, j;
- Token nullId; /* Fake token for an empty ID list */
- DbFixer sFix; /* For assigning database names to pTable */
- int isTemp; /* True for a temporary index */
- sqlite3 *db = pParse->db;
-
- int iDb; /* Index of the database that is being written */
- Token *pName = 0; /* Unqualified name of the index to create */
-
- if( pParse->nErr || sqlite3_malloc_failed ) goto exit_create_index;
-
- /*
- ** Find the table that is to be indexed. Return early if not found.
- */
- if( pTblName!=0 ){
-
- /* Use the two-part index name to determine the database
- ** to search for the table. 'Fix' the table name to this db
- ** before looking up the table.
- */
- assert( pName1 && pName2 );
- iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
- if( iDb<0 ) goto exit_create_index;
-
- /* If the index name was unqualified, check if the the table
- ** is a temp table. If so, set the database to 1.
- */
- pTab = sqlite3SrcListLookup(pParse, pTblName);
- if( pName2 && pName2->n==0 && pTab && pTab->iDb==1 ){
- iDb = 1;
- }
-
- if( sqlite3FixInit(&sFix, pParse, iDb, "index", pName) &&
- sqlite3FixSrcList(&sFix, pTblName)
- ){
- goto exit_create_index;
- }
- pTab = sqlite3LocateTable(pParse, pTblName->a[0].zName,
- pTblName->a[0].zDatabase);
- if( !pTab ) goto exit_create_index;
- assert( iDb==pTab->iDb );
- }else{
- assert( pName==0 );
- pTab = pParse->pNewTable;
- iDb = pTab->iDb;
- }
-
- if( pTab==0 || pParse->nErr ) goto exit_create_index;
- if( pTab->readOnly ){
- sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
- goto exit_create_index;
- }
- if( pTab->pSelect ){
- sqlite3ErrorMsg(pParse, "views may not be indexed");
- goto exit_create_index;
- }
- isTemp = pTab->iDb==1;
-
- /*
- ** Find the name of the index. Make sure there is not already another
- ** index or table with the same name.
- **
- ** Exception: If we are reading the names of permanent indices from the
- ** sqlite_master table (because some other process changed the schema) and
- ** one of the index names collides with the name of a temporary table or
- ** index, then we will continue to process this index.
- **
- ** If pName==0 it means that we are
- ** dealing with a primary key or UNIQUE constraint. We have to invent our
- ** own name.
- */
- if( pName ){
- zName = sqlite3NameFromToken(pName);
- if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
- if( zName==0 ) goto exit_create_index;
- if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
- goto exit_create_index;
- }
- if( !db->init.busy ){
- Index *pISameName; /* Another index with the same name */
- Table *pTSameName; /* A table with same name as the index */
- if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
- if( (pISameName = sqlite3FindIndex(db, zName, db->aDb[iDb].zName))!=0 ){
- sqlite3ErrorMsg(pParse, "index %s already exists", zName);
- goto exit_create_index;
- }
- if( (pTSameName = sqlite3FindTable(db, zName, 0))!=0 ){
- sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
- goto exit_create_index;
- }
- }
- }else if( pName==0 ){
- char zBuf[30];
- int n;
- Index *pLoop;
- for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
- sprintf(zBuf,"_%d",n);
- zName = 0;
- sqlite3SetString(&zName, "sqlite_autoindex_", pTab->zName, zBuf, (char*)0);
- if( zName==0 ) goto exit_create_index;
- }
-
- /* Check for authorization to create an index.
- */
-#ifndef SQLITE_OMIT_AUTHORIZATION
- {
- const char *zDb = db->aDb[pTab->iDb].zName;
- if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
- goto exit_create_index;
- }
- i = SQLITE_CREATE_INDEX;
- if( isTemp ) i = SQLITE_CREATE_TEMP_INDEX;
- if( sqlite3AuthCheck(pParse, i, zName, pTab->zName, zDb) ){
- goto exit_create_index;
- }
- }
-#endif
-
- /* If pList==0, it means this routine was called to make a primary
- ** key out of the last column added to the table under construction.
- ** So create a fake list to simulate this.
- */
- if( pList==0 ){
- nullId.z = pTab->aCol[pTab->nCol-1].zName;
- nullId.n = strlen(nullId.z);
- pList = sqlite3ExprListAppend(0, 0, &nullId);
- if( pList==0 ) goto exit_create_index;
- }
-
- /*
- ** Allocate the index structure.
- */
- pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 +
- (sizeof(int) + sizeof(CollSeq*))*pList->nExpr );
- if( pIndex==0 ) goto exit_create_index;
- pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr];
- pIndex->zName = (char*)&pIndex->aiColumn[pList->nExpr];
- strcpy(pIndex->zName, zName);
- pIndex->pTable = pTab;
- pIndex->nColumn = pList->nExpr;
- pIndex->onError = onError;
- pIndex->autoIndex = pName==0;
- pIndex->iDb = iDb;
-
- /* Scan the names of the columns of the table to be indexed and
- ** load the column indices into the Index structure. Report an error
- ** if any column is not found.
- */
- for(i=0; i<pList->nExpr; i++){
- for(j=0; j<pTab->nCol; j++){
- if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break;
- }
- if( j>=pTab->nCol ){
- sqlite3ErrorMsg(pParse, "table %s has no column named %s",
- pTab->zName, pList->a[i].zName);
- goto exit_create_index;
- }
- pIndex->aiColumn[i] = j;
- if( pList->a[i].pExpr ){
- assert( pList->a[i].pExpr->pColl );
- pIndex->keyInfo.aColl[i] = pList->a[i].pExpr->pColl;
- }else{
- pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl;
- }
- assert( pIndex->keyInfo.aColl[i] );
- if( !db->init.busy &&
- sqlite3CheckCollSeq(pParse, pIndex->keyInfo.aColl[i])
- ){
- goto exit_create_index;
- }
- }
- pIndex->keyInfo.nField = pList->nExpr;
-
- if( pTab==pParse->pNewTable ){
- /* This routine has been called to create an automatic index as a
- ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
- ** a PRIMARY KEY or UNIQUE clause following the column definitions.
- ** i.e. one of:
- **
- ** CREATE TABLE t(x PRIMARY KEY, y);
- ** CREATE TABLE t(x, y, UNIQUE(x, y));
- **
- ** Either way, check to see if the table already has such an index. If
- ** so, don't bother creating this one. This only applies to
- ** automatically created indices. Users can do as they wish with
- ** explicit indices.
- */
- Index *pIdx;
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- int k;
- assert( pIdx->onError!=OE_None );
- assert( pIdx->autoIndex );
- assert( pIndex->onError!=OE_None );
-
- if( pIdx->nColumn!=pIndex->nColumn ) continue;
- for(k=0; k<pIdx->nColumn; k++){
- if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
- if( pIdx->keyInfo.aColl[k]!=pIndex->keyInfo.aColl[k] ) break;
- }
- if( k==pIdx->nColumn ){
- if( pIdx->onError!=pIndex->onError ){
- /* This constraint creates the same index as a previous
- ** constraint specified somewhere in the CREATE TABLE statement.
- ** However the ON CONFLICT clauses are different. If both this
- ** constraint and the previous equivalent constraint have explicit
- ** ON CONFLICT clauses this is an error. Otherwise, use the
- ** explicitly specified behaviour for the index.
- */
- if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){
- sqlite3ErrorMsg(pParse,
- "conflicting ON CONFLICT clauses specified", 0);
- }
- if( pIdx->onError==OE_Default ){
- pIdx->onError = pIndex->onError;
- }
- }
- goto exit_create_index;
- }
- }
- }
-
- /* Link the new Index structure to its table and to the other
- ** in-memory database structures.
- */
- if( db->init.busy ){
- Index *p;
- p = sqlite3HashInsert(&db->aDb[pIndex->iDb].idxHash,
- pIndex->zName, strlen(pIndex->zName)+1, pIndex);
- if( p ){
- assert( p==pIndex ); /* Malloc must have failed */
- goto exit_create_index;
- }
- db->flags |= SQLITE_InternChanges;
- if( pTblName!=0 ){
- pIndex->tnum = db->init.newTnum;
- }
- }
-
- /* If the db->init.busy is 0 then create the index on disk. This
- ** involves writing the index into the master table and filling in the
- ** index with the current table contents.
- **
- ** The db->init.busy is 0 when the user first enters a CREATE INDEX
- ** command. db->init.busy is 1 when a database is opened and
- ** CREATE INDEX statements are read out of the master table. In
- ** the latter case the index already exists on disk, which is why
- ** we don't want to recreate it.
- **
- ** If pTblName==0 it means this index is generated as a primary key
- ** or UNIQUE constraint of a CREATE TABLE statement. Since the table
- ** has just been created, it contains no data and the index initialization
- ** step can be skipped.
- */
- else if( db->init.busy==0 ){
- int n;
- Vdbe *v;
- int lbl1, lbl2;
-
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto exit_create_index;
- if( pTblName!=0 ){
- sqlite3BeginWriteOperation(pParse, 0, iDb);
- sqlite3OpenMasterTable(v, iDb);
- }
- sqlite3VdbeAddOp(v, OP_NewRecno, 0, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, "index", P3_STATIC);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pIndex->zName, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
- sqlite3VdbeAddOp(v, OP_CreateIndex, iDb, 0);
- if( pTblName ){
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
- sqlite3VdbeOp3(v, OP_OpenWrite, 1, 0,
- (char*)&pIndex->keyInfo, P3_KEYINFO);
- }
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- if( pStart && pEnd ){
- if( onError==OE_None ){
- sqlite3VdbeChangeP3(v, -1, "CREATE INDEX ", P3_STATIC);
- }else{
- sqlite3VdbeChangeP3(v, -1, "CREATE UNIQUE INDEX ", P3_STATIC);
- }
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- n = Addr(pEnd->z) - Addr(pName->z) + 1;
- sqlite3VdbeChangeP3(v, -1, pName->z, n);
- sqlite3VdbeAddOp(v, OP_Concat, 0, 0);
- }
- sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
- sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
- if( pTblName ){
- sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
- sqlite3VdbeAddOp(v, OP_OpenRead, 2, pTab->tnum);
- /* VdbeComment((v, "%s", pTab->zName)); */
- sqlite3VdbeAddOp(v, OP_SetNumColumns, 2, pTab->nCol);
- lbl2 = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_Rewind, 2, lbl2);
- lbl1 = sqlite3VdbeCurrentAddr(v);
- sqlite3GenerateIndexKey(v, pIndex, 2);
- sqlite3VdbeOp3(v, OP_IdxPut, 1, pIndex->onError!=OE_None,
- "indexed columns are not unique", P3_STATIC);
- sqlite3VdbeAddOp(v, OP_Next, 2, lbl1);
- sqlite3VdbeResolveLabel(v, lbl2);
- sqlite3VdbeAddOp(v, OP_Close, 2, 0);
- sqlite3VdbeAddOp(v, OP_Close, 1, 0);
- sqlite3ChangeCookie(db, v, iDb);
- sqlite3VdbeAddOp(v, OP_Close, 0, 0);
- sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
- sqlite3MPrintf("name='%q'", pIndex->zName), P3_DYNAMIC);
- }
- }
-
- /* When adding an index to the list of indices for a table, make
- ** sure all indices labeled OE_Replace come after all those labeled
- ** OE_Ignore. This is necessary for the correct operation of UPDATE
- ** and INSERT.
- */
- if( db->init.busy || pTblName==0 ){
- if( onError!=OE_Replace || pTab->pIndex==0
- || pTab->pIndex->onError==OE_Replace){
- pIndex->pNext = pTab->pIndex;
- pTab->pIndex = pIndex;
- }else{
- Index *pOther = pTab->pIndex;
- while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
- pOther = pOther->pNext;
- }
- pIndex->pNext = pOther->pNext;
- pOther->pNext = pIndex;
- }
- pIndex = 0;
- }
-
- /* Clean up before exiting */
-exit_create_index:
- if( pIndex ){
- freeIndex(pIndex);
- }
- sqlite3ExprListDelete(pList);
- sqlite3SrcListDelete(pTblName);
- sqliteFree(zName);
- return;
-}
-
-/*
-** This routine will drop an existing named index. This routine
-** implements the DROP INDEX statement.
-*/
-void sqlite3DropIndex(Parse *pParse, SrcList *pName){
- Index *pIndex;
- Vdbe *v;
- sqlite3 *db = pParse->db;
-
- if( pParse->nErr || sqlite3_malloc_failed ) return;
- assert( pName->nSrc==1 );
- if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) return;
- pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
- if( pIndex==0 ){
- sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
- pParse->checkSchema = 1;
- goto exit_drop_index;
- }
- if( pIndex->autoIndex ){
- sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
- "or PRIMARY KEY constraint cannot be dropped", 0);
- goto exit_drop_index;
- }
-#ifndef SQLITE_OMIT_AUTHORIZATION
- {
- int code = SQLITE_DROP_INDEX;
- Table *pTab = pIndex->pTable;
- const char *zDb = db->aDb[pIndex->iDb].zName;
- const char *zTab = SCHEMA_TABLE(pIndex->iDb);
- if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
- goto exit_drop_index;
- }
- if( pIndex->iDb ) code = SQLITE_DROP_TEMP_INDEX;
- if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
- goto exit_drop_index;
- }
- }
-#endif
-
- /* Generate code to remove the index and from the master table */
- v = sqlite3GetVdbe(pParse);
- if( v ){
- static const VdbeOpList dropIndex[] = {
- { OP_Rewind, 0, ADDR(9), 0},
- { OP_String8, 0, 0, 0}, /* 1 */
- { OP_MemStore, 1, 1, 0},
- { OP_MemLoad, 1, 0, 0}, /* 3 */
- { OP_Column, 0, 1, 0},
- { OP_Eq, 0, ADDR(8), 0},
- { OP_Next, 0, ADDR(3), 0},
- { OP_Goto, 0, ADDR(9), 0},
- { OP_Delete, 0, 0, 0}, /* 8 */
- };
- int base;
-
- sqlite3BeginWriteOperation(pParse, 0, pIndex->iDb);
- sqlite3OpenMasterTable(v, pIndex->iDb);
- base = sqlite3VdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
- sqlite3VdbeChangeP3(v, base+1, pIndex->zName, 0);
- sqlite3ChangeCookie(db, v, pIndex->iDb);
- sqlite3VdbeAddOp(v, OP_Close, 0, 0);
- sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
- sqlite3VdbeOp3(v, OP_DropIndex, pIndex->iDb, 0, pIndex->zName, 0);
- }
-
-exit_drop_index:
- sqlite3SrcListDelete(pName);
-}
-
-/*
-** Append a new element to the given IdList. Create a new IdList if
-** need be.
-**
-** A new IdList is returned, or NULL if malloc() fails.
-*/
-IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){
- if( pList==0 ){
- pList = sqliteMalloc( sizeof(IdList) );
- if( pList==0 ) return 0;
- pList->nAlloc = 0;
- }
- if( pList->nId>=pList->nAlloc ){
- struct IdList_item *a;
- pList->nAlloc = pList->nAlloc*2 + 5;
- a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]) );
- if( a==0 ){
- sqlite3IdListDelete(pList);
- return 0;
- }
- pList->a = a;
- }
- memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
- pList->a[pList->nId].zName = sqlite3NameFromToken(pToken);
- pList->nId++;
- return pList;
-}
-
-/*
-** Append a new table name to the given SrcList. Create a new SrcList if
-** need be. A new entry is created in the SrcList even if pToken is NULL.
-**
-** A new SrcList is returned, or NULL if malloc() fails.
-**
-** If pDatabase is not null, it means that the table has an optional
-** database name prefix. Like this: "database.table". The pDatabase
-** points to the table name and the pTable points to the database name.
-** The SrcList.a[].zName field is filled with the table name which might
-** come from pTable (if pDatabase is NULL) or from pDatabase.
-** SrcList.a[].zDatabase is filled with the database name from pTable,
-** or with NULL if no database is specified.
-**
-** In other words, if call like this:
-**
-** sqlite3SrcListAppend(A,B,0);
-**
-** Then B is a table name and the database name is unspecified. If called
-** like this:
-**
-** sqlite3SrcListAppend(A,B,C);
-**
-** Then C is the table name and B is the database name.
-*/
-SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){
- struct SrcList_item *pItem;
- if( pList==0 ){
- pList = sqliteMalloc( sizeof(SrcList) );
- if( pList==0 ) return 0;
- pList->nAlloc = 1;
- }
- if( pList->nSrc>=pList->nAlloc ){
- SrcList *pNew;
- pList->nAlloc *= 2;
- pNew = sqliteRealloc(pList,
- sizeof(*pList) + (pList->nAlloc-1)*sizeof(pList->a[0]) );
- if( pNew==0 ){
- sqlite3SrcListDelete(pList);
- return 0;
- }
- pList = pNew;
- }
- pItem = &pList->a[pList->nSrc];
- memset(pItem, 0, sizeof(pList->a[0]));
- if( pDatabase && pDatabase->z==0 ){
- pDatabase = 0;
- }
- if( pDatabase && pTable ){
- Token *pTemp = pDatabase;
- pDatabase = pTable;
- pTable = pTemp;
- }
- pItem->zName = sqlite3NameFromToken(pTable);
- pItem->zDatabase = sqlite3NameFromToken(pDatabase);
- pItem->iCursor = -1;
- pList->nSrc++;
- return pList;
-}
-
-/*
-** Assign cursors to all tables in a SrcList
-*/
-void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
- int i;
- for(i=0; i<pList->nSrc; i++){
- if( pList->a[i].iCursor<0 ){
- pList->a[i].iCursor = pParse->nTab++;
- }
- }
-}
-
-/*
-** Add an alias to the last identifier on the given identifier list.
-*/
-void sqlite3SrcListAddAlias(SrcList *pList, Token *pToken){
- if( pList && pList->nSrc>0 ){
- pList->a[pList->nSrc-1].zAlias = sqlite3NameFromToken(pToken);
- }
-}
-
-/*
-** Delete an IdList.
-*/
-void sqlite3IdListDelete(IdList *pList){
- int i;
- if( pList==0 ) return;
- for(i=0; i<pList->nId; i++){
- sqliteFree(pList->a[i].zName);
- }
- sqliteFree(pList->a);
- sqliteFree(pList);
-}
-
-/*
-** Return the index in pList of the identifier named zId. Return -1
-** if not found.
-*/
-int sqlite3IdListIndex(IdList *pList, const char *zName){
- int i;
- if( pList==0 ) return -1;
- for(i=0; i<pList->nId; i++){
- if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i;
- }
- return -1;
-}
-
-/*
-** Delete an entire SrcList including all its substructure.
-*/
-void sqlite3SrcListDelete(SrcList *pList){
- int i;
- struct SrcList_item *pItem;
- if( pList==0 ) return;
- for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
- sqliteFree(pItem->zDatabase);
- sqliteFree(pItem->zName);
- sqliteFree(pItem->zAlias);
- if( pItem->pTab && pItem->pTab->isTransient ){
- sqlite3DeleteTable(0, pItem->pTab);
- }
- sqlite3SelectDelete(pItem->pSelect);
- sqlite3ExprDelete(pItem->pOn);
- sqlite3IdListDelete(pItem->pUsing);
- }
- sqliteFree(pList);
-}
-
-/*
-** Begin a transaction
-*/
-void sqlite3BeginTransaction(Parse *pParse, int type){
- sqlite3 *db;
- Vdbe *v;
- int i;
-
- if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3_malloc_failed ) return;
- if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;
-
- v = sqlite3GetVdbe(pParse);
- if( !v ) return;
- if( type!=TK_DEFERRED ){
- for(i=0; i<db->nDb; i++){
- sqlite3VdbeAddOp(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1);
- }
- }
- sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0);
-}
-
-/*
-** Commit a transaction
-*/
-void sqlite3CommitTransaction(Parse *pParse){
- sqlite3 *db;
- Vdbe *v;
-
- if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3_malloc_failed ) return;
- if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return;
-
- v = sqlite3GetVdbe(pParse);
- if( v ){
- sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 0);
- }
-}
-
-/*
-** Rollback a transaction
-*/
-void sqlite3RollbackTransaction(Parse *pParse){
- sqlite3 *db;
- Vdbe *v;
-
- if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3_malloc_failed ) return;
- if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return;
-
- v = sqlite3GetVdbe(pParse);
- if( v ){
- sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 1);
- }
-}
-
-/*
-** Make sure the TEMP database is open and available for use. Return
-** the number of errors. Leave any error messages in the pParse structure.
-*/
-static int sqlite3OpenTempDatabase(Parse *pParse){
- sqlite3 *db = pParse->db;
- if( db->aDb[1].pBt==0 && !pParse->explain ){
- int rc = sqlite3BtreeFactory(db, 0, 0, MAX_PAGES, &db->aDb[1].pBt);
- if( rc!=SQLITE_OK ){
- sqlite3ErrorMsg(pParse, "unable to open a temporary database "
- "file for storing temporary tables");
- pParse->rc = rc;
- return 1;
- }
- if( db->flags & !db->autoCommit ){
- rc = sqlite3BtreeBeginTrans(db->aDb[1].pBt, 1);
- if( rc!=SQLITE_OK ){
- sqlite3ErrorMsg(pParse, "unable to get a write lock on "
- "the temporary database file");
- pParse->rc = rc;
- return 1;
- }
- }
- }
- return 0;
-}
-
-/*
-** Generate VDBE code that will verify the schema cookie and start
-** a read-transaction for all named database files.
-**
-** It is important that all schema cookies be verified and all
-** read transactions be started before anything else happens in
-** the VDBE program. But this routine can be called after much other
-** code has been generated. So here is what we do:
-**
-** The first time this routine is called, we code an OP_Goto that
-** will jump to a subroutine at the end of the program. Then we
-** record every database that needs its schema verified in the
-** pParse->cookieMask field. Later, after all other code has been
-** generated, the subroutine that does the cookie verifications and
-** starts the transactions will be coded and the OP_Goto P2 value
-** will be made to point to that subroutine. The generation of the
-** cookie verification subroutine code happens in sqlite3FinishCoding().
-**
-** If iDb<0 then code the OP_Goto only - don't set flag to verify the
-** schema on any databases. This can be used to position the OP_Goto
-** early in the code, before we know if any database tables will be used.
-*/
-void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
- sqlite3 *db;
- Vdbe *v;
- int mask;
-
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) return; /* This only happens if there was a prior error */
- db = pParse->db;
- if( pParse->cookieGoto==0 ){
- pParse->cookieGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0)+1;
- }
- if( iDb>=0 ){
- assert( iDb<db->nDb );
- assert( db->aDb[iDb].pBt!=0 || iDb==1 );
- assert( iDb<32 );
- mask = 1<<iDb;
- if( (pParse->cookieMask & mask)==0 ){
- pParse->cookieMask |= mask;
- pParse->cookieValue[iDb] = db->aDb[iDb].schema_cookie;
- if( iDb==1 ){
- sqlite3OpenTempDatabase(pParse);
- }
- }
- }
-}
-
-/*
-** Generate VDBE code that prepares for doing an operation that
-** might change the database.
-**
-** This routine starts a new transaction if we are not already within
-** a transaction. If we are already within a transaction, then a checkpoint
-** is set if the setStatement parameter is true. A checkpoint should
-** be set for operations that might fail (due to a constraint) part of
-** the way through and which will need to undo some writes without having to
-** rollback the whole transaction. For operations where all constraints
-** can be checked before any changes are made to the database, it is never
-** necessary to undo a write and the checkpoint should not be set.
-**
-** Only database iDb and the temp database are made writable by this call.
-** If iDb==0, then the main and temp databases are made writable. If
-** iDb==1 then only the temp database is made writable. If iDb>1 then the
-** specified auxiliary database and the temp database are made writable.
-*/
-void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
- Vdbe *v = sqlite3GetVdbe(pParse);
- if( v==0 ) return;
- sqlite3CodeVerifySchema(pParse, iDb);
- pParse->writeMask |= 1<<iDb;
- if( setStatement ){
- sqlite3VdbeAddOp(v, OP_Statement, iDb, 0);
- }
- if( iDb!=1 && pParse->db->aDb[1].pBt!=0 ){
- sqlite3BeginWriteOperation(pParse, setStatement, 1);
- }
-}
-
-/*
-** Return the transient sqlite3_value object used for encoding conversions
-** during SQL compilation.
-*/
-sqlite3_value *sqlite3GetTransientValue(sqlite3 *db){
- if( !db->pValue ){
- db->pValue = sqlite3ValueNew();
- }
- return db->pValue;
-}
diff --git a/kopete/plugins/statistics/sqlite/date.c b/kopete/plugins/statistics/sqlite/date.c
deleted file mode 100644
index 634e81d5..00000000
--- a/kopete/plugins/statistics/sqlite/date.c
+++ /dev/null
@@ -1,893 +0,0 @@
-/*
-** 2003 October 31
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains the C functions that implement date and time
-** functions for SQLite.
-**
-** There is only one exported symbol in this file - the function
-** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
-** All other code has file scope.
-**
-** $Id$
-**
-** NOTES:
-**
-** SQLite processes all times and dates as Julian Day numbers. The
-** dates and times are stored as the number of days since noon
-** in Greenwich on November 24, 4714 B.C. according to the Gregorian
-** calendar system.
-**
-** 1970-01-01 00:00:00 is JD 2440587.5
-** 2000-01-01 00:00:00 is JD 2451544.5
-**
-** This implemention requires years to be expressed as a 4-digit number
-** which means that only dates between 0000-01-01 and 9999-12-31 can
-** be represented, even though julian day numbers allow a much wider
-** range of dates.
-**
-** The Gregorian calendar system is used for all dates and times,
-** even those that predate the Gregorian calendar. Historians usually
-** use the Julian calendar for dates prior to 1582-10-15 and for some
-** dates afterwards, depending on locale. Beware of this difference.
-**
-** The conversion algorithms are implemented based on descriptions
-** in the following text:
-**
-** Jean Meeus
-** Astronomical Algorithms, 2nd Edition, 1998
-** ISBM 0-943396-61-1
-** Willmann-Bell, Inc
-** Richmond, Virginia (USA)
-*/
-#include "sqliteInt.h"
-#include "os.h"
-#include <ctype.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <time.h>
-
-#ifndef SQLITE_OMIT_DATETIME_FUNCS
-
-/*
-** A structure for holding a single date and time.
-*/
-typedef struct DateTime DateTime;
-struct DateTime {
- double rJD; /* The julian day number */
- int Y, M, D; /* Year, month, and day */
- int h, m; /* Hour and minutes */
- int tz; /* Timezone offset in minutes */
- double s; /* Seconds */
- char validYMD; /* True if Y,M,D are valid */
- char validHMS; /* True if h,m,s are valid */
- char validJD; /* True if rJD is valid */
- char validTZ; /* True if tz is valid */
-};
-
-
-/*
-** Convert zDate into one or more integers. Additional arguments
-** come in groups of 5 as follows:
-**
-** N number of digits in the integer
-** min minimum allowed value of the integer
-** max maximum allowed value of the integer
-** nextC first character after the integer
-** pVal where to write the integers value.
-**
-** Conversions continue until one with nextC==0 is encountered.
-** The function returns the number of successful conversions.
-*/
-static int getDigits(const char *zDate, ...){
- va_list ap;
- int val;
- int N;
- int min;
- int max;
- int nextC;
- int *pVal;
- int cnt = 0;
- va_start(ap, zDate);
- do{
- N = va_arg(ap, int);
- min = va_arg(ap, int);
- max = va_arg(ap, int);
- nextC = va_arg(ap, int);
- pVal = va_arg(ap, int*);
- val = 0;
- while( N-- ){
- if( !isdigit(*(u8*)zDate) ){
- return cnt;
- }
- val = val*10 + *zDate - '0';
- zDate++;
- }
- if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
- return cnt;
- }
- *pVal = val;
- zDate++;
- cnt++;
- }while( nextC );
- return cnt;
-}
-
-/*
-** Read text from z[] and convert into a floating point number. Return
-** the number of digits converted.
-*/
-static int getValue(const char *z, double *pR){
- const char *zEnd;
- *pR = sqlite3AtoF(z, &zEnd);
- return zEnd - z;
-}
-
-/*
-** Parse a timezone extension on the end of a date-time.
-** The extension is of the form:
-**
-** (+/-)HH:MM
-**
-** If the parse is successful, write the number of minutes
-** of change in *pnMin and return 0. If a parser error occurs,
-** return 0.
-**
-** A missing specifier is not considered an error.
-*/
-static int parseTimezone(const char *zDate, DateTime *p){
- int sgn = 0;
- int nHr, nMn;
- while( isspace(*(u8*)zDate) ){ zDate++; }
- p->tz = 0;
- if( *zDate=='-' ){
- sgn = -1;
- }else if( *zDate=='+' ){
- sgn = +1;
- }else{
- return *zDate!=0;
- }
- zDate++;
- if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
- return 1;
- }
- zDate += 5;
- p->tz = sgn*(nMn + nHr*60);
- while( isspace(*(u8*)zDate) ){ zDate++; }
- return *zDate!=0;
-}
-
-/*
-** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF.
-** The HH, MM, and SS must each be exactly 2 digits. The
-** fractional seconds FFFF can be one or more digits.
-**
-** Return 1 if there is a parsing error and 0 on success.
-*/
-static int parseHhMmSs(const char *zDate, DateTime *p){
- int h, m, s;
- double ms = 0.0;
- if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
- return 1;
- }
- zDate += 5;
- if( *zDate==':' ){
- zDate++;
- if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
- return 1;
- }
- zDate += 2;
- if( *zDate=='.' && isdigit((u8)zDate[1]) ){
- double rScale = 1.0;
- zDate++;
- while( isdigit(*(u8*)zDate) ){
- ms = ms*10.0 + *zDate - '0';
- rScale *= 10.0;
- zDate++;
- }
- ms /= rScale;
- }
- }else{
- s = 0;
- }
- p->validJD = 0;
- p->validHMS = 1;
- p->h = h;
- p->m = m;
- p->s = s + ms;
- if( parseTimezone(zDate, p) ) return 1;
- p->validTZ = p->tz!=0;
- return 0;
-}
-
-/*
-** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume
-** that the YYYY-MM-DD is according to the Gregorian calendar.
-**
-** Reference: Meeus page 61
-*/
-static void computeJD(DateTime *p){
- int Y, M, D, A, B, X1, X2;
-
- if( p->validJD ) return;
- if( p->validYMD ){
- Y = p->Y;
- M = p->M;
- D = p->D;
- }else{
- Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */
- M = 1;
- D = 1;
- }
- if( M<=2 ){
- Y--;
- M += 12;
- }
- A = Y/100;
- B = 2 - A + (A/4);
- X1 = 365.25*(Y+4716);
- X2 = 30.6001*(M+1);
- p->rJD = X1 + X2 + D + B - 1524.5;
- p->validJD = 1;
- p->validYMD = 0;
- if( p->validHMS ){
- p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0;
- if( p->validTZ ){
- p->rJD += p->tz*60/86400.0;
- p->validHMS = 0;
- p->validTZ = 0;
- }
- }
-}
-
-/*
-** Parse dates of the form
-**
-** YYYY-MM-DD HH:MM:SS.FFF
-** YYYY-MM-DD HH:MM:SS
-** YYYY-MM-DD HH:MM
-** YYYY-MM-DD
-**
-** Write the result into the DateTime structure and return 0
-** on success and 1 if the input string is not a well-formed
-** date.
-*/
-static int parseYyyyMmDd(const char *zDate, DateTime *p){
- int Y, M, D, neg;
-
- if( zDate[0]=='-' ){
- zDate++;
- neg = 1;
- }else{
- neg = 0;
- }
- if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
- return 1;
- }
- zDate += 10;
- while( isspace(*(u8*)zDate) ){ zDate++; }
- if( parseHhMmSs(zDate, p)==0 ){
- /* We got the time */
- }else if( *zDate==0 ){
- p->validHMS = 0;
- }else{
- return 1;
- }
- p->validJD = 0;
- p->validYMD = 1;
- p->Y = neg ? -Y : Y;
- p->M = M;
- p->D = D;
- if( p->validTZ ){
- computeJD(p);
- }
- return 0;
-}
-
-/*
-** Attempt to parse the given string into a Julian Day Number. Return
-** the number of errors.
-**
-** The following are acceptable forms for the input string:
-**
-** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM
-** DDDD.DD
-** now
-**
-** In the first form, the +/-HH:MM is always optional. The fractional
-** seconds extension (the ".FFF") is optional. The seconds portion
-** (":SS.FFF") is option. The year and date can be omitted as long
-** as there is a time string. The time string can be omitted as long
-** as there is a year and date.
-*/
-static int parseDateOrTime(const char *zDate, DateTime *p){
- memset(p, 0, sizeof(*p));
- if( parseYyyyMmDd(zDate,p)==0 ){
- return 0;
- }else if( parseHhMmSs(zDate, p)==0 ){
- return 0;
- }else if( sqlite3StrICmp(zDate,"now")==0){
- double r;
- if( sqlite3OsCurrentTime(&r)==0 ){
- p->rJD = r;
- p->validJD = 1;
- return 0;
- }
- return 1;
- }else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){
- p->rJD = sqlite3AtoF(zDate, 0);
- p->validJD = 1;
- return 0;
- }
- return 1;
-}
-
-/*
-** Compute the Year, Month, and Day from the julian day number.
-*/
-static void computeYMD(DateTime *p){
- int Z, A, B, C, D, E, X1;
- if( p->validYMD ) return;
- if( !p->validJD ){
- p->Y = 2000;
- p->M = 1;
- p->D = 1;
- }else{
- Z = p->rJD + 0.5;
- A = (Z - 1867216.25)/36524.25;
- A = Z + 1 + A - (A/4);
- B = A + 1524;
- C = (B - 122.1)/365.25;
- D = 365.25*C;
- E = (B-D)/30.6001;
- X1 = 30.6001*E;
- p->D = B - D - X1;
- p->M = E<14 ? E-1 : E-13;
- p->Y = p->M>2 ? C - 4716 : C - 4715;
- }
- p->validYMD = 1;
-}
-
-/*
-** Compute the Hour, Minute, and Seconds from the julian day number.
-*/
-static void computeHMS(DateTime *p){
- int Z, s;
- if( p->validHMS ) return;
- Z = p->rJD + 0.5;
- s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5;
- p->s = 0.001*s;
- s = p->s;
- p->s -= s;
- p->h = s/3600;
- s -= p->h*3600;
- p->m = s/60;
- p->s += s - p->m*60;
- p->validHMS = 1;
-}
-
-/*
-** Compute both YMD and HMS
-*/
-static void computeYMD_HMS(DateTime *p){
- computeYMD(p);
- computeHMS(p);
-}
-
-/*
-** Clear the YMD and HMS and the TZ
-*/
-static void clearYMD_HMS_TZ(DateTime *p){
- p->validYMD = 0;
- p->validHMS = 0;
- p->validTZ = 0;
-}
-
-/*
-** Compute the difference (in days) between localtime and UTC (a.k.a. GMT)
-** for the time value p where p is in UTC.
-*/
-static double localtimeOffset(DateTime *p){
- DateTime x, y;
- time_t t;
- struct tm *pTm;
- x = *p;
- computeYMD_HMS(&x);
- if( x.Y<1971 || x.Y>=2038 ){
- x.Y = 2000;
- x.M = 1;
- x.D = 1;
- x.h = 0;
- x.m = 0;
- x.s = 0.0;
- } else {
- int s = x.s + 0.5;
- x.s = s;
- }
- x.tz = 0;
- x.validJD = 0;
- computeJD(&x);
- t = (x.rJD-2440587.5)*86400.0 + 0.5;
- sqlite3OsEnterMutex();
- pTm = localtime(&t);
- y.Y = pTm->tm_year + 1900;
- y.M = pTm->tm_mon + 1;
- y.D = pTm->tm_mday;
- y.h = pTm->tm_hour;
- y.m = pTm->tm_min;
- y.s = pTm->tm_sec;
- sqlite3OsLeaveMutex();
- y.validYMD = 1;
- y.validHMS = 1;
- y.validJD = 0;
- y.validTZ = 0;
- computeJD(&y);
- return y.rJD - x.rJD;
-}
-
-/*
-** Process a modifier to a date-time stamp. The modifiers are
-** as follows:
-**
-** NNN days
-** NNN hours
-** NNN minutes
-** NNN.NNNN seconds
-** NNN months
-** NNN years
-** start of month
-** start of year
-** start of week
-** start of day
-** weekday N
-** unixepoch
-** localtime
-** utc
-**
-** Return 0 on success and 1 if there is any kind of error.
-*/
-static int parseModifier(const char *zMod, DateTime *p){
- int rc = 1;
- int n;
- double r;
- char *z, zBuf[30];
- z = zBuf;
- for(n=0; n<sizeof(zBuf)-1 && zMod[n]; n++){
- z[n] = tolower(zMod[n]);
- }
- z[n] = 0;
- switch( z[0] ){
- case 'l': {
- /* localtime
- **
- ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
- ** show local time.
- */
- if( strcmp(z, "localtime")==0 ){
- computeJD(p);
- p->rJD += localtimeOffset(p);
- clearYMD_HMS_TZ(p);
- rc = 0;
- }
- break;
- }
- case 'u': {
- /*
- ** unixepoch
- **
- ** Treat the current value of p->rJD as the number of
- ** seconds since 1970. Convert to a real julian day number.
- */
- if( strcmp(z, "unixepoch")==0 && p->validJD ){
- p->rJD = p->rJD/86400.0 + 2440587.5;
- clearYMD_HMS_TZ(p);
- rc = 0;
- }else if( strcmp(z, "utc")==0 ){
- double c1;
- computeJD(p);
- c1 = localtimeOffset(p);
- p->rJD -= c1;
- clearYMD_HMS_TZ(p);
- p->rJD += c1 - localtimeOffset(p);
- rc = 0;
- }
- break;
- }
- case 'w': {
- /*
- ** weekday N
- **
- ** Move the date to the same time on the next occurrence of
- ** weekday N where 0==Sunday, 1==Monday, and so forth. If the
- ** date is already on the appropriate weekday, this is a no-op.
- */
- if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0
- && (n=r)==r && n>=0 && r<7 ){
- int Z;
- computeYMD_HMS(p);
- p->validTZ = 0;
- p->validJD = 0;
- computeJD(p);
- Z = p->rJD + 1.5;
- Z %= 7;
- if( Z>n ) Z -= 7;
- p->rJD += n - Z;
- clearYMD_HMS_TZ(p);
- rc = 0;
- }
- break;
- }
- case 's': {
- /*
- ** start of TTTTT
- **
- ** Move the date backwards to the beginning of the current day,
- ** or month or year.
- */
- if( strncmp(z, "start of ", 9)!=0 ) break;
- z += 9;
- computeYMD(p);
- p->validHMS = 1;
- p->h = p->m = 0;
- p->s = 0.0;
- p->validTZ = 0;
- p->validJD = 0;
- if( strcmp(z,"month")==0 ){
- p->D = 1;
- rc = 0;
- }else if( strcmp(z,"year")==0 ){
- computeYMD(p);
- p->M = 1;
- p->D = 1;
- rc = 0;
- }else if( strcmp(z,"day")==0 ){
- rc = 0;
- }
- break;
- }
- case '+':
- case '-':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': {
- n = getValue(z, &r);
- if( n<=0 ) break;
- if( z[n]==':' ){
- /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
- ** specified number of hours, minutes, seconds, and fractional seconds
- ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
- ** omitted.
- */
- const char *z2 = z;
- DateTime tx;
- int day;
- if( !isdigit(*(u8*)z2) ) z2++;
- memset(&tx, 0, sizeof(tx));
- if( parseHhMmSs(z2, &tx) ) break;
- computeJD(&tx);
- tx.rJD -= 0.5;
- day = (int)tx.rJD;
- tx.rJD -= day;
- if( z[0]=='-' ) tx.rJD = -tx.rJD;
- computeJD(p);
- clearYMD_HMS_TZ(p);
- p->rJD += tx.rJD;
- rc = 0;
- break;
- }
- z += n;
- while( isspace(*(u8*)z) ) z++;
- n = strlen(z);
- if( n>10 || n<3 ) break;
- if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
- computeJD(p);
- rc = 0;
- if( n==3 && strcmp(z,"day")==0 ){
- p->rJD += r;
- }else if( n==4 && strcmp(z,"hour")==0 ){
- p->rJD += r/24.0;
- }else if( n==6 && strcmp(z,"minute")==0 ){
- p->rJD += r/(24.0*60.0);
- }else if( n==6 && strcmp(z,"second")==0 ){
- p->rJD += r/(24.0*60.0*60.0);
- }else if( n==5 && strcmp(z,"month")==0 ){
- int x, y;
- computeYMD_HMS(p);
- p->M += r;
- x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
- p->Y += x;
- p->M -= x*12;
- p->validJD = 0;
- computeJD(p);
- y = r;
- if( y!=r ){
- p->rJD += (r - y)*30.0;
- }
- }else if( n==4 && strcmp(z,"year")==0 ){
- computeYMD_HMS(p);
- p->Y += r;
- p->validJD = 0;
- computeJD(p);
- }else{
- rc = 1;
- }
- clearYMD_HMS_TZ(p);
- break;
- }
- default: {
- break;
- }
- }
- return rc;
-}
-
-/*
-** Process time function arguments. argv[0] is a date-time stamp.
-** argv[1] and following are modifiers. Parse them all and write
-** the resulting time into the DateTime structure p. Return 0
-** on success and 1 if there are any errors.
-*/
-static int isDate(int argc, sqlite3_value **argv, DateTime *p){
- int i;
- if( argc==0 ) return 1;
- if( SQLITE_NULL==sqlite3_value_type(argv[0]) ||
- parseDateOrTime(sqlite3_value_text(argv[0]), p) ) return 1;
- for(i=1; i<argc; i++){
- if( SQLITE_NULL==sqlite3_value_type(argv[i]) ||
- parseModifier(sqlite3_value_text(argv[i]), p) ) return 1;
- }
- return 0;
-}
-
-
-/*
-** The following routines implement the various date and time functions
-** of SQLite.
-*/
-
-/*
-** julianday( TIMESTRING, MOD, MOD, ...)
-**
-** Return the julian day number of the date specified in the arguments
-*/
-static void juliandayFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- DateTime x;
- if( isDate(argc, argv, &x)==0 ){
- computeJD(&x);
- sqlite3_result_double(context, x.rJD);
- }
-}
-
-/*
-** datetime( TIMESTRING, MOD, MOD, ...)
-**
-** Return YYYY-MM-DD HH:MM:SS
-*/
-static void datetimeFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- DateTime x;
- if( isDate(argc, argv, &x)==0 ){
- char zBuf[100];
- computeYMD_HMS(&x);
- sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m,
- (int)(x.s));
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
- }
-}
-
-/*
-** time( TIMESTRING, MOD, MOD, ...)
-**
-** Return HH:MM:SS
-*/
-static void timeFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- DateTime x;
- if( isDate(argc, argv, &x)==0 ){
- char zBuf[100];
- computeHMS(&x);
- sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
- }
-}
-
-/*
-** date( TIMESTRING, MOD, MOD, ...)
-**
-** Return YYYY-MM-DD
-*/
-static void dateFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- DateTime x;
- if( isDate(argc, argv, &x)==0 ){
- char zBuf[100];
- computeYMD(&x);
- sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
- }
-}
-
-/*
-** strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
-**
-** Return a string described by FORMAT. Conversions as follows:
-**
-** %d day of month
-** %f ** fractional seconds SS.SSS
-** %H hour 00-24
-** %j day of year 000-366
-** %J ** Julian day number
-** %m month 01-12
-** %M minute 00-59
-** %s seconds since 1970-01-01
-** %S seconds 00-59
-** %w day of week 0-6 sunday==0
-** %W week of year 00-53
-** %Y year 0000-9999
-** %% %
-*/
-static void strftimeFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- DateTime x;
- int n, i, j;
- char *z;
- const char *zFmt = sqlite3_value_text(argv[0]);
- char zBuf[100];
- if( zFmt==0 || isDate(argc-1, argv+1, &x) ) return;
- for(i=0, n=1; zFmt[i]; i++, n++){
- if( zFmt[i]=='%' ){
- switch( zFmt[i+1] ){
- case 'd':
- case 'H':
- case 'm':
- case 'M':
- case 'S':
- case 'W':
- n++;
- /* fall thru */
- case 'w':
- case '%':
- break;
- case 'f':
- n += 8;
- break;
- case 'j':
- n += 3;
- break;
- case 'Y':
- n += 8;
- break;
- case 's':
- case 'J':
- n += 50;
- break;
- default:
- return; /* ERROR. return a NULL */
- }
- i++;
- }
- }
- if( n<sizeof(zBuf) ){
- z = zBuf;
- }else{
- z = sqliteMalloc( n );
- if( z==0 ) return;
- }
- computeJD(&x);
- computeYMD_HMS(&x);
- for(i=j=0; zFmt[i]; i++){
- if( zFmt[i]!='%' ){
- z[j++] = zFmt[i];
- }else{
- i++;
- switch( zFmt[i] ){
- case 'd': sprintf(&z[j],"%02d",x.D); j+=2; break;
- case 'f': {
- int s = x.s;
- int ms = (x.s - s)*1000.0;
- sprintf(&z[j],"%02d.%03d",s,ms);
- j += strlen(&z[j]);
- break;
- }
- case 'H': sprintf(&z[j],"%02d",x.h); j+=2; break;
- case 'W': /* Fall thru */
- case 'j': {
- int n; /* Number of days since 1st day of year */
- DateTime y = x;
- y.validJD = 0;
- y.M = 1;
- y.D = 1;
- computeJD(&y);
- n = x.rJD - y.rJD;
- if( zFmt[i]=='W' ){
- int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
- wd = ((int)(x.rJD+0.5)) % 7;
- sprintf(&z[j],"%02d",(n+7-wd)/7);
- j += 2;
- }else{
- sprintf(&z[j],"%03d",n+1);
- j += 3;
- }
- break;
- }
- case 'J': sprintf(&z[j],"%.16g",x.rJD); j+=strlen(&z[j]); break;
- case 'm': sprintf(&z[j],"%02d",x.M); j+=2; break;
- case 'M': sprintf(&z[j],"%02d",x.m); j+=2; break;
- case 's': {
- sprintf(&z[j],"%d",(int)((x.rJD-2440587.5)*86400.0 + 0.5));
- j += strlen(&z[j]);
- break;
- }
- case 'S': sprintf(&z[j],"%02d",(int)(x.s+0.5)); j+=2; break;
- case 'w': z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break;
- case 'Y': sprintf(&z[j],"%04d",x.Y); j+=strlen(&z[j]); break;
- case '%': z[j++] = '%'; break;
- }
- }
- }
- z[j] = 0;
- sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
- if( z!=zBuf ){
- sqliteFree(z);
- }
-}
-
-
-#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
-
-/*
-** This function registered all of the above C functions as SQL
-** functions. This should be the only routine in this file with
-** external linkage.
-*/
-void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
-#ifndef SQLITE_OMIT_DATETIME_FUNCS
- static const struct {
- char *zName;
- int nArg;
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
- } aFuncs[] = {
- { "julianday", -1, juliandayFunc },
- { "date", -1, dateFunc },
- { "time", -1, timeFunc },
- { "datetime", -1, datetimeFunc },
- { "strftime", -1, strftimeFunc },
- };
- int i;
-
- for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
- sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
- SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
- }
-#endif
-}
diff --git a/kopete/plugins/statistics/sqlite/delete.c b/kopete/plugins/statistics/sqlite/delete.c
deleted file mode 100644
index 866da61d..00000000
--- a/kopete/plugins/statistics/sqlite/delete.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains C code routines that are called by the parser
-** to handle DELETE FROM statements.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-
-/*
-** Look up every table that is named in pSrc. If any table is not found,
-** add an error message to pParse->zErrMsg and return NULL. If all tables
-** are found, return a pointer to the last table.
-*/
-Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
- Table *pTab = 0;
- int i;
- struct SrcList_item *pItem;
- for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
- pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
- pItem->pTab = pTab;
- }
- return pTab;
-}
-
-/*
-** Check to make sure the given table is writable. If it is not
-** writable, generate an error message and return 1. If it is
-** writable return 0;
-*/
-int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
- if( pTab->readOnly ){
- sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
- return 1;
- }
- if( !viewOk && pTab->pSelect ){
- sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
- return 1;
- }
- return 0;
-}
-
-/*
-** Generate code that will open a table for reading.
-*/
-void sqlite3OpenTableForReading(
- Vdbe *v, /* Generate code into this VDBE */
- int iCur, /* The cursor number of the table */
- Table *pTab /* The table to be opened */
-){
- sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
- sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
- VdbeComment((v, "# %s", pTab->zName));
- sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
-}
-
-
-/*
-** Process a DELETE FROM statement.
-*/
-void sqlite3DeleteFrom(
- Parse *pParse, /* The parser context */
- SrcList *pTabList, /* The table from which we should delete things */
- Expr *pWhere /* The WHERE clause. May be null */
-){
- Vdbe *v; /* The virtual database engine */
- Table *pTab; /* The table from which records will be deleted */
- const char *zDb; /* Name of database holding pTab */
- int end, addr = 0; /* A couple addresses of generated code */
- int i; /* Loop counter */
- WhereInfo *pWInfo; /* Information about the WHERE clause */
- Index *pIdx; /* For looping over indices of the table */
- int iCur; /* VDBE Cursor number for pTab */
- sqlite3 *db; /* Main database structure */
- int isView; /* True if attempting to delete from a view */
- AuthContext sContext; /* Authorization context */
-
- int row_triggers_exist = 0; /* True if any triggers exist */
- int before_triggers; /* True if there are BEFORE triggers */
- int after_triggers; /* True if there are AFTER triggers */
- int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
-
- sContext.pParse = 0;
- if( pParse->nErr || sqlite3_malloc_failed ){
- pTabList = 0;
- goto delete_from_cleanup;
- }
- db = pParse->db;
- assert( pTabList->nSrc==1 );
-
- /* Locate the table which we want to delete. This table has to be
- ** put in an SrcList structure because some of the subroutines we
- ** will be calling are designed to work with multiple tables and expect
- ** an SrcList* parameter instead of just a Table* parameter.
- */
- pTab = sqlite3SrcListLookup(pParse, pTabList);
- if( pTab==0 ) goto delete_from_cleanup;
- before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
- TK_DELETE, TK_BEFORE, TK_ROW, 0);
- after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
- TK_DELETE, TK_AFTER, TK_ROW, 0);
- row_triggers_exist = before_triggers || after_triggers;
- isView = pTab->pSelect!=0;
- if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
- goto delete_from_cleanup;
- }
- assert( pTab->iDb<db->nDb );
- zDb = db->aDb[pTab->iDb].zName;
- if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
- goto delete_from_cleanup;
- }
-
- /* If pTab is really a view, make sure it has been initialized.
- */
- if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){
- goto delete_from_cleanup;
- }
-
- /* Allocate a cursor used to store the old.* data for a trigger.
- */
- if( row_triggers_exist ){
- oldIdx = pParse->nTab++;
- }
-
- /* Resolve the column names in all the expressions.
- */
- assert( pTabList->nSrc==1 );
- iCur = pTabList->a[0].iCursor = pParse->nTab++;
- if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
- goto delete_from_cleanup;
- }
-
- /* Start the view context
- */
- if( isView ){
- sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
- }
-
- /* Begin generating code.
- */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ){
- goto delete_from_cleanup;
- }
- sqlite3VdbeCountChanges(v);
- sqlite3BeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
-
- /* If we are trying to delete from a view, construct that view into
- ** a temporary table.
- */
- if( isView ){
- Select *pView = sqlite3SelectDup(pTab->pSelect);
- sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
- sqlite3SelectDelete(pView);
- }
-
- /* Initialize the counter of the number of rows deleted, if
- ** we are counting rows.
- */
- if( db->flags & SQLITE_CountRows ){
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
- }
-
- /* Special case: A DELETE without a WHERE clause deletes everything.
- ** It is easier just to erase the whole table. Note, however, that
- ** this means that the row change count will be incorrect.
- */
- if( pWhere==0 && !row_triggers_exist ){
- if( db->flags & SQLITE_CountRows ){
- /* If counting rows deleted, just count the total number of
- ** entries in the table. */
- int endOfLoop = sqlite3VdbeMakeLabel(v);
- int addr;
- if( !isView ){
- sqlite3OpenTableForReading(v, iCur, pTab);
- }
- sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
- addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
- sqlite3VdbeAddOp(v, OP_Next, iCur, addr);
- sqlite3VdbeResolveLabel(v, endOfLoop);
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
- }
- }
- }
-
- /* The usual case: There is a WHERE clause so we have to scan through
- ** the table and pick which records to delete.
- */
- else{
- /* Ensure all required collation sequences are available. */
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
- goto delete_from_cleanup;
- }
- }
-
- /* Begin the database scan
- */
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
- if( pWInfo==0 ) goto delete_from_cleanup;
-
- /* Remember the key of every item to be deleted.
- */
- sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
- if( db->flags & SQLITE_CountRows ){
- sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
- }
-
- /* End the database scan loop.
- */
- sqlite3WhereEnd(pWInfo);
-
- /* Open the pseudo-table used to store OLD if there are triggers.
- */
- if( row_triggers_exist ){
- sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
- }
-
- /* Delete every item whose key was written to the list during the
- ** database scan. We have to delete items after the scan is complete
- ** because deleting an item can change the scan order.
- */
- sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
- end = sqlite3VdbeMakeLabel(v);
-
- /* This is the beginning of the delete loop when there are
- ** row triggers.
- */
- if( row_triggers_exist ){
- addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- if( !isView ){
- sqlite3OpenTableForReading(v, iCur, pTab);
- }
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
- sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
- sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
- sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
-
- sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1,
- oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
- addr);
- }
-
- if( !isView ){
- /* Open cursors for the table we are deleting from and all its
- ** indices. If there are row triggers, this happens inside the
- ** OP_ListRead loop because the cursor have to all be closed
- ** before the trigger fires. If there are no row triggers, the
- ** cursors are opened only once on the outside the loop.
- */
- sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
-
- /* This is the beginning of the delete loop when there are no
- ** row triggers */
- if( !row_triggers_exist ){
- addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
- }
-
- /* Delete the row */
- sqlite3GenerateRowDelete(db, v, pTab, iCur, 1);
- }
-
- /* If there are row triggers, close all cursors then invoke
- ** the AFTER triggers
- */
- if( row_triggers_exist ){
- if( !isView ){
- for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
- sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
- }
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
- sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1,
- oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
- addr);
- }
-
- /* End of the delete loop */
- sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
- sqlite3VdbeResolveLabel(v, end);
- sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
-
- /* Close the cursors after the loop if there are no row triggers */
- if( !row_triggers_exist ){
- for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
- sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
- }
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
- }
-
- /*
- ** Return the number of rows that were deleted.
- */
- if( db->flags & SQLITE_CountRows ){
- sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, "rows deleted", P3_STATIC);
- }
-
-delete_from_cleanup:
- sqlite3AuthContextPop(&sContext);
- sqlite3SrcListDelete(pTabList);
- sqlite3ExprDelete(pWhere);
- return;
-}
-
-/*
-** This routine generates VDBE code that causes a single row of a
-** single table to be deleted.
-**
-** The VDBE must be in a particular state when this routine is called.
-** These are the requirements:
-**
-** 1. A read/write cursor pointing to pTab, the table containing the row
-** to be deleted, must be opened as cursor number "base".
-**
-** 2. Read/write cursors for all indices of pTab must be open as
-** cursor number base+i for the i-th index.
-**
-** 3. The record number of the row to be deleted must be on the top
-** of the stack.
-**
-** This routine pops the top of the stack to remove the record number
-** and then generates code to remove both the table record and all index
-** entries that point to that record.
-*/
-void sqlite3GenerateRowDelete(
- sqlite3 *db, /* The database containing the index */
- Vdbe *v, /* Generate code into this VDBE */
- Table *pTab, /* Table containing the row to be deleted */
- int iCur, /* Cursor number for the table */
- int count /* Increment the row change counter */
-){
- int addr;
- addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
- sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
- sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
- sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
-}
-
-/*
-** This routine generates VDBE code that causes the deletion of all
-** index entries associated with a single row of a single table.
-**
-** The VDBE must be in a particular state when this routine is called.
-** These are the requirements:
-**
-** 1. A read/write cursor pointing to pTab, the table containing the row
-** to be deleted, must be opened as cursor number "iCur".
-**
-** 2. Read/write cursors for all indices of pTab must be open as
-** cursor number iCur+i for the i-th index.
-**
-** 3. The "iCur" cursor must be pointing to the row that is to be
-** deleted.
-*/
-void sqlite3GenerateRowIndexDelete(
- sqlite3 *db, /* The database containing the index */
- Vdbe *v, /* Generate code into this VDBE */
- Table *pTab, /* Table containing the row to be deleted */
- int iCur, /* Cursor number for the table */
- char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
-){
- int i;
- Index *pIdx;
-
- for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
- if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
- sqlite3GenerateIndexKey(v, pIdx, iCur);
- sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
- }
-}
-
-/*
-** Generate code that will assemble an index key and put it on the top
-** of the tack. The key with be for index pIdx which is an index on pTab.
-** iCur is the index of a cursor open on the pTab table and pointing to
-** the entry that needs indexing.
-*/
-void sqlite3GenerateIndexKey(
- Vdbe *v, /* Generate code into this VDBE */
- Index *pIdx, /* The index for which to generate a key */
- int iCur /* Cursor number for the pIdx->pTable table */
-){
- int j;
- Table *pTab = pIdx->pTable;
-
- sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
- for(j=0; j<pIdx->nColumn; j++){
- int idx = pIdx->aiColumn[j];
- if( idx==pTab->iPKey ){
- sqlite3VdbeAddOp(v, OP_Dup, j, 0);
- }else{
- sqlite3VdbeAddOp(v, OP_Column, iCur, idx);
- }
- }
- sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24));
- sqlite3IndexAffinityStr(v, pIdx);
-}
diff --git a/kopete/plugins/statistics/sqlite/encode.c b/kopete/plugins/statistics/sqlite/encode.c
deleted file mode 100644
index b10c96b3..00000000
--- a/kopete/plugins/statistics/sqlite/encode.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
-** 2002 April 25
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains helper routines used to translate binary data into
-** a null-terminated string (suitable for use in SQLite) and back again.
-** These are convenience routines for use by people who want to store binary
-** data in an SQLite database. The code in this file is not used by any other
-** part of the SQLite library.
-**
-** $Id$
-*/
-#include <string.h>
-#include <assert.h>
-
-/*
-** How This Encoder Works
-**
-** The output is allowed to contain any character except 0x27 (') and
-** 0x00. This is accomplished by using an escape character to encode
-** 0x27 and 0x00 as a two-byte sequence. The escape character is always
-** 0x01. An 0x00 is encoded as the two byte sequence 0x01 0x01. The
-** 0x27 character is encoded as the two byte sequence 0x01 0x28. Finally,
-** the escape character itself is encoded as the two-character sequence
-** 0x01 0x02.
-**
-** To summarize, the encoder works by using an escape sequences as follows:
-**
-** 0x00 -> 0x01 0x01
-** 0x01 -> 0x01 0x02
-** 0x27 -> 0x01 0x28
-**
-** If that were all the encoder did, it would work, but in certain cases
-** it could double the size of the encoded string. For example, to
-** encode a string of 100 0x27 characters would require 100 instances of
-** the 0x01 0x03 escape sequence resulting in a 200-character output.
-** We would prefer to keep the size of the encoded string smaller than
-** this.
-**
-** To minimize the encoding size, we first add a fixed offset value to each
-** byte in the sequence. The addition is modulo 256. (That is to say, if
-** the sum of the original character value and the offset exceeds 256, then
-** the higher order bits are truncated.) The offset is chosen to minimize
-** the number of characters in the string that need to be escaped. For
-** example, in the case above where the string was composed of 100 0x27
-** characters, the offset might be 0x01. Each of the 0x27 characters would
-** then be converted into an 0x28 character which would not need to be
-** escaped at all and so the 100 character input string would be converted
-** into just 100 characters of output. Actually 101 characters of output -
-** we have to record the offset used as the first byte in the sequence so
-** that the string can be decoded. Since the offset value is stored as
-** part of the output string and the output string is not allowed to contain
-** characters 0x00 or 0x27, the offset cannot be 0x00 or 0x27.
-**
-** Here, then, are the encoding steps:
-**
-** (1) Choose an offset value and make it the first character of
-** output.
-**
-** (2) Copy each input character into the output buffer, one by
-** one, adding the offset value as you copy.
-**
-** (3) If the value of an input character plus offset is 0x00, replace
-** that one character by the two-character sequence 0x01 0x01.
-** If the sum is 0x01, replace it with 0x01 0x02. If the sum
-** is 0x27, replace it with 0x01 0x03.
-**
-** (4) Put a 0x00 terminator at the end of the output.
-**
-** Decoding is obvious:
-**
-** (5) Copy encoded characters except the first into the decode
-** buffer. Set the first encoded character aside for use as
-** the offset in step 7 below.
-**
-** (6) Convert each 0x01 0x01 sequence into a single character 0x00.
-** Convert 0x01 0x02 into 0x01. Convert 0x01 0x28 into 0x27.
-**
-** (7) Subtract the offset value that was the first character of
-** the encoded buffer from all characters in the output buffer.
-**
-** The only tricky part is step (1) - how to compute an offset value to
-** minimize the size of the output buffer. This is accomplished by testing
-** all offset values and picking the one that results in the fewest number
-** of escapes. To do that, we first scan the entire input and count the
-** number of occurances of each character value in the input. Suppose
-** the number of 0x00 characters is N(0), the number of occurances of 0x01
-** is N(1), and so forth up to the number of occurances of 0xff is N(255).
-** An offset of 0 is not allowed so we don't have to test it. The number
-** of escapes required for an offset of 1 is N(1)+N(2)+N(40). The number
-** of escapes required for an offset of 2 is N(2)+N(3)+N(41). And so forth.
-** In this way we find the offset that gives the minimum number of escapes,
-** and thus minimizes the length of the output string.
-*/
-
-/*
-** Encode a binary buffer "in" of size n bytes so that it contains
-** no instances of characters '\'' or '\000'. The output is
-** null-terminated and can be used as a string value in an INSERT
-** or UPDATE statement. Use sqlite_decode_binary() to convert the
-** string back into its original binary.
-**
-** The result is written into a preallocated output buffer "out".
-** "out" must be able to hold at least 2 +(257*n)/254 bytes.
-** In other words, the output will be expanded by as much as 3
-** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.
-** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)
-**
-** The return value is the number of characters in the encoded
-** string, excluding the "\000" terminator.
-**
-** If out==NULL then no output is generated but the routine still returns
-** the number of characters that would have been generated if out had
-** not been NULL.
-*/
-int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out){
- int i, j, e, m;
- unsigned char x;
- int cnt[256];
- if( n<=0 ){
- if( out ){
- out[0] = 'x';
- out[1] = 0;
- }
- return 1;
- }
- memset(cnt, 0, sizeof(cnt));
- for(i=n-1; i>=0; i--){ cnt[in[i]]++; }
- m = n;
- for(i=1; i<256; i++){
- int sum;
- if( i=='\'' ) continue;
- sum = cnt[i] + cnt[(i+1)&0xff] + cnt[(i+'\'')&0xff];
- if( sum<m ){
- m = sum;
- e = i;
- if( m==0 ) break;
- }
- }
- if( out==0 ){
- return n+m+1;
- }
- out[0] = e;
- j = 1;
- for(i=0; i<n; i++){
- x = in[i] - e;
- if( x==0 || x==1 || x=='\''){
- out[j++] = 1;
- x++;
- }
- out[j++] = x;
- }
- out[j] = 0;
- assert( j==n+m+1 );
- return j;
-}
-
-/*
-** Decode the string "in" into binary data and write it into "out".
-** This routine reverses the encoding created by sqlite_encode_binary().
-** The output will always be a few bytes less than the input. The number
-** of bytes of output is returned. If the input is not a well-formed
-** encoding, -1 is returned.
-**
-** The "in" and "out" parameters may point to the same buffer in order
-** to decode a string in place.
-*/
-int sqlite_decode_binary(const unsigned char *in, unsigned char *out){
- int i, e;
- unsigned char c;
- e = *(in++);
- i = 0;
- while( (c = *(in++))!=0 ){
- if( c==1 ){
- c = *(in++) - 1;
- }
- out[i++] = c + e;
- }
- return i;
-}
-
-#ifdef ENCODER_TEST
-#include <stdio.h>
-/*
-** The subroutines above are not tested by the usual test suite. To test
-** these routines, compile just this one file with a -DENCODER_TEST=1 option
-** and run the result.
-*/
-int main(int argc, char **argv){
- int i, j, n, m, nOut, nByteIn, nByteOut;
- unsigned char in[30000];
- unsigned char out[33000];
-
- nByteIn = nByteOut = 0;
- for(i=0; i<sizeof(in); i++){
- printf("Test %d: ", i+1);
- n = rand() % (i+1);
- if( i%100==0 ){
- int k;
- for(j=k=0; j<n; j++){
- /* if( k==0 || k=='\'' ) k++; */
- in[j] = k;
- k = (k+1)&0xff;
- }
- }else{
- for(j=0; j<n; j++) in[j] = rand() & 0xff;
- }
- nByteIn += n;
- nOut = sqlite_encode_binary(in, n, out);
- nByteOut += nOut;
- if( nOut!=strlen(out) ){
- printf(" ERROR return value is %d instead of %d\n", nOut, strlen(out));
- exit(1);
- }
- if( nOut!=sqlite_encode_binary(in, n, 0) ){
- printf(" ERROR actual output size disagrees with predicted size\n");
- exit(1);
- }
- m = (256*n + 1262)/253;
- printf("size %d->%d (max %d)", n, strlen(out)+1, m);
- if( strlen(out)+1>m ){
- printf(" ERROR output too big\n");
- exit(1);
- }
- for(j=0; out[j]; j++){
- if( out[j]=='\'' ){
- printf(" ERROR contains (')\n");
- exit(1);
- }
- }
- j = sqlite_decode_binary(out, out);
- if( j!=n ){
- printf(" ERROR decode size %d\n", j);
- exit(1);
- }
- if( memcmp(in, out, n)!=0 ){
- printf(" ERROR decode mismatch\n");
- exit(1);
- }
- printf(" OK\n");
- }
- fprintf(stderr,"Finished. Total encoding: %d->%d bytes\n",
- nByteIn, nByteOut);
- fprintf(stderr,"Avg size increase: %.3f%%\n",
- (nByteOut-nByteIn)*100.0/(double)nByteIn);
-}
-#endif /* ENCODER_TEST */
-
-
-
diff --git a/kopete/plugins/statistics/sqlite/expr.c b/kopete/plugins/statistics/sqlite/expr.c
deleted file mode 100644
index 2da3645b..00000000
--- a/kopete/plugins/statistics/sqlite/expr.c
+++ /dev/null
@@ -1,1927 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains routines used for analyzing expressions and
-** for generating VDBE code that evaluates expressions in SQLite.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-#include <ctype.h>
-
-/*
-** Return the 'affinity' of the expression pExpr if any.
-**
-** If pExpr is a column, a reference to a column via an 'AS' alias,
-** or a sub-select with a column as the return value, then the
-** affinity of that column is returned. Otherwise, 0x00 is returned,
-** indicating no affinity for the expression.
-**
-** i.e. the WHERE clause expresssions in the following statements all
-** have an affinity:
-**
-** CREATE TABLE t1(a);
-** SELECT * FROM t1 WHERE a;
-** SELECT a AS b FROM t1 WHERE b;
-** SELECT * FROM t1 WHERE (select a from t1);
-*/
-char sqlite3ExprAffinity(Expr *pExpr){
- if( pExpr->op==TK_AS ){
- return sqlite3ExprAffinity(pExpr->pLeft);
- }
- if( pExpr->op==TK_SELECT ){
- return sqlite3ExprAffinity(pExpr->pSelect->pEList->a[0].pExpr);
- }
- return pExpr->affinity;
-}
-
-/*
-** Return the default collation sequence for the expression pExpr. If
-** there is no default collation type, return 0.
-*/
-CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
- CollSeq *pColl = 0;
- if( pExpr ){
- pColl = pExpr->pColl;
- if( pExpr->op==TK_AS && !pColl ){
- return sqlite3ExprCollSeq(pParse, pExpr->pLeft);
- }
- }
- if( sqlite3CheckCollSeq(pParse, pColl) ){
- pColl = 0;
- }
- return pColl;
-}
-
-/*
-** pExpr is the left operand of a comparison operator. aff2 is the
-** type affinity of the right operand. This routine returns the
-** type affinity that should be used for the comparison operator.
-*/
-char sqlite3CompareAffinity(Expr *pExpr, char aff2){
- char aff1 = sqlite3ExprAffinity(pExpr);
- if( aff1 && aff2 ){
- /* Both sides of the comparison are columns. If one has numeric or
- ** integer affinity, use that. Otherwise use no affinity.
- */
- if( aff1==SQLITE_AFF_INTEGER || aff2==SQLITE_AFF_INTEGER ){
- return SQLITE_AFF_INTEGER;
- }else if( aff1==SQLITE_AFF_NUMERIC || aff2==SQLITE_AFF_NUMERIC ){
- return SQLITE_AFF_NUMERIC;
- }else{
- return SQLITE_AFF_NONE;
- }
- }else if( !aff1 && !aff2 ){
- /* Neither side of the comparison is a column. Compare the
- ** results directly.
- */
- /* return SQLITE_AFF_NUMERIC; // Ticket #805 */
- return SQLITE_AFF_NONE;
- }else{
- /* One side is a column, the other is not. Use the columns affinity. */
- return (aff1 + aff2);
- }
-}
-
-/*
-** pExpr is a comparison operator. Return the type affinity that should
-** be applied to both operands prior to doing the comparison.
-*/
-static char comparisonAffinity(Expr *pExpr){
- char aff;
- assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT ||
- pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE ||
- pExpr->op==TK_NE );
- assert( pExpr->pLeft );
- aff = sqlite3ExprAffinity(pExpr->pLeft);
- if( pExpr->pRight ){
- aff = sqlite3CompareAffinity(pExpr->pRight, aff);
- }
- else if( pExpr->pSelect ){
- aff = sqlite3CompareAffinity(pExpr->pSelect->pEList->a[0].pExpr, aff);
- }
- else if( !aff ){
- aff = SQLITE_AFF_NUMERIC;
- }
- return aff;
-}
-
-/*
-** pExpr is a comparison expression, eg. '=', '<', IN(...) etc.
-** idx_affinity is the affinity of an indexed column. Return true
-** if the index with affinity idx_affinity may be used to implement
-** the comparison in pExpr.
-*/
-int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
- char aff = comparisonAffinity(pExpr);
- return
- (aff==SQLITE_AFF_NONE) ||
- (aff==SQLITE_AFF_NUMERIC && idx_affinity==SQLITE_AFF_INTEGER) ||
- (aff==SQLITE_AFF_INTEGER && idx_affinity==SQLITE_AFF_NUMERIC) ||
- (aff==idx_affinity);
-}
-
-/*
-** Return the P1 value that should be used for a binary comparison
-** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2.
-** If jumpIfNull is true, then set the low byte of the returned
-** P1 value to tell the opcode to jump if either expression
-** evaluates to NULL.
-*/
-static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
- char aff = sqlite3ExprAffinity(pExpr2);
- return (((int)sqlite3CompareAffinity(pExpr1, aff))<<8)+(jumpIfNull?1:0);
-}
-
-/*
-** Return a pointer to the collation sequence that should be used by
-** a binary comparison operator comparing pLeft and pRight.
-**
-** If the left hand expression has a collating sequence type, then it is
-** used. Otherwise the collation sequence for the right hand expression
-** is used, or the default (BINARY) if neither expression has a collating
-** type.
-*/
-static CollSeq* binaryCompareCollSeq(Parse *pParse, Expr *pLeft, Expr *pRight){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pLeft);
- if( !pColl ){
- pColl = sqlite3ExprCollSeq(pParse, pRight);
- }
- return pColl;
-}
-
-/*
-** Generate code for a comparison operator.
-*/
-static int codeCompare(
- Parse *pParse, /* The parsing (and code generating) context */
- Expr *pLeft, /* The left operand */
- Expr *pRight, /* The right operand */
- int opcode, /* The comparison opcode */
- int dest, /* Jump here if true. */
- int jumpIfNull /* If true, jump if either operand is NULL */
-){
- int p1 = binaryCompareP1(pLeft, pRight, jumpIfNull);
- CollSeq *p3 = binaryCompareCollSeq(pParse, pLeft, pRight);
- return sqlite3VdbeOp3(pParse->pVdbe, opcode, p1, dest, (void*)p3, P3_COLLSEQ);
-}
-
-/*
-** Construct a new expression node and return a pointer to it. Memory
-** for this node is obtained from sqliteMalloc(). The calling function
-** is responsible for making sure the node eventually gets freed.
-*/
-Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
- Expr *pNew;
- pNew = sqliteMalloc( sizeof(Expr) );
- if( pNew==0 ){
- /* When malloc fails, we leak memory from pLeft and pRight */
- return 0;
- }
- pNew->op = op;
- pNew->pLeft = pLeft;
- pNew->pRight = pRight;
- if( pToken ){
- assert( pToken->dyn==0 );
- pNew->span = pNew->token = *pToken;
- }else if( pLeft && pRight ){
- sqlite3ExprSpan(pNew, &pLeft->span, &pRight->span);
- }
- return pNew;
-}
-
-/*
-** Join two expressions using an AND operator. If either expression is
-** NULL, then just return the other expression.
-*/
-Expr *sqlite3ExprAnd(Expr *pLeft, Expr *pRight){
- if( pLeft==0 ){
- return pRight;
- }else if( pRight==0 ){
- return pLeft;
- }else{
- return sqlite3Expr(TK_AND, pLeft, pRight, 0);
- }
-}
-
-/*
-** Set the Expr.span field of the given expression to span all
-** text between the two given tokens.
-*/
-void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
- assert( pRight!=0 );
- assert( pLeft!=0 );
- if( !sqlite3_malloc_failed && pRight->z && pLeft->z ){
- assert( pLeft->dyn==0 || pLeft->z[pLeft->n]==0 );
- if( pLeft->dyn==0 && pRight->dyn==0 ){
- pExpr->span.z = pLeft->z;
- pExpr->span.n = pRight->n + Addr(pRight->z) - Addr(pLeft->z);
- }else{
- pExpr->span.z = 0;
- }
- }
-}
-
-/*
-** Construct a new expression node for a function with multiple
-** arguments.
-*/
-Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){
- Expr *pNew;
- pNew = sqliteMalloc( sizeof(Expr) );
- if( pNew==0 ){
- /* sqlite3ExprListDelete(pList); // Leak pList when malloc fails */
- return 0;
- }
- pNew->op = TK_FUNCTION;
- pNew->pList = pList;
- if( pToken ){
- assert( pToken->dyn==0 );
- pNew->token = *pToken;
- }else{
- pNew->token.z = 0;
- }
- pNew->span = pNew->token;
- return pNew;
-}
-
-/*
-** Assign a variable number to an expression that encodes a wildcard
-** in the original SQL statement.
-**
-** Wildcards consisting of a single "?" are assigned the next sequential
-** variable number.
-**
-** Wildcards of the form "?nnn" are assigned the number "nnn". We make
-** sure "nnn" is not too be to avoid a denial of service attack when
-** the SQL statement comes from an external source.
-**
-** Wildcards of the form ":aaa" or "$aaa" are assigned the same number
-** as the previous instance of the same wildcard. Or if this is the first
-** instance of the wildcard, the next sequenial variable number is
-** assigned.
-*/
-void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
- Token *pToken;
- if( pExpr==0 ) return;
- pToken = &pExpr->token;
- assert( pToken->n>=1 );
- assert( pToken->z!=0 );
- assert( pToken->z[0]!=0 );
- if( pToken->n==1 ){
- /* Wildcard of the form "?". Assign the next variable number */
- pExpr->iTable = ++pParse->nVar;
- }else if( pToken->z[0]=='?' ){
- /* Wildcard of the form "?nnn". Convert "nnn" to an integer and
- ** use it as the variable number */
- int i;
- pExpr->iTable = i = atoi(&pToken->z[1]);
- if( i<1 || i>SQLITE_MAX_VARIABLE_NUMBER ){
- sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
- SQLITE_MAX_VARIABLE_NUMBER);
- }
- if( i>pParse->nVar ){
- pParse->nVar = i;
- }
- }else{
- /* Wildcards of the form ":aaa" or "$aaa". Reuse the same variable
- ** number as the prior appearance of the same name, or if the name
- ** has never appeared before, reuse the same variable number
- */
- int i, n;
- n = pToken->n;
- for(i=0; i<pParse->nVarExpr; i++){
- Expr *pE;
- if( (pE = pParse->apVarExpr[i])!=0
- && pE->token.n==n
- && memcmp(pE->token.z, pToken->z, n)==0 ){
- pExpr->iTable = pE->iTable;
- break;
- }
- }
- if( i>=pParse->nVarExpr ){
- pExpr->iTable = ++pParse->nVar;
- if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
- pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
- pParse->apVarExpr = sqliteRealloc(pParse->apVarExpr,
- pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
- }
- if( !sqlite3_malloc_failed ){
- assert( pParse->apVarExpr!=0 );
- pParse->apVarExpr[pParse->nVarExpr++] = pExpr;
- }
- }
- }
-}
-
-/*
-** Recursively delete an expression tree.
-*/
-void sqlite3ExprDelete(Expr *p){
- if( p==0 ) return;
- if( p->span.dyn ) sqliteFree((char*)p->span.z);
- if( p->token.dyn ) sqliteFree((char*)p->token.z);
- sqlite3ExprDelete(p->pLeft);
- sqlite3ExprDelete(p->pRight);
- sqlite3ExprListDelete(p->pList);
- sqlite3SelectDelete(p->pSelect);
- sqliteFree(p);
-}
-
-
-/*
-** The following group of routines make deep copies of expressions,
-** expression lists, ID lists, and select statements. The copies can
-** be deleted (by being passed to their respective ...Delete() routines)
-** without effecting the originals.
-**
-** The expression list, ID, and source lists return by sqlite3ExprListDup(),
-** sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded
-** by subsequent calls to sqlite*ListAppend() routines.
-**
-** Any tables that the SrcList might point to are not duplicated.
-*/
-Expr *sqlite3ExprDup(Expr *p){
- Expr *pNew;
- if( p==0 ) return 0;
- pNew = sqliteMallocRaw( sizeof(*p) );
- if( pNew==0 ) return 0;
- memcpy(pNew, p, sizeof(*pNew));
- if( p->token.z!=0 ){
- pNew->token.z = sqliteStrDup(p->token.z);
- pNew->token.dyn = 1;
- }else{
- assert( pNew->token.z==0 );
- }
- pNew->span.z = 0;
- pNew->pLeft = sqlite3ExprDup(p->pLeft);
- pNew->pRight = sqlite3ExprDup(p->pRight);
- pNew->pList = sqlite3ExprListDup(p->pList);
- pNew->pSelect = sqlite3SelectDup(p->pSelect);
- return pNew;
-}
-void sqlite3TokenCopy(Token *pTo, Token *pFrom){
- if( pTo->dyn ) sqliteFree((char*)pTo->z);
- if( pFrom->z ){
- pTo->n = pFrom->n;
- pTo->z = sqliteStrNDup(pFrom->z, pFrom->n);
- pTo->dyn = 1;
- }else{
- pTo->z = 0;
- }
-}
-ExprList *sqlite3ExprListDup(ExprList *p){
- ExprList *pNew;
- struct ExprList_item *pItem, *pOldItem;
- int i;
- if( p==0 ) return 0;
- pNew = sqliteMalloc( sizeof(*pNew) );
- if( pNew==0 ) return 0;
- pNew->nExpr = pNew->nAlloc = p->nExpr;
- pNew->a = pItem = sqliteMalloc( p->nExpr*sizeof(p->a[0]) );
- if( pItem==0 ){
- sqliteFree(pNew);
- return 0;
- }
- pOldItem = p->a;
- for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
- Expr *pNewExpr, *pOldExpr;
- pItem->pExpr = pNewExpr = sqlite3ExprDup(pOldExpr = pOldItem->pExpr);
- if( pOldExpr->span.z!=0 && pNewExpr ){
- /* Always make a copy of the span for top-level expressions in the
- ** expression list. The logic in SELECT processing that determines
- ** the names of columns in the result set needs this information */
- sqlite3TokenCopy(&pNewExpr->span, &pOldExpr->span);
- }
- assert( pNewExpr==0 || pNewExpr->span.z!=0
- || pOldExpr->span.z==0 || sqlite3_malloc_failed );
- pItem->zName = sqliteStrDup(pOldItem->zName);
- pItem->sortOrder = pOldItem->sortOrder;
- pItem->isAgg = pOldItem->isAgg;
- pItem->done = 0;
- }
- return pNew;
-}
-SrcList *sqlite3SrcListDup(SrcList *p){
- SrcList *pNew;
- int i;
- int nByte;
- if( p==0 ) return 0;
- nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
- pNew = sqliteMallocRaw( nByte );
- if( pNew==0 ) return 0;
- pNew->nSrc = pNew->nAlloc = p->nSrc;
- for(i=0; i<p->nSrc; i++){
- struct SrcList_item *pNewItem = &pNew->a[i];
- struct SrcList_item *pOldItem = &p->a[i];
- pNewItem->zDatabase = sqliteStrDup(pOldItem->zDatabase);
- pNewItem->zName = sqliteStrDup(pOldItem->zName);
- pNewItem->zAlias = sqliteStrDup(pOldItem->zAlias);
- pNewItem->jointype = pOldItem->jointype;
- pNewItem->iCursor = pOldItem->iCursor;
- pNewItem->pTab = 0;
- pNewItem->pSelect = sqlite3SelectDup(pOldItem->pSelect);
- pNewItem->pOn = sqlite3ExprDup(pOldItem->pOn);
- pNewItem->pUsing = sqlite3IdListDup(pOldItem->pUsing);
- }
- return pNew;
-}
-IdList *sqlite3IdListDup(IdList *p){
- IdList *pNew;
- int i;
- if( p==0 ) return 0;
- pNew = sqliteMallocRaw( sizeof(*pNew) );
- if( pNew==0 ) return 0;
- pNew->nId = pNew->nAlloc = p->nId;
- pNew->a = sqliteMallocRaw( p->nId*sizeof(p->a[0]) );
- if( pNew->a==0 ) return 0;
- for(i=0; i<p->nId; i++){
- struct IdList_item *pNewItem = &pNew->a[i];
- struct IdList_item *pOldItem = &p->a[i];
- pNewItem->zName = sqliteStrDup(pOldItem->zName);
- pNewItem->idx = pOldItem->idx;
- }
- return pNew;
-}
-Select *sqlite3SelectDup(Select *p){
- Select *pNew;
- if( p==0 ) return 0;
- pNew = sqliteMallocRaw( sizeof(*p) );
- if( pNew==0 ) return 0;
- pNew->isDistinct = p->isDistinct;
- pNew->pEList = sqlite3ExprListDup(p->pEList);
- pNew->pSrc = sqlite3SrcListDup(p->pSrc);
- pNew->pWhere = sqlite3ExprDup(p->pWhere);
- pNew->pGroupBy = sqlite3ExprListDup(p->pGroupBy);
- pNew->pHaving = sqlite3ExprDup(p->pHaving);
- pNew->pOrderBy = sqlite3ExprListDup(p->pOrderBy);
- pNew->op = p->op;
- pNew->pPrior = sqlite3SelectDup(p->pPrior);
- pNew->nLimit = p->nLimit;
- pNew->nOffset = p->nOffset;
- pNew->zSelect = 0;
- pNew->iLimit = -1;
- pNew->iOffset = -1;
- pNew->ppOpenTemp = 0;
- return pNew;
-}
-
-
-/*
-** Add a new element to the end of an expression list. If pList is
-** initially NULL, then create a new expression list.
-*/
-ExprList *sqlite3ExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
- if( pList==0 ){
- pList = sqliteMalloc( sizeof(ExprList) );
- if( pList==0 ){
- /* sqlite3ExprDelete(pExpr); // Leak memory if malloc fails */
- return 0;
- }
- assert( pList->nAlloc==0 );
- }
- if( pList->nAlloc<=pList->nExpr ){
- pList->nAlloc = pList->nAlloc*2 + 4;
- pList->a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]));
- if( pList->a==0 ){
- /* sqlite3ExprDelete(pExpr); // Leak memory if malloc fails */
- pList->nExpr = pList->nAlloc = 0;
- return pList;
- }
- }
- assert( pList->a!=0 );
- if( pExpr || pName ){
- struct ExprList_item *pItem = &pList->a[pList->nExpr++];
- memset(pItem, 0, sizeof(*pItem));
- pItem->pExpr = pExpr;
- pItem->zName = sqlite3NameFromToken(pName);
- }
- return pList;
-}
-
-/*
-** Delete an entire expression list.
-*/
-void sqlite3ExprListDelete(ExprList *pList){
- int i;
- struct ExprList_item *pItem;
- if( pList==0 ) return;
- assert( pList->a!=0 || (pList->nExpr==0 && pList->nAlloc==0) );
- assert( pList->nExpr<=pList->nAlloc );
- for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
- sqlite3ExprDelete(pItem->pExpr);
- sqliteFree(pItem->zName);
- }
- sqliteFree(pList->a);
- sqliteFree(pList);
-}
-
-/*
-** Walk an expression tree. Return 1 if the expression is constant
-** and 0 if it involves variables.
-**
-** For the purposes of this function, a double-quoted string (ex: "abc")
-** is considered a variable but a single-quoted string (ex: 'abc') is
-** a constant.
-*/
-int sqlite3ExprIsConstant(Expr *p){
- switch( p->op ){
- case TK_ID:
- case TK_COLUMN:
- case TK_DOT:
- case TK_FUNCTION:
- return 0;
- case TK_NULL:
- case TK_STRING:
- case TK_BLOB:
- case TK_INTEGER:
- case TK_FLOAT:
- case TK_VARIABLE:
- return 1;
- default: {
- if( p->pLeft && !sqlite3ExprIsConstant(p->pLeft) ) return 0;
- if( p->pRight && !sqlite3ExprIsConstant(p->pRight) ) return 0;
- if( p->pList ){
- int i;
- for(i=0; i<p->pList->nExpr; i++){
- if( !sqlite3ExprIsConstant(p->pList->a[i].pExpr) ) return 0;
- }
- }
- return p->pLeft!=0 || p->pRight!=0 || (p->pList && p->pList->nExpr>0);
- }
- }
- return 0;
-}
-
-/*
-** If the given expression codes a constant integer that is small enough
-** to fit in a 32-bit integer, return 1 and put the value of the integer
-** in *pValue. If the expression is not an integer or if it is too big
-** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
-*/
-int sqlite3ExprIsInteger(Expr *p, int *pValue){
- switch( p->op ){
- case TK_INTEGER: {
- if( sqlite3GetInt32(p->token.z, pValue) ){
- return 1;
- }
- break;
- }
- case TK_STRING: {
- const u8 *z = (u8*)p->token.z;
- int n = p->token.n;
- if( n>0 && z[0]=='-' ){ z++; n--; }
- while( n>0 && *z && isdigit(*z) ){ z++; n--; }
- if( n==0 && sqlite3GetInt32(p->token.z, pValue) ){
- return 1;
- }
- break;
- }
- case TK_UPLUS: {
- return sqlite3ExprIsInteger(p->pLeft, pValue);
- }
- case TK_UMINUS: {
- int v;
- if( sqlite3ExprIsInteger(p->pLeft, &v) ){
- *pValue = -v;
- return 1;
- }
- break;
- }
- default: break;
- }
- return 0;
-}
-
-/*
-** Return TRUE if the given string is a row-id column name.
-*/
-int sqlite3IsRowid(const char *z){
- if( sqlite3StrICmp(z, "_ROWID_")==0 ) return 1;
- if( sqlite3StrICmp(z, "ROWID")==0 ) return 1;
- if( sqlite3StrICmp(z, "OID")==0 ) return 1;
- return 0;
-}
-
-/*
-** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
-** that name in the set of source tables in pSrcList and make the pExpr
-** expression node refer back to that source column. The following changes
-** are made to pExpr:
-**
-** pExpr->iDb Set the index in db->aDb[] of the database holding
-** the table.
-** pExpr->iTable Set to the cursor number for the table obtained
-** from pSrcList.
-** pExpr->iColumn Set to the column number within the table.
-** pExpr->op Set to TK_COLUMN.
-** pExpr->pLeft Any expression this points to is deleted
-** pExpr->pRight Any expression this points to is deleted.
-**
-** The pDbToken is the name of the database (the "X"). This value may be
-** NULL meaning that name is of the form Y.Z or Z. Any available database
-** can be used. The pTableToken is the name of the table (the "Y"). This
-** value can be NULL if pDbToken is also NULL. If pTableToken is NULL it
-** means that the form of the name is Z and that columns from any table
-** can be used.
-**
-** If the name cannot be resolved unambiguously, leave an error message
-** in pParse and return non-zero. Return zero on success.
-*/
-static int lookupName(
- Parse *pParse, /* The parsing context */
- Token *pDbToken, /* Name of the database containing table, or NULL */
- Token *pTableToken, /* Name of table containing column, or NULL */
- Token *pColumnToken, /* Name of the column. */
- SrcList *pSrcList, /* List of tables used to resolve column names */
- ExprList *pEList, /* List of expressions used to resolve "AS" */
- Expr *pExpr /* Make this EXPR node point to the selected column */
-){
- char *zDb = 0; /* Name of the database. The "X" in X.Y.Z */
- char *zTab = 0; /* Name of the table. The "Y" in X.Y.Z or Y.Z */
- char *zCol = 0; /* Name of the column. The "Z" */
- int i, j; /* Loop counters */
- int cnt = 0; /* Number of matching column names */
- int cntTab = 0; /* Number of matching table names */
- sqlite3 *db = pParse->db; /* The database */
-
- assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */
- zDb = sqlite3NameFromToken(pDbToken);
- zTab = sqlite3NameFromToken(pTableToken);
- zCol = sqlite3NameFromToken(pColumnToken);
- if( sqlite3_malloc_failed ){
- return 1; /* Leak memory (zDb and zTab) if malloc fails */
- }
- assert( zTab==0 || pEList==0 );
-
- pExpr->iTable = -1;
- for(i=0; i<pSrcList->nSrc; i++){
- struct SrcList_item *pItem = &pSrcList->a[i];
- Table *pTab = pItem->pTab;
- Column *pCol;
-
- if( pTab==0 ) continue;
- assert( pTab->nCol>0 );
- if( zTab ){
- if( pItem->zAlias ){
- char *zTabName = pItem->zAlias;
- if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
- }else{
- char *zTabName = pTab->zName;
- if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
- if( zDb!=0 && sqlite3StrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){
- continue;
- }
- }
- }
- if( 0==(cntTab++) ){
- pExpr->iTable = pItem->iCursor;
- pExpr->iDb = pTab->iDb;
- }
- for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
- if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
- cnt++;
- pExpr->iTable = pItem->iCursor;
- pExpr->iDb = pTab->iDb;
- /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
- pExpr->iColumn = j==pTab->iPKey ? -1 : j;
- pExpr->affinity = pTab->aCol[j].affinity;
- pExpr->pColl = pTab->aCol[j].pColl;
- break;
- }
- }
- }
-
- /* If we have not already resolved the name, then maybe
- ** it is a new.* or old.* trigger argument reference
- */
- if( zDb==0 && zTab!=0 && cnt==0 && pParse->trigStack!=0 ){
- TriggerStack *pTriggerStack = pParse->trigStack;
- Table *pTab = 0;
- if( pTriggerStack->newIdx != -1 && sqlite3StrICmp("new", zTab) == 0 ){
- pExpr->iTable = pTriggerStack->newIdx;
- assert( pTriggerStack->pTab );
- pTab = pTriggerStack->pTab;
- }else if( pTriggerStack->oldIdx != -1 && sqlite3StrICmp("old", zTab) == 0 ){
- pExpr->iTable = pTriggerStack->oldIdx;
- assert( pTriggerStack->pTab );
- pTab = pTriggerStack->pTab;
- }
-
- if( pTab ){
- int j;
- Column *pCol = pTab->aCol;
-
- pExpr->iDb = pTab->iDb;
- cntTab++;
- for(j=0; j < pTab->nCol; j++, pCol++) {
- if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
- cnt++;
- pExpr->iColumn = j==pTab->iPKey ? -1 : j;
- pExpr->affinity = pTab->aCol[j].affinity;
- pExpr->pColl = pTab->aCol[j].pColl;
- break;
- }
- }
- }
- }
-
- /*
- ** Perhaps the name is a reference to the ROWID
- */
- if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) ){
- cnt = 1;
- pExpr->iColumn = -1;
- pExpr->affinity = SQLITE_AFF_INTEGER;
- }
-
- /*
- ** If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z
- ** might refer to an result-set alias. This happens, for example, when
- ** we are resolving names in the WHERE clause of the following command:
- **
- ** SELECT a+b AS x FROM table WHERE x<10;
- **
- ** In cases like this, replace pExpr with a copy of the expression that
- ** forms the result set entry ("a+b" in the example) and return immediately.
- ** Note that the expression in the result set should have already been
- ** resolved by the time the WHERE clause is resolved.
- */
- if( cnt==0 && pEList!=0 ){
- for(j=0; j<pEList->nExpr; j++){
- char *zAs = pEList->a[j].zName;
- if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
- assert( pExpr->pLeft==0 && pExpr->pRight==0 );
- pExpr->op = TK_AS;
- pExpr->iColumn = j;
- pExpr->pLeft = sqlite3ExprDup(pEList->a[j].pExpr);
- sqliteFree(zCol);
- assert( zTab==0 && zDb==0 );
- return 0;
- }
- }
- }
-
- /*
- ** If X and Y are NULL (in other words if only the column name Z is
- ** supplied) and the value of Z is enclosed in double-quotes, then
- ** Z is a string literal if it doesn't match any column names. In that
- ** case, we need to return right away and not make any changes to
- ** pExpr.
- */
- if( cnt==0 && zTab==0 && pColumnToken->z[0]=='"' ){
- sqliteFree(zCol);
- return 0;
- }
-
- /*
- ** cnt==0 means there was not match. cnt>1 means there were two or
- ** more matches. Either way, we have an error.
- */
- if( cnt!=1 ){
- char *z = 0;
- char *zErr;
- zErr = cnt==0 ? "no such column: %s" : "ambiguous column name: %s";
- if( zDb ){
- sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, 0);
- }else if( zTab ){
- sqlite3SetString(&z, zTab, ".", zCol, 0);
- }else{
- z = sqliteStrDup(zCol);
- }
- sqlite3ErrorMsg(pParse, zErr, z);
- sqliteFree(z);
- }
-
- /* Clean up and return
- */
- sqliteFree(zDb);
- sqliteFree(zTab);
- sqliteFree(zCol);
- sqlite3ExprDelete(pExpr->pLeft);
- pExpr->pLeft = 0;
- sqlite3ExprDelete(pExpr->pRight);
- pExpr->pRight = 0;
- pExpr->op = TK_COLUMN;
- sqlite3AuthRead(pParse, pExpr, pSrcList);
- return cnt!=1;
-}
-
-/*
-** This routine walks an expression tree and resolves references to
-** table columns. Nodes of the form ID.ID or ID resolve into an
-** index to the table in the table list and a column offset. The
-** Expr.opcode for such nodes is changed to TK_COLUMN. The Expr.iTable
-** value is changed to the index of the referenced table in pTabList
-** plus the "base" value. The base value will ultimately become the
-** VDBE cursor number for a cursor that is pointing into the referenced
-** table. The Expr.iColumn value is changed to the index of the column
-** of the referenced table. The Expr.iColumn value for the special
-** ROWID column is -1. Any INTEGER PRIMARY KEY column is tried as an
-** alias for ROWID.
-**
-** We also check for instances of the IN operator. IN comes in two
-** forms:
-**
-** expr IN (exprlist)
-** and
-** expr IN (SELECT ...)
-**
-** The first form is handled by creating a set holding the list
-** of allowed values. The second form causes the SELECT to generate
-** a temporary table.
-**
-** This routine also looks for scalar SELECTs that are part of an expression.
-** If it finds any, it generates code to write the value of that select
-** into a memory cell.
-**
-** Unknown columns or tables provoke an error. The function returns
-** the number of errors seen and leaves an error message on pParse->zErrMsg.
-*/
-int sqlite3ExprResolveIds(
- Parse *pParse, /* The parser context */
- SrcList *pSrcList, /* List of tables used to resolve column names */
- ExprList *pEList, /* List of expressions used to resolve "AS" */
- Expr *pExpr /* The expression to be analyzed. */
-){
- int i;
-
- if( pExpr==0 || pSrcList==0 ) return 0;
- for(i=0; i<pSrcList->nSrc; i++){
- assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab );
- }
- switch( pExpr->op ){
- /* Double-quoted strings (ex: "abc") are used as identifiers if
- ** possible. Otherwise they remain as strings. Single-quoted
- ** strings (ex: 'abc') are always string literals.
- */
- case TK_STRING: {
- if( pExpr->token.z[0]=='\'' ) break;
- /* Fall thru into the TK_ID case if this is a double-quoted string */
- }
- /* A lone identifier is the name of a columnd.
- */
- case TK_ID: {
- if( lookupName(pParse, 0, 0, &pExpr->token, pSrcList, pEList, pExpr) ){
- return 1;
- }
- break;
- }
-
- /* A table name and column name: ID.ID
- ** Or a database, table and column: ID.ID.ID
- */
- case TK_DOT: {
- Token *pColumn;
- Token *pTable;
- Token *pDb;
- Expr *pRight;
-
- pRight = pExpr->pRight;
- if( pRight->op==TK_ID ){
- pDb = 0;
- pTable = &pExpr->pLeft->token;
- pColumn = &pRight->token;
- }else{
- assert( pRight->op==TK_DOT );
- pDb = &pExpr->pLeft->token;
- pTable = &pRight->pLeft->token;
- pColumn = &pRight->pRight->token;
- }
- if( lookupName(pParse, pDb, pTable, pColumn, pSrcList, 0, pExpr) ){
- return 1;
- }
- break;
- }
-
- case TK_IN: {
- char affinity;
- Vdbe *v = sqlite3GetVdbe(pParse);
- KeyInfo keyInfo;
- int addr; /* Address of OP_OpenTemp instruction */
-
- if( v==0 ) return 1;
- if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
- return 1;
- }
- affinity = sqlite3ExprAffinity(pExpr->pLeft);
-
- /* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
- ** expression it is handled the same way. A temporary table is
- ** filled with single-field index keys representing the results
- ** from the SELECT or the <exprlist>.
- **
- ** If the 'x' expression is a column value, or the SELECT...
- ** statement returns a column value, then the affinity of that
- ** column is used to build the index keys. If both 'x' and the
- ** SELECT... statement are columns, then numeric affinity is used
- ** if either column has NUMERIC or INTEGER affinity. If neither
- ** 'x' nor the SELECT... statement are columns, then numeric affinity
- ** is used.
- */
- pExpr->iTable = pParse->nTab++;
- addr = sqlite3VdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 0);
- memset(&keyInfo, 0, sizeof(keyInfo));
- keyInfo.nField = 1;
- sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1);
-
- if( pExpr->pSelect ){
- /* Case 1: expr IN (SELECT ...)
- **
- ** Generate code to write the results of the select into the temporary
- ** table allocated and opened above.
- */
- int iParm = pExpr->iTable + (((int)affinity)<<16);
- ExprList *pEList;
- assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
- sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0);
- pEList = pExpr->pSelect->pEList;
- if( pEList && pEList->nExpr>0 ){
- keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft,
- pEList->a[0].pExpr);
- }
- }else if( pExpr->pList ){
- /* Case 2: expr IN (exprlist)
- **
- ** For each expression, build an index key from the evaluation and
- ** store it in the temporary table. If <expr> is a column, then use
- ** that columns affinity when building index keys. If <expr> is not
- ** a column, use numeric affinity.
- */
- int i;
- if( !affinity ){
- affinity = SQLITE_AFF_NUMERIC;
- }
- keyInfo.aColl[0] = pExpr->pLeft->pColl;
-
- /* Loop through each expression in <exprlist>. */
- for(i=0; i<pExpr->pList->nExpr; i++){
- Expr *pE2 = pExpr->pList->a[i].pExpr;
-
- /* Check that the expression is constant and valid. */
- if( !sqlite3ExprIsConstant(pE2) ){
- sqlite3ErrorMsg(pParse,
- "right-hand side of IN operator must be constant");
- return 1;
- }
- if( sqlite3ExprCheck(pParse, pE2, 0, 0) ){
- return 1;
- }
-
- /* Evaluate the expression and insert it into the temp table */
- sqlite3ExprCode(pParse, pE2);
- sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1);
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- sqlite3VdbeAddOp(v, OP_PutStrKey, pExpr->iTable, 0);
- }
- }
- sqlite3VdbeChangeP3(v, addr, (void *)&keyInfo, P3_KEYINFO);
-
- break;
- }
-
- case TK_SELECT: {
- /* This has to be a scalar SELECT. Generate code to put the
- ** value of this select in a memory cell and record the number
- ** of the memory cell in iColumn.
- */
- pExpr->iColumn = pParse->nMem++;
- if(sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0)){
- return 1;
- }
- break;
- }
-
- /* For all else, just recursively walk the tree */
- default: {
- if( pExpr->pLeft
- && sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
- return 1;
- }
- if( pExpr->pRight
- && sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pRight) ){
- return 1;
- }
- if( pExpr->pList ){
- int i;
- ExprList *pList = pExpr->pList;
- for(i=0; i<pList->nExpr; i++){
- Expr *pArg = pList->a[i].pExpr;
- if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pArg) ){
- return 1;
- }
- }
- }
- }
- }
- return 0;
-}
-
-/*
-** pExpr is a node that defines a function of some kind. It might
-** be a syntactic function like "count(x)" or it might be a function
-** that implements an operator, like "a LIKE b".
-**
-** This routine makes *pzName point to the name of the function and
-** *pnName hold the number of characters in the function name.
-*/
-static void getFunctionName(Expr *pExpr, const char **pzName, int *pnName){
- switch( pExpr->op ){
- case TK_FUNCTION: {
- *pzName = pExpr->token.z;
- *pnName = pExpr->token.n;
- break;
- }
- case TK_LIKE: {
- *pzName = "like";
- *pnName = 4;
- break;
- }
- case TK_GLOB: {
- *pzName = "glob";
- *pnName = 4;
- break;
- }
- default: {
- *pzName = "can't happen";
- *pnName = 12;
- break;
- }
- }
-}
-
-/*
-** Error check the functions in an expression. Make sure all
-** function names are recognized and all functions have the correct
-** number of arguments. Leave an error message in pParse->zErrMsg
-** if anything is amiss. Return the number of errors.
-**
-** if pIsAgg is not null and this expression is an aggregate function
-** (like count(*) or max(value)) then write a 1 into *pIsAgg.
-*/
-int sqlite3ExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
- int nErr = 0;
- if( pExpr==0 ) return 0;
- switch( pExpr->op ){
- case TK_GLOB:
- case TK_LIKE:
- case TK_FUNCTION: {
- int n = pExpr->pList ? pExpr->pList->nExpr : 0; /* Number of arguments */
- int no_such_func = 0; /* True if no such function exists */
- int wrong_num_args = 0; /* True if wrong number of arguments */
- int is_agg = 0; /* True if is an aggregate function */
- int i;
- int nId; /* Number of characters in function name */
- const char *zId; /* The function name. */
- FuncDef *pDef;
- int enc = pParse->db->enc;
-
- getFunctionName(pExpr, &zId, &nId);
- pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
- if( pDef==0 ){
- pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0);
- if( pDef==0 ){
- no_such_func = 1;
- }else{
- wrong_num_args = 1;
- }
- }else{
- is_agg = pDef->xFunc==0;
- }
- if( is_agg && !allowAgg ){
- sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId, zId);
- nErr++;
- is_agg = 0;
- }else if( no_such_func ){
- sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
- nErr++;
- }else if( wrong_num_args ){
- sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
- nId, zId);
- nErr++;
- }
- if( is_agg ){
- pExpr->op = TK_AGG_FUNCTION;
- if( pIsAgg ) *pIsAgg = 1;
- }
- for(i=0; nErr==0 && i<n; i++){
- nErr = sqlite3ExprCheck(pParse, pExpr->pList->a[i].pExpr,
- allowAgg && !is_agg, pIsAgg);
- }
- /* FIX ME: Compute pExpr->affinity based on the expected return
- ** type of the function
- */
- }
- default: {
- if( pExpr->pLeft ){
- nErr = sqlite3ExprCheck(pParse, pExpr->pLeft, allowAgg, pIsAgg);
- }
- if( nErr==0 && pExpr->pRight ){
- nErr = sqlite3ExprCheck(pParse, pExpr->pRight, allowAgg, pIsAgg);
- }
- if( nErr==0 && pExpr->pList ){
- int n = pExpr->pList->nExpr;
- int i;
- for(i=0; nErr==0 && i<n; i++){
- Expr *pE2 = pExpr->pList->a[i].pExpr;
- nErr = sqlite3ExprCheck(pParse, pE2, allowAgg, pIsAgg);
- }
- }
- break;
- }
- }
- return nErr;
-}
-
-/*
-** Call sqlite3ExprResolveIds() followed by sqlite3ExprCheck().
-**
-** This routine is provided as a convenience since it is very common
-** to call ResolveIds() and Check() back to back.
-*/
-int sqlite3ExprResolveAndCheck(
- Parse *pParse, /* The parser context */
- SrcList *pSrcList, /* List of tables used to resolve column names */
- ExprList *pEList, /* List of expressions used to resolve "AS" */
- Expr *pExpr, /* The expression to be analyzed. */
- int allowAgg, /* True to allow aggregate expressions */
- int *pIsAgg /* Set to TRUE if aggregates are found */
-){
- if( pExpr==0 ) return 0;
- if( sqlite3ExprResolveIds(pParse,pSrcList,pEList,pExpr) ){
- return 1;
- }
- return sqlite3ExprCheck(pParse, pExpr, allowAgg, pIsAgg);
-}
-
-/*
-** Generate an instruction that will put the integer describe by
-** text z[0..n-1] on the stack.
-*/
-static void codeInteger(Vdbe *v, const char *z, int n){
- int i;
- if( sqlite3GetInt32(z, &i) ){
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- }else if( sqlite3FitsIn64Bits(z) ){
- sqlite3VdbeOp3(v, OP_Integer, 0, 0, z, n);
- }else{
- sqlite3VdbeOp3(v, OP_Real, 0, 0, z, n);
- }
-}
-
-/*
-** Generate code into the current Vdbe to evaluate the given
-** expression and leave the result on the top of stack.
-**
-** This code depends on the fact that certain token values (ex: TK_EQ)
-** are the same as opcode values (ex: OP_Eq) that implement the corresponding
-** operation. Special comments in vdbe.c and the mkopcodeh.awk script in
-** the make process cause these values to align. Assert()s in the code
-** below verify that the numbers are aligned correctly.
-*/
-void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
- Vdbe *v = pParse->pVdbe;
- int op;
- if( v==0 || pExpr==0 ) return;
- op = pExpr->op;
- switch( op ){
- case TK_COLUMN: {
- if( pParse->useAgg ){
- sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
- }else if( pExpr->iColumn>=0 ){
- sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
-#ifndef NDEBUG
- if( pExpr->span.z && pExpr->span.n>0 && pExpr->span.n<100 ){
- VdbeComment((v, "# %T", &pExpr->span));
- }
-#endif
- }else{
- sqlite3VdbeAddOp(v, OP_Recno, pExpr->iTable, 0);
- }
- break;
- }
- case TK_INTEGER: {
- codeInteger(v, pExpr->token.z, pExpr->token.n);
- break;
- }
- case TK_FLOAT:
- case TK_STRING: {
- assert( TK_FLOAT==OP_Real );
- assert( TK_STRING==OP_String8 );
- sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z, pExpr->token.n);
- sqlite3VdbeDequoteP3(v, -1);
- break;
- }
- case TK_BLOB: {
- assert( TK_BLOB==OP_HexBlob );
- sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z+1, pExpr->token.n-1);
- sqlite3VdbeDequoteP3(v, -1);
- break;
- }
- case TK_NULL: {
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- break;
- }
- case TK_VARIABLE: {
- sqlite3VdbeAddOp(v, OP_Variable, pExpr->iTable, 0);
- if( pExpr->token.n>1 ){
- sqlite3VdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n);
- }
- break;
- }
- case TK_LT:
- case TK_LE:
- case TK_GT:
- case TK_GE:
- case TK_NE:
- case TK_EQ: {
- assert( TK_LT==OP_Lt );
- assert( TK_LE==OP_Le );
- assert( TK_GT==OP_Gt );
- assert( TK_GE==OP_Ge );
- assert( TK_EQ==OP_Eq );
- assert( TK_NE==OP_Ne );
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3ExprCode(pParse, pExpr->pRight);
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0);
- break;
- }
- case TK_AND:
- case TK_OR:
- case TK_PLUS:
- case TK_STAR:
- case TK_MINUS:
- case TK_REM:
- case TK_BITAND:
- case TK_BITOR:
- case TK_SLASH:
- case TK_LSHIFT:
- case TK_RSHIFT:
- case TK_CONCAT: {
- assert( TK_AND==OP_And );
- assert( TK_OR==OP_Or );
- assert( TK_PLUS==OP_Add );
- assert( TK_MINUS==OP_Subtract );
- assert( TK_REM==OP_Remainder );
- assert( TK_BITAND==OP_BitAnd );
- assert( TK_BITOR==OP_BitOr );
- assert( TK_SLASH==OP_Divide );
- assert( TK_LSHIFT==OP_ShiftLeft );
- assert( TK_RSHIFT==OP_ShiftRight );
- assert( TK_CONCAT==OP_Concat );
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3ExprCode(pParse, pExpr->pRight);
- sqlite3VdbeAddOp(v, op, 0, 0);
- break;
- }
- case TK_UMINUS: {
- Expr *pLeft = pExpr->pLeft;
- assert( pLeft );
- if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){
- Token *p = &pLeft->token;
- char *z = sqliteMalloc( p->n + 2 );
- sprintf(z, "-%.*s", p->n, p->z);
- if( pLeft->op==TK_FLOAT ){
- sqlite3VdbeOp3(v, OP_Real, 0, 0, z, p->n+1);
- }else{
- codeInteger(v, z, p->n+1);
- }
- sqliteFree(z);
- break;
- }
- /* Fall through into TK_NOT */
- }
- case TK_BITNOT:
- case TK_NOT: {
- assert( TK_BITNOT==OP_BitNot );
- assert( TK_NOT==OP_Not );
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3VdbeAddOp(v, op, 0, 0);
- break;
- }
- case TK_ISNULL:
- case TK_NOTNULL: {
- int dest;
- assert( TK_ISNULL==OP_IsNull );
- assert( TK_NOTNULL==OP_NotNull );
- sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
- sqlite3ExprCode(pParse, pExpr->pLeft);
- dest = sqlite3VdbeCurrentAddr(v) + 2;
- sqlite3VdbeAddOp(v, op, 1, dest);
- sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
- break;
- }
- case TK_AGG_FUNCTION: {
- sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
- break;
- }
- case TK_GLOB:
- case TK_LIKE:
- case TK_FUNCTION: {
- ExprList *pList = pExpr->pList;
- int nExpr = pList ? pList->nExpr : 0;
- FuncDef *pDef;
- int nId;
- const char *zId;
- int p2 = 0;
- int i;
- u8 enc = pParse->db->enc;
- CollSeq *pColl = 0;
- getFunctionName(pExpr, &zId, &nId);
- pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0);
- assert( pDef!=0 );
- nExpr = sqlite3ExprCodeExprList(pParse, pList);
- for(i=0; i<nExpr && i<32; i++){
- if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
- p2 |= (1<<i);
- }
- if( pDef->needCollSeq && !pColl ){
- pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
- }
- }
- if( pDef->needCollSeq ){
- if( !pColl ) pColl = pParse->db->pDfltColl;
- sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
- }
- sqlite3VdbeOp3(v, OP_Function, nExpr, p2, (char*)pDef, P3_FUNCDEF);
- break;
- }
- case TK_SELECT: {
- sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
- VdbeComment((v, "# load subquery result"));
- break;
- }
- case TK_IN: {
- int addr;
- char affinity;
-
- /* Figure out the affinity to use to create a key from the results
- ** of the expression. affinityStr stores a static string suitable for
- ** P3 of OP_MakeRecord.
- */
- affinity = comparisonAffinity(pExpr);
-
- sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
-
- /* Code the <expr> from "<expr> IN (...)". The temporary table
- ** pExpr->iTable contains the values that make up the (...) set.
- */
- sqlite3ExprCode(pParse, pExpr->pLeft);
- addr = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+4); /* addr + 0 */
- sqlite3VdbeAddOp(v, OP_Pop, 2, 0);
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, addr+7);
- sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1); /* addr + 4 */
- sqlite3VdbeAddOp(v, OP_Found, pExpr->iTable, addr+7);
- sqlite3VdbeAddOp(v, OP_AddImm, -1, 0); /* addr + 6 */
-
- break;
- }
- case TK_BETWEEN: {
- Expr *pLeft = pExpr->pLeft;
- struct ExprList_item *pLItem = pExpr->pList->a;
- Expr *pRight = pLItem->pExpr;
- sqlite3ExprCode(pParse, pLeft);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3ExprCode(pParse, pRight);
- codeCompare(pParse, pLeft, pRight, OP_Ge, 0, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- pLItem++;
- pRight = pLItem->pExpr;
- sqlite3ExprCode(pParse, pRight);
- codeCompare(pParse, pLeft, pRight, OP_Le, 0, 0);
- sqlite3VdbeAddOp(v, OP_And, 0, 0);
- break;
- }
- case TK_UPLUS:
- case TK_AS: {
- sqlite3ExprCode(pParse, pExpr->pLeft);
- break;
- }
- case TK_CASE: {
- int expr_end_label;
- int jumpInst;
- int addr;
- int nExpr;
- int i;
- ExprList *pEList;
- struct ExprList_item *aListelem;
-
- assert(pExpr->pList);
- assert((pExpr->pList->nExpr % 2) == 0);
- assert(pExpr->pList->nExpr > 0);
- pEList = pExpr->pList;
- aListelem = pEList->a;
- nExpr = pEList->nExpr;
- expr_end_label = sqlite3VdbeMakeLabel(v);
- if( pExpr->pLeft ){
- sqlite3ExprCode(pParse, pExpr->pLeft);
- }
- for(i=0; i<nExpr; i=i+2){
- sqlite3ExprCode(pParse, aListelem[i].pExpr);
- if( pExpr->pLeft ){
- sqlite3VdbeAddOp(v, OP_Dup, 1, 1);
- jumpInst = codeCompare(pParse, pExpr->pLeft, aListelem[i].pExpr,
- OP_Ne, 0, 1);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- }else{
- jumpInst = sqlite3VdbeAddOp(v, OP_IfNot, 1, 0);
- }
- sqlite3ExprCode(pParse, aListelem[i+1].pExpr);
- sqlite3VdbeAddOp(v, OP_Goto, 0, expr_end_label);
- addr = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeChangeP2(v, jumpInst, addr);
- }
- if( pExpr->pLeft ){
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- }
- if( pExpr->pRight ){
- sqlite3ExprCode(pParse, pExpr->pRight);
- }else{
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- }
- sqlite3VdbeResolveLabel(v, expr_end_label);
- break;
- }
- case TK_RAISE: {
- if( !pParse->trigStack ){
- sqlite3ErrorMsg(pParse,
- "RAISE() may only be used within a trigger-program");
- return;
- }
- if( pExpr->iColumn!=OE_Ignore ){
- assert( pExpr->iColumn==OE_Rollback ||
- pExpr->iColumn == OE_Abort ||
- pExpr->iColumn == OE_Fail );
- sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn,
- pExpr->token.z, pExpr->token.n);
- sqlite3VdbeDequoteP3(v, -1);
- } else {
- assert( pExpr->iColumn == OE_Ignore );
- sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
- VdbeComment((v, "# raise(IGNORE)"));
- }
- }
- break;
- }
-}
-
-/*
-** Generate code that pushes the value of every element of the given
-** expression list onto the stack.
-**
-** Return the number of elements pushed onto the stack.
-*/
-int sqlite3ExprCodeExprList(
- Parse *pParse, /* Parsing context */
- ExprList *pList /* The expression list to be coded */
-){
- struct ExprList_item *pItem;
- int i, n;
- Vdbe *v;
- if( pList==0 ) return 0;
- v = sqlite3GetVdbe(pParse);
- n = pList->nExpr;
- for(pItem=pList->a, i=0; i<n; i++, pItem++){
- sqlite3ExprCode(pParse, pItem->pExpr);
- }
- return n;
-}
-
-/*
-** Generate code for a boolean expression such that a jump is made
-** to the label "dest" if the expression is true but execution
-** continues straight thru if the expression is false.
-**
-** If the expression evaluates to NULL (neither true nor false), then
-** take the jump if the jumpIfNull flag is true.
-**
-** This code depends on the fact that certain token values (ex: TK_EQ)
-** are the same as opcode values (ex: OP_Eq) that implement the corresponding
-** operation. Special comments in vdbe.c and the mkopcodeh.awk script in
-** the make process cause these values to align. Assert()s in the code
-** below verify that the numbers are aligned correctly.
-*/
-void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
- Vdbe *v = pParse->pVdbe;
- int op = 0;
- if( v==0 || pExpr==0 ) return;
- op = pExpr->op;
- switch( op ){
- case TK_AND: {
- int d2 = sqlite3VdbeMakeLabel(v);
- sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, !jumpIfNull);
- sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
- sqlite3VdbeResolveLabel(v, d2);
- break;
- }
- case TK_OR: {
- sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
- sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
- break;
- }
- case TK_NOT: {
- sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
- break;
- }
- case TK_LT:
- case TK_LE:
- case TK_GT:
- case TK_GE:
- case TK_NE:
- case TK_EQ: {
- assert( TK_LT==OP_Lt );
- assert( TK_LE==OP_Le );
- assert( TK_GT==OP_Gt );
- assert( TK_GE==OP_Ge );
- assert( TK_EQ==OP_Eq );
- assert( TK_NE==OP_Ne );
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3ExprCode(pParse, pExpr->pRight);
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, dest, jumpIfNull);
- break;
- }
- case TK_ISNULL:
- case TK_NOTNULL: {
- assert( TK_ISNULL==OP_IsNull );
- assert( TK_NOTNULL==OP_NotNull );
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3VdbeAddOp(v, op, 1, dest);
- break;
- }
- case TK_BETWEEN: {
- /* The expression "x BETWEEN y AND z" is implemented as:
- **
- ** 1 IF (x < y) GOTO 3
- ** 2 IF (x <= z) GOTO <dest>
- ** 3 ...
- */
- int addr;
- Expr *pLeft = pExpr->pLeft;
- Expr *pRight = pExpr->pList->a[0].pExpr;
- sqlite3ExprCode(pParse, pLeft);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3ExprCode(pParse, pRight);
- addr = codeCompare(pParse, pLeft, pRight, OP_Lt, 0, !jumpIfNull);
-
- pRight = pExpr->pList->a[1].pExpr;
- sqlite3ExprCode(pParse, pRight);
- codeCompare(pParse, pLeft, pRight, OP_Le, dest, jumpIfNull);
-
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
- sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- break;
- }
- default: {
- sqlite3ExprCode(pParse, pExpr);
- sqlite3VdbeAddOp(v, OP_If, jumpIfNull, dest);
- break;
- }
- }
-}
-
-/*
-** Generate code for a boolean expression such that a jump is made
-** to the label "dest" if the expression is false but execution
-** continues straight thru if the expression is true.
-**
-** If the expression evaluates to NULL (neither true nor false) then
-** jump if jumpIfNull is true or fall through if jumpIfNull is false.
-*/
-void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
- Vdbe *v = pParse->pVdbe;
- int op = 0;
- if( v==0 || pExpr==0 ) return;
-
- /* The value of pExpr->op and op are related as follows:
- **
- ** pExpr->op op
- ** --------- ----------
- ** TK_ISNULL OP_NotNull
- ** TK_NOTNULL OP_IsNull
- ** TK_NE OP_Eq
- ** TK_EQ OP_Ne
- ** TK_GT OP_Le
- ** TK_LE OP_Gt
- ** TK_GE OP_Lt
- ** TK_LT OP_Ge
- **
- ** For other values of pExpr->op, op is undefined and unused.
- ** The value of TK_ and OP_ constants are arranged such that we
- ** can compute the mapping above using the following expression.
- ** Assert()s verify that the computation is correct.
- */
- op = ((pExpr->op+(TK_ISNULL&1))^1)-(TK_ISNULL&1);
-
- /* Verify correct alignment of TK_ and OP_ constants
- */
- assert( pExpr->op!=TK_ISNULL || op==OP_NotNull );
- assert( pExpr->op!=TK_NOTNULL || op==OP_IsNull );
- assert( pExpr->op!=TK_NE || op==OP_Eq );
- assert( pExpr->op!=TK_EQ || op==OP_Ne );
- assert( pExpr->op!=TK_LT || op==OP_Ge );
- assert( pExpr->op!=TK_LE || op==OP_Gt );
- assert( pExpr->op!=TK_GT || op==OP_Le );
- assert( pExpr->op!=TK_GE || op==OP_Lt );
-
- switch( pExpr->op ){
- case TK_AND: {
- sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
- sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
- break;
- }
- case TK_OR: {
- int d2 = sqlite3VdbeMakeLabel(v);
- sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, !jumpIfNull);
- sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
- sqlite3VdbeResolveLabel(v, d2);
- break;
- }
- case TK_NOT: {
- sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
- break;
- }
- case TK_LT:
- case TK_LE:
- case TK_GT:
- case TK_GE:
- case TK_NE:
- case TK_EQ: {
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3ExprCode(pParse, pExpr->pRight);
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, dest, jumpIfNull);
- break;
- }
- case TK_ISNULL:
- case TK_NOTNULL: {
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3VdbeAddOp(v, op, 1, dest);
- break;
- }
- case TK_BETWEEN: {
- /* The expression is "x BETWEEN y AND z". It is implemented as:
- **
- ** 1 IF (x >= y) GOTO 3
- ** 2 GOTO <dest>
- ** 3 IF (x > z) GOTO <dest>
- */
- int addr;
- Expr *pLeft = pExpr->pLeft;
- Expr *pRight = pExpr->pList->a[0].pExpr;
- sqlite3ExprCode(pParse, pLeft);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3ExprCode(pParse, pRight);
- addr = sqlite3VdbeCurrentAddr(v);
- codeCompare(pParse, pLeft, pRight, OP_Ge, addr+3, !jumpIfNull);
-
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, dest);
- pRight = pExpr->pList->a[1].pExpr;
- sqlite3ExprCode(pParse, pRight);
- codeCompare(pParse, pLeft, pRight, OP_Gt, dest, jumpIfNull);
- break;
- }
- default: {
- sqlite3ExprCode(pParse, pExpr);
- sqlite3VdbeAddOp(v, OP_IfNot, jumpIfNull, dest);
- break;
- }
- }
-}
-
-/*
-** Do a deep comparison of two expression trees. Return TRUE (non-zero)
-** if they are identical and return FALSE if they differ in any way.
-*/
-int sqlite3ExprCompare(Expr *pA, Expr *pB){
- int i;
- if( pA==0 ){
- return pB==0;
- }else if( pB==0 ){
- return 0;
- }
- if( pA->op!=pB->op ) return 0;
- if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
- if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
- if( pA->pList ){
- if( pB->pList==0 ) return 0;
- if( pA->pList->nExpr!=pB->pList->nExpr ) return 0;
- for(i=0; i<pA->pList->nExpr; i++){
- if( !sqlite3ExprCompare(pA->pList->a[i].pExpr, pB->pList->a[i].pExpr) ){
- return 0;
- }
- }
- }else if( pB->pList ){
- return 0;
- }
- if( pA->pSelect || pB->pSelect ) return 0;
- if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
- if( pA->token.z ){
- if( pB->token.z==0 ) return 0;
- if( pB->token.n!=pA->token.n ) return 0;
- if( sqlite3StrNICmp(pA->token.z, pB->token.z, pB->token.n)!=0 ) return 0;
- }
- return 1;
-}
-
-/*
-** Add a new element to the pParse->aAgg[] array and return its index.
-*/
-static int appendAggInfo(Parse *pParse){
- if( (pParse->nAgg & 0x7)==0 ){
- int amt = pParse->nAgg + 8;
- AggExpr *aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0]));
- if( aAgg==0 ){
- return -1;
- }
- pParse->aAgg = aAgg;
- }
- memset(&pParse->aAgg[pParse->nAgg], 0, sizeof(pParse->aAgg[0]));
- return pParse->nAgg++;
-}
-
-/*
-** Analyze the given expression looking for aggregate functions and
-** for variables that need to be added to the pParse->aAgg[] array.
-** Make additional entries to the pParse->aAgg[] array as necessary.
-**
-** This routine should only be called after the expression has been
-** analyzed by sqlite3ExprResolveIds() and sqlite3ExprCheck().
-**
-** If errors are seen, leave an error message in zErrMsg and return
-** the number of errors.
-*/
-int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
- int i;
- AggExpr *aAgg;
- int nErr = 0;
-
- if( pExpr==0 ) return 0;
- switch( pExpr->op ){
- case TK_COLUMN: {
- aAgg = pParse->aAgg;
- for(i=0; i<pParse->nAgg; i++){
- if( aAgg[i].isAgg ) continue;
- if( aAgg[i].pExpr->iTable==pExpr->iTable
- && aAgg[i].pExpr->iColumn==pExpr->iColumn ){
- break;
- }
- }
- if( i>=pParse->nAgg ){
- i = appendAggInfo(pParse);
- if( i<0 ) return 1;
- pParse->aAgg[i].isAgg = 0;
- pParse->aAgg[i].pExpr = pExpr;
- }
- pExpr->iAgg = i;
- break;
- }
- case TK_AGG_FUNCTION: {
- aAgg = pParse->aAgg;
- for(i=0; i<pParse->nAgg; i++){
- if( !aAgg[i].isAgg ) continue;
- if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){
- break;
- }
- }
- if( i>=pParse->nAgg ){
- u8 enc = pParse->db->enc;
- i = appendAggInfo(pParse);
- if( i<0 ) return 1;
- pParse->aAgg[i].isAgg = 1;
- pParse->aAgg[i].pExpr = pExpr;
- pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db,
- pExpr->token.z, pExpr->token.n,
- pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
- }
- pExpr->iAgg = i;
- break;
- }
- default: {
- if( pExpr->pLeft ){
- nErr = sqlite3ExprAnalyzeAggregates(pParse, pExpr->pLeft);
- }
- if( nErr==0 && pExpr->pRight ){
- nErr = sqlite3ExprAnalyzeAggregates(pParse, pExpr->pRight);
- }
- if( nErr==0 && pExpr->pList ){
- int n = pExpr->pList->nExpr;
- int i;
- for(i=0; nErr==0 && i<n; i++){
- nErr = sqlite3ExprAnalyzeAggregates(pParse, pExpr->pList->a[i].pExpr);
- }
- }
- break;
- }
- }
- return nErr;
-}
-
-/*
-** Locate a user function given a name, a number of arguments and a flag
-** indicating whether the function prefers UTF-16 over UTF-8. Return a
-** pointer to the FuncDef structure that defines that function, or return
-** NULL if the function does not exist.
-**
-** If the createFlag argument is true, then a new (blank) FuncDef
-** structure is created and liked into the "db" structure if a
-** no matching function previously existed. When createFlag is true
-** and the nArg parameter is -1, then only a function that accepts
-** any number of arguments will be returned.
-**
-** If createFlag is false and nArg is -1, then the first valid
-** function found is returned. A function is valid if either xFunc
-** or xStep is non-zero.
-**
-** If createFlag is false, then a function with the required name and
-** number of arguments may be returned even if the eTextRep flag does not
-** match that requested.
-*/
-FuncDef *sqlite3FindFunction(
- sqlite3 *db, /* An open database */
- const char *zName, /* Name of the function. Not null-terminated */
- int nName, /* Number of characters in the name */
- int nArg, /* Number of arguments. -1 means any number */
- u8 enc, /* Preferred text encoding */
- int createFlag /* Create new entry if true and does not otherwise exist */
-){
- FuncDef *p; /* Iterator variable */
- FuncDef *pFirst; /* First function with this name */
- FuncDef *pBest = 0; /* Best match found so far */
- int bestmatch = 0;
-
-
- assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
- if( nArg<-1 ) nArg = -1;
-
- pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName);
- for(p=pFirst; p; p=p->pNext){
- /* During the search for the best function definition, bestmatch is set
- ** as follows to indicate the quality of the match with the definition
- ** pointed to by pBest:
- **
- ** 0: pBest is NULL. No match has been found.
- ** 1: A variable arguments function that prefers UTF-8 when a UTF-16
- ** encoding is requested, or vice versa.
- ** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is
- ** requested, or vice versa.
- ** 3: A variable arguments function using the same text encoding.
- ** 4: A function with the exact number of arguments requested that
- ** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa.
- ** 5: A function with the exact number of arguments requested that
- ** prefers UTF-16LE when UTF-16BE is requested, or vice versa.
- ** 6: An exact match.
- **
- ** A larger value of 'matchqual' indicates a more desirable match.
- */
- if( p->nArg==-1 || p->nArg==nArg || nArg==-1 ){
- int match = 1; /* Quality of this match */
- if( p->nArg==nArg || nArg==-1 ){
- match = 4;
- }
- if( enc==p->iPrefEnc ){
- match += 2;
- }
- else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) ||
- (enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){
- match += 1;
- }
-
- if( match>bestmatch ){
- pBest = p;
- bestmatch = match;
- }
- }
- }
-
- /* If the createFlag parameter is true, and the seach did not reveal an
- ** exact match for the name, number of arguments and encoding, then add a
- ** new entry to the hash table and return it.
- */
- if( createFlag && bestmatch<6 &&
- (pBest = sqliteMalloc(sizeof(*pBest)+nName+1)) ){
- pBest->nArg = nArg;
- pBest->pNext = pFirst;
- pBest->zName = (char*)&pBest[1];
- pBest->iPrefEnc = enc;
- memcpy(pBest->zName, zName, nName);
- pBest->zName[nName] = 0;
- sqlite3HashInsert(&db->aFunc, pBest->zName, nName, (void*)pBest);
- }
-
- if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){
- return pBest;
- }
- return 0;
-}
diff --git a/kopete/plugins/statistics/sqlite/func.c b/kopete/plugins/statistics/sqlite/func.c
deleted file mode 100644
index f61bdae3..00000000
--- a/kopete/plugins/statistics/sqlite/func.c
+++ /dev/null
@@ -1,1018 +0,0 @@
-/*
-** 2002 February 23
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains the C functions that implement various SQL
-** functions of SQLite.
-**
-** There is only one exported symbol in this file - the function
-** sqliteRegisterBuildinFunctions() found at the bottom of the file.
-** All other code has file scope.
-**
-** $Id$
-*/
-#include <ctype.h>
-#include <math.h>
-#include <stdlib.h>
-#include <assert.h>
-#include "sqliteInt.h"
-#include "vdbeInt.h"
-#include "os.h"
-
-static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
- return context->pColl;
-}
-
-/*
-** Implementation of the non-aggregate min() and max() functions
-*/
-static void minmaxFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- int i;
- int mask; /* 0 for min() or 0xffffffff for max() */
- int iBest;
- CollSeq *pColl;
-
- if( argc==0 ) return;
- mask = sqlite3_user_data(context)==0 ? 0 : -1;
- pColl = sqlite3GetFuncCollSeq(context);
- assert( pColl );
- assert( mask==-1 || mask==0 );
- iBest = 0;
- if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
- for(i=1; i<argc; i++){
- if( sqlite3_value_type(argv[i])==SQLITE_NULL ) return;
- if( (sqlite3MemCompare(argv[iBest], argv[i], pColl)^mask)>=0 ){
- iBest = i;
- }
- }
- sqlite3_result_value(context, argv[iBest]);
-}
-
-/*
-** Return the type of the argument.
-*/
-static void typeofFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- const char *z = 0;
- switch( sqlite3_value_type(argv[0]) ){
- case SQLITE_NULL: z = "null"; break;
- case SQLITE_INTEGER: z = "integer"; break;
- case SQLITE_TEXT: z = "text"; break;
- case SQLITE_FLOAT: z = "real"; break;
- case SQLITE_BLOB: z = "blob"; break;
- }
- sqlite3_result_text(context, z, -1, SQLITE_STATIC);
-}
-
-/*
-** Implementation of the length() function
-*/
-static void lengthFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- int len;
-
- assert( argc==1 );
- switch( sqlite3_value_type(argv[0]) ){
- case SQLITE_BLOB:
- case SQLITE_INTEGER:
- case SQLITE_FLOAT: {
- sqlite3_result_int(context, sqlite3_value_bytes(argv[0]));
- break;
- }
- case SQLITE_TEXT: {
- const char *z = sqlite3_value_text(argv[0]);
- for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; }
- sqlite3_result_int(context, len);
- break;
- }
- default: {
- sqlite3_result_null(context);
- break;
- }
- }
-}
-
-/*
-** Implementation of the abs() function
-*/
-static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- assert( argc==1 );
- switch( sqlite3_value_type(argv[0]) ){
- case SQLITE_INTEGER: {
- i64 iVal = sqlite3_value_int64(argv[0]);
- if( iVal<0 ) iVal = iVal * -1;
- sqlite3_result_int64(context, iVal);
- break;
- }
- case SQLITE_NULL: {
- sqlite3_result_null(context);
- break;
- }
- default: {
- double rVal = sqlite3_value_double(argv[0]);
- if( rVal<0 ) rVal = rVal * -1.0;
- sqlite3_result_double(context, rVal);
- break;
- }
- }
-}
-
-/*
-** Implementation of the substr() function
-*/
-static void substrFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- const char *z;
- const char *z2;
- int i;
- int p1, p2, len;
-
- assert( argc==3 );
- z = sqlite3_value_text(argv[0]);
- if( z==0 ) return;
- p1 = sqlite3_value_int(argv[1]);
- p2 = sqlite3_value_int(argv[2]);
- for(len=0, z2=z; *z2; z2++){ if( (0xc0&*z2)!=0x80 ) len++; }
- if( p1<0 ){
- p1 += len;
- if( p1<0 ){
- p2 += p1;
- p1 = 0;
- }
- }else if( p1>0 ){
- p1--;
- }
- if( p1+p2>len ){
- p2 = len-p1;
- }
- for(i=0; i<p1 && z[i]; i++){
- if( (z[i]&0xc0)==0x80 ) p1++;
- }
- while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p1++; }
- for(; i<p1+p2 && z[i]; i++){
- if( (z[i]&0xc0)==0x80 ) p2++;
- }
- while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; }
- if( p2<0 ) p2 = 0;
- sqlite3_result_text(context, &z[p1], p2, SQLITE_TRANSIENT);
-}
-
-/*
-** Implementation of the round() function
-*/
-static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- int n = 0;
- double r;
- char zBuf[100];
- assert( argc==1 || argc==2 );
- if( argc==2 ){
- if( SQLITE_NULL==sqlite3_value_type(argv[1]) ) return;
- n = sqlite3_value_int(argv[1]);
- if( n>30 ) n = 30;
- if( n<0 ) n = 0;
- }
- if( SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
- r = sqlite3_value_double(argv[0]);
- sprintf(zBuf,"%.*f",n,r);
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
-}
-
-/*
-** Implementation of the upper() and lower() SQL functions.
-*/
-static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- unsigned char *z;
- int i;
- if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
- z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
- if( z==0 ) return;
- strcpy(z, sqlite3_value_text(argv[0]));
- for(i=0; z[i]; i++){
- z[i] = toupper(z[i]);
- }
- sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
- sqliteFree(z);
-}
-static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- unsigned char *z;
- int i;
- if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
- z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
- if( z==0 ) return;
- strcpy(z, sqlite3_value_text(argv[0]));
- for(i=0; z[i]; i++){
- z[i] = tolower(z[i]);
- }
- sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
- sqliteFree(z);
-}
-
-/*
-** Implementation of the IFNULL(), NVL(), and COALESCE() functions.
-** All three do the same thing. They return the first non-NULL
-** argument.
-*/
-static void ifnullFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- int i;
- for(i=0; i<argc; i++){
- if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
- sqlite3_result_value(context, argv[i]);
- break;
- }
- }
-}
-
-/*
-** Implementation of random(). Return a random integer.
-*/
-static void randomFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- int r;
- sqlite3Randomness(sizeof(r), &r);
- sqlite3_result_int(context, r);
-}
-
-/*
-** Implementation of the last_insert_rowid() SQL function. The return
-** value is the same as the sqlite3_last_insert_rowid() API function.
-*/
-static void last_insert_rowid(
- sqlite3_context *context,
- int arg,
- sqlite3_value **argv
-){
- sqlite3 *db = sqlite3_user_data(context);
- sqlite3_result_int64(context, sqlite3_last_insert_rowid(db));
-}
-
-/*
-** Implementation of the changes() SQL function. The return value is the
-** same as the sqlite3_changes() API function.
-*/
-static void changes(
- sqlite3_context *context,
- int arg,
- sqlite3_value **argv
-){
- sqlite3 *db = sqlite3_user_data(context);
- sqlite3_result_int(context, sqlite3_changes(db));
-}
-
-/*
-** Implementation of the total_changes() SQL function. The return value is
-** the same as the sqlite3_total_changes() API function.
-*/
-static void total_changes(
- sqlite3_context *context,
- int arg,
- sqlite3_value **argv
-){
- sqlite3 *db = sqlite3_user_data(context);
- sqlite3_result_int(context, sqlite3_total_changes(db));
-}
-
-/*
-** A structure defining how to do GLOB-style comparisons.
-*/
-struct compareInfo {
- u8 matchAll;
- u8 matchOne;
- u8 matchSet;
- u8 noCase;
-};
-static const struct compareInfo globInfo = { '*', '?', '[', 0 };
-static const struct compareInfo likeInfo = { '%', '_', 0, 1 };
-
-/*
-** X is a pointer to the first byte of a UTF-8 character. Increment
-** X so that it points to the next character. This only works right
-** if X points to a well-formed UTF-8 string.
-*/
-#define sqliteNextChar(X) while( (0xc0&*++(X))==0x80 ){}
-#define sqliteCharVal(X) sqlite3ReadUtf8(X)
-
-
-/*
-** Compare two UTF-8 strings for equality where the first string can
-** potentially be a "glob" expression. Return true (1) if they
-** are the same and false (0) if they are different.
-**
-** Globbing rules:
-**
-** '*' Matches any sequence of zero or more characters.
-**
-** '?' Matches exactly one character.
-**
-** [...] Matches one character from the enclosed list of
-** characters.
-**
-** [^...] Matches one character not in the enclosed list.
-**
-** With the [...] and [^...] matching, a ']' character can be included
-** in the list by making it the first character after '[' or '^'. A
-** range of characters can be specified using '-'. Example:
-** "[a-z]" matches any single lower-case letter. To match a '-', make
-** it the last character in the list.
-**
-** This routine is usually quick, but can be N**2 in the worst case.
-**
-** Hints: to match '*' or '?', put them in "[]". Like this:
-**
-** abc[*]xyz Matches "abc*xyz" only
-*/
-int patternCompare(
- const u8 *zPattern, /* The glob pattern */
- const u8 *zString, /* The string to compare against the glob */
- const struct compareInfo *pInfo /* Information about how to do the compare */
-){
- register int c;
- int invert;
- int seen;
- int c2;
- u8 matchOne = pInfo->matchOne;
- u8 matchAll = pInfo->matchAll;
- u8 matchSet = pInfo->matchSet;
- u8 noCase = pInfo->noCase;
-
- while( (c = *zPattern)!=0 ){
- if( c==matchAll ){
- while( (c=zPattern[1]) == matchAll || c == matchOne ){
- if( c==matchOne ){
- if( *zString==0 ) return 0;
- sqliteNextChar(zString);
- }
- zPattern++;
- }
- if( c==0 ) return 1;
- if( c==matchSet ){
- while( *zString && patternCompare(&zPattern[1],zString,pInfo)==0 ){
- sqliteNextChar(zString);
- }
- return *zString!=0;
- }else{
- while( (c2 = *zString)!=0 ){
- if( noCase ){
- c2 = sqlite3UpperToLower[c2];
- c = sqlite3UpperToLower[c];
- while( c2 != 0 && c2 != c ){ c2 = sqlite3UpperToLower[*++zString]; }
- }else{
- while( c2 != 0 && c2 != c ){ c2 = *++zString; }
- }
- if( c2==0 ) return 0;
- if( patternCompare(&zPattern[1],zString,pInfo) ) return 1;
- sqliteNextChar(zString);
- }
- return 0;
- }
- }else if( c==matchOne ){
- if( *zString==0 ) return 0;
- sqliteNextChar(zString);
- zPattern++;
- }else if( c==matchSet ){
- int prior_c = 0;
- seen = 0;
- invert = 0;
- c = sqliteCharVal(zString);
- if( c==0 ) return 0;
- c2 = *++zPattern;
- if( c2=='^' ){ invert = 1; c2 = *++zPattern; }
- if( c2==']' ){
- if( c==']' ) seen = 1;
- c2 = *++zPattern;
- }
- while( (c2 = sqliteCharVal(zPattern))!=0 && c2!=']' ){
- if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 && prior_c>0 ){
- zPattern++;
- c2 = sqliteCharVal(zPattern);
- if( c>=prior_c && c<=c2 ) seen = 1;
- prior_c = 0;
- }else if( c==c2 ){
- seen = 1;
- prior_c = c2;
- }else{
- prior_c = c2;
- }
- sqliteNextChar(zPattern);
- }
- if( c2==0 || (seen ^ invert)==0 ) return 0;
- sqliteNextChar(zString);
- zPattern++;
- }else{
- if( noCase ){
- if( sqlite3UpperToLower[c] != sqlite3UpperToLower[*zString] ) return 0;
- }else{
- if( c != *zString ) return 0;
- }
- zPattern++;
- zString++;
- }
- }
- return *zString==0;
-}
-
-
-/*
-** Implementation of the like() SQL function. This function implements
-** the build-in LIKE operator. The first argument to the function is the
-** pattern and the second argument is the string. So, the SQL statements:
-**
-** A LIKE B
-**
-** is implemented as like(B,A).
-**
-** If the pointer retrieved by via a call to sqlite3_user_data() is
-** not NULL, then this function uses UTF-16. Otherwise UTF-8.
-*/
-static void likeFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- const unsigned char *zA = sqlite3_value_text(argv[0]);
- const unsigned char *zB = sqlite3_value_text(argv[1]);
- if( zA && zB ){
- sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo));
- }
-}
-
-/*
-** Implementation of the glob() SQL function. This function implements
-** the build-in GLOB operator. The first argument to the function is the
-** string and the second argument is the pattern. So, the SQL statements:
-**
-** A GLOB B
-**
-** is implemented as glob(A,B).
-*/
-static void globFunc(sqlite3_context *context, int arg, sqlite3_value **argv){
- const unsigned char *zA = sqlite3_value_text(argv[0]);
- const unsigned char *zB = sqlite3_value_text(argv[1]);
- if( zA && zB ){
- sqlite3_result_int(context, patternCompare(zA, zB, &globInfo));
- }
-}
-
-/*
-** Implementation of the NULLIF(x,y) function. The result is the first
-** argument if the arguments are different. The result is NULL if the
-** arguments are equal to each other.
-*/
-static void nullifFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- CollSeq *pColl = sqlite3GetFuncCollSeq(context);
- if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){
- sqlite3_result_value(context, argv[0]);
- }
-}
-
-/*
-** Implementation of the VERSION(*) function. The result is the version
-** of the SQLite library that is running.
-*/
-static void versionFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
-}
-
-/*
-** EXPERIMENTAL - This is not an official function. The interface may
-** change. This function may disappear. Do not write code that depends
-** on this function.
-**
-** Implementation of the QUOTE() function. This function takes a single
-** argument. If the argument is numeric, the return value is the same as
-** the argument. If the argument is NULL, the return value is the string
-** "NULL". Otherwise, the argument is enclosed in single quotes with
-** single-quote escapes.
-*/
-static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- if( argc<1 ) return;
- switch( sqlite3_value_type(argv[0]) ){
- case SQLITE_NULL: {
- sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC);
- break;
- }
- case SQLITE_INTEGER:
- case SQLITE_FLOAT: {
- sqlite3_result_value(context, argv[0]);
- break;
- }
- case SQLITE_BLOB: {
- static const char hexdigits[] = {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
- char *zText = 0;
- int nBlob = sqlite3_value_bytes(argv[0]);
- char const *zBlob = sqlite3_value_blob(argv[0]);
-
- zText = (char *)sqliteMalloc((2*nBlob)+4);
- if( !zText ){
- sqlite3_result_error(context, "out of memory", -1);
- }else{
- int i;
- for(i=0; i<nBlob; i++){
- zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F];
- zText[(i*2)+3] = hexdigits[(zBlob[i])&0x0F];
- }
- zText[(nBlob*2)+2] = '\'';
- zText[(nBlob*2)+3] = '\0';
- zText[0] = 'X';
- zText[1] = '\'';
- sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
- sqliteFree(zText);
- }
- break;
- }
- case SQLITE_TEXT: {
- int i,j,n;
- const char *zArg = sqlite3_value_text(argv[0]);
- char *z;
-
- for(i=n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
- z = sqliteMalloc( i+n+3 );
- if( z==0 ) return;
- z[0] = '\'';
- for(i=0, j=1; zArg[i]; i++){
- z[j++] = zArg[i];
- if( zArg[i]=='\'' ){
- z[j++] = '\'';
- }
- }
- z[j++] = '\'';
- z[j] = 0;
- sqlite3_result_text(context, z, j, SQLITE_TRANSIENT);
- sqliteFree(z);
- }
- }
-}
-
-#ifdef SQLITE_SOUNDEX
-/*
-** Compute the soundex encoding of a word.
-*/
-static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- char zResult[8];
- const u8 *zIn;
- int i, j;
- static const unsigned char iCode[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
- 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
- 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
- };
- assert( argc==1 );
- zIn = (u8*)sqlite3_value_text(argv[0]);
- for(i=0; zIn[i] && !isalpha(zIn[i]); i++){}
- if( zIn[i] ){
- zResult[0] = toupper(zIn[i]);
- for(j=1; j<4 && zIn[i]; i++){
- int code = iCode[zIn[i]&0x7f];
- if( code>0 ){
- zResult[j++] = code + '0';
- }
- }
- while( j<4 ){
- zResult[j++] = '0';
- }
- zResult[j] = 0;
- sqlite3_result_text(context, zResult, 4, SQLITE_TRANSIENT);
- }else{
- sqlite3_result_text(context, "?000", 4, SQLITE_STATIC);
- }
-}
-#endif
-
-#ifdef SQLITE_TEST
-/*
-** This function generates a string of random characters. Used for
-** generating test data.
-*/
-static void randStr(sqlite3_context *context, int argc, sqlite3_value **argv){
- static const unsigned char zSrc[] =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789"
- ".-!,:*^+=_|?/<> ";
- int iMin, iMax, n, r, i;
- unsigned char zBuf[1000];
- if( argc>=1 ){
- iMin = sqlite3_value_int(argv[0]);
- if( iMin<0 ) iMin = 0;
- if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1;
- }else{
- iMin = 1;
- }
- if( argc>=2 ){
- iMax = sqlite3_value_int(argv[1]);
- if( iMax<iMin ) iMax = iMin;
- if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf)-1;
- }else{
- iMax = 50;
- }
- n = iMin;
- if( iMax>iMin ){
- sqlite3Randomness(sizeof(r), &r);
- r &= 0x7fffffff;
- n += r%(iMax + 1 - iMin);
- }
- assert( n<sizeof(zBuf) );
- sqlite3Randomness(n, zBuf);
- for(i=0; i<n; i++){
- zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)];
- }
- zBuf[n] = 0;
- sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
-}
-#endif /* SQLITE_TEST */
-
-#ifdef SQLITE_TEST
-/*
-** The following two SQL functions are used to test returning a text
-** result with a destructor. Function 'test_destructor' takes one argument
-** and returns the same argument interpreted as TEXT. A destructor is
-** passed with the sqlite3_result_text() call.
-**
-** SQL function 'test_destructor_count' returns the number of outstanding
-** allocations made by 'test_destructor';
-**
-** WARNING: Not threadsafe.
-*/
-static int test_destructor_count_var = 0;
-static void destructor(void *p){
- char *zVal = (char *)p;
- assert(zVal);
- zVal--;
- sqliteFree(zVal);
- test_destructor_count_var--;
-}
-static void test_destructor(
- sqlite3_context *pCtx,
- int nArg,
- sqlite3_value **argv
-){
- char *zVal;
- int len;
- sqlite3 *db = sqlite3_user_data(pCtx);
-
- test_destructor_count_var++;
- assert( nArg==1 );
- if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
- len = sqlite3ValueBytes(argv[0], db->enc);
- zVal = sqliteMalloc(len+3);
- zVal[len] = 0;
- zVal[len-1] = 0;
- assert( zVal );
- zVal++;
- memcpy(zVal, sqlite3ValueText(argv[0], db->enc), len);
- if( db->enc==SQLITE_UTF8 ){
- sqlite3_result_text(pCtx, zVal, -1, destructor);
- }else if( db->enc==SQLITE_UTF16LE ){
- sqlite3_result_text16le(pCtx, zVal, -1, destructor);
- }else{
- sqlite3_result_text16be(pCtx, zVal, -1, destructor);
- }
-}
-static void test_destructor_count(
- sqlite3_context *pCtx,
- int nArg,
- sqlite3_value **argv
-){
- sqlite3_result_int(pCtx, test_destructor_count_var);
-}
-#endif /* SQLITE_TEST */
-
-#ifdef SQLITE_TEST
-/*
-** Routines for testing the sqlite3_get_auxdata() and sqlite3_set_auxdata()
-** interface.
-**
-** The test_auxdata() SQL function attempts to register each of its arguments
-** as auxiliary data. If there are no prior registrations of aux data for
-** that argument (meaning the argument is not a constant or this is its first
-** call) then the result for that argument is 0. If there is a prior
-** registration, the result for that argument is 1. The overall result
-** is the individual argument results separated by spaces.
-*/
-static void free_test_auxdata(void *p) {sqliteFree(p);}
-static void test_auxdata(
- sqlite3_context *pCtx,
- int nArg,
- sqlite3_value **argv
-){
- int i;
- char *zRet = sqliteMalloc(nArg*2);
- if( !zRet ) return;
- for(i=0; i<nArg; i++){
- char const *z = sqlite3_value_text(argv[i]);
- if( z ){
- char *zAux = sqlite3_get_auxdata(pCtx, i);
- if( zAux ){
- zRet[i*2] = '1';
- if( strcmp(zAux, z) ){
- sqlite3_result_error(pCtx, "Auxilary data corruption", -1);
- return;
- }
- }else{
- zRet[i*2] = '0';
- zAux = sqliteStrDup(z);
- sqlite3_set_auxdata(pCtx, i, zAux, free_test_auxdata);
- }
- zRet[i*2+1] = ' ';
- }
- }
- sqlite3_result_text(pCtx, zRet, 2*nArg-1, free_test_auxdata);
-}
-#endif /* SQLITE_TEST */
-
-/*
-** An instance of the following structure holds the context of a
-** sum() or avg() aggregate computation.
-*/
-typedef struct SumCtx SumCtx;
-struct SumCtx {
- double sum; /* Sum of terms */
- int cnt; /* Number of elements summed */
-};
-
-/*
-** Routines used to compute the sum or average.
-*/
-static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
- SumCtx *p;
- if( argc<1 ) return;
- p = sqlite3_aggregate_context(context, sizeof(*p));
- if( p && SQLITE_NULL!=sqlite3_value_type(argv[0]) ){
- p->sum += sqlite3_value_double(argv[0]);
- p->cnt++;
- }
-}
-static void sumFinalize(sqlite3_context *context){
- SumCtx *p;
- p = sqlite3_aggregate_context(context, sizeof(*p));
- sqlite3_result_double(context, p ? p->sum : 0.0);
-}
-static void avgFinalize(sqlite3_context *context){
- SumCtx *p;
- p = sqlite3_aggregate_context(context, sizeof(*p));
- if( p && p->cnt>0 ){
- sqlite3_result_double(context, p->sum/(double)p->cnt);
- }
-}
-
-/*
-** An instance of the following structure holds the context of a
-** variance or standard deviation computation.
-*/
-typedef struct StdDevCtx StdDevCtx;
-struct StdDevCtx {
- double sum; /* Sum of terms */
- double sum2; /* Sum of the squares of terms */
- int cnt; /* Number of terms counted */
-};
-
-#if 0 /* Omit because math library is required */
-/*
-** Routines used to compute the standard deviation as an aggregate.
-*/
-static void stdDevStep(sqlite3_context *context, int argc, const char **argv){
- StdDevCtx *p;
- double x;
- if( argc<1 ) return;
- p = sqlite3_aggregate_context(context, sizeof(*p));
- if( p && argv[0] ){
- x = sqlite3AtoF(argv[0], 0);
- p->sum += x;
- p->sum2 += x*x;
- p->cnt++;
- }
-}
-static void stdDevFinalize(sqlite3_context *context){
- double rN = sqlite3_aggregate_count(context);
- StdDevCtx *p = sqlite3_aggregate_context(context, sizeof(*p));
- if( p && p->cnt>1 ){
- double rCnt = cnt;
- sqlite3_set_result_double(context,
- sqrt((p->sum2 - p->sum*p->sum/rCnt)/(rCnt-1.0)));
- }
-}
-#endif
-
-/*
-** The following structure keeps track of state information for the
-** count() aggregate function.
-*/
-typedef struct CountCtx CountCtx;
-struct CountCtx {
- int n;
-};
-
-/*
-** Routines to implement the count() aggregate function.
-*/
-static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
- CountCtx *p;
- p = sqlite3_aggregate_context(context, sizeof(*p));
- if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && p ){
- p->n++;
- }
-}
-static void countFinalize(sqlite3_context *context){
- CountCtx *p;
- p = sqlite3_aggregate_context(context, sizeof(*p));
- sqlite3_result_int(context, p ? p->n : 0);
-}
-
-/*
-** This function tracks state information for the min() and max()
-** aggregate functions.
-*/
-typedef struct MinMaxCtx MinMaxCtx;
-struct MinMaxCtx {
- char *z; /* The best so far */
- char zBuf[28]; /* Space that can be used for storage */
-};
-
-/*
-** Routines to implement min() and max() aggregate functions.
-*/
-static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv){
- Mem *pArg = (Mem *)argv[0];
- Mem *pBest;
-
- if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
- pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest));
- if( !pBest ) return;
-
- if( pBest->flags ){
- int max;
- int cmp;
- CollSeq *pColl = sqlite3GetFuncCollSeq(context);
- /* This step function is used for both the min() and max() aggregates,
- ** the only difference between the two being that the sense of the
- ** comparison is inverted. For the max() aggregate, the
- ** sqlite3_user_data() function returns (void *)-1. For min() it
- ** returns (void *)db, where db is the sqlite3* database pointer.
- ** Therefore the next statement sets variable 'max' to 1 for the max()
- ** aggregate, or 0 for min().
- */
- max = ((sqlite3_user_data(context)==(void *)-1)?1:0);
- cmp = sqlite3MemCompare(pBest, pArg, pColl);
- if( (max && cmp<0) || (!max && cmp>0) ){
- sqlite3VdbeMemCopy(pBest, pArg);
- }
- }else{
- sqlite3VdbeMemCopy(pBest, pArg);
- }
-}
-static void minMaxFinalize(sqlite3_context *context){
- sqlite3_value *pRes;
- pRes = (sqlite3_value *)sqlite3_aggregate_context(context, sizeof(Mem));
- if( pRes->flags ){
- sqlite3_result_value(context, pRes);
- }
- sqlite3VdbeMemRelease(pRes);
-}
-
-
-/*
-** This function registered all of the above C functions as SQL
-** functions. This should be the only routine in this file with
-** external linkage.
-*/
-void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
- static const struct {
- char *zName;
- signed char nArg;
- u8 argType; /* 0: none. 1: db 2: (-1) */
- u8 eTextRep; /* 1: UTF-16. 0: UTF-8 */
- u8 needCollSeq;
- void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
- } aFuncs[] = {
- { "min", -1, 0, SQLITE_UTF8, 1, minmaxFunc },
- { "min", 0, 0, SQLITE_UTF8, 1, 0 },
- { "max", -1, 2, SQLITE_UTF8, 1, minmaxFunc },
- { "max", 0, 2, SQLITE_UTF8, 1, 0 },
- { "typeof", 1, 0, SQLITE_UTF8, 0, typeofFunc },
- { "length", 1, 0, SQLITE_UTF8, 0, lengthFunc },
- { "substr", 3, 0, SQLITE_UTF8, 0, substrFunc },
- { "substr", 3, 0, SQLITE_UTF16LE, 0, sqlite3utf16Substr },
- { "abs", 1, 0, SQLITE_UTF8, 0, absFunc },
- { "round", 1, 0, SQLITE_UTF8, 0, roundFunc },
- { "round", 2, 0, SQLITE_UTF8, 0, roundFunc },
- { "upper", 1, 0, SQLITE_UTF8, 0, upperFunc },
- { "lower", 1, 0, SQLITE_UTF8, 0, lowerFunc },
- { "coalesce", -1, 0, SQLITE_UTF8, 0, ifnullFunc },
- { "coalesce", 0, 0, SQLITE_UTF8, 0, 0 },
- { "coalesce", 1, 0, SQLITE_UTF8, 0, 0 },
- { "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
- { "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
- { "like", 2, 0, SQLITE_UTF8, 0, likeFunc },
- { "glob", 2, 0, SQLITE_UTF8, 0, globFunc },
- { "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
- { "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
- { "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
- { "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid },
- { "changes", 0, 1, SQLITE_UTF8, 0, changes },
- { "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes },
-#ifdef SQLITE_SOUNDEX
- { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
-#endif
-#ifdef SQLITE_TEST
- { "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
- { "test_destructor", 1, 1, SQLITE_UTF8, 0, test_destructor},
- { "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count},
- { "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata},
-#endif
- };
- static const struct {
- char *zName;
- signed char nArg;
- u8 argType;
- u8 needCollSeq;
- void (*xStep)(sqlite3_context*,int,sqlite3_value**);
- void (*xFinalize)(sqlite3_context*);
- } aAggs[] = {
- { "min", 1, 0, 1, minmaxStep, minMaxFinalize },
- { "max", 1, 2, 1, minmaxStep, minMaxFinalize },
- { "sum", 1, 0, 0, sumStep, sumFinalize },
- { "avg", 1, 0, 0, sumStep, avgFinalize },
- { "count", 0, 0, 0, countStep, countFinalize },
- { "count", 1, 0, 0, countStep, countFinalize },
-#if 0
- { "stddev", 1, 0, stdDevStep, stdDevFinalize },
-#endif
- };
- int i;
-
- for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
- void *pArg = 0;
- switch( aFuncs[i].argType ){
- case 1: pArg = db; break;
- case 2: pArg = (void *)(-1); break;
- }
- sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
- aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0);
- if( aFuncs[i].needCollSeq ){
- FuncDef *pFunc = sqlite3FindFunction(db, aFuncs[i].zName,
- strlen(aFuncs[i].zName), aFuncs[i].nArg, aFuncs[i].eTextRep, 0);
- if( pFunc && aFuncs[i].needCollSeq ){
- pFunc->needCollSeq = 1;
- }
- }
- }
- for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
- void *pArg = 0;
- switch( aAggs[i].argType ){
- case 1: pArg = db; break;
- case 2: pArg = (void *)(-1); break;
- }
- sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
- pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
- if( aAggs[i].needCollSeq ){
- FuncDef *pFunc = sqlite3FindFunction( db, aAggs[i].zName,
- strlen(aAggs[i].zName), aAggs[i].nArg, SQLITE_UTF8, 0);
- if( pFunc && aAggs[i].needCollSeq ){
- pFunc->needCollSeq = 1;
- }
- }
- }
- sqlite3RegisterDateTimeFunctions(db);
-}
diff --git a/kopete/plugins/statistics/sqlite/hash.c b/kopete/plugins/statistics/sqlite/hash.c
deleted file mode 100644
index 23e2e197..00000000
--- a/kopete/plugins/statistics/sqlite/hash.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
-** 2001 September 22
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This is the implementation of generic hash-tables
-** used in SQLite.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-#include <assert.h>
-
-/* Turn bulk memory into a hash table object by initializing the
-** fields of the Hash structure.
-**
-** "pNew" is a pointer to the hash table that is to be initialized.
-** keyClass is one of the constants SQLITE_HASH_INT, SQLITE_HASH_POINTER,
-** SQLITE_HASH_BINARY, or SQLITE_HASH_STRING. The value of keyClass
-** determines what kind of key the hash table will use. "copyKey" is
-** true if the hash table should make its own private copy of keys and
-** false if it should just use the supplied pointer. CopyKey only makes
-** sense for SQLITE_HASH_STRING and SQLITE_HASH_BINARY and is ignored
-** for other key classes.
-*/
-void sqlite3HashInit(Hash *pNew, int keyClass, int copyKey){
- assert( pNew!=0 );
- assert( keyClass>=SQLITE_HASH_STRING && keyClass<=SQLITE_HASH_BINARY );
- pNew->keyClass = keyClass;
-#if 0
- if( keyClass==SQLITE_HASH_POINTER || keyClass==SQLITE_HASH_INT ) copyKey = 0;
-#endif
- pNew->copyKey = copyKey;
- pNew->first = 0;
- pNew->count = 0;
- pNew->htsize = 0;
- pNew->ht = 0;
-}
-
-/* Remove all entries from a hash table. Reclaim all memory.
-** Call this routine to delete a hash table or to reset a hash table
-** to the empty state.
-*/
-void sqlite3HashClear(Hash *pH){
- HashElem *elem; /* For looping over all elements of the table */
-
- assert( pH!=0 );
- elem = pH->first;
- pH->first = 0;
- if( pH->ht ) sqliteFree(pH->ht);
- pH->ht = 0;
- pH->htsize = 0;
- while( elem ){
- HashElem *next_elem = elem->next;
- if( pH->copyKey && elem->pKey ){
- sqliteFree(elem->pKey);
- }
- sqliteFree(elem);
- elem = next_elem;
- }
- pH->count = 0;
-}
-
-#if 0 /* NOT USED */
-/*
-** Hash and comparison functions when the mode is SQLITE_HASH_INT
-*/
-static int intHash(const void *pKey, int nKey){
- return nKey ^ (nKey<<8) ^ (nKey>>8);
-}
-static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){
- return n2 - n1;
-}
-#endif
-
-#if 0 /* NOT USED */
-/*
-** Hash and comparison functions when the mode is SQLITE_HASH_POINTER
-*/
-static int ptrHash(const void *pKey, int nKey){
- uptr x = Addr(pKey);
- return x ^ (x<<8) ^ (x>>8);
-}
-static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
- if( pKey1==pKey2 ) return 0;
- if( pKey1<pKey2 ) return -1;
- return 1;
-}
-#endif
-
-/*
-** Hash and comparison functions when the mode is SQLITE_HASH_STRING
-*/
-static int strHash(const void *pKey, int nKey){
- return sqlite3HashNoCase((const char*)pKey, nKey);
-}
-static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
- if( n1!=n2 ) return 1;
- return sqlite3StrNICmp((const char*)pKey1,(const char*)pKey2,n1);
-}
-
-/*
-** Hash and comparison functions when the mode is SQLITE_HASH_BINARY
-*/
-static int binHash(const void *pKey, int nKey){
- int h = 0;
- const char *z = (const char *)pKey;
- while( nKey-- > 0 ){
- h = (h<<3) ^ h ^ *(z++);
- }
- return h & 0x7fffffff;
-}
-static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){
- if( n1!=n2 ) return 1;
- return memcmp(pKey1,pKey2,n1);
-}
-
-/*
-** Return a pointer to the appropriate hash function given the key class.
-**
-** The C syntax in this function definition may be unfamilar to some
-** programmers, so we provide the following additional explanation:
-**
-** The name of the function is "hashFunction". The function takes a
-** single parameter "keyClass". The return value of hashFunction()
-** is a pointer to another function. Specifically, the return value
-** of hashFunction() is a pointer to a function that takes two parameters
-** with types "const void*" and "int" and returns an "int".
-*/
-static int (*hashFunction(int keyClass))(const void*,int){
-#if 0 /* HASH_INT and HASH_POINTER are never used */
- switch( keyClass ){
- case SQLITE_HASH_INT: return &intHash;
- case SQLITE_HASH_POINTER: return &ptrHash;
- case SQLITE_HASH_STRING: return &strHash;
- case SQLITE_HASH_BINARY: return &binHash;;
- default: break;
- }
- return 0;
-#else
- if( keyClass==SQLITE_HASH_STRING ){
- return &strHash;
- }else{
- assert( keyClass==SQLITE_HASH_BINARY );
- return &binHash;
- }
-#endif
-}
-
-/*
-** Return a pointer to the appropriate hash function given the key class.
-**
-** For help in interpreted the obscure C code in the function definition,
-** see the header comment on the previous function.
-*/
-static int (*compareFunction(int keyClass))(const void*,int,const void*,int){
-#if 0 /* HASH_INT and HASH_POINTER are never used */
- switch( keyClass ){
- case SQLITE_HASH_INT: return &intCompare;
- case SQLITE_HASH_POINTER: return &ptrCompare;
- case SQLITE_HASH_STRING: return &strCompare;
- case SQLITE_HASH_BINARY: return &binCompare;
- default: break;
- }
- return 0;
-#else
- if( keyClass==SQLITE_HASH_STRING ){
- return &strCompare;
- }else{
- assert( keyClass==SQLITE_HASH_BINARY );
- return &binCompare;
- }
-#endif
-}
-
-/* Link an element into the hash table
-*/
-static void insertElement(
- Hash *pH, /* The complete hash table */
- struct _ht *pEntry, /* The entry into which pNew is inserted */
- HashElem *pNew /* The element to be inserted */
-){
- HashElem *pHead; /* First element already in pEntry */
- pHead = pEntry->chain;
- if( pHead ){
- pNew->next = pHead;
- pNew->prev = pHead->prev;
- if( pHead->prev ){ pHead->prev->next = pNew; }
- else { pH->first = pNew; }
- pHead->prev = pNew;
- }else{
- pNew->next = pH->first;
- if( pH->first ){ pH->first->prev = pNew; }
- pNew->prev = 0;
- pH->first = pNew;
- }
- pEntry->count++;
- pEntry->chain = pNew;
-}
-
-
-/* Resize the hash table so that it cantains "new_size" buckets.
-** "new_size" must be a power of 2. The hash table might fail
-** to resize if sqliteMalloc() fails.
-*/
-static void rehash(Hash *pH, int new_size){
- struct _ht *new_ht; /* The new hash table */
- HashElem *elem, *next_elem; /* For looping over existing elements */
- int (*xHash)(const void*,int); /* The hash function */
-
- assert( (new_size & (new_size-1))==0 );
- new_ht = (struct _ht *)sqliteMalloc( new_size*sizeof(struct _ht) );
- if( new_ht==0 ) return;
- if( pH->ht ) sqliteFree(pH->ht);
- pH->ht = new_ht;
- pH->htsize = new_size;
- xHash = hashFunction(pH->keyClass);
- for(elem=pH->first, pH->first=0; elem; elem = next_elem){
- int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
- next_elem = elem->next;
- insertElement(pH, &new_ht[h], elem);
- }
-}
-
-/* This function (for internal use only) locates an element in an
-** hash table that matches the given key. The hash for this key has
-** already been computed and is passed as the 4th parameter.
-*/
-static HashElem *findElementGivenHash(
- const Hash *pH, /* The pH to be searched */
- const void *pKey, /* The key we are searching for */
- int nKey,
- int h /* The hash for this key. */
-){
- HashElem *elem; /* Used to loop thru the element list */
- int count; /* Number of elements left to test */
- int (*xCompare)(const void*,int,const void*,int); /* comparison function */
-
- if( pH->ht ){
- struct _ht *pEntry = &pH->ht[h];
- elem = pEntry->chain;
- count = pEntry->count;
- xCompare = compareFunction(pH->keyClass);
- while( count-- && elem ){
- if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
- return elem;
- }
- elem = elem->next;
- }
- }
- return 0;
-}
-
-/* Remove a single entry from the hash table given a pointer to that
-** element and a hash on the element's key.
-*/
-static void removeElementGivenHash(
- Hash *pH, /* The pH containing "elem" */
- HashElem* elem, /* The element to be removed from the pH */
- int h /* Hash value for the element */
-){
- struct _ht *pEntry;
- if( elem->prev ){
- elem->prev->next = elem->next;
- }else{
- pH->first = elem->next;
- }
- if( elem->next ){
- elem->next->prev = elem->prev;
- }
- pEntry = &pH->ht[h];
- if( pEntry->chain==elem ){
- pEntry->chain = elem->next;
- }
- pEntry->count--;
- if( pEntry->count<=0 ){
- pEntry->chain = 0;
- }
- if( pH->copyKey && elem->pKey ){
- sqliteFree(elem->pKey);
- }
- sqliteFree( elem );
- pH->count--;
-}
-
-/* Attempt to locate an element of the hash table pH with a key
-** that matches pKey,nKey. Return the data for this element if it is
-** found, or NULL if there is no match.
-*/
-void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){
- int h; /* A hash on key */
- HashElem *elem; /* The element that matches key */
- int (*xHash)(const void*,int); /* The hash function */
-
- if( pH==0 || pH->ht==0 ) return 0;
- xHash = hashFunction(pH->keyClass);
- assert( xHash!=0 );
- h = (*xHash)(pKey,nKey);
- assert( (pH->htsize & (pH->htsize-1))==0 );
- elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1));
- return elem ? elem->data : 0;
-}
-
-/* Insert an element into the hash table pH. The key is pKey,nKey
-** and the data is "data".
-**
-** If no element exists with a matching key, then a new
-** element is created. A copy of the key is made if the copyKey
-** flag is set. NULL is returned.
-**
-** If another element already exists with the same key, then the
-** new data replaces the old data and the old data is returned.
-** The key is not copied in this instance. If a malloc fails, then
-** the new data is returned and the hash table is unchanged.
-**
-** If the "data" parameter to this function is NULL, then the
-** element corresponding to "key" is removed from the hash table.
-*/
-void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
- int hraw; /* Raw hash value of the key */
- int h; /* the hash of the key modulo hash table size */
- HashElem *elem; /* Used to loop thru the element list */
- HashElem *new_elem; /* New element added to the pH */
- int (*xHash)(const void*,int); /* The hash function */
-
- assert( pH!=0 );
- xHash = hashFunction(pH->keyClass);
- assert( xHash!=0 );
- hraw = (*xHash)(pKey, nKey);
- assert( (pH->htsize & (pH->htsize-1))==0 );
- h = hraw & (pH->htsize-1);
- elem = findElementGivenHash(pH,pKey,nKey,h);
- if( elem ){
- void *old_data = elem->data;
- if( data==0 ){
- removeElementGivenHash(pH,elem,h);
- }else{
- elem->data = data;
- }
- return old_data;
- }
- if( data==0 ) return 0;
- new_elem = (HashElem*)sqliteMalloc( sizeof(HashElem) );
- if( new_elem==0 ) return data;
- if( pH->copyKey && pKey!=0 ){
- new_elem->pKey = sqliteMallocRaw( nKey );
- if( new_elem->pKey==0 ){
- sqliteFree(new_elem);
- return data;
- }
- memcpy((void*)new_elem->pKey, pKey, nKey);
- }else{
- new_elem->pKey = (void*)pKey;
- }
- new_elem->nKey = nKey;
- pH->count++;
- if( pH->htsize==0 ){
- rehash(pH,8);
- if( pH->htsize==0 ){
- pH->count = 0;
- sqliteFree(new_elem);
- return data;
- }
- }
- if( pH->count > pH->htsize ){
- rehash(pH,pH->htsize*2);
- }
- assert( pH->htsize>0 );
- assert( (pH->htsize & (pH->htsize-1))==0 );
- h = hraw & (pH->htsize-1);
- insertElement(pH, &pH->ht[h], new_elem);
- new_elem->data = data;
- return 0;
-}
diff --git a/kopete/plugins/statistics/sqlite/hash.h b/kopete/plugins/statistics/sqlite/hash.h
deleted file mode 100644
index cf004ddc..00000000
--- a/kopete/plugins/statistics/sqlite/hash.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
-** 2001 September 22
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This is the header file for the generic hash-table implemenation
-** used in SQLite.
-**
-** $Id$
-*/
-#ifndef _SQLITE_HASH_H_
-#define _SQLITE_HASH_H_
-
-/* Forward declarations of structures. */
-typedef struct Hash Hash;
-typedef struct HashElem HashElem;
-
-/* A complete hash table is an instance of the following structure.
-** The internals of this structure are intended to be opaque -- client
-** code should not attempt to access or modify the fields of this structure
-** directly. Change this structure only by using the routines below.
-** However, many of the "procedures" and "functions" for modifying and
-** accessing this structure are really macros, so we can't really make
-** this structure opaque.
-*/
-struct Hash {
- char keyClass; /* SQLITE_HASH_INT, _POINTER, _STRING, _BINARY */
- char copyKey; /* True if copy of key made on insert */
- int count; /* Number of entries in this table */
- HashElem *first; /* The first element of the array */
- int htsize; /* Number of buckets in the hash table */
- struct _ht { /* the hash table */
- int count; /* Number of entries with this hash */
- HashElem *chain; /* Pointer to first entry with this hash */
- } *ht;
-};
-
-/* Each element in the hash table is an instance of the following
-** structure. All elements are stored on a single doubly-linked list.
-**
-** Again, this structure is intended to be opaque, but it can't really
-** be opaque because it is used by macros.
-*/
-struct HashElem {
- HashElem *next, *prev; /* Next and previous elements in the table */
- void *data; /* Data associated with this element */
- void *pKey; int nKey; /* Key associated with this element */
-};
-
-/*
-** There are 4 different modes of operation for a hash table:
-**
-** SQLITE_HASH_INT nKey is used as the key and pKey is ignored.
-**
-** SQLITE_HASH_POINTER pKey is used as the key and nKey is ignored.
-**
-** SQLITE_HASH_STRING pKey points to a string that is nKey bytes long
-** (including the null-terminator, if any). Case
-** is ignored in comparisons.
-**
-** SQLITE_HASH_BINARY pKey points to binary data nKey bytes long.
-** memcmp() is used to compare keys.
-**
-** A copy of the key is made for SQLITE_HASH_STRING and SQLITE_HASH_BINARY
-** if the copyKey parameter to HashInit is 1.
-*/
-/* #define SQLITE_HASH_INT 1 // NOT USED */
-/* #define SQLITE_HASH_POINTER 2 // NOT USED */
-#define SQLITE_HASH_STRING 3
-#define SQLITE_HASH_BINARY 4
-
-/*
-** Access routines. To delete, insert a NULL pointer.
-*/
-void sqlite3HashInit(Hash*, int keytype, int copyKey);
-void *sqlite3HashInsert(Hash*, const void *pKey, int nKey, void *pData);
-void *sqlite3HashFind(const Hash*, const void *pKey, int nKey);
-void sqlite3HashClear(Hash*);
-
-/*
-** Macros for looping over all elements of a hash table. The idiom is
-** like this:
-**
-** Hash h;
-** HashElem *p;
-** ...
-** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){
-** SomeStructure *pData = sqliteHashData(p);
-** // do something with pData
-** }
-*/
-#define sqliteHashFirst(H) ((H)->first)
-#define sqliteHashNext(E) ((E)->next)
-#define sqliteHashData(E) ((E)->data)
-#define sqliteHashKey(E) ((E)->pKey)
-#define sqliteHashKeysize(E) ((E)->nKey)
-
-/*
-** Number of entries in a hash table
-*/
-#define sqliteHashCount(H) ((H)->count)
-
-#endif /* _SQLITE_HASH_H_ */
diff --git a/kopete/plugins/statistics/sqlite/insert.c b/kopete/plugins/statistics/sqlite/insert.c
deleted file mode 100644
index 65cbdc8f..00000000
--- a/kopete/plugins/statistics/sqlite/insert.c
+++ /dev/null
@@ -1,1018 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains C code routines that are called by the parser
-** to handle INSERT statements in SQLite.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-
-/*
-** Set P3 of the most recently inserted opcode to a column affinity
-** string for index pIdx. A column affinity string has one character
-** for each column in the table, according to the affinity of the column:
-**
-** Character Column affinity
-** ------------------------------
-** 'n' NUMERIC
-** 'i' INTEGER
-** 't' TEXT
-** 'o' NONE
-*/
-void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
- if( !pIdx->zColAff ){
- /* The first time a column affinity string for a particular index is
- ** required, it is allocated and populated here. It is then stored as
- ** a member of the Index structure for subsequent use.
- **
- ** The column affinity string will eventually be deleted by
- ** sqliteDeleteIndex() when the Index structure itself is cleaned
- ** up.
- */
- int n;
- Table *pTab = pIdx->pTable;
- pIdx->zColAff = (char *)sqliteMalloc(pIdx->nColumn+1);
- if( !pIdx->zColAff ){
- return;
- }
- for(n=0; n<pIdx->nColumn; n++){
- pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity;
- }
- pIdx->zColAff[pIdx->nColumn] = '\0';
- }
-
- sqlite3VdbeChangeP3(v, -1, pIdx->zColAff, 0);
-}
-
-/*
-** Set P3 of the most recently inserted opcode to a column affinity
-** string for table pTab. A column affinity string has one character
-** for each column indexed by the index, according to the affinity of the
-** column:
-**
-** Character Column affinity
-** ------------------------------
-** 'n' NUMERIC
-** 'i' INTEGER
-** 't' TEXT
-** 'o' NONE
-*/
-void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
- /* The first time a column affinity string for a particular table
- ** is required, it is allocated and populated here. It is then
- ** stored as a member of the Table structure for subsequent use.
- **
- ** The column affinity string will eventually be deleted by
- ** sqlite3DeleteTable() when the Table structure itself is cleaned up.
- */
- if( !pTab->zColAff ){
- char *zColAff;
- int i;
-
- zColAff = (char *)sqliteMalloc(pTab->nCol+1);
- if( !zColAff ){
- return;
- }
-
- for(i=0; i<pTab->nCol; i++){
- zColAff[i] = pTab->aCol[i].affinity;
- }
- zColAff[pTab->nCol] = '\0';
-
- pTab->zColAff = zColAff;
- }
-
- sqlite3VdbeChangeP3(v, -1, pTab->zColAff, 0);
-}
-
-
-/*
-** This routine is call to handle SQL of the following forms:
-**
-** insert into TABLE (IDLIST) values(EXPRLIST)
-** insert into TABLE (IDLIST) select
-**
-** The IDLIST following the table name is always optional. If omitted,
-** then a list of all columns for the table is substituted. The IDLIST
-** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted.
-**
-** The pList parameter holds EXPRLIST in the first form of the INSERT
-** statement above, and pSelect is NULL. For the second form, pList is
-** NULL and pSelect is a pointer to the select statement used to generate
-** data for the insert.
-**
-** The code generated follows one of three templates. For a simple
-** select with data coming from a VALUES clause, the code executes
-** once straight down through. The template looks like this:
-**
-** open write cursor to <table> and its indices
-** puts VALUES clause expressions onto the stack
-** write the resulting record into <table>
-** cleanup
-**
-** If the statement is of the form
-**
-** INSERT INTO <table> SELECT ...
-**
-** And the SELECT clause does not read from <table> at any time, then
-** the generated code follows this template:
-**
-** goto B
-** A: setup for the SELECT
-** loop over the tables in the SELECT
-** gosub C
-** end loop
-** cleanup after the SELECT
-** goto D
-** B: open write cursor to <table> and its indices
-** goto A
-** C: insert the select result into <table>
-** return
-** D: cleanup
-**
-** The third template is used if the insert statement takes its
-** values from a SELECT but the data is being inserted into a table
-** that is also read as part of the SELECT. In the third form,
-** we have to use a intermediate table to store the results of
-** the select. The template is like this:
-**
-** goto B
-** A: setup for the SELECT
-** loop over the tables in the SELECT
-** gosub C
-** end loop
-** cleanup after the SELECT
-** goto D
-** C: insert the select result into the intermediate table
-** return
-** B: open a cursor to an intermediate table
-** goto A
-** D: open write cursor to <table> and its indices
-** loop over the intermediate table
-** transfer values form intermediate table into <table>
-** end the loop
-** cleanup
-*/
-void sqlite3Insert(
- Parse *pParse, /* Parser context */
- SrcList *pTabList, /* Name of table into which we are inserting */
- ExprList *pList, /* List of values to be inserted */
- Select *pSelect, /* A SELECT statement to use as the data source */
- IdList *pColumn, /* Column names corresponding to IDLIST. */
- int onError /* How to handle constraint errors */
-){
- Table *pTab; /* The table to insert into */
- char *zTab; /* Name of the table into which we are inserting */
- const char *zDb; /* Name of the database holding this table */
- int i, j, idx; /* Loop counters */
- Vdbe *v; /* Generate code into this virtual machine */
- Index *pIdx; /* For looping over indices of the table */
- int nColumn; /* Number of columns in the data */
- int base = 0; /* VDBE Cursor number for pTab */
- int iCont=0,iBreak=0; /* Beginning and end of the loop over srcTab */
- sqlite3 *db; /* The main database structure */
- int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
- int endOfLoop; /* Label for the end of the insertion loop */
- int useTempTable; /* Store SELECT results in intermediate table */
- int srcTab = 0; /* Data comes from this temporary cursor if >=0 */
- int iSelectLoop = 0; /* Address of code that implements the SELECT */
- int iCleanup = 0; /* Address of the cleanup code */
- int iInsertBlock = 0; /* Address of the subroutine used to insert data */
- int iCntMem = 0; /* Memory cell used for the row counter */
- int isView; /* True if attempting to insert into a view */
-
- int row_triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
- int before_triggers; /* True if there are BEFORE triggers */
- int after_triggers; /* True if there are AFTER triggers */
- int newIdx = -1; /* Cursor for the NEW table */
-
- if( pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
- db = pParse->db;
-
- /* Locate the table into which we will be inserting new information.
- */
- assert( pTabList->nSrc==1 );
- zTab = pTabList->a[0].zName;
- if( zTab==0 ) goto insert_cleanup;
- pTab = sqlite3SrcListLookup(pParse, pTabList);
- if( pTab==0 ){
- goto insert_cleanup;
- }
- assert( pTab->iDb<db->nDb );
- zDb = db->aDb[pTab->iDb].zName;
- if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
- goto insert_cleanup;
- }
-
- /* Ensure that:
- * (a) the table is not read-only,
- * (b) that if it is a view then ON INSERT triggers exist
- */
- before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger, TK_INSERT,
- TK_BEFORE, TK_ROW, 0);
- after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger, TK_INSERT,
- TK_AFTER, TK_ROW, 0);
- row_triggers_exist = before_triggers || after_triggers;
- isView = pTab->pSelect!=0;
- if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
- goto insert_cleanup;
- }
- if( pTab==0 ) goto insert_cleanup;
-
- /* If pTab is really a view, make sure it has been initialized.
- */
- if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){
- goto insert_cleanup;
- }
-
- /* Ensure all required collation sequences are available. */
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
- goto insert_cleanup;
- }
- }
-
- /* Allocate a VDBE
- */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto insert_cleanup;
- sqlite3VdbeCountChanges(v);
- sqlite3BeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb);
-
- /* if there are row triggers, allocate a temp table for new.* references. */
- if( row_triggers_exist ){
- newIdx = pParse->nTab++;
- }
-
- /* Figure out how many columns of data are supplied. If the data
- ** is coming from a SELECT statement, then this step also generates
- ** all the code to implement the SELECT statement and invoke a subroutine
- ** to process each row of the result. (Template 2.) If the SELECT
- ** statement uses the the table that is being inserted into, then the
- ** subroutine is also coded here. That subroutine stores the SELECT
- ** results in a temporary table. (Template 3.)
- */
- if( pSelect ){
- /* Data is coming from a SELECT. Generate code to implement that SELECT
- */
- int rc, iInitCode;
- iInitCode = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
- iSelectLoop = sqlite3VdbeCurrentAddr(v);
- iInsertBlock = sqlite3VdbeMakeLabel(v);
- rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0,0);
- if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
- iCleanup = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
- assert( pSelect->pEList );
- nColumn = pSelect->pEList->nExpr;
-
- /* Set useTempTable to TRUE if the result of the SELECT statement
- ** should be written into a temporary table. Set to FALSE if each
- ** row of the SELECT can be written directly into the result table.
- **
- ** A temp table must be used if the table being updated is also one
- ** of the tables being read by the SELECT statement. Also use a
- ** temp table in the case of row triggers.
- */
- if( row_triggers_exist ){
- useTempTable = 1;
- }else{
- int addr = 0;
- useTempTable = 0;
- while( useTempTable==0 ){
- VdbeOp *pOp;
- addr = sqlite3VdbeFindOp(v, addr, OP_OpenRead, pTab->tnum);
- if( addr==0 ) break;
- pOp = sqlite3VdbeGetOp(v, addr-2);
- if( pOp->opcode==OP_Integer && pOp->p1==pTab->iDb ){
- useTempTable = 1;
- }
- }
- }
-
- if( useTempTable ){
- /* Generate the subroutine that SELECT calls to process each row of
- ** the result. Store the result in a temporary table
- */
- srcTab = pParse->nTab++;
- sqlite3VdbeResolveLabel(v, iInsertBlock);
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
- sqlite3TableAffinityStr(v, pTab);
- sqlite3VdbeAddOp(v, OP_NewRecno, srcTab, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- sqlite3VdbeAddOp(v, OP_PutIntKey, srcTab, 0);
- sqlite3VdbeAddOp(v, OP_Return, 0, 0);
-
- /* The following code runs first because the GOTO at the very top
- ** of the program jumps to it. Create the temporary table, then jump
- ** back up and execute the SELECT code above.
- */
- sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v));
- sqlite3VdbeAddOp(v, OP_OpenTemp, srcTab, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn);
- sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
- sqlite3VdbeResolveLabel(v, iCleanup);
- }else{
- sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v));
- }
- }else{
- /* This is the case if the data for the INSERT is coming from a VALUES
- ** clause
- */
- SrcList dummy;
- assert( pList!=0 );
- srcTab = -1;
- useTempTable = 0;
- assert( pList );
- nColumn = pList->nExpr;
- dummy.nSrc = 0;
- for(i=0; i<nColumn; i++){
- if( sqlite3ExprResolveAndCheck(pParse,&dummy,0,pList->a[i].pExpr,0,0) ){
- goto insert_cleanup;
- }
- }
- }
-
- /* Make sure the number of columns in the source data matches the number
- ** of columns to be inserted into the table.
- */
- if( pColumn==0 && nColumn!=pTab->nCol ){
- sqlite3ErrorMsg(pParse,
- "table %S has %d columns but %d values were supplied",
- pTabList, 0, pTab->nCol, nColumn);
- goto insert_cleanup;
- }
- if( pColumn!=0 && nColumn!=pColumn->nId ){
- sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);
- goto insert_cleanup;
- }
-
- /* If the INSERT statement included an IDLIST term, then make sure
- ** all elements of the IDLIST really are columns of the table and
- ** remember the column indices.
- **
- ** If the table has an INTEGER PRIMARY KEY column and that column
- ** is named in the IDLIST, then record in the keyColumn variable
- ** the index into IDLIST of the primary key column. keyColumn is
- ** the index of the primary key as it appears in IDLIST, not as
- ** is appears in the original table. (The index of the primary
- ** key in the original table is pTab->iPKey.)
- */
- if( pColumn ){
- for(i=0; i<pColumn->nId; i++){
- pColumn->a[i].idx = -1;
- }
- for(i=0; i<pColumn->nId; i++){
- for(j=0; j<pTab->nCol; j++){
- if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
- pColumn->a[i].idx = j;
- if( j==pTab->iPKey ){
- keyColumn = i;
- }
- break;
- }
- }
- if( j>=pTab->nCol ){
- if( sqlite3IsRowid(pColumn->a[i].zName) ){
- keyColumn = i;
- }else{
- sqlite3ErrorMsg(pParse, "table %S has no column named %s",
- pTabList, 0, pColumn->a[i].zName);
- pParse->nErr++;
- goto insert_cleanup;
- }
- }
- }
- }
-
- /* If there is no IDLIST term but the table has an integer primary
- ** key, the set the keyColumn variable to the primary key column index
- ** in the original table definition.
- */
- if( pColumn==0 ){
- keyColumn = pTab->iPKey;
- }
-
- /* Open the temp table for FOR EACH ROW triggers
- */
- if( row_triggers_exist ){
- sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
- }
-
- /* Initialize the count of rows to be inserted
- */
- if( db->flags & SQLITE_CountRows ){
- iCntMem = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, iCntMem, 1);
- }
-
- /* Open tables and indices if there are no row triggers */
- if( !row_triggers_exist ){
- base = pParse->nTab;
- sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
- }
-
- /* If the data source is a temporary table, then we have to create
- ** a loop because there might be multiple rows of data. If the data
- ** source is a subroutine call from the SELECT statement, then we need
- ** to launch the SELECT statement processing.
- */
- if( useTempTable ){
- iBreak = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_Rewind, srcTab, iBreak);
- iCont = sqlite3VdbeCurrentAddr(v);
- }else if( pSelect ){
- sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
- sqlite3VdbeResolveLabel(v, iInsertBlock);
- }
-
- /* Run the BEFORE and INSTEAD OF triggers, if there are any
- */
- endOfLoop = sqlite3VdbeMakeLabel(v);
- if( before_triggers ){
-
- /* build the NEW.* reference row. Note that if there is an INTEGER
- ** PRIMARY KEY into which a NULL is being inserted, that NULL will be
- ** translated into a unique ID for the row. But on a BEFORE trigger,
- ** we do not know what the unique ID will be (because the insert has
- ** not happened yet) so we substitute a rowid of -1
- */
- if( keyColumn<0 ){
- sqlite3VdbeAddOp(v, OP_Integer, -1, 0);
- }else if( useTempTable ){
- sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn);
- }else if( pSelect ){
- sqlite3VdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
- }else{
- sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr);
- sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeAddOp(v, OP_Integer, -1, 0);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
- }
-
- /* Create the new column data
- */
- for(i=0; i<pTab->nCol; i++){
- if( pColumn==0 ){
- j = i;
- }else{
- for(j=0; j<pColumn->nId; j++){
- if( pColumn->a[j].idx==i ) break;
- }
- }
- if( pColumn && j>=pColumn->nId ){
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
- }else if( useTempTable ){
- sqlite3VdbeAddOp(v, OP_Column, srcTab, j);
- }else if( pSelect ){
- sqlite3VdbeAddOp(v, OP_Dup, nColumn-j-1, 1);
- }else{
- sqlite3ExprCode(pParse, pList->a[j].pExpr);
- }
- }
- sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
-
- /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
- ** do not attempt any conversions before assembling the record.
- ** If this is a real table, attempt conversions as required by the
- ** table column affinities.
- */
- if( !isView ){
- sqlite3TableAffinityStr(v, pTab);
- }
- sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
-
- /* Fire BEFORE or INSTEAD OF triggers */
- if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TK_BEFORE, pTab,
- newIdx, -1, onError, endOfLoop) ){
- goto insert_cleanup;
- }
- }
-
- /* If any triggers exists, the opening of tables and indices is deferred
- ** until now.
- */
- if( row_triggers_exist && !isView ){
- base = pParse->nTab;
- sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
- }
-
- /* Push the record number for the new entry onto the stack. The
- ** record number is a randomly generate integer created by NewRecno
- ** except when the table has an INTEGER PRIMARY KEY column, in which
- ** case the record number is the same as that column.
- */
- if( !isView ){
- if( keyColumn>=0 ){
- if( useTempTable ){
- sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn);
- }else if( pSelect ){
- sqlite3VdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
- }else{
- sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr);
- }
- /* If the PRIMARY KEY expression is NULL, then use OP_NewRecno
- ** to generate a unique primary key value.
- */
- sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeAddOp(v, OP_NewRecno, base, 0);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
- }else{
- sqlite3VdbeAddOp(v, OP_NewRecno, base, 0);
- }
-
- /* Push onto the stack, data for all columns of the new entry, beginning
- ** with the first column.
- */
- for(i=0; i<pTab->nCol; i++){
- if( i==pTab->iPKey ){
- /* The value of the INTEGER PRIMARY KEY column is always a NULL.
- ** Whenever this column is read, the record number will be substituted
- ** in its place. So will fill this column with a NULL to avoid
- ** taking up data space with information that will never be used. */
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- continue;
- }
- if( pColumn==0 ){
- j = i;
- }else{
- for(j=0; j<pColumn->nId; j++){
- if( pColumn->a[j].idx==i ) break;
- }
- }
- if( pColumn && j>=pColumn->nId ){
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
- }else if( useTempTable ){
- sqlite3VdbeAddOp(v, OP_Column, srcTab, j);
- }else if( pSelect ){
- sqlite3VdbeAddOp(v, OP_Dup, i+nColumn-j, 1);
- }else{
- sqlite3ExprCode(pParse, pList->a[j].pExpr);
- }
- }
-
- /* Generate code to check constraints and generate index keys and
- ** do the insertion.
- */
- sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
- 0, onError, endOfLoop);
- sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
- after_triggers ? newIdx : -1);
- }
-
- /* Update the count of rows that are inserted
- */
- if( (db->flags & SQLITE_CountRows)!=0 ){
- sqlite3VdbeAddOp(v, OP_MemIncr, iCntMem, 0);
- }
-
- if( row_triggers_exist ){
- /* Close all tables opened */
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Close, base, 0);
- for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
- sqlite3VdbeAddOp(v, OP_Close, idx+base, 0);
- }
- }
-
- /* Code AFTER triggers */
- if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TK_AFTER, pTab, newIdx, -1,
- onError, endOfLoop) ){
- goto insert_cleanup;
- }
- }
-
- /* The bottom of the loop, if the data source is a SELECT statement
- */
- sqlite3VdbeResolveLabel(v, endOfLoop);
- if( useTempTable ){
- sqlite3VdbeAddOp(v, OP_Next, srcTab, iCont);
- sqlite3VdbeResolveLabel(v, iBreak);
- sqlite3VdbeAddOp(v, OP_Close, srcTab, 0);
- }else if( pSelect ){
- sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
- sqlite3VdbeAddOp(v, OP_Return, 0, 0);
- sqlite3VdbeResolveLabel(v, iCleanup);
- }
-
- if( !row_triggers_exist ){
- /* Close all tables opened */
- sqlite3VdbeAddOp(v, OP_Close, base, 0);
- for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
- sqlite3VdbeAddOp(v, OP_Close, idx+base, 0);
- }
- }
-
- /*
- ** Return the number of rows inserted.
- */
- if( db->flags & SQLITE_CountRows ){
- sqlite3VdbeAddOp(v, OP_MemLoad, iCntMem, 0);
- sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, "rows inserted", P3_STATIC);
- }
-
-insert_cleanup:
- sqlite3SrcListDelete(pTabList);
- if( pList ) sqlite3ExprListDelete(pList);
- if( pSelect ) sqlite3SelectDelete(pSelect);
- sqlite3IdListDelete(pColumn);
-}
-
-/*
-** Generate code to do a constraint check prior to an INSERT or an UPDATE.
-**
-** When this routine is called, the stack contains (from bottom to top)
-** the following values:
-**
-** 1. The recno of the row to be updated before the update. This
-** value is omitted unless we are doing an UPDATE that involves a
-** change to the record number.
-**
-** 2. The recno of the row after the update.
-**
-** 3. The data in the first column of the entry after the update.
-**
-** i. Data from middle columns...
-**
-** N. The data in the last column of the entry after the update.
-**
-** The old recno shown as entry (1) above is omitted unless both isUpdate
-** and recnoChng are 1. isUpdate is true for UPDATEs and false for
-** INSERTs and recnoChng is true if the record number is being changed.
-**
-** The code generated by this routine pushes additional entries onto
-** the stack which are the keys for new index entries for the new record.
-** The order of index keys is the same as the order of the indices on
-** the pTable->pIndex list. A key is only created for index i if
-** aIdxUsed!=0 and aIdxUsed[i]!=0.
-**
-** This routine also generates code to check constraints. NOT NULL,
-** CHECK, and UNIQUE constraints are all checked. If a constraint fails,
-** then the appropriate action is performed. There are five possible
-** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE.
-**
-** Constraint type Action What Happens
-** --------------- ---------- ----------------------------------------
-** any ROLLBACK The current transaction is rolled back and
-** sqlite3_exec() returns immediately with a
-** return code of SQLITE_CONSTRAINT.
-**
-** any ABORT Back out changes from the current command
-** only (do not do a complete rollback) then
-** cause sqlite3_exec() to return immediately
-** with SQLITE_CONSTRAINT.
-**
-** any FAIL Sqlite_exec() returns immediately with a
-** return code of SQLITE_CONSTRAINT. The
-** transaction is not rolled back and any
-** prior changes are retained.
-**
-** any IGNORE The record number and data is popped from
-** the stack and there is an immediate jump
-** to label ignoreDest.
-**
-** NOT NULL REPLACE The NULL value is replace by the default
-** value for that column. If the default value
-** is NULL, the action is the same as ABORT.
-**
-** UNIQUE REPLACE The other row that conflicts with the row
-** being inserted is removed.
-**
-** CHECK REPLACE Illegal. The results in an exception.
-**
-** Which action to take is determined by the overrideError parameter.
-** Or if overrideError==OE_Default, then the pParse->onError parameter
-** is used. Or if pParse->onError==OE_Default then the onError value
-** for the constraint is used.
-**
-** The calling routine must open a read/write cursor for pTab with
-** cursor number "base". All indices of pTab must also have open
-** read/write cursors with cursor number base+i for the i-th cursor.
-** Except, if there is no possibility of a REPLACE action then
-** cursors do not need to be open for indices where aIdxUsed[i]==0.
-**
-** If the isUpdate flag is true, it means that the "base" cursor is
-** initially pointing to an entry that is being updated. The isUpdate
-** flag causes extra code to be generated so that the "base" cursor
-** is still pointing at the same entry after the routine returns.
-** Without the isUpdate flag, the "base" cursor might be moved.
-*/
-void sqlite3GenerateConstraintChecks(
- Parse *pParse, /* The parser context */
- Table *pTab, /* the table into which we are inserting */
- int base, /* Index of a read/write cursor pointing at pTab */
- char *aIdxUsed, /* Which indices are used. NULL means all are used */
- int recnoChng, /* True if the record number will change */
- int isUpdate, /* True for UPDATE, False for INSERT */
- int overrideError, /* Override onError to this if not OE_Default */
- int ignoreDest /* Jump to this label on an OE_Ignore resolution */
-){
- int i;
- Vdbe *v;
- int nCol;
- int onError;
- int addr;
- int extra;
- int iCur;
- Index *pIdx;
- int seenReplace = 0;
- int jumpInst1=0, jumpInst2;
- int contAddr;
- int hasTwoRecnos = (isUpdate && recnoChng);
-
- v = sqlite3GetVdbe(pParse);
- assert( v!=0 );
- assert( pTab->pSelect==0 ); /* This table is not a VIEW */
- nCol = pTab->nCol;
-
- /* Test all NOT NULL constraints.
- */
- for(i=0; i<nCol; i++){
- if( i==pTab->iPKey ){
- continue;
- }
- onError = pTab->aCol[i].notNull;
- if( onError==OE_None ) continue;
- if( overrideError!=OE_Default ){
- onError = overrideError;
- }else if( onError==OE_Default ){
- onError = OE_Abort;
- }
- if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){
- onError = OE_Abort;
- }
- sqlite3VdbeAddOp(v, OP_Dup, nCol-1-i, 1);
- addr = sqlite3VdbeAddOp(v, OP_NotNull, 1, 0);
- switch( onError ){
- case OE_Rollback:
- case OE_Abort:
- case OE_Fail: {
- char *zMsg = 0;
- sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
- sqlite3SetString(&zMsg, pTab->zName, ".", pTab->aCol[i].zName,
- " may not be NULL", (char*)0);
- sqlite3VdbeChangeP3(v, -1, zMsg, P3_DYNAMIC);
- break;
- }
- case OE_Ignore: {
- sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest);
- break;
- }
- case OE_Replace: {
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
- sqlite3VdbeAddOp(v, OP_Push, nCol-i, 0);
- break;
- }
- default: assert(0);
- }
- sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
- }
-
- /* Test all CHECK constraints
- */
- /**** TBD ****/
-
- /* If we have an INTEGER PRIMARY KEY, make sure the primary key
- ** of the new record does not previously exist. Except, if this
- ** is an UPDATE and the primary key is not changing, that is OK.
- */
- if( recnoChng ){
- onError = pTab->keyConf;
- if( overrideError!=OE_Default ){
- onError = overrideError;
- }else if( onError==OE_Default ){
- onError = OE_Abort;
- }
-
- if( isUpdate ){
- sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);
- sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);
- jumpInst1 = sqlite3VdbeAddOp(v, OP_Eq, 0, 0);
- }
- sqlite3VdbeAddOp(v, OP_Dup, nCol, 1);
- jumpInst2 = sqlite3VdbeAddOp(v, OP_NotExists, base, 0);
- switch( onError ){
- default: {
- onError = OE_Abort;
- /* Fall thru into the next case */
- }
- case OE_Rollback:
- case OE_Abort:
- case OE_Fail: {
- sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError,
- "PRIMARY KEY must be unique", P3_STATIC);
- break;
- }
- case OE_Replace: {
- sqlite3GenerateRowIndexDelete(pParse->db, v, pTab, base, 0);
- if( isUpdate ){
- sqlite3VdbeAddOp(v, OP_Dup, nCol+hasTwoRecnos, 1);
- sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
- }
- seenReplace = 1;
- break;
- }
- case OE_Ignore: {
- assert( seenReplace==0 );
- sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest);
- break;
- }
- }
- contAddr = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeChangeP2(v, jumpInst2, contAddr);
- if( isUpdate ){
- sqlite3VdbeChangeP2(v, jumpInst1, contAddr);
- sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);
- sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
- }
- }
-
- /* Test all UNIQUE constraints by creating entries for each UNIQUE
- ** index and making sure that duplicate entries do not already exist.
- ** Add the new records to the indices as we go.
- */
- extra = -1;
- for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
- if( aIdxUsed && aIdxUsed[iCur]==0 ) continue; /* Skip unused indices */
- extra++;
-
- /* Create a key for accessing the index entry */
- sqlite3VdbeAddOp(v, OP_Dup, nCol+extra, 1);
- for(i=0; i<pIdx->nColumn; i++){
- int idx = pIdx->aiColumn[i];
- if( idx==pTab->iPKey ){
- sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol+1, 1);
- }else{
- sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1);
- }
- }
- jumpInst1 = sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24));
- sqlite3IndexAffinityStr(v, pIdx);
-
- /* Find out what action to take in case there is an indexing conflict */
- onError = pIdx->onError;
- if( onError==OE_None ) continue; /* pIdx is not a UNIQUE index */
- if( overrideError!=OE_Default ){
- onError = overrideError;
- }else if( onError==OE_Default ){
- onError = OE_Abort;
- }
- if( seenReplace ){
- if( onError==OE_Ignore ) onError = OE_Replace;
- else if( onError==OE_Fail ) onError = OE_Abort;
- }
-
-
- /* Check to see if the new index entry will be unique */
- sqlite3VdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1);
- jumpInst2 = sqlite3VdbeAddOp(v, OP_IsUnique, base+iCur+1, 0);
-
- /* Generate code that executes if the new index entry is not unique */
- switch( onError ){
- case OE_Rollback:
- case OE_Abort:
- case OE_Fail: {
- int j, n1, n2;
- char zErrMsg[200];
- strcpy(zErrMsg, pIdx->nColumn>1 ? "columns " : "column ");
- n1 = strlen(zErrMsg);
- for(j=0; j<pIdx->nColumn && n1<sizeof(zErrMsg)-30; j++){
- char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
- n2 = strlen(zCol);
- if( j>0 ){
- strcpy(&zErrMsg[n1], ", ");
- n1 += 2;
- }
- if( n1+n2>sizeof(zErrMsg)-30 ){
- strcpy(&zErrMsg[n1], "...");
- n1 += 3;
- break;
- }else{
- strcpy(&zErrMsg[n1], zCol);
- n1 += n2;
- }
- }
- strcpy(&zErrMsg[n1],
- pIdx->nColumn>1 ? " are not unique" : " is not unique");
- sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, zErrMsg, 0);
- break;
- }
- case OE_Ignore: {
- assert( seenReplace==0 );
- sqlite3VdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRecnos, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest);
- break;
- }
- case OE_Replace: {
- sqlite3GenerateRowDelete(pParse->db, v, pTab, base, 0);
- if( isUpdate ){
- sqlite3VdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1);
- sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
- }
- seenReplace = 1;
- break;
- }
- default: assert(0);
- }
- contAddr = sqlite3VdbeCurrentAddr(v);
- assert( contAddr<(1<<24) );
-#if NULL_DISTINCT_FOR_UNIQUE
- sqlite3VdbeChangeP2(v, jumpInst1, contAddr | (1<<24));
-#endif
- sqlite3VdbeChangeP2(v, jumpInst2, contAddr);
- }
-}
-
-/*
-** This routine generates code to finish the INSERT or UPDATE operation
-** that was started by a prior call to sqlite3GenerateConstraintChecks.
-** The stack must contain keys for all active indices followed by data
-** and the recno for the new entry. This routine creates the new
-** entries in all indices and in the main table.
-**
-** The arguments to this routine should be the same as the first six
-** arguments to sqlite3GenerateConstraintChecks.
-*/
-void sqlite3CompleteInsertion(
- Parse *pParse, /* The parser context */
- Table *pTab, /* the table into which we are inserting */
- int base, /* Index of a read/write cursor pointing at pTab */
- char *aIdxUsed, /* Which indices are used. NULL means all are used */
- int recnoChng, /* True if the record number will change */
- int isUpdate, /* True for UPDATE, False for INSERT */
- int newIdx /* Index of NEW table for triggers. -1 if none */
-){
- int i;
- Vdbe *v;
- int nIdx;
- Index *pIdx;
- int pik_flags;
-
- v = sqlite3GetVdbe(pParse);
- assert( v!=0 );
- assert( pTab->pSelect==0 ); /* This table is not a VIEW */
- for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
- for(i=nIdx-1; i>=0; i--){
- if( aIdxUsed && aIdxUsed[i]==0 ) continue;
- sqlite3VdbeAddOp(v, OP_IdxPut, base+i+1, 0);
- }
- sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
- sqlite3TableAffinityStr(v, pTab);
- if( newIdx>=0 ){
- sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
- sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
- sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
- }
- pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID));
- sqlite3VdbeAddOp(v, OP_PutIntKey, base, pik_flags);
-
- if( isUpdate && recnoChng ){
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- }
-}
-
-/*
-** Generate code that will open cursors for a table and for all
-** indices of that table. The "base" parameter is the cursor number used
-** for the table. Indices are opened on subsequent cursors.
-*/
-void sqlite3OpenTableAndIndices(
- Parse *pParse, /* Parsing context */
- Table *pTab, /* Table to be opened */
- int base, /* Cursor number assigned to the table */
- int op /* OP_OpenRead or OP_OpenWrite */
-){
- int i;
- Index *pIdx;
- Vdbe *v = sqlite3GetVdbe(pParse);
- assert( v!=0 );
- sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
- sqlite3VdbeAddOp(v, op, base, pTab->tnum);
- VdbeComment((v, "# %s", pTab->zName));
- sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol);
- for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
- sqlite3VdbeOp3(v, op, i+base, pIdx->tnum,
- (char*)&pIdx->keyInfo, P3_KEYINFO);
- }
- if( pParse->nTab<=base+i ){
- pParse->nTab = base+i;
- }
-}
diff --git a/kopete/plugins/statistics/sqlite/legacy.c b/kopete/plugins/statistics/sqlite/legacy.c
deleted file mode 100644
index f575f1f0..00000000
--- a/kopete/plugins/statistics/sqlite/legacy.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** Main file for the SQLite library. The routines in this file
-** implement the programmer interface to the library. Routines in
-** other files are for internal use by SQLite and should not be
-** accessed by users of the library.
-**
-** $Id$
-*/
-
-#include "sqliteInt.h"
-#include "os.h"
-#include <ctype.h>
-
-/*
-** Execute SQL code. Return one of the SQLITE_ success/failure
-** codes. Also write an error message into memory obtained from
-** malloc() and make *pzErrMsg point to that message.
-**
-** If the SQL is a query, then for each row in the query result
-** the xCallback() function is called. pArg becomes the first
-** argument to xCallback(). If xCallback=NULL then no callback
-** is invoked, even for queries.
-*/
-int sqlite3_exec(
- sqlite3 *db, /* The database on which the SQL executes */
- const char *zSql, /* The SQL to be executed */
- sqlite3_callback xCallback, /* Invoke this callback routine */
- void *pArg, /* First argument to xCallback() */
- char **pzErrMsg /* Write error messages here */
-){
- int rc = SQLITE_OK;
- const char *zLeftover;
- sqlite3_stmt *pStmt = 0;
- char **azCols = 0;
-
- int nRetry = 0;
- int nChange = 0;
- int nCallback;
-
- if( zSql==0 ) return SQLITE_OK;
- while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
- int nCol;
- char **azVals = 0;
-
- pStmt = 0;
- rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover);
- if( rc!=SQLITE_OK ){
- if( pStmt ) sqlite3_finalize(pStmt);
- continue;
- }
- if( !pStmt ){
- /* this happens for a comment or white-space */
- zSql = zLeftover;
- continue;
- }
-
- db->nChange += nChange;
- nCallback = 0;
-
- nCol = sqlite3_column_count(pStmt);
- azCols = sqliteMalloc(2*nCol*sizeof(const char *));
- if( nCol && !azCols ){
- rc = SQLITE_NOMEM;
- goto exec_out;
- }
-
- while( 1 ){
- int i;
- rc = sqlite3_step(pStmt);
-
- /* Invoke the callback function if required */
- if( xCallback && (SQLITE_ROW==rc ||
- (SQLITE_DONE==rc && !nCallback && db->flags&SQLITE_NullCallback)) ){
- if( 0==nCallback ){
- for(i=0; i<nCol; i++){
- azCols[i] = (char *)sqlite3_column_name(pStmt, i);
- }
- nCallback++;
- }
- if( rc==SQLITE_ROW ){
- azVals = &azCols[nCol];
- for(i=0; i<nCol; i++){
- azVals[i] = (char *)sqlite3_column_text(pStmt, i);
- }
- }
- if( xCallback(pArg, nCol, azVals, azCols) ){
- rc = SQLITE_ABORT;
- goto exec_out;
- }
- }
-
- if( rc!=SQLITE_ROW ){
- rc = sqlite3_finalize(pStmt);
- pStmt = 0;
- if( db->pVdbe==0 ){
- nChange = db->nChange;
- }
- if( rc!=SQLITE_SCHEMA ){
- nRetry = 0;
- zSql = zLeftover;
- while( isspace((unsigned char)zSql[0]) ) zSql++;
- }
- break;
- }
- }
-
- sqliteFree(azCols);
- azCols = 0;
- }
-
-exec_out:
- if( pStmt ) sqlite3_finalize(pStmt);
- if( azCols ) sqliteFree(azCols);
-
- if( sqlite3_malloc_failed ){
- rc = SQLITE_NOMEM;
- }
- if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
- *pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db)));
- if( *pzErrMsg ){
- strcpy(*pzErrMsg, sqlite3_errmsg(db));
- }
- }else if( pzErrMsg ){
- *pzErrMsg = 0;
- }
-
- return rc;
-}
diff --git a/kopete/plugins/statistics/sqlite/lempar.c b/kopete/plugins/statistics/sqlite/lempar.c
deleted file mode 100644
index ee1edbfa..00000000
--- a/kopete/plugins/statistics/sqlite/lempar.c
+++ /dev/null
@@ -1,687 +0,0 @@
-/* Driver template for the LEMON parser generator.
-** The author disclaims copyright to this source code.
-*/
-/* First off, code is include which follows the "include" declaration
-** in the input file. */
-#include <stdio.h>
-%%
-/* Next is all token values, in a form suitable for use by makeheaders.
-** This section will be null unless lemon is run with the -m switch.
-*/
-/*
-** These constants (all generated automatically by the parser generator)
-** specify the various kinds of tokens (terminals) that the parser
-** understands.
-**
-** Each symbol here is a terminal symbol in the grammar.
-*/
-%%
-/* Make sure the INTERFACE macro is defined.
-*/
-#ifndef INTERFACE
-# define INTERFACE 1
-#endif
-/* The next thing included is series of defines which control
-** various aspects of the generated parser.
-** YYCODETYPE is the data type used for storing terminal
-** and nonterminal numbers. "unsigned char" is
-** used if there are fewer than 250 terminals
-** and nonterminals. "int" is used otherwise.
-** YYNOCODE is a number of type YYCODETYPE which corresponds
-** to no legal terminal or nonterminal number. This
-** number is used to fill in empty slots of the hash
-** table.
-** YYFALLBACK If defined, this indicates that one or more tokens
-** have fall-back values which should be used if the
-** original value of the token will not parse.
-** YYACTIONTYPE is the data type used for storing terminal
-** and nonterminal numbers. "unsigned char" is
-** used if there are fewer than 250 rules and
-** states combined. "int" is used otherwise.
-** ParseTOKENTYPE is the data type used for minor tokens given
-** directly to the parser from the tokenizer.
-** YYMINORTYPE is the data type used for all minor tokens.
-** This is typically a union of many types, one of
-** which is ParseTOKENTYPE. The entry in the union
-** for base tokens is called "yy0".
-** YYSTACKDEPTH is the maximum depth of the parser's stack.
-** ParseARG_SDECL A static variable declaration for the %extra_argument
-** ParseARG_PDECL A parameter declaration for the %extra_argument
-** ParseARG_STORE Code to store %extra_argument into yypParser
-** ParseARG_FETCH Code to extract %extra_argument from yypParser
-** YYNSTATE the combined number of states.
-** YYNRULE the number of rules in the grammar
-** YYERRORSYMBOL is the code number of the error symbol. If not
-** defined, then do no error processing.
-*/
-%%
-#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
-#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
-#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
-
-/* Next are that tables used to determine what action to take based on the
-** current state and lookahead token. These tables are used to implement
-** functions that take a state number and lookahead value and return an
-** action integer.
-**
-** Suppose the action integer is N. Then the action is determined as
-** follows
-**
-** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
-** token onto the stack and goto state N.
-**
-** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
-**
-** N == YYNSTATE+YYNRULE A syntax error has occurred.
-**
-** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
-**
-** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
-** slots in the yy_action[] table.
-**
-** The action table is constructed as a single large table named yy_action[].
-** Given state S and lookahead X, the action is computed as
-**
-** yy_action[ yy_shift_ofst[S] + X ]
-**
-** If the index value yy_shift_ofst[S]+X is out of range or if the value
-** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
-** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
-** and that yy_default[S] should be used instead.
-**
-** The formula above is for computing the action when the lookahead is
-** a terminal symbol. If the lookahead is a non-terminal (as occurs after
-** a reduce action) then the yy_reduce_ofst[] array is used in place of
-** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
-** YY_SHIFT_USE_DFLT.
-**
-** The following are the tables generated in this section:
-**
-** yy_action[] A single table containing all actions.
-** yy_lookahead[] A table containing the lookahead for each entry in
-** yy_action. Used to detect hash collisions.
-** yy_shift_ofst[] For each state, the offset into yy_action for
-** shifting terminals.
-** yy_reduce_ofst[] For each state, the offset into yy_action for
-** shifting non-terminals after a reduce.
-** yy_default[] Default action for each state.
-*/
-%%
-#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
-
-/* The next table maps tokens into fallback tokens. If a construct
-** like the following:
-**
-** %fallback ID X Y Z.
-**
-** appears in the grammer, then ID becomes a fallback token for X, Y,
-** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
-** but it does not parse, the type of the token is changed to ID and
-** the parse is retried before an error is thrown.
-*/
-#ifdef YYFALLBACK
-static const YYCODETYPE yyFallback[] = {
-%%
-};
-#endif /* YYFALLBACK */
-
-/* The following structure represents a single element of the
-** parser's stack. Information stored includes:
-**
-** + The state number for the parser at this level of the stack.
-**
-** + The value of the token stored at this level of the stack.
-** (In other words, the "major" token.)
-**
-** + The semantic value stored at this level of the stack. This is
-** the information used by the action routines in the grammar.
-** It is sometimes called the "minor" token.
-*/
-struct yyStackEntry {
- int stateno; /* The state-number */
- int major; /* The major token value. This is the code
- ** number for the token at this stack level */
- YYMINORTYPE minor; /* The user-supplied minor token value. This
- ** is the value of the token */
-};
-typedef struct yyStackEntry yyStackEntry;
-
-/* The state of the parser is completely contained in an instance of
-** the following structure */
-struct yyParser {
- int yyidx; /* Index of top element in stack */
- int yyerrcnt; /* Shifts left before out of the error */
- ParseARG_SDECL /* A place to hold %extra_argument */
- yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
-};
-typedef struct yyParser yyParser;
-
-#ifndef NDEBUG
-#include <stdio.h>
-static FILE *yyTraceFILE = 0;
-static char *yyTracePrompt = 0;
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/*
-** Turn parser tracing on by giving a stream to which to write the trace
-** and a prompt to preface each trace message. Tracing is turned off
-** by making either argument NULL
-**
-** Inputs:
-** <ul>
-** <li> A FILE* to which trace output should be written.
-** If NULL, then tracing is turned off.
-** <li> A prefix string written at the beginning of every
-** line of trace output. If NULL, then tracing is
-** turned off.
-** </ul>
-**
-** Outputs:
-** None.
-*/
-void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
- yyTraceFILE = TraceFILE;
- yyTracePrompt = zTracePrompt;
- if( yyTraceFILE==0 ) yyTracePrompt = 0;
- else if( yyTracePrompt==0 ) yyTraceFILE = 0;
-}
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/* For tracing shifts, the names of all terminals and nonterminals
-** are required. The following table supplies these names */
-static const char *yyTokenName[] = {
-%%
-};
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/* For tracing reduce actions, the names of all rules are required.
-*/
-static const char *yyRuleName[] = {
-%%
-};
-#endif /* NDEBUG */
-
-/*
-** This function returns the symbolic name associated with a token
-** value.
-*/
-const char *ParseTokenName(int tokenType){
-#ifndef NDEBUG
- if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
- return yyTokenName[tokenType];
- }else{
- return "Unknown";
- }
-#else
- return "";
-#endif
-}
-
-/*
-** This function allocates a new parser.
-** The only argument is a pointer to a function which works like
-** malloc.
-**
-** Inputs:
-** A pointer to the function used to allocate memory.
-**
-** Outputs:
-** A pointer to a parser. This pointer is used in subsequent calls
-** to Parse and ParseFree.
-*/
-void *ParseAlloc(void *(*mallocProc)(size_t)){
- yyParser *pParser;
- pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
- if( pParser ){
- pParser->yyidx = -1;
- }
- return pParser;
-}
-
-/* The following function deletes the value associated with a
-** symbol. The symbol can be either a terminal or nonterminal.
-** "yymajor" is the symbol code, and "yypminor" is a pointer to
-** the value.
-*/
-static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
- switch( yymajor ){
- /* Here is inserted the actions which take place when a
- ** terminal or non-terminal is destroyed. This can happen
- ** when the symbol is popped from the stack during a
- ** reduce or during error processing or when a parser is
- ** being destroyed before it is finished parsing.
- **
- ** Note: during a reduce, the only symbols destroyed are those
- ** which appear on the RHS of the rule, but which are not used
- ** inside the C code.
- */
-%%
- default: break; /* If no destructor action specified: do nothing */
- }
-}
-
-/*
-** Pop the parser's stack once.
-**
-** If there is a destructor routine associated with the token which
-** is popped from the stack, then call it.
-**
-** Return the major token number for the symbol popped.
-*/
-static int yy_pop_parser_stack(yyParser *pParser){
- YYCODETYPE yymajor;
- yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
-
- if( pParser->yyidx<0 ) return 0;
-#ifndef NDEBUG
- if( yyTraceFILE && pParser->yyidx>=0 ){
- fprintf(yyTraceFILE,"%sPopping %s\n",
- yyTracePrompt,
- yyTokenName[yytos->major]);
- }
-#endif
- yymajor = yytos->major;
- yy_destructor( yymajor, &yytos->minor);
- pParser->yyidx--;
- return yymajor;
-}
-
-/*
-** Deallocate and destroy a parser. Destructors are all called for
-** all stack elements before shutting the parser down.
-**
-** Inputs:
-** <ul>
-** <li> A pointer to the parser. This should be a pointer
-** obtained from ParseAlloc.
-** <li> A pointer to a function used to reclaim memory obtained
-** from malloc.
-** </ul>
-*/
-void ParseFree(
- void *p, /* The parser to be deleted */
- void (*freeProc)(void*) /* Function used to reclaim memory */
-){
- yyParser *pParser = (yyParser*)p;
- if( pParser==0 ) return;
- while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
- (*freeProc)((void*)pParser);
-}
-
-/*
-** Find the appropriate action for a parser given the terminal
-** look-ahead token iLookAhead.
-**
-** If the look-ahead token is YYNOCODE, then check to see if the action is
-** independent of the look-ahead. If it is, return the action, otherwise
-** return YY_NO_ACTION.
-*/
-static int yy_find_shift_action(
- yyParser *pParser, /* The parser */
- int iLookAhead /* The look-ahead token */
-){
- int i;
- int stateno = pParser->yystack[pParser->yyidx].stateno;
-
- /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
- i = yy_shift_ofst[stateno];
- if( i==YY_SHIFT_USE_DFLT ){
- return yy_default[stateno];
- }
- if( iLookAhead==YYNOCODE ){
- return YY_NO_ACTION;
- }
- i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
-#ifdef YYFALLBACK
- int iFallback; /* Fallback token */
- if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
- && (iFallback = yyFallback[iLookAhead])!=0 ){
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
- yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
- }
-#endif
- return yy_find_shift_action(pParser, iFallback);
- }
-#endif
- return yy_default[stateno];
- }else{
- return yy_action[i];
- }
-}
-
-/*
-** Find the appropriate action for a parser given the non-terminal
-** look-ahead token iLookAhead.
-**
-** If the look-ahead token is YYNOCODE, then check to see if the action is
-** independent of the look-ahead. If it is, return the action, otherwise
-** return YY_NO_ACTION.
-*/
-static int yy_find_reduce_action(
- yyParser *pParser, /* The parser */
- int iLookAhead /* The look-ahead token */
-){
- int i;
- int stateno = pParser->yystack[pParser->yyidx].stateno;
-
- i = yy_reduce_ofst[stateno];
- if( i==YY_REDUCE_USE_DFLT ){
- return yy_default[stateno];
- }
- if( iLookAhead==YYNOCODE ){
- return YY_NO_ACTION;
- }
- i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
- return yy_default[stateno];
- }else{
- return yy_action[i];
- }
-}
-
-/*
-** Perform a shift action.
-*/
-static void yy_shift(
- yyParser *yypParser, /* The parser to be shifted */
- int yyNewState, /* The new state to shift in */
- int yyMajor, /* The major token to shift in */
- YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
-){
- yyStackEntry *yytos;
- yypParser->yyidx++;
- if( yypParser->yyidx>=YYSTACKDEPTH ){
- ParseARG_FETCH;
- yypParser->yyidx--;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will execute if the parser
- ** stack every overflows */
-%%
- ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
- return;
- }
- yytos = &yypParser->yystack[yypParser->yyidx];
- yytos->stateno = yyNewState;
- yytos->major = yyMajor;
- yytos->minor = *yypMinor;
-#ifndef NDEBUG
- if( yyTraceFILE && yypParser->yyidx>0 ){
- int i;
- fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
- fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
- for(i=1; i<=yypParser->yyidx; i++)
- fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
- fprintf(yyTraceFILE,"\n");
- }
-#endif
-}
-
-/* The following table contains information about every rule that
-** is used during the reduce.
-*/
-static struct {
- YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
- unsigned char nrhs; /* Number of right-hand side symbols in the rule */
-} yyRuleInfo[] = {
-%%
-};
-
-static void yy_accept(yyParser*); /* Forward Declaration */
-
-/*
-** Perform a reduce action and the shift that must immediately
-** follow the reduce.
-*/
-static void yy_reduce(
- yyParser *yypParser, /* The parser */
- int yyruleno /* Number of the rule by which to reduce */
-){
- int yygoto; /* The next state */
- int yyact; /* The next action */
- YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
- yyStackEntry *yymsp; /* The top of the parser's stack */
- int yysize; /* Amount to pop the stack */
- ParseARG_FETCH;
- yymsp = &yypParser->yystack[yypParser->yyidx];
-#ifndef NDEBUG
- if( yyTraceFILE && yyruleno>=0
- && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
- fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
- yyRuleName[yyruleno]);
- }
-#endif /* NDEBUG */
-
- switch( yyruleno ){
- /* Beginning here are the reduction cases. A typical example
- ** follows:
- ** case 0:
- ** #line <lineno> <grammarfile>
- ** { ... } // User supplied code
- ** #line <lineno> <thisfile>
- ** break;
- */
-%%
- };
- yygoto = yyRuleInfo[yyruleno].lhs;
- yysize = yyRuleInfo[yyruleno].nrhs;
- yypParser->yyidx -= yysize;
- yyact = yy_find_reduce_action(yypParser,yygoto);
- if( yyact < YYNSTATE ){
- yy_shift(yypParser,yyact,yygoto,&yygotominor);
- }else if( yyact == YYNSTATE + YYNRULE + 1 ){
- yy_accept(yypParser);
- }
-}
-
-/*
-** The following code executes when the parse fails
-*/
-static void yy_parse_failed(
- yyParser *yypParser /* The parser */
-){
- ParseARG_FETCH;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will be executed whenever the
- ** parser fails */
-%%
- ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-
-/*
-** The following code executes when a syntax error first occurs.
-*/
-static void yy_syntax_error(
- yyParser *yypParser, /* The parser */
- int yymajor, /* The major type of the error token */
- YYMINORTYPE yyminor /* The minor type of the error token */
-){
- ParseARG_FETCH;
-#define TOKEN (yyminor.yy0)
-%%
- ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-
-/*
-** The following is executed when the parser accepts
-*/
-static void yy_accept(
- yyParser *yypParser /* The parser */
-){
- ParseARG_FETCH;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will be executed whenever the
- ** parser accepts */
-%%
- ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-
-/* The main parser program.
-** The first argument is a pointer to a structure obtained from
-** "ParseAlloc" which describes the current state of the parser.
-** The second argument is the major token number. The third is
-** the minor token. The fourth optional argument is whatever the
-** user wants (and specified in the grammar) and is available for
-** use by the action routines.
-**
-** Inputs:
-** <ul>
-** <li> A pointer to the parser (an opaque structure.)
-** <li> The major token number.
-** <li> The minor token number.
-** <li> An option argument of a grammar-specified type.
-** </ul>
-**
-** Outputs:
-** None.
-*/
-void Parse(
- void *yyp, /* The parser */
- int yymajor, /* The major token code number */
- ParseTOKENTYPE yyminor /* The value for the token */
- ParseARG_PDECL /* Optional %extra_argument parameter */
-){
- YYMINORTYPE yyminorunion;
- int yyact; /* The parser action. */
- int yyendofinput; /* True if we are at the end of input */
- int yyerrorhit = 0; /* True if yymajor has invoked an error */
- yyParser *yypParser; /* The parser */
-
- /* (re)initialize the parser, if necessary */
- yypParser = (yyParser*)yyp;
- if( yypParser->yyidx<0 ){
- if( yymajor==0 ) return;
- yypParser->yyidx = 0;
- yypParser->yyerrcnt = -1;
- yypParser->yystack[0].stateno = 0;
- yypParser->yystack[0].major = 0;
- }
- yyminorunion.yy0 = yyminor;
- yyendofinput = (yymajor==0);
- ParseARG_STORE;
-
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
- }
-#endif
-
- do{
- yyact = yy_find_shift_action(yypParser,yymajor);
- if( yyact<YYNSTATE ){
- yy_shift(yypParser,yyact,yymajor,&yyminorunion);
- yypParser->yyerrcnt--;
- if( yyendofinput && yypParser->yyidx>=0 ){
- yymajor = 0;
- }else{
- yymajor = YYNOCODE;
- }
- }else if( yyact < YYNSTATE + YYNRULE ){
- yy_reduce(yypParser,yyact-YYNSTATE);
- }else if( yyact == YY_ERROR_ACTION ){
- int yymx;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
- }
-#endif
-#ifdef YYERRORSYMBOL
- /* A syntax error has occurred.
- ** The response to an error depends upon whether or not the
- ** grammar defines an error token "ERROR".
- **
- ** This is what we do if the grammar does define ERROR:
- **
- ** * Call the %syntax_error function.
- **
- ** * Begin popping the stack until we enter a state where
- ** it is legal to shift the error symbol, then shift
- ** the error symbol.
- **
- ** * Set the error count to three.
- **
- ** * Begin accepting and shifting new tokens. No new error
- ** processing will occur until three tokens have been
- ** shifted successfully.
- **
- */
- if( yypParser->yyerrcnt<0 ){
- yy_syntax_error(yypParser,yymajor,yyminorunion);
- }
- yymx = yypParser->yystack[yypParser->yyidx].major;
- if( yymx==YYERRORSYMBOL || yyerrorhit ){
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sDiscard input token %s\n",
- yyTracePrompt,yyTokenName[yymajor]);
- }
-#endif
- yy_destructor(yymajor,&yyminorunion);
- yymajor = YYNOCODE;
- }else{
- while(
- yypParser->yyidx >= 0 &&
- yymx != YYERRORSYMBOL &&
- (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
- ){
- yy_pop_parser_stack(yypParser);
- }
- if( yypParser->yyidx < 0 || yymajor==0 ){
- yy_destructor(yymajor,&yyminorunion);
- yy_parse_failed(yypParser);
- yymajor = YYNOCODE;
- }else if( yymx!=YYERRORSYMBOL ){
- YYMINORTYPE u2;
- u2.YYERRSYMDT = 0;
- yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
- }
- }
- yypParser->yyerrcnt = 3;
- yyerrorhit = 1;
-#else /* YYERRORSYMBOL is not defined */
- /* This is what we do if the grammar does not define ERROR:
- **
- ** * Report an error message, and throw away the input token.
- **
- ** * If the input token is $, then fail the parse.
- **
- ** As before, subsequent error messages are suppressed until
- ** three input tokens have been successfully shifted.
- */
- if( yypParser->yyerrcnt<=0 ){
- yy_syntax_error(yypParser,yymajor,yyminorunion);
- }
- yypParser->yyerrcnt = 3;
- yy_destructor(yymajor,&yyminorunion);
- if( yyendofinput ){
- yy_parse_failed(yypParser);
- }
- yymajor = YYNOCODE;
-#endif
- }else{
- yy_accept(yypParser);
- yymajor = YYNOCODE;
- }
- }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
- return;
-}
diff --git a/kopete/plugins/statistics/sqlite/main.c b/kopete/plugins/statistics/sqlite/main.c
deleted file mode 100644
index 0ae7e1b2..00000000
--- a/kopete/plugins/statistics/sqlite/main.c
+++ /dev/null
@@ -1,1346 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** Main file for the SQLite library. The routines in this file
-** implement the programmer interface to the library. Routines in
-** other files are for internal use by SQLite and should not be
-** accessed by users of the library.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-#include "os.h"
-#include <ctype.h>
-
-/*
-** The following constant value is used by the SQLITE_BIGENDIAN and
-** SQLITE_LITTLEENDIAN macros.
-*/
-const int sqlite3one = 1;
-
-/*
-** Fill the InitData structure with an error message that indicates
-** that the database is corrupt.
-*/
-static void corruptSchema(InitData *pData, const char *zExtra){
- if( !sqlite3_malloc_failed ){
- sqlite3SetString(pData->pzErrMsg, "malformed database schema",
- zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
- }
-}
-
-/*
-** This is the callback routine for the code that initializes the
-** database. See sqlite3Init() below for additional information.
-** This routine is also called from the OP_ParseSchema opcode of the VDBE.
-**
-** Each callback contains the following information:
-**
-** argv[0] = name of thing being created
-** argv[1] = root page number for table or index. NULL for trigger or view.
-** argv[2] = SQL text for the CREATE statement.
-** argv[3] = "1" for temporary files, "0" for main database, "2" or more
-** for auxiliary database files.
-**
-*/
-int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
- InitData *pData = (InitData*)pInit;
- sqlite3 *db = pData->db;
- int iDb;
-
- assert( argc==4 );
- if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
- if( argv[1]==0 || argv[3]==0 ){
- corruptSchema(pData, 0);
- return 1;
- }
- iDb = atoi(argv[3]);
- assert( iDb>=0 && iDb<db->nDb );
- if( argv[2] && argv[2][0] ){
- /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
- ** But because db->init.busy is set to 1, no VDBE code is generated
- ** or executed. All the parser does is build the internal data
- ** structures that describe the table, index, or view.
- */
- char *zErr;
- int rc;
- assert( db->init.busy );
- db->init.iDb = iDb;
- db->init.newTnum = atoi(argv[1]);
- rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
- db->init.iDb = 0;
- if( SQLITE_OK!=rc ){
- corruptSchema(pData, zErr);
- sqlite3_free(zErr);
- return rc;
- }
- }else{
- /* If the SQL column is blank it means this is an index that
- ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
- ** constraint for a CREATE TABLE. The index should have already
- ** been created when we processed the CREATE TABLE. All we have
- ** to do here is record the root page number for that index.
- */
- Index *pIndex;
- pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName);
- if( pIndex==0 || pIndex->tnum!=0 ){
- /* This can occur if there exists an index on a TEMP table which
- ** has the same name as another index on a permanent index. Since
- ** the permanent table is hidden by the TEMP table, we can also
- ** safely ignore the index on the permanent table.
- */
- /* Do Nothing */;
- }else{
- pIndex->tnum = atoi(argv[1]);
- }
- }
- return 0;
-}
-
-/*
-** Attempt to read the database schema and initialize internal
-** data structures for a single database file. The index of the
-** database file is given by iDb. iDb==0 is used for the main
-** database. iDb==1 should never be used. iDb>=2 is used for
-** auxiliary databases. Return one of the SQLITE_ error codes to
-** indicate success or failure.
-*/
-static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
- int rc;
- BtCursor *curMain;
- int size;
- Table *pTab;
- char const *azArg[5];
- char zDbNum[30];
- int meta[10];
- InitData initData;
- char const *zMasterSchema;
- char const *zMasterName;
-
- /*
- ** The master database table has a structure like this
- */
- static const char master_schema[] =
- "CREATE TABLE sqlite_master(\n"
- " type text,\n"
- " name text,\n"
- " tbl_name text,\n"
- " rootpage integer,\n"
- " sql text\n"
- ")"
- ;
- static const char temp_master_schema[] =
- "CREATE TEMP TABLE sqlite_temp_master(\n"
- " type text,\n"
- " name text,\n"
- " tbl_name text,\n"
- " rootpage integer,\n"
- " sql text\n"
- ")"
- ;
-
- assert( iDb>=0 && iDb<db->nDb );
-
- /* zMasterSchema and zInitScript are set to point at the master schema
- ** and initialisation script appropriate for the database being
- ** initialised. zMasterName is the name of the master table.
- */
- if( iDb==1 ){
- zMasterSchema = temp_master_schema;
- zMasterName = TEMP_MASTER_NAME;
- }else{
- zMasterSchema = master_schema;
- zMasterName = MASTER_NAME;
- }
-
- /* Construct the schema tables. */
- sqlite3SafetyOff(db);
- azArg[0] = zMasterName;
- azArg[1] = "1";
- azArg[2] = zMasterSchema;
- sprintf(zDbNum, "%d", iDb);
- azArg[3] = zDbNum;
- azArg[4] = 0;
- initData.db = db;
- initData.pzErrMsg = pzErrMsg;
- rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0);
- if( rc!=SQLITE_OK ){
- sqlite3SafetyOn(db);
- return rc;
- }
- pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
- if( pTab ){
- pTab->readOnly = 1;
- }
- sqlite3SafetyOn(db);
-
- /* Create a cursor to hold the database open
- */
- if( db->aDb[iDb].pBt==0 ){
- if( iDb==1 ) DbSetProperty(db, 1, DB_SchemaLoaded);
- return SQLITE_OK;
- }
- rc = sqlite3BtreeCursor(db->aDb[iDb].pBt, MASTER_ROOT, 0, 0, 0, &curMain);
- if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){
- sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
- return rc;
- }
-
- /* Get the database meta information.
- **
- ** Meta values are as follows:
- ** meta[0] Schema cookie. Changes with each schema change.
- ** meta[1] File format of schema layer.
- ** meta[2] Size of the page cache.
- ** meta[3] Use freelist if 0. Autovacuum if greater than zero.
- ** meta[4] Db text encoding. 1:UTF-8 3:UTF-16 LE 4:UTF-16 BE
- ** meta[5]
- ** meta[6]
- ** meta[7]
- ** meta[8]
- ** meta[9]
- **
- ** Note: The hash defined SQLITE_UTF* symbols in sqliteInt.h correspond to
- ** the possible values of meta[4].
- */
- if( rc==SQLITE_OK ){
- int i;
- for(i=0; rc==SQLITE_OK && i<sizeof(meta)/sizeof(meta[0]); i++){
- rc = sqlite3BtreeGetMeta(db->aDb[iDb].pBt, i+1, (u32 *)&meta[i]);
- }
- if( rc ){
- sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
- sqlite3BtreeCloseCursor(curMain);
- return rc;
- }
- }else{
- memset(meta, 0, sizeof(meta));
- }
- db->aDb[iDb].schema_cookie = meta[0];
-
- /* If opening a non-empty database, check the text encoding. For the
- ** main database, set sqlite3.enc to the encoding of the main database.
- ** For an attached db, it is an error if the encoding is not the same
- ** as sqlite3.enc.
- */
- if( meta[4] ){ /* text encoding */
- if( iDb==0 ){
- /* If opening the main database, set db->enc. */
- db->enc = (u8)meta[4];
- db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0);
- }else{
- /* If opening an attached database, the encoding much match db->enc */
- if( meta[4]!=db->enc ){
- sqlite3BtreeCloseCursor(curMain);
- sqlite3SetString(pzErrMsg, "attached databases must use the same"
- " text encoding as main database", (char*)0);
- return SQLITE_ERROR;
- }
- }
- }
-
- size = meta[2];
- if( size==0 ){ size = MAX_PAGES; }
- db->aDb[iDb].cache_size = size;
-
- if( iDb==0 ){
- db->file_format = meta[1];
- if( db->file_format==0 ){
- /* This happens if the database was initially empty */
- db->file_format = 1;
- }
- }
-
- /*
- ** file_format==1 Version 3.0.0.
- */
- if( meta[1]>1 ){
- sqlite3BtreeCloseCursor(curMain);
- sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
- return SQLITE_ERROR;
- }
-
- sqlite3BtreeSetCacheSize(db->aDb[iDb].pBt, db->aDb[iDb].cache_size);
-
- /* Read the schema information out of the schema tables
- */
- assert( db->init.busy );
- if( rc==SQLITE_EMPTY ){
- /* For an empty database, there is nothing to read */
- rc = SQLITE_OK;
- }else{
- char *zSql;
- zSql = sqlite3MPrintf(
- "SELECT name, rootpage, sql, %s FROM '%q'.%s",
- zDbNum, db->aDb[iDb].zName, zMasterName);
- sqlite3SafetyOff(db);
- rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
- sqlite3SafetyOn(db);
- sqliteFree(zSql);
- sqlite3BtreeCloseCursor(curMain);
- }
- if( sqlite3_malloc_failed ){
- sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
- rc = SQLITE_NOMEM;
- sqlite3ResetInternalSchema(db, 0);
- }
- if( rc==SQLITE_OK ){
- DbSetProperty(db, iDb, DB_SchemaLoaded);
- }else{
- sqlite3ResetInternalSchema(db, iDb);
- }
- return rc;
-}
-
-/*
-** Initialize all database files - the main database file, the file
-** used to store temporary tables, and any additional database files
-** created using ATTACH statements. Return a success code. If an
-** error occurs, write an error message into *pzErrMsg.
-**
-** After the database is initialized, the SQLITE_Initialized
-** bit is set in the flags field of the sqlite structure.
-*/
-int sqlite3Init(sqlite3 *db, char **pzErrMsg){
- int i, rc;
-
- if( db->init.busy ) return SQLITE_OK;
- assert( (db->flags & SQLITE_Initialized)==0 );
- rc = SQLITE_OK;
- db->init.busy = 1;
- for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
- if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
- rc = sqlite3InitOne(db, i, pzErrMsg);
- if( rc ){
- sqlite3ResetInternalSchema(db, i);
- }
- }
-
- /* Once all the other databases have been initialised, load the schema
- ** for the TEMP database. This is loaded last, as the TEMP database
- ** schema may contain references to objects in other databases.
- */
- if( rc==SQLITE_OK && db->nDb>1 && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
- rc = sqlite3InitOne(db, 1, pzErrMsg);
- if( rc ){
- sqlite3ResetInternalSchema(db, 1);
- }
- }
-
- db->init.busy = 0;
- if( rc==SQLITE_OK ){
- db->flags |= SQLITE_Initialized;
- sqlite3CommitInternalChanges(db);
- }
-
- if( rc!=SQLITE_OK ){
- db->flags &= ~SQLITE_Initialized;
- }
- return rc;
-}
-
-/*
-** This routine is a no-op if the database schema is already initialised.
-** Otherwise, the schema is loaded. An error code is returned.
-*/
-int sqlite3ReadSchema(Parse *pParse){
- int rc = SQLITE_OK;
- sqlite3 *db = pParse->db;
- if( !db->init.busy ){
- if( (db->flags & SQLITE_Initialized)==0 ){
- rc = sqlite3Init(db, &pParse->zErrMsg);
- }
- }
- assert( rc!=SQLITE_OK || (db->flags & SQLITE_Initialized)||db->init.busy );
- if( rc!=SQLITE_OK ){
- pParse->rc = rc;
- pParse->nErr++;
- }
- return rc;
-}
-
-/*
-** The version of the library
-*/
-const char rcsid3[] = "@(#) \044Id: SQLite version " SQLITE_VERSION " $";
-const char sqlite3_version[] = SQLITE_VERSION;
-const char *sqlite3_libversion(void){ return sqlite3_version; }
-
-/*
-** This is the default collating function named "BINARY" which is always
-** available.
-*/
-static int binaryCollatingFunc(
- void *NotUsed,
- int nKey1, const void *pKey1,
- int nKey2, const void *pKey2
-){
- int rc, n;
- n = nKey1<nKey2 ? nKey1 : nKey2;
- rc = memcmp(pKey1, pKey2, n);
- if( rc==0 ){
- rc = nKey1 - nKey2;
- }
- return rc;
-}
-
-/*
-** Another built-in collating sequence: NOCASE.
-**
-** This collating sequence is intended to be used for "case independant
-** comparison". SQLite's knowledge of upper and lower case equivalents
-** extends only to the 26 characters used in the English language.
-**
-** At the moment there is only a UTF-8 implementation.
-*/
-static int nocaseCollatingFunc(
- void *NotUsed,
- int nKey1, const void *pKey1,
- int nKey2, const void *pKey2
-){
- int r = sqlite3StrNICmp(
- (const char *)pKey1, (const char *)pKey2, (nKey1<nKey2)?nKey1:nKey2);
- if( 0==r ){
- r = nKey1-nKey2;
- }
- return r;
-}
-
-/*
-** Return the ROWID of the most recent insert
-*/
-sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
- return db->lastRowid;
-}
-
-/*
-** Return the number of changes in the most recent call to sqlite3_exec().
-*/
-int sqlite3_changes(sqlite3 *db){
- return db->nChange;
-}
-
-/*
-** Return the number of changes since the database handle was opened.
-*/
-int sqlite3_total_changes(sqlite3 *db){
- return db->nTotalChange;
-}
-
-/*
-** Close an existing SQLite database
-*/
-int sqlite3_close(sqlite3 *db){
- HashElem *i;
- int j;
-
- if( !db ){
- return SQLITE_OK;
- }
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
-
- /* If there are any outstanding VMs, return SQLITE_BUSY. */
- if( db->pVdbe ){
- sqlite3Error(db, SQLITE_BUSY,
- "Unable to close due to unfinalised statements");
- return SQLITE_BUSY;
- }
- assert( !sqlite3SafetyCheck(db) );
-
- /* FIX ME: db->magic may be set to SQLITE_MAGIC_CLOSED if the database
- ** cannot be opened for some reason. So this routine needs to run in
- ** that case. But maybe there should be an extra magic value for the
- ** "failed to open" state.
- */
- if( db->magic!=SQLITE_MAGIC_CLOSED && sqlite3SafetyOn(db) ){
- /* printf("DID NOT CLOSE\n"); fflush(stdout); */
- return SQLITE_ERROR;
- }
-
- for(j=0; j<db->nDb; j++){
- struct Db *pDb = &db->aDb[j];
- if( pDb->pBt ){
- sqlite3BtreeClose(pDb->pBt);
- pDb->pBt = 0;
- }
- }
- sqlite3ResetInternalSchema(db, 0);
- assert( db->nDb<=2 );
- assert( db->aDb==db->aDbStatic );
- for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
- FuncDef *pFunc, *pNext;
- for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){
- pNext = pFunc->pNext;
- sqliteFree(pFunc);
- }
- }
-
- for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
- CollSeq *pColl = (CollSeq *)sqliteHashData(i);
- sqliteFree(pColl);
- }
- sqlite3HashClear(&db->aCollSeq);
-
- sqlite3HashClear(&db->aFunc);
- sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */
- if( db->pValue ){
- sqlite3ValueFree(db->pValue);
- }
- if( db->pErr ){
- sqlite3ValueFree(db->pErr);
- }
-
- db->magic = SQLITE_MAGIC_ERROR;
- sqliteFree(db);
- return SQLITE_OK;
-}
-
-/*
-** Rollback all database files.
-*/
-void sqlite3RollbackAll(sqlite3 *db){
- int i;
- for(i=0; i<db->nDb; i++){
- if( db->aDb[i].pBt ){
- sqlite3BtreeRollback(db->aDb[i].pBt);
- db->aDb[i].inTrans = 0;
- }
- }
- sqlite3ResetInternalSchema(db, 0);
-}
-
-/*
-** Return a static string that describes the kind of error specified in the
-** argument.
-*/
-const char *sqlite3ErrStr(int rc){
- const char *z;
- switch( rc ){
- case SQLITE_ROW:
- case SQLITE_DONE:
- case SQLITE_OK: z = "not an error"; break;
- case SQLITE_ERROR: z = "SQL logic error or missing database"; break;
- case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break;
- case SQLITE_PERM: z = "access permission denied"; break;
- case SQLITE_ABORT: z = "callback requested query abort"; break;
- case SQLITE_BUSY: z = "database is locked"; break;
- case SQLITE_LOCKED: z = "database table is locked"; break;
- case SQLITE_NOMEM: z = "out of memory"; break;
- case SQLITE_READONLY: z = "attempt to write a readonly database"; break;
- case SQLITE_INTERRUPT: z = "interrupted"; break;
- case SQLITE_IOERR: z = "disk I/O error"; break;
- case SQLITE_CORRUPT: z = "database disk image is malformed"; break;
- case SQLITE_NOTFOUND: z = "table or record not found"; break;
- case SQLITE_FULL: z = "database is full"; break;
- case SQLITE_CANTOPEN: z = "unable to open database file"; break;
- case SQLITE_PROTOCOL: z = "database locking protocol failure"; break;
- case SQLITE_EMPTY: z = "table contains no data"; break;
- case SQLITE_SCHEMA: z = "database schema has changed"; break;
- case SQLITE_TOOBIG: z = "too much data for one table row"; break;
- case SQLITE_CONSTRAINT: z = "constraint failed"; break;
- case SQLITE_MISMATCH: z = "datatype mismatch"; break;
- case SQLITE_MISUSE: z = "library routine called out of sequence";break;
- case SQLITE_NOLFS: z = "kernel lacks large file support"; break;
- case SQLITE_AUTH: z = "authorization denied"; break;
- case SQLITE_FORMAT: z = "auxiliary database format error"; break;
- case SQLITE_RANGE: z = "bind index out of range"; break;
- case SQLITE_NOTADB: z = "file is encrypted or is not a database";break;
- default: z = "unknown error"; break;
- }
- return z;
-}
-
-/*
-** This routine implements a busy callback that sleeps and tries
-** again until a timeout value is reached. The timeout value is
-** an integer number of milliseconds passed in as the first
-** argument.
-*/
-static int sqliteDefaultBusyCallback(
- void *Timeout, /* Maximum amount of time to wait */
- int count /* Number of times table has been busy */
-){
-#if SQLITE_MIN_SLEEP_MS==1
- static const char delays[] =
- { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 50, 100};
- static const short int totals[] =
- { 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228, 287};
-# define NDELAY (sizeof(delays)/sizeof(delays[0]))
- ptr timeout = (ptr)Timeout;
- ptr delay, prior;
-
- if( count <= NDELAY ){
- delay = delays[count-1];
- prior = totals[count-1];
- }else{
- delay = delays[NDELAY-1];
- prior = totals[NDELAY-1] + delay*(count-NDELAY-1);
- }
- if( prior + delay > timeout ){
- delay = timeout - prior;
- if( delay<=0 ) return 0;
- }
- sqlite3OsSleep(delay);
- return 1;
-#else
- int timeout = (int)Timeout;
- if( (count+1)*1000 > timeout ){
- return 0;
- }
- sqlite3OsSleep(1000);
- return 1;
-#endif
-}
-
-/*
-** This routine sets the busy callback for an Sqlite database to the
-** given callback function with the given argument.
-*/
-int sqlite3_busy_handler(
- sqlite3 *db,
- int (*xBusy)(void*,int),
- void *pArg
-){
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
- db->busyHandler.xFunc = xBusy;
- db->busyHandler.pArg = pArg;
- return SQLITE_OK;
-}
-
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
-/*
-** This routine sets the progress callback for an Sqlite database to the
-** given callback function with the given argument. The progress callback will
-** be invoked every nOps opcodes.
-*/
-void sqlite3_progress_handler(
- sqlite3 *db,
- int nOps,
- int (*xProgress)(void*),
- void *pArg
-){
- if( !sqlite3SafetyCheck(db) ){
- if( nOps>0 ){
- db->xProgress = xProgress;
- db->nProgressOps = nOps;
- db->pProgressArg = pArg;
- }else{
- db->xProgress = 0;
- db->nProgressOps = 0;
- db->pProgressArg = 0;
- }
- }
-}
-#endif
-
-
-/*
-** This routine installs a default busy handler that waits for the
-** specified number of milliseconds before returning 0.
-*/
-int sqlite3_busy_timeout(sqlite3 *db, int ms){
- if( ms>0 ){
- sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)(ptr)ms);
- }else{
- sqlite3_busy_handler(db, 0, 0);
- }
- return SQLITE_OK;
-}
-
-/*
-** Cause any pending operation to stop at its earliest opportunity.
-*/
-void sqlite3_interrupt(sqlite3 *db){
- if( !sqlite3SafetyCheck(db) ){
- db->flags |= SQLITE_Interrupt;
- }
-}
-
-/*
-** Windows systems should call this routine to free memory that
-** is returned in the in the errmsg parameter of sqlite3_open() when
-** SQLite is a DLL. For some reason, it does not work to call free()
-** directly.
-**
-** Note that we need to call free() not sqliteFree() here.
-*/
-void sqlite3_free(char *p){ free(p); }
-
-/*
-** Create new user functions.
-*/
-int sqlite3_create_function(
- sqlite3 *db,
- const char *zFunctionName,
- int nArg,
- int enc,
- void *pUserData,
- void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
- void (*xStep)(sqlite3_context*,int,sqlite3_value **),
- void (*xFinal)(sqlite3_context*)
-){
- FuncDef *p;
- int nName;
-
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
- if( zFunctionName==0 ||
- (xFunc && (xFinal || xStep)) ||
- (!xFunc && (xFinal && !xStep)) ||
- (!xFunc && (!xFinal && xStep)) ||
- (nArg<-1 || nArg>127) ||
- (255<(nName = strlen(zFunctionName))) ){
- return SQLITE_ERROR;
- }
-
- /* If SQLITE_UTF16 is specified as the encoding type, transform this
- ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
- ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
- **
- ** If SQLITE_ANY is specified, add three versions of the function
- ** to the hash table.
- */
- if( enc==SQLITE_UTF16 ){
- enc = SQLITE_UTF16NATIVE;
- }else if( enc==SQLITE_ANY ){
- int rc;
- rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF8,
- pUserData, xFunc, xStep, xFinal);
- if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF16LE,
- pUserData, xFunc, xStep, xFinal);
- if( rc!=SQLITE_OK ) return rc;
- enc = SQLITE_UTF16BE;
- }
-
- p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1);
- if( p==0 ) return SQLITE_NOMEM;
- p->xFunc = xFunc;
- p->xStep = xStep;
- p->xFinalize = xFinal;
- p->pUserData = pUserData;
- return SQLITE_OK;
-}
-int sqlite3_create_function16(
- sqlite3 *db,
- const void *zFunctionName,
- int nArg,
- int eTextRep,
- void *pUserData,
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
- void (*xStep)(sqlite3_context*,int,sqlite3_value**),
- void (*xFinal)(sqlite3_context*)
-){
- int rc;
- char const *zFunc8;
- sqlite3_value *pTmp;
-
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
- pTmp = sqlite3GetTransientValue(db);
- sqlite3ValueSetStr(pTmp, -1, zFunctionName, SQLITE_UTF16NATIVE,SQLITE_STATIC);
- zFunc8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
-
- if( !zFunc8 ){
- return SQLITE_NOMEM;
- }
- rc = sqlite3_create_function(db, zFunc8, nArg, eTextRep,
- pUserData, xFunc, xStep, xFinal);
- return rc;
-}
-
-/*
-** Register a trace function. The pArg from the previously registered trace
-** is returned.
-**
-** A NULL trace function means that no tracing is executes. A non-NULL
-** trace is a pointer to a function that is invoked at the start of each
-** sqlite3_exec().
-*/
-void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
- void *pOld = db->pTraceArg;
- db->xTrace = xTrace;
- db->pTraceArg = pArg;
- return pOld;
-}
-
-/*** EXPERIMENTAL ***
-**
-** Register a function to be invoked when a transaction comments.
-** If either function returns non-zero, then the commit becomes a
-** rollback.
-*/
-void *sqlite3_commit_hook(
- sqlite3 *db, /* Attach the hook to this database */
- int (*xCallback)(void*), /* Function to invoke on each commit */
- void *pArg /* Argument to the function */
-){
- void *pOld = db->pCommitArg;
- db->xCommitCallback = xCallback;
- db->pCommitArg = pArg;
- return pOld;
-}
-
-
-/*
-** This routine is called to create a connection to a database BTree
-** driver. If zFilename is the name of a file, then that file is
-** opened and used. If zFilename is the magic name ":memory:" then
-** the database is stored in memory (and is thus forgotten as soon as
-** the connection is closed.) If zFilename is NULL then the database
-** is for temporary use only and is deleted as soon as the connection
-** is closed.
-**
-** A temporary database can be either a disk file (that is automatically
-** deleted when the file is closed) or a set of red-black trees held in memory,
-** depending on the values of the TEMP_STORE compile-time macro and the
-** db->temp_store variable, according to the following chart:
-**
-** TEMP_STORE db->temp_store Location of temporary database
-** ---------- -------------- ------------------------------
-** 0 any file
-** 1 1 file
-** 1 2 memory
-** 1 0 file
-** 2 1 file
-** 2 2 memory
-** 2 0 memory
-** 3 any memory
-*/
-int sqlite3BtreeFactory(
- const sqlite3 *db, /* Main database when opening aux otherwise 0 */
- const char *zFilename, /* Name of the file containing the BTree database */
- int omitJournal, /* if TRUE then do not journal this file */
- int nCache, /* How many pages in the page cache */
- Btree **ppBtree /* Pointer to new Btree object written here */
-){
- int btree_flags = 0;
- int rc;
-
- assert( ppBtree != 0);
- if( omitJournal ){
- btree_flags |= BTREE_OMIT_JOURNAL;
- }
- if( zFilename==0 ){
-#ifndef TEMP_STORE
-# define TEMP_STORE 1
-#endif
-#if TEMP_STORE==0
- /* Do nothing */
-#endif
-#if TEMP_STORE==1
- if( db->temp_store==2 ) zFilename = ":memory:";
-#endif
-#if TEMP_STORE==2
- if( db->temp_store!=1 ) zFilename = ":memory:";
-#endif
-#if TEMP_STORE==3
- zFilename = ":memory:";
-#endif
- }
-
- rc = sqlite3BtreeOpen(zFilename, ppBtree, btree_flags);
- if( rc==SQLITE_OK ){
- sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler);
- sqlite3BtreeSetCacheSize(*ppBtree, nCache);
- }
- return rc;
-}
-
-/*
-** Return UTF-8 encoded English language explanation of the most recent
-** error.
-*/
-const char *sqlite3_errmsg(sqlite3 *db){
- const char *z;
- if( sqlite3_malloc_failed ){
- return sqlite3ErrStr(SQLITE_NOMEM);
- }
- if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
- return sqlite3ErrStr(SQLITE_MISUSE);
- }
- z = sqlite3_value_text(db->pErr);
- if( z==0 ){
- z = sqlite3ErrStr(db->errCode);
- }
- return z;
-}
-
-/*
-** Return UTF-16 encoded English language explanation of the most recent
-** error.
-*/
-const void *sqlite3_errmsg16(sqlite3 *db){
- /* Because all the characters in the string are in the unicode
- ** range 0x00-0xFF, if we pad the big-endian string with a
- ** zero byte, we can obtain the little-endian string with
- ** &big_endian[1].
- */
- static const char outOfMemBe[] = {
- 0, 'o', 0, 'u', 0, 't', 0, ' ',
- 0, 'o', 0, 'f', 0, ' ',
- 0, 'm', 0, 'e', 0, 'm', 0, 'o', 0, 'r', 0, 'y', 0, 0, 0
- };
- static const char misuseBe [] = {
- 0, 'l', 0, 'i', 0, 'b', 0, 'r', 0, 'a', 0, 'r', 0, 'y', 0, ' ',
- 0, 'r', 0, 'o', 0, 'u', 0, 't', 0, 'i', 0, 'n', 0, 'e', 0, ' ',
- 0, 'c', 0, 'a', 0, 'l', 0, 'l', 0, 'e', 0, 'd', 0, ' ',
- 0, 'o', 0, 'u', 0, 't', 0, ' ',
- 0, 'o', 0, 'f', 0, ' ',
- 0, 's', 0, 'e', 0, 'q', 0, 'u', 0, 'e', 0, 'n', 0, 'c', 0, 'e', 0, 0, 0
- };
-
- const void *z;
- if( sqlite3_malloc_failed ){
- return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
- }
- if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
- return (void *)(&misuseBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
- }
- z = sqlite3_value_text16(db->pErr);
- if( z==0 ){
- sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode),
- SQLITE_UTF8, SQLITE_STATIC);
- z = sqlite3_value_text16(db->pErr);
- }
- return z;
-}
-
-/*
-** Return the most recent error code generated by an SQLite routine.
-*/
-int sqlite3_errcode(sqlite3 *db){
- if( sqlite3_malloc_failed ){
- return SQLITE_NOMEM;
- }
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
- return db->errCode;
-}
-
-/*
-** Check schema cookies in all databases. If any cookie is out
-** of date, return 0. If all schema cookies are current, return 1.
-*/
-static int schemaIsValid(sqlite3 *db){
- int iDb;
- int rc;
- BtCursor *curTemp;
- int cookie;
- int allOk = 1;
-
- for(iDb=0; allOk && iDb<db->nDb; iDb++){
- Btree *pBt;
- pBt = db->aDb[iDb].pBt;
- if( pBt==0 ) continue;
- rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp);
- if( rc==SQLITE_OK ){
- rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
- if( rc==SQLITE_OK && cookie!=db->aDb[iDb].schema_cookie ){
- allOk = 0;
- }
- sqlite3BtreeCloseCursor(curTemp);
- }
- }
- return allOk;
-}
-
-/*
-** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
-*/
-int sqlite3_prepare(
- sqlite3 *db, /* Database handle. */
- const char *zSql, /* UTF-8 encoded SQL statement. */
- int nBytes, /* Length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
- const char** pzTail /* OUT: End of parsed string */
-){
- Parse sParse;
- char *zErrMsg = 0;
- int rc = SQLITE_OK;
-
- if( sqlite3_malloc_failed ){
- return SQLITE_NOMEM;
- }
-
- assert( ppStmt );
- *ppStmt = 0;
- if( sqlite3SafetyOn(db) ){
- return SQLITE_MISUSE;
- }
-
- memset(&sParse, 0, sizeof(sParse));
- sParse.db = db;
- sqlite3RunParser(&sParse, zSql, &zErrMsg);
-
- if( sqlite3_malloc_failed ){
- rc = SQLITE_NOMEM;
- sqlite3RollbackAll(db);
- sqlite3ResetInternalSchema(db, 0);
- db->flags &= ~SQLITE_InTrans;
- goto prepare_out;
- }
- if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
- if( sParse.rc!=SQLITE_OK && sParse.checkSchema && !schemaIsValid(db) ){
- sParse.rc = SQLITE_SCHEMA;
- }
- if( sParse.rc==SQLITE_SCHEMA ){
- sqlite3ResetInternalSchema(db, 0);
- }
- if( pzTail ) *pzTail = sParse.zTail;
- rc = sParse.rc;
-
- if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
- sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
- sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 2, "p1", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC);
- }
-
-prepare_out:
- if( sqlite3SafetyOff(db) ){
- rc = SQLITE_MISUSE;
- }
- if( rc==SQLITE_OK ){
- *ppStmt = (sqlite3_stmt*)sParse.pVdbe;
- }else if( sParse.pVdbe ){
- sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
- }
-
- if( zErrMsg ){
- sqlite3Error(db, rc, "%s", zErrMsg);
- sqliteFree(zErrMsg);
- }else{
- sqlite3Error(db, rc, 0);
- }
- return rc;
-}
-
-/*
-** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
-*/
-int sqlite3_prepare16(
- sqlite3 *db, /* Database handle. */
- const void *zSql, /* UTF-8 encoded SQL statement. */
- int nBytes, /* Length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
- const void **pzTail /* OUT: End of parsed string */
-){
- /* This function currently works by first transforming the UTF-16
- ** encoded string to UTF-8, then invoking sqlite3_prepare(). The
- ** tricky bit is figuring out the pointer to return in *pzTail.
- */
- char const *zSql8 = 0;
- char const *zTail8 = 0;
- int rc;
- sqlite3_value *pTmp;
-
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
- pTmp = sqlite3GetTransientValue(db);
- sqlite3ValueSetStr(pTmp, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
- zSql8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
- if( !zSql8 ){
- sqlite3Error(db, SQLITE_NOMEM, 0);
- return SQLITE_NOMEM;
- }
- rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8);
-
- if( zTail8 && pzTail ){
- /* If sqlite3_prepare returns a tail pointer, we calculate the
- ** equivalent pointer into the UTF-16 string by counting the unicode
- ** characters between zSql8 and zTail8, and then returning a pointer
- ** the same number of characters into the UTF-16 string.
- */
- int chars_parsed = sqlite3utf8CharLen(zSql8, zTail8-zSql8);
- *pzTail = (u8 *)zSql + sqlite3utf16ByteLen(zSql, chars_parsed);
- }
-
- return rc;
-}
-
-/*
-** This routine does the work of opening a database on behalf of
-** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"
-** is UTF-8 encoded. The fourth argument, "def_enc" is one of the TEXT_*
-** macros from sqliteInt.h. If we end up creating a new database file
-** (not opening an existing one), the text encoding of the database
-** will be set to this value.
-*/
-static int openDatabase(
- const char *zFilename, /* Database filename UTF-8 encoded */
- sqlite3 **ppDb /* OUT: Returned database handle */
-){
- sqlite3 *db;
- int rc, i;
- char *zErrMsg = 0;
-
- /* Allocate the sqlite data structure */
- db = sqliteMalloc( sizeof(sqlite3) );
- if( db==0 ) goto opendb_out;
- db->priorNewRowid = 0;
- db->magic = SQLITE_MAGIC_BUSY;
- db->nDb = 2;
- db->aDb = db->aDbStatic;
- db->enc = SQLITE_UTF8;
- db->autoCommit = 1;
- /* db->flags |= SQLITE_ShortColNames; */
- sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
- for(i=0; i<db->nDb; i++){
- sqlite3HashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1);
- }
-
- /* Add the default collation sequence BINARY. BINARY works for both UTF-8
- ** and UTF-16, so add a version for each to avoid any unnecessary
- ** conversions. The only error that can occur here is a malloc() failure.
- */
- sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binaryCollatingFunc);
- sqlite3_create_collation(db, "BINARY", SQLITE_UTF16LE, 0,binaryCollatingFunc);
- sqlite3_create_collation(db, "BINARY", SQLITE_UTF16BE, 0,binaryCollatingFunc);
- db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0);
- if( !db->pDfltColl ){
- rc = db->errCode;
- assert( rc!=SQLITE_OK );
- db->magic = SQLITE_MAGIC_CLOSED;
- goto opendb_out;
- }
-
- /* Also add a UTF-8 case-insensitive collation sequence. */
- sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
-
- /* Open the backend database driver */
- rc = sqlite3BtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
- if( rc!=SQLITE_OK ){
- sqlite3Error(db, rc, 0);
- db->magic = SQLITE_MAGIC_CLOSED;
- goto opendb_out;
- }
- db->aDb[0].zName = "main";
- db->aDb[1].zName = "temp";
-
- /* The default safety_level for the main database is 'full' for the temp
- ** database it is 'NONE'. This matches the pager layer defaults. */
- db->aDb[0].safety_level = 3;
- db->aDb[1].safety_level = 1;
-
- /* Register all built-in functions, but do not attempt to read the
- ** database schema yet. This is delayed until the first time the database
- ** is accessed.
- */
- sqlite3RegisterBuiltinFunctions(db);
- if( rc==SQLITE_OK ){
- sqlite3Error(db, SQLITE_OK, 0);
- db->magic = SQLITE_MAGIC_OPEN;
- }else{
- sqlite3Error(db, rc, "%s", zErrMsg, 0);
- if( zErrMsg ) sqliteFree(zErrMsg);
- db->magic = SQLITE_MAGIC_CLOSED;
- }
-
-opendb_out:
- if( sqlite3_errcode(db)==SQLITE_OK && sqlite3_malloc_failed ){
- sqlite3Error(db, SQLITE_NOMEM, 0);
- }
- *ppDb = db;
- return sqlite3_errcode(db);
-}
-
-/*
-** Open a new database handle.
-*/
-int sqlite3_open(
- const char *zFilename,
- sqlite3 **ppDb
-){
- return openDatabase(zFilename, ppDb);
-}
-
-/*
-** Open a new database handle.
-*/
-int sqlite3_open16(
- const void *zFilename,
- sqlite3 **ppDb
-){
- char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */
- int rc = SQLITE_NOMEM;
- sqlite3_value *pVal;
-
- assert( ppDb );
- *ppDb = 0;
- pVal = sqlite3ValueNew();
- sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
- zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
- if( zFilename8 ){
- rc = openDatabase(zFilename8, ppDb);
- if( rc==SQLITE_OK && *ppDb ){
- sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
- }
- }
- if( pVal ){
- sqlite3ValueFree(pVal);
- }
-
- return rc;
-}
-
-/*
-** The following routine destroys a virtual machine that is created by
-** the sqlite3_compile() routine. The integer returned is an SQLITE_
-** success/failure code that describes the result of executing the virtual
-** machine.
-**
-** This routine sets the error code and string returned by
-** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
-*/
-int sqlite3_finalize(sqlite3_stmt *pStmt){
- int rc;
- if( pStmt==0 ){
- rc = SQLITE_OK;
- }else{
- rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
- }
- return rc;
-}
-
-/*
-** Terminate the current execution of an SQL statement and reset it
-** back to its starting state so that it can be reused. A success code from
-** the prior execution is returned.
-**
-** This routine sets the error code and string returned by
-** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
-*/
-int sqlite3_reset(sqlite3_stmt *pStmt){
- int rc;
- if( pStmt==0 ){
- rc = SQLITE_OK;
- }else{
- rc = sqlite3VdbeReset((Vdbe*)pStmt);
- sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
- }
- return rc;
-}
-
-/*
-** Register a new collation sequence with the database handle db.
-*/
-int sqlite3_create_collation(
- sqlite3* db,
- const char *zName,
- int enc,
- void* pCtx,
- int(*xCompare)(void*,int,const void*,int,const void*)
-){
- CollSeq *pColl;
- int rc = SQLITE_OK;
-
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
-
- /* If SQLITE_UTF16 is specified as the encoding type, transform this
- ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
- ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
- */
- if( enc==SQLITE_UTF16 ){
- enc = SQLITE_UTF16NATIVE;
- }
-
- if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){
- sqlite3Error(db, SQLITE_ERROR,
- "Param 3 to sqlite3_create_collation() must be one of "
- "SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE"
- );
- return SQLITE_ERROR;
- }
- pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1);
- if( 0==pColl ){
- rc = SQLITE_NOMEM;
- }else{
- pColl->xCmp = xCompare;
- pColl->pUser = pCtx;
- pColl->enc = enc;
- }
- sqlite3Error(db, rc, 0);
- return rc;
-}
-
-/*
-** Register a new collation sequence with the database handle db.
-*/
-int sqlite3_create_collation16(
- sqlite3* db,
- const char *zName,
- int enc,
- void* pCtx,
- int(*xCompare)(void*,int,const void*,int,const void*)
-){
- char const *zName8;
- sqlite3_value *pTmp;
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
- pTmp = sqlite3GetTransientValue(db);
- sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF16NATIVE, SQLITE_STATIC);
- zName8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
- return sqlite3_create_collation(db, zName8, enc, pCtx, xCompare);
-}
-
-/*
-** Register a collation sequence factory callback with the database handle
-** db. Replace any previously installed collation sequence factory.
-*/
-int sqlite3_collation_needed(
- sqlite3 *db,
- void *pCollNeededArg,
- void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
-){
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
- db->xCollNeeded = xCollNeeded;
- db->xCollNeeded16 = 0;
- db->pCollNeededArg = pCollNeededArg;
- return SQLITE_OK;
-}
-
-/*
-** Register a collation sequence factory callback with the database handle
-** db. Replace any previously installed collation sequence factory.
-*/
-int sqlite3_collation_needed16(
- sqlite3 *db,
- void *pCollNeededArg,
- void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
-){
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
- db->xCollNeeded = 0;
- db->xCollNeeded16 = xCollNeeded16;
- db->pCollNeededArg = pCollNeededArg;
- return SQLITE_OK;
-}
diff --git a/kopete/plugins/statistics/sqlite/opcodes.c b/kopete/plugins/statistics/sqlite/opcodes.c
deleted file mode 100644
index b6f01219..00000000
--- a/kopete/plugins/statistics/sqlite/opcodes.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Automatically generated. Do not edit */
-/* See the mkopcodec.h script for details. */
-const char *const sqlite3OpcodeNames[] = { "?",
- "ContextPop",
- "IntegrityCk",
- "DropTrigger",
- "DropIndex",
- "Recno",
- "KeyAsData",
- "Delete",
- "MoveGt",
- "VerifyCookie",
- "Push",
- "Dup",
- "Blob",
- "IdxGT",
- "IdxRecno",
- "RowKey",
- "PutStrKey",
- "IsUnique",
- "SetNumColumns",
- "IdxIsNull",
- "NullRow",
- "OpenPseudo",
- "OpenWrite",
- "OpenRead",
- "Transaction",
- "AutoCommit",
- "Pop",
- "Halt",
- "Vacuum",
- "ListRead",
- "RowData",
- "NotExists",
- "MoveLe",
- "SetCookie",
- "Variable",
- "AggNext",
- "AggReset",
- "Sort",
- "IdxDelete",
- "ResetCount",
- "OpenTemp",
- "IdxColumn",
- "Integer",
- "AggSet",
- "CreateIndex",
- "IdxPut",
- "MoveLt",
- "Return",
- "MemLoad",
- "SortNext",
- "IdxLT",
- "Rewind",
- "AddImm",
- "AggFunc",
- "AggInit",
- "MemIncr",
- "ListReset",
- "Clear",
- "Or",
- "And",
- "Not",
- "PutIntKey",
- "If",
- "Callback",
- "IsNull",
- "NotNull",
- "Ne",
- "Eq",
- "Gt",
- "Le",
- "Lt",
- "Ge",
- "BitAnd",
- "BitOr",
- "ShiftLeft",
- "ShiftRight",
- "Add",
- "Subtract",
- "Multiply",
- "Divide",
- "Remainder",
- "Concat",
- "Negative",
- "SortReset",
- "BitNot",
- "String8",
- "SortPut",
- "Last",
- "NotFound",
- "MakeRecord",
- "String",
- "Goto",
- "AggFocus",
- "DropTable",
- "Column",
- "Noop",
- "AggGet",
- "CreateTable",
- "NewRecno",
- "Found",
- "Distinct",
- "Close",
- "Statement",
- "IfNot",
- "Pull",
- "MemStore",
- "Next",
- "Prev",
- "MoveGe",
- "MustBeInt",
- "ForceInt",
- "CollSeq",
- "Gosub",
- "ContextPush",
- "ListRewind",
- "ListWrite",
- "ParseSchema",
- "Destroy",
- "IdxGE",
- "FullKey",
- "ReadCookie",
- "AbsValue",
- "Real",
- "HexBlob",
- "Function",
-};
diff --git a/kopete/plugins/statistics/sqlite/opcodes.h b/kopete/plugins/statistics/sqlite/opcodes.h
deleted file mode 100644
index 7b792c5a..00000000
--- a/kopete/plugins/statistics/sqlite/opcodes.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/* Automatically generated. Do not edit */
-/* See the mkopcodeh.awk script for details */
-#define OP_ContextPop 1
-#define OP_IntegrityCk 2
-#define OP_DropTrigger 3
-#define OP_DropIndex 4
-#define OP_Recno 5
-#define OP_KeyAsData 6
-#define OP_Delete 7
-#define OP_MoveGt 8
-#define OP_VerifyCookie 9
-#define OP_Push 10
-#define OP_Dup 11
-#define OP_Blob 12
-#define OP_IdxGT 13
-#define OP_IdxRecno 14
-#define OP_RowKey 15
-#define OP_PutStrKey 16
-#define OP_IsUnique 17
-#define OP_SetNumColumns 18
-#define OP_Eq 67
-#define OP_IdxIsNull 19
-#define OP_NullRow 20
-#define OP_OpenPseudo 21
-#define OP_OpenWrite 22
-#define OP_OpenRead 23
-#define OP_Transaction 24
-#define OP_AutoCommit 25
-#define OP_Negative 82
-#define OP_Pop 26
-#define OP_Halt 27
-#define OP_Vacuum 28
-#define OP_ListRead 29
-#define OP_RowData 30
-#define OP_NotExists 31
-#define OP_MoveLe 32
-#define OP_SetCookie 33
-#define OP_Variable 34
-#define OP_AggNext 35
-#define OP_AggReset 36
-#define OP_Sort 37
-#define OP_IdxDelete 38
-#define OP_ResetCount 39
-#define OP_OpenTemp 40
-#define OP_IdxColumn 41
-#define OP_NotNull 65
-#define OP_Ge 71
-#define OP_Remainder 80
-#define OP_Divide 79
-#define OP_Integer 42
-#define OP_AggSet 43
-#define OP_CreateIndex 44
-#define OP_IdxPut 45
-#define OP_MoveLt 46
-#define OP_And 59
-#define OP_ShiftLeft 74
-#define OP_Real 122
-#define OP_Return 47
-#define OP_MemLoad 48
-#define OP_SortNext 49
-#define OP_IdxLT 50
-#define OP_Rewind 51
-#define OP_Gt 68
-#define OP_AddImm 52
-#define OP_Subtract 77
-#define OP_AggFunc 53
-#define OP_AggInit 54
-#define OP_MemIncr 55
-#define OP_ListReset 56
-#define OP_Clear 57
-#define OP_PutIntKey 61
-#define OP_IsNull 64
-#define OP_If 62
-#define OP_Callback 63
-#define OP_SortReset 83
-#define OP_SortPut 86
-#define OP_Last 87
-#define OP_NotFound 88
-#define OP_MakeRecord 89
-#define OP_BitAnd 72
-#define OP_Add 76
-#define OP_HexBlob 123
-#define OP_String 90
-#define OP_Goto 91
-#define OP_AggFocus 92
-#define OP_DropTable 93
-#define OP_Column 94
-#define OP_Noop 95
-#define OP_Not 60
-#define OP_Le 69
-#define OP_BitOr 73
-#define OP_Multiply 78
-#define OP_String8 85
-#define OP_AggGet 96
-#define OP_CreateTable 97
-#define OP_NewRecno 98
-#define OP_Found 99
-#define OP_Distinct 100
-#define OP_Close 101
-#define OP_Statement 102
-#define OP_IfNot 103
-#define OP_Pull 104
-#define OP_MemStore 105
-#define OP_Next 106
-#define OP_Prev 107
-#define OP_MoveGe 108
-#define OP_Lt 70
-#define OP_Ne 66
-#define OP_MustBeInt 109
-#define OP_ForceInt 110
-#define OP_ShiftRight 75
-#define OP_CollSeq 111
-#define OP_Gosub 112
-#define OP_ContextPush 113
-#define OP_ListRewind 114
-#define OP_ListWrite 115
-#define OP_ParseSchema 116
-#define OP_Destroy 117
-#define OP_IdxGE 118
-#define OP_FullKey 119
-#define OP_ReadCookie 120
-#define OP_BitNot 84
-#define OP_AbsValue 121
-#define OP_Or 58
-#define OP_Function 124
-#define OP_Concat 81
diff --git a/kopete/plugins/statistics/sqlite/os.h b/kopete/plugins/statistics/sqlite/os.h
deleted file mode 100644
index fc478baa..00000000
--- a/kopete/plugins/statistics/sqlite/os.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
-** 2001 September 16
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This header file (together with is companion C source-code file
-** "os.c") attempt to abstract the underlying operating system so that
-** the SQLite library will work on both POSIX and windows systems.
-*/
-#ifndef _SQLITE_OS_H_
-#define _SQLITE_OS_H_
-
-/*
-** Figure out if we are dealing with Unix, Windows or MacOS.
-**
-** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix.
-** The MacOS build is designed to use CodeWarrior (tested with v8)
-*/
-#if !defined(OS_UNIX) && !defined(OS_TEST)
-# ifndef OS_WIN
-# ifndef OS_MAC
-# if defined(__MACOS__)
-# define OS_MAC 1
-# define OS_WIN 0
-# define OS_UNIX 0
-# elif defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
-# define OS_MAC 0
-# define OS_WIN 1
-# define OS_UNIX 0
-# else
-# define OS_MAC 0
-# define OS_WIN 0
-# define OS_UNIX 1
-# endif
-# else
-# define OS_WIN 0
-# define OS_UNIX 0
-# endif
-# else
-# define OS_MAC 0
-# define OS_UNIX 0
-# endif
-#else
-# define OS_MAC 0
-# ifndef OS_WIN
-# define OS_WIN 0
-# endif
-#endif
-
-/*
-** Invoke the appropriate operating-system specific header file.
-*/
-#if OS_TEST
-# include "os_test.h"
-#endif
-#if OS_UNIX
-# include "os_unix.h"
-#endif
-#if OS_WIN
-# include "os_win.h"
-#endif
-#if OS_MAC
-# include "os_mac.h"
-#endif
-
-/*
-** Temporary files are named starting with this prefix followed by 16 random
-** alphanumeric characters, and no file extension. They are stored in the
-** OS's standard temporary file directory, and are deleted prior to exit.
-** If sqlite is being embedded in another program, you may wish to change the
-** prefix to reflect your program's name, so that if your program exits
-** prematurely, old temporary files can be easily identified. This can be done
-** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line.
-*/
-#ifndef TEMP_FILE_PREFIX
-# define TEMP_FILE_PREFIX "sqlite_"
-#endif
-
-/*
-** The following values may be passed as the second argument to
-** sqlite3OsLock(). The various locks exhibit the following semantics:
-**
-** SHARED: Any number of processes may hold a SHARED lock simultaneously.
-** RESERVED: A single process may hold a RESERVED lock on a file at
-** any time. Other processes may hold and obtain new SHARED locks.
-** PENDING: A single process may hold a PENDING lock on a file at
-** any one time. Existing SHARED locks may persist, but no new
-** SHARED locks may be obtained by other processes.
-** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
-**
-** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
-** process that requests an EXCLUSIVE lock may actually obtain a PENDING
-** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
-** sqlite3OsLock().
-*/
-#define NO_LOCK 0
-#define SHARED_LOCK 1
-#define RESERVED_LOCK 2
-#define PENDING_LOCK 3
-#define EXCLUSIVE_LOCK 4
-
-/*
-** File Locking Notes: (Mostly about windows but also some info for Unix)
-**
-** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
-** those functions are not available. So we use only LockFile() and
-** UnlockFile().
-**
-** LockFile() prevents not just writing but also reading by other processes.
-** A SHARED_LOCK is obtained by locking a single randomly-chosen
-** byte out of a specific range of bytes. The lock byte is obtained at
-** random so two separate readers can probably access the file at the
-** same time, unless they are unlucky and choose the same lock byte.
-** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
-** There can only be one writer. A RESERVED_LOCK is obtained by locking
-** a single byte of the file that is designated as the reserved lock byte.
-** A PENDING_LOCK is obtained by locking a designated byte different from
-** the RESERVED_LOCK byte.
-**
-** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
-** which means we can use reader/writer locks. When reader/writer locks
-** are used, the lock is placed on the same range of bytes that is used
-** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
-** will support two or more Win95 readers or two or more WinNT readers.
-** But a single Win95 reader will lock out all WinNT readers and a single
-** WinNT reader will lock out all other Win95 readers.
-**
-** The following #defines specify the range of bytes used for locking.
-** SHARED_SIZE is the number of bytes available in the pool from which
-** a random byte is selected for a shared lock. The pool of bytes for
-** shared locks begins at SHARED_FIRST.
-**
-** These #defines are available in os.h so that Unix can use the same
-** byte ranges for locking. This leaves open the possiblity of having
-** clients on win95, winNT, and unix all talking to the same shared file
-** and all locking correctly. To do so would require that samba (or whatever
-** tool is being used for file sharing) implements locks correctly between
-** windows and unix. I'm guessing that isn't likely to happen, but by
-** using the same locking range we are at least open to the possibility.
-**
-** Locking in windows is manditory. For this reason, we cannot store
-** actual data in the bytes used for locking. The pager never allocates
-** the pages involved in locking therefore. SHARED_SIZE is selected so
-** that all locks will fit on a single page even at the minimum page size.
-** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
-** is set high so that we don't have to allocate an unused page except
-** for very large databases. But one should test the page skipping logic
-** by setting PENDING_BYTE low and running the entire regression suite.
-**
-** Changing the value of PENDING_BYTE results in a subtly incompatible
-** file format. Depending on how it is changed, you might not notice
-** the incompatibility right away, even running a full regression test.
-** The default location of PENDING_BYTE is the first byte past the
-** 1GB boundary.
-**
-*/
-#define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */
-/* #define PENDING_BYTE 0x5400 // Page 20 - for testing */
-#define RESERVED_BYTE (PENDING_BYTE+1)
-#define SHARED_FIRST (PENDING_BYTE+2)
-#define SHARED_SIZE 510
-
-
-int sqlite3OsDelete(const char*);
-int sqlite3OsFileExists(const char*);
-int sqlite3OsOpenReadWrite(const char*, OsFile*, int*);
-int sqlite3OsOpenExclusive(const char*, OsFile*, int);
-int sqlite3OsOpenReadOnly(const char*, OsFile*);
-int sqlite3OsOpenDirectory(const char*, OsFile*);
-int sqlite3OsSyncDirectory(const char*);
-int sqlite3OsTempFileName(char*);
-int sqlite3OsClose(OsFile*);
-int sqlite3OsRead(OsFile*, void*, int amt);
-int sqlite3OsWrite(OsFile*, const void*, int amt);
-int sqlite3OsSeek(OsFile*, i64 offset);
-int sqlite3OsSync(OsFile*);
-int sqlite3OsTruncate(OsFile*, i64 size);
-int sqlite3OsFileSize(OsFile*, i64 *pSize);
-int sqlite3OsRandomSeed(char*);
-int sqlite3OsSleep(int ms);
-int sqlite3OsCurrentTime(double*);
-int sqlite3OsFileModTime(OsFile*, double*);
-void sqlite3OsEnterMutex(void);
-void sqlite3OsLeaveMutex(void);
-char *sqlite3OsFullPathname(const char*);
-int sqlite3OsLock(OsFile*, int);
-int sqlite3OsUnlock(OsFile*, int);
-int sqlite3OsCheckReservedLock(OsFile *id);
-
-#endif /* _SQLITE_OS_H_ */
diff --git a/kopete/plugins/statistics/sqlite/os_common.h b/kopete/plugins/statistics/sqlite/os_common.h
deleted file mode 100644
index 94311b96..00000000
--- a/kopete/plugins/statistics/sqlite/os_common.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-** 2004 May 22
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This file contains macros and a little bit of code that is common to
-** all of the platform-specific files (os_*.c) and is #included into those
-** files.
-**
-** This file should be #included by the os_*.c files only. It is not a
-** general purpose header file.
-*/
-
-/*
-** At least two bugs have slipped in because we changed the MEMORY_DEBUG
-** macro to SQLITE_DEBUG and some older makefiles have not yet made the
-** switch. The following code should catch this problem at compile-time.
-*/
-#ifdef MEMORY_DEBUG
-# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
-#endif
-
-
-int sqlite3_os_trace = 0;
-#ifdef SQLITE_DEBUG
-static int last_page = 0;
-#define SEEK(X) last_page=(X)
-#define TRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X)
-#define TRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y)
-#define TRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z)
-#define TRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define TRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define TRACE6(X,Y,Z,A,B,C) if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define TRACE7(X,Y,Z,A,B,C,D) \
- if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
-#else
-#define SEEK(X)
-#define TRACE1(X)
-#define TRACE2(X,Y)
-#define TRACE3(X,Y,Z)
-#define TRACE4(X,Y,Z,A)
-#define TRACE5(X,Y,Z,A,B)
-#define TRACE6(X,Y,Z,A,B,C)
-#define TRACE7(X,Y,Z,A,B,C,D)
-#endif
-
-/*
-** Macros for performance tracing. Normally turned off. Only works
-** on i486 hardware.
-*/
-#ifdef SQLITE_PERFORMANCE_TRACE
-__inline__ unsigned long long int hwtime(void){
- unsigned long long int x;
- __asm__("rdtsc\n\t"
- "mov %%edx, %%ecx\n\t"
- :"=A" (x));
- return x;
-}
-static unsigned long long int g_start;
-static unsigned int elapse;
-#define TIMER_START g_start=hwtime()
-#define TIMER_END elapse=hwtime()-g_start
-#define TIMER_ELAPSED elapse
-#else
-#define TIMER_START
-#define TIMER_END
-#define TIMER_ELAPSED 0
-#endif
-
-/*
-** If we compile with the SQLITE_TEST macro set, then the following block
-** of code will give us the ability to simulate a disk I/O error. This
-** is used for testing the I/O recovery logic.
-*/
-#ifdef SQLITE_TEST
-int sqlite3_io_error_pending = 0;
-int sqlite3_diskfull_pending = 0;
-#define SimulateIOError(A) \
- if( sqlite3_io_error_pending ) \
- if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
-static void local_ioerr(){
- sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */
-}
-#define SimulateDiskfullError \
- if( sqlite3_diskfull_pending ) \
- if( sqlite3_diskfull_pending-- == 1 ){ local_ioerr(); return SQLITE_FULL; }
-#else
-#define SimulateIOError(A)
-#define SimulateDiskfullError
-#endif
-
-/*
-** When testing, keep a count of the number of open files.
-*/
-#ifdef SQLITE_TEST
-int sqlite3_open_file_count = 0;
-#define OpenCounter(X) sqlite3_open_file_count+=(X)
-#else
-#define OpenCounter(X)
-#endif
diff --git a/kopete/plugins/statistics/sqlite/os_mac.c b/kopete/plugins/statistics/sqlite/os_mac.c
deleted file mode 100644
index f84c168d..00000000
--- a/kopete/plugins/statistics/sqlite/os_mac.c
+++ /dev/null
@@ -1,738 +0,0 @@
-/*
-** 2004 May 22
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This file contains code that is specific classic mac. Mac OS X
-** uses the os_unix.c file, not this one.
-*/
-#include "sqliteInt.h"
-#include "os.h"
-#if OS_MAC /* This file used on classic mac only */
-
-#include <extras.h>
-#include <path2fss.h>
-#include <TextUtils.h>
-#include <FinderRegistry.h>
-#include <Folders.h>
-#include <Timer.h>
-#include <OSUtils.h>
-
-/*
-** Macros used to determine whether or not to use threads.
-*/
-#if defined(THREADSAFE) && THREADSAFE
-# include <Multiprocessing.h>
-# define SQLITE_MACOS_MULTITASKING 1
-#endif
-
-/*
-** Include code that is common to all os_*.c files
-*/
-#include "os_common.h"
-
-/*
-** Delete the named file
-*/
-int sqlite3OsDelete(const char *zFilename){
- unlink(zFilename);
- return SQLITE_OK;
-}
-
-/*
-** Return TRUE if the named file exists.
-*/
-int sqlite3OsFileExists(const char *zFilename){
- return access(zFilename, 0)==0;
-}
-
-/*
-** Attempt to open a file for both reading and writing. If that
-** fails, try opening it read-only. If the file does not exist,
-** try to create it.
-**
-** On success, a handle for the open file is written to *id
-** and *pReadonly is set to 0 if the file was opened for reading and
-** writing or 1 if the file was opened read-only. The function returns
-** SQLITE_OK.
-**
-** On failure, the function returns SQLITE_CANTOPEN and leaves
-** *id and *pReadonly unchanged.
-*/
-int sqlite3OsOpenReadWrite(
- const char *zFilename,
- OsFile *id,
- int *pReadonly
-){
- FSSpec fsSpec;
-# ifdef _LARGE_FILE
- HFSUniStr255 dfName;
- FSRef fsRef;
- if( __path2fss(zFilename, &fsSpec) != noErr ){
- if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
- return SQLITE_CANTOPEN;
- }
- if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
- return SQLITE_CANTOPEN;
- FSGetDataForkName(&dfName);
- if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
- fsRdWrShPerm, &(id->refNum)) != noErr ){
- if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
- fsRdWrPerm, &(id->refNum)) != noErr ){
- if (FSOpenFork(&fsRef, dfName.length, dfName.unicode,
- fsRdPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
- else
- *pReadonly = 1;
- } else
- *pReadonly = 0;
- } else
- *pReadonly = 0;
-# else
- __path2fss(zFilename, &fsSpec);
- if( !sqlite3OsFileExists(zFilename) ){
- if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
- return SQLITE_CANTOPEN;
- }
- if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNum)) != noErr ){
- if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ){
- if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
- else
- *pReadonly = 1;
- } else
- *pReadonly = 0;
- } else
- *pReadonly = 0;
-# endif
- if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
- id->refNumRF = -1;
- }
- id->locked = 0;
- id->delOnClose = 0;
- OpenCounter(+1);
- return SQLITE_OK;
-}
-
-
-/*
-** Attempt to open a new file for exclusive access by this process.
-** The file will be opened for both reading and writing. To avoid
-** a potential security problem, we do not allow the file to have
-** previously existed. Nor do we allow the file to be a symbolic
-** link.
-**
-** If delFlag is true, then make arrangements to automatically delete
-** the file when it is closed.
-**
-** On success, write the file handle into *id and return SQLITE_OK.
-**
-** On failure, return SQLITE_CANTOPEN.
-*/
-int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
- FSSpec fsSpec;
-# ifdef _LARGE_FILE
- HFSUniStr255 dfName;
- FSRef fsRef;
- __path2fss(zFilename, &fsSpec);
- if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
- return SQLITE_CANTOPEN;
- if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
- return SQLITE_CANTOPEN;
- FSGetDataForkName(&dfName);
- if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
- fsRdWrPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
-# else
- __path2fss(zFilename, &fsSpec);
- if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
- return SQLITE_CANTOPEN;
- if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
-# endif
- id->refNumRF = -1;
- id->locked = 0;
- id->delOnClose = delFlag;
- if (delFlag)
- id->pathToDel = sqlite3OsFullPathname(zFilename);
- OpenCounter(+1);
- return SQLITE_OK;
-}
-
-/*
-** Attempt to open a new file for read-only access.
-**
-** On success, write the file handle into *id and return SQLITE_OK.
-**
-** On failure, return SQLITE_CANTOPEN.
-*/
-int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
- FSSpec fsSpec;
-# ifdef _LARGE_FILE
- HFSUniStr255 dfName;
- FSRef fsRef;
- if( __path2fss(zFilename, &fsSpec) != noErr )
- return SQLITE_CANTOPEN;
- if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
- return SQLITE_CANTOPEN;
- FSGetDataForkName(&dfName);
- if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
- fsRdPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
-# else
- __path2fss(zFilename, &fsSpec);
- if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
-# endif
- if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
- id->refNumRF = -1;
- }
- id->locked = 0;
- id->delOnClose = 0;
- OpenCounter(+1);
- return SQLITE_OK;
-}
-
-/*
-** Attempt to open a file descriptor for the directory that contains a
-** file. This file descriptor can be used to fsync() the directory
-** in order to make sure the creation of a new file is actually written
-** to disk.
-**
-** This routine is only meaningful for Unix. It is a no-op under
-** windows since windows does not support hard links.
-**
-** On success, a handle for a previously open file is at *id is
-** updated with the new directory file descriptor and SQLITE_OK is
-** returned.
-**
-** On failure, the function returns SQLITE_CANTOPEN and leaves
-** *id unchanged.
-*/
-int sqlite3OsOpenDirectory(
- const char *zDirname,
- OsFile *id
-){
- return SQLITE_OK;
-}
-
-/*
-** Create a temporary file name in zBuf. zBuf must be big enough to
-** hold at least SQLITE_TEMPNAME_SIZE characters.
-*/
-int sqlite3OsTempFileName(char *zBuf){
- static char zChars[] =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789";
- int i, j;
- char zTempPath[SQLITE_TEMPNAME_SIZE];
- char zdirName[32];
- CInfoPBRec infoRec;
- Str31 dirName;
- memset(&infoRec, 0, sizeof(infoRec));
- memset(zTempPath, 0, SQLITE_TEMPNAME_SIZE);
- if( FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
- &(infoRec.dirInfo.ioVRefNum), &(infoRec.dirInfo.ioDrParID)) == noErr ){
- infoRec.dirInfo.ioNamePtr = dirName;
- do{
- infoRec.dirInfo.ioFDirIndex = -1;
- infoRec.dirInfo.ioDrDirID = infoRec.dirInfo.ioDrParID;
- if( PBGetCatInfoSync(&infoRec) == noErr ){
- CopyPascalStringToC(dirName, zdirName);
- i = strlen(zdirName);
- memmove(&(zTempPath[i+1]), zTempPath, strlen(zTempPath));
- strcpy(zTempPath, zdirName);
- zTempPath[i] = ':';
- }else{
- *zTempPath = 0;
- break;
- }
- } while( infoRec.dirInfo.ioDrDirID != fsRtDirID );
- }
- if( *zTempPath == 0 )
- getcwd(zTempPath, SQLITE_TEMPNAME_SIZE-24);
- for(;;){
- sprintf(zBuf, "%s"TEMP_FILE_PREFIX, zTempPath);
- j = strlen(zBuf);
- sqlite3Randomness(15, &zBuf[j]);
- for(i=0; i<15; i++, j++){
- zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
- }
- zBuf[j] = 0;
- if( !sqlite3OsFileExists(zBuf) ) break;
- }
- return SQLITE_OK;
-}
-
-/*
-** Close a file.
-*/
-int sqlite3OsClose(OsFile *id){
- if( id->refNumRF!=-1 )
- FSClose(id->refNumRF);
-# ifdef _LARGE_FILE
- FSCloseFork(id->refNum);
-# else
- FSClose(id->refNum);
-# endif
- if( id->delOnClose ){
- unlink(id->pathToDel);
- sqliteFree(id->pathToDel);
- }
- OpenCounter(-1);
- return SQLITE_OK;
-}
-
-/*
-** Read data from a file into a buffer. Return SQLITE_OK if all
-** bytes were read successfully and SQLITE_IOERR if anything goes
-** wrong.
-*/
-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
- int got;
- SimulateIOError(SQLITE_IOERR);
- TRACE2("READ %d\n", last_page);
-# ifdef _LARGE_FILE
- FSReadFork(id->refNum, fsAtMark, 0, (ByteCount)amt, pBuf, (ByteCount*)&got);
-# else
- got = amt;
- FSRead(id->refNum, &got, pBuf);
-# endif
- if( got==amt ){
- return SQLITE_OK;
- }else{
- return SQLITE_IOERR;
- }
-}
-
-/*
-** Write data from a buffer into a file. Return SQLITE_OK on success
-** or some other error code on failure.
-*/
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
- OSErr oserr;
- int wrote = 0;
- SimulateIOError(SQLITE_IOERR);
- TRACE2("WRITE %d\n", last_page);
- while( amt>0 ){
-# ifdef _LARGE_FILE
- oserr = FSWriteFork(id->refNum, fsAtMark, 0,
- (ByteCount)amt, pBuf, (ByteCount*)&wrote);
-# else
- wrote = amt;
- oserr = FSWrite(id->refNum, &wrote, pBuf);
-# endif
- if( wrote == 0 || oserr != noErr)
- break;
- amt -= wrote;
- pBuf = &((char*)pBuf)[wrote];
- }
- if( oserr != noErr || amt>wrote ){
- return SQLITE_FULL;
- }
- return SQLITE_OK;
-}
-
-/*
-** Move the read/write pointer in a file.
-*/
-int sqlite3OsSeek(OsFile *id, off_t offset){
- off_t curSize;
- SEEK(offset/1024 + 1);
- if( sqlite3OsFileSize(id, &curSize) != SQLITE_OK ){
- return SQLITE_IOERR;
- }
- if( offset >= curSize ){
- if( sqlite3OsTruncate(id, offset+1) != SQLITE_OK ){
- return SQLITE_IOERR;
- }
- }
-# ifdef _LARGE_FILE
- if( FSSetForkPosition(id->refNum, fsFromStart, offset) != noErr ){
-# else
- if( SetFPos(id->refNum, fsFromStart, offset) != noErr ){
-# endif
- return SQLITE_IOERR;
- }else{
- return SQLITE_OK;
- }
-}
-
-/*
-** Make sure all writes to a particular file are committed to disk.
-**
-** Under Unix, also make sure that the directory entry for the file
-** has been created by fsync-ing the directory that contains the file.
-** If we do not do this and we encounter a power failure, the directory
-** entry for the journal might not exist after we reboot. The next
-** SQLite to access the file will not know that the journal exists (because
-** the directory entry for the journal was never created) and the transaction
-** will not roll back - possibly leading to database corruption.
-*/
-int sqlite3OsSync(OsFile *id){
-# ifdef _LARGE_FILE
- if( FSFlushFork(id->refNum) != noErr ){
-# else
- ParamBlockRec params;
- memset(&params, 0, sizeof(ParamBlockRec));
- params.ioParam.ioRefNum = id->refNum;
- if( PBFlushFileSync(&params) != noErr ){
-# endif
- return SQLITE_IOERR;
- }else{
- return SQLITE_OK;
- }
-}
-
-/*
-** Sync the directory zDirname. This is a no-op on operating systems other
-** than UNIX.
-*/
-int sqlite3OsSyncDirectory(const char *zDirname){
- SimulateIOError(SQLITE_IOERR);
- return SQLITE_OK;
-}
-
-/*
-** Truncate an open file to a specified size
-*/
-int sqlite3OsTruncate(OsFile *id, off_t nByte){
- SimulateIOError(SQLITE_IOERR);
-# ifdef _LARGE_FILE
- if( FSSetForkSize(id->refNum, fsFromStart, nByte) != noErr){
-# else
- if( SetEOF(id->refNum, nByte) != noErr ){
-# endif
- return SQLITE_IOERR;
- }else{
- return SQLITE_OK;
- }
-}
-
-/*
-** Determine the current size of a file in bytes
-*/
-int sqlite3OsFileSize(OsFile *id, off_t *pSize){
-# ifdef _LARGE_FILE
- if( FSGetForkSize(id->refNum, pSize) != noErr){
-# else
- if( GetEOF(id->refNum, pSize) != noErr ){
-# endif
- return SQLITE_IOERR;
- }else{
- return SQLITE_OK;
- }
-}
-
-/*
-** Windows file locking notes: [similar issues apply to MacOS]
-**
-** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
-** those functions are not available. So we use only LockFile() and
-** UnlockFile().
-**
-** LockFile() prevents not just writing but also reading by other processes.
-** (This is a design error on the part of Windows, but there is nothing
-** we can do about that.) So the region used for locking is at the
-** end of the file where it is unlikely to ever interfere with an
-** actual read attempt.
-**
-** A database read lock is obtained by locking a single randomly-chosen
-** byte out of a specific range of bytes. The lock byte is obtained at
-** random so two separate readers can probably access the file at the
-** same time, unless they are unlucky and choose the same lock byte.
-** A database write lock is obtained by locking all bytes in the range.
-** There can only be one writer.
-**
-** A lock is obtained on the first byte of the lock range before acquiring
-** either a read lock or a write lock. This prevents two processes from
-** attempting to get a lock at a same time. The semantics of
-** sqlite3OsReadLock() require that if there is already a write lock, that
-** lock is converted into a read lock atomically. The lock on the first
-** byte allows us to drop the old write lock and get the read lock without
-** another process jumping into the middle and messing us up. The same
-** argument applies to sqlite3OsWriteLock().
-**
-** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
-** which means we can use reader/writer locks. When reader writer locks
-** are used, the lock is placed on the same range of bytes that is used
-** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
-** will support two or more Win95 readers or two or more WinNT readers.
-** But a single Win95 reader will lock out all WinNT readers and a single
-** WinNT reader will lock out all other Win95 readers.
-**
-** Note: On MacOS we use the resource fork for locking.
-**
-** The following #defines specify the range of bytes used for locking.
-** N_LOCKBYTE is the number of bytes available for doing the locking.
-** The first byte used to hold the lock while the lock is changing does
-** not count toward this number. FIRST_LOCKBYTE is the address of
-** the first byte in the range of bytes used for locking.
-*/
-#define N_LOCKBYTE 10239
-#define FIRST_LOCKBYTE (0x000fffff - N_LOCKBYTE)
-
-/*
-** Change the status of the lock on the file "id" to be a readlock.
-** If the file was write locked, then this reduces the lock to a read.
-** If the file was read locked, then this acquires a new read lock.
-**
-** Return SQLITE_OK on success and SQLITE_BUSY on failure. If this
-** library was compiled with large file support (LFS) but LFS is not
-** available on the host, then an SQLITE_NOLFS is returned.
-*/
-int sqlite3OsReadLock(OsFile *id){
- int rc;
- if( id->locked>0 || id->refNumRF == -1 ){
- rc = SQLITE_OK;
- }else{
- int lk;
- OSErr res;
- int cnt = 5;
- ParamBlockRec params;
- sqlite3Randomness(sizeof(lk), &lk);
- lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
- memset(&params, 0, sizeof(params));
- params.ioParam.ioRefNum = id->refNumRF;
- params.ioParam.ioPosMode = fsFromStart;
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
- params.ioParam.ioReqCount = 1;
- while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
- UInt32 finalTicks;
- Delay(1, &finalTicks); /* 1/60 sec */
- }
- if( res == noErr ){
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
- params.ioParam.ioReqCount = N_LOCKBYTE;
- PBUnlockRangeSync(&params);
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE+lk;
- params.ioParam.ioReqCount = 1;
- res = PBLockRangeSync(&params);
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
- params.ioParam.ioReqCount = 1;
- PBUnlockRangeSync(&params);
- }
- if( res == noErr ){
- id->locked = lk;
- rc = SQLITE_OK;
- }else{
- rc = SQLITE_BUSY;
- }
- }
- return rc;
-}
-
-/*
-** Change the lock status to be an exclusive or write lock. Return
-** SQLITE_OK on success and SQLITE_BUSY on a failure. If this
-** library was compiled with large file support (LFS) but LFS is not
-** available on the host, then an SQLITE_NOLFS is returned.
-*/
-int sqlite3OsWriteLock(OsFile *id){
- int rc;
- if( id->locked<0 || id->refNumRF == -1 ){
- rc = SQLITE_OK;
- }else{
- OSErr res;
- int cnt = 5;
- ParamBlockRec params;
- memset(&params, 0, sizeof(params));
- params.ioParam.ioRefNum = id->refNumRF;
- params.ioParam.ioPosMode = fsFromStart;
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
- params.ioParam.ioReqCount = 1;
- while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
- UInt32 finalTicks;
- Delay(1, &finalTicks); /* 1/60 sec */
- }
- if( res == noErr ){
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE + id->locked;
- params.ioParam.ioReqCount = 1;
- if( id->locked==0
- || PBUnlockRangeSync(&params)==noErr ){
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
- params.ioParam.ioReqCount = N_LOCKBYTE;
- res = PBLockRangeSync(&params);
- }else{
- res = afpRangeNotLocked;
- }
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
- params.ioParam.ioReqCount = 1;
- PBUnlockRangeSync(&params);
- }
- if( res == noErr ){
- id->locked = -1;
- rc = SQLITE_OK;
- }else{
- rc = SQLITE_BUSY;
- }
- }
- return rc;
-}
-
-/*
-** Unlock the given file descriptor. If the file descriptor was
-** not previously locked, then this routine is a no-op. If this
-** library was compiled with large file support (LFS) but LFS is not
-** available on the host, then an SQLITE_NOLFS is returned.
-*/
-int sqlite3OsUnlock(OsFile *id){
- int rc;
- ParamBlockRec params;
- memset(&params, 0, sizeof(params));
- params.ioParam.ioRefNum = id->refNumRF;
- params.ioParam.ioPosMode = fsFromStart;
- if( id->locked==0 || id->refNumRF == -1 ){
- rc = SQLITE_OK;
- }else if( id->locked<0 ){
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
- params.ioParam.ioReqCount = N_LOCKBYTE;
- PBUnlockRangeSync(&params);
- rc = SQLITE_OK;
- id->locked = 0;
- }else{
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE+id->locked;
- params.ioParam.ioReqCount = 1;
- PBUnlockRangeSync(&params);
- rc = SQLITE_OK;
- id->locked = 0;
- }
- return rc;
-}
-
-/*
-** Get information to seed the random number generator. The seed
-** is written into the buffer zBuf[256]. The calling function must
-** supply a sufficiently large buffer.
-*/
-int sqlite3OsRandomSeed(char *zBuf){
- /* We have to initialize zBuf to prevent valgrind from reporting
- ** errors. The reports issued by valgrind are incorrect - we would
- ** prefer that the randomness be increased by making use of the
- ** uninitialized space in zBuf - but valgrind errors tend to worry
- ** some users. Rather than argue, it seems easier just to initialize
- ** the whole array and silence valgrind, even if that means less randomness
- ** in the random seed.
- **
- ** When testing, initializing zBuf[] to zero is all we do. That means
- ** that we always use the same random number sequence.* This makes the
- ** tests repeatable.
- */
- memset(zBuf, 0, 256);
-#if !defined(SQLITE_TEST)
- {
- int pid;
- Microseconds((UnsignedWide*)zBuf);
- pid = getpid();
- memcpy(&zBuf[sizeof(UnsignedWide)], &pid, sizeof(pid));
- }
-#endif
- return SQLITE_OK;
-}
-
-/*
-** Sleep for a little while. Return the amount of time slept.
-*/
-int sqlite3OsSleep(int ms){
- UInt32 finalTicks;
- UInt32 ticks = (((UInt32)ms+16)*3)/50; /* 1/60 sec per tick */
- Delay(ticks, &finalTicks);
- return (int)((ticks*50)/3);
-}
-
-/*
-** Static variables used for thread synchronization
-*/
-static int inMutex = 0;
-#ifdef SQLITE_MACOS_MULTITASKING
- static MPCriticalRegionID criticalRegion;
-#endif
-
-/*
-** The following pair of routine implement mutual exclusion for
-** multi-threaded processes. Only a single thread is allowed to
-** executed code that is surrounded by EnterMutex() and LeaveMutex().
-**
-** SQLite uses only a single Mutex. There is not much critical
-** code and what little there is executes quickly and without blocking.
-*/
-void sqlite3OsEnterMutex(){
-#ifdef SQLITE_MACOS_MULTITASKING
- static volatile int notInit = 1;
- if( notInit ){
- if( notInit == 2 ) /* as close as you can get to thread safe init */
- MPYield();
- else{
- notInit = 2;
- MPCreateCriticalRegion(&criticalRegion);
- notInit = 0;
- }
- }
- MPEnterCriticalRegion(criticalRegion, kDurationForever);
-#endif
- assert( !inMutex );
- inMutex = 1;
-}
-void sqlite3OsLeaveMutex(){
- assert( inMutex );
- inMutex = 0;
-#ifdef SQLITE_MACOS_MULTITASKING
- MPExitCriticalRegion(criticalRegion);
-#endif
-}
-
-/*
-** Turn a relative pathname into a full pathname. Return a pointer
-** to the full pathname stored in space obtained from sqliteMalloc().
-** The calling function is responsible for freeing this space once it
-** is no longer needed.
-*/
-char *sqlite3OsFullPathname(const char *zRelative){
- char *zFull = 0;
- if( zRelative[0]==':' ){
- char zBuf[_MAX_PATH+1];
- sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), &(zRelative[1]),
- (char*)0);
- }else{
- if( strchr(zRelative, ':') ){
- sqlite3SetString(&zFull, zRelative, (char*)0);
- }else{
- char zBuf[_MAX_PATH+1];
- sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), zRelative, (char*)0);
- }
- }
- return zFull;
-}
-
-/*
-** The following variable, if set to a non-zero value, becomes the result
-** returned from sqlite3OsCurrentTime(). This is used for testing.
-*/
-#ifdef SQLITE_TEST
-int sqlite3_current_time = 0;
-#endif
-
-/*
-** Find the current time (in Universal Coordinated Time). Write the
-** current time and date as a Julian Day number into *prNow and
-** return 0. Return 1 if the time and date cannot be found.
-*/
-int sqlite3OsCurrentTime(double *prNow){
- *prNow = 0.0; /**** FIX ME *****/
-#ifdef SQLITE_TEST
- if( sqlite3_current_time ){
- *prNow = sqlite3_current_time/86400.0 + 2440587.5;
- }
-#endif
- return 0;
-}
-
-#endif /* OS_MAC */
diff --git a/kopete/plugins/statistics/sqlite/os_mac.h b/kopete/plugins/statistics/sqlite/os_mac.h
deleted file mode 100644
index 5b60f818..00000000
--- a/kopete/plugins/statistics/sqlite/os_mac.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-** 2004 May 22
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This header file defines OS-specific features of classic Mac.
-** OS X uses the os_unix.h file, not this one.
-*/
-#ifndef _SQLITE_OS_MAC_H_
-#define _SQLITE_OS_MAC_H_
-
-
-#include <unistd.h>
-#include <Files.h>
-#define SQLITE_TEMPNAME_SIZE _MAX_PATH
-#define SQLITE_MIN_SLEEP_MS 17
-
-/*
-** The OsFile structure is a operating-system independing representation
-** of an open file handle. It is defined differently for each architecture.
-**
-** This is the definition for class Mac.
-*/
-typedef struct OsFile OsFile;
-struct OsFile {
- SInt16 refNum; /* Data fork/file reference number */
- SInt16 refNumRF; /* Resource fork reference number (for locking) */
- int locked; /* 0: unlocked, <0: write lock, >0: read lock */
- int delOnClose; /* True if file is to be deleted on close */
- char *pathToDel; /* Name of file to delete on close */
-};
-
-
-#endif /* _SQLITE_OS_MAC_H_ */
diff --git a/kopete/plugins/statistics/sqlite/os_unix.c b/kopete/plugins/statistics/sqlite/os_unix.c
deleted file mode 100644
index 94fca701..00000000
--- a/kopete/plugins/statistics/sqlite/os_unix.c
+++ /dev/null
@@ -1,1276 +0,0 @@
-/*
-** 2004 May 22
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This file contains code that is specific to Unix systems.
-*/
-#include "sqliteInt.h"
-#include "os.h"
-#if OS_UNIX /* This file is used on unix only */
-
-
-#include <time.h>
-#include <errno.h>
-#include <unistd.h>
-#ifndef O_LARGEFILE
-# define O_LARGEFILE 0
-#endif
-#ifdef SQLITE_DISABLE_LFS
-# undef O_LARGEFILE
-# define O_LARGEFILE 0
-#endif
-#ifndef O_NOFOLLOW
-# define O_NOFOLLOW 0
-#endif
-#ifndef O_BINARY
-# define O_BINARY 0
-#endif
-
-
-/*
-** The DJGPP compiler environment looks mostly like Unix, but it
-** lacks the fcntl() system call. So redefine fcntl() to be something
-** that always succeeds. This means that locking does not occur under
-** DJGPP. But its DOS - what did you expect?
-*/
-#ifdef __DJGPP__
-# define fcntl(A,B,C) 0
-#endif
-
-/*
-** Macros used to determine whether or not to use threads. The
-** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for
-** Posix threads and SQLITE_W32_THREADS is defined if we are
-** synchronizing using Win32 threads.
-*/
-#if defined(THREADSAFE) && THREADSAFE
-# include <pthread.h>
-# define SQLITE_UNIX_THREADS 1
-#endif
-
-
-/*
-** Include code that is common to all os_*.c files
-*/
-#include "os_common.h"
-
-#if defined(THREADSAFE) && THREADSAFE && defined(__linux__)
-#define getpid pthread_self
-#endif
-
-/*
-** Here is the dirt on POSIX advisory locks: ANSI STD 1003.1 (1996)
-** section 6.5.2.2 lines 483 through 490 specify that when a process
-** sets or clears a lock, that operation overrides any prior locks set
-** by the same process. It does not explicitly say so, but this implies
-** that it overrides locks set by the same process using a different
-** file descriptor. Consider this test case:
-**
-** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644);
-** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644);
-**
-** Suppose ./file1 and ./file2 are really the same file (because
-** one is a hard or symbolic link to the other) then if you set
-** an exclusive lock on fd1, then try to get an exclusive lock
-** on fd2, it works. I would have expected the second lock to
-** fail since there was already a lock on the file due to fd1.
-** But not so. Since both locks came from the same process, the
-** second overrides the first, even though they were on different
-** file descriptors opened on different file names.
-**
-** Bummer. If you ask me, this is broken. Badly broken. It means
-** that we cannot use POSIX locks to synchronize file access among
-** competing threads of the same process. POSIX locks will work fine
-** to synchronize access for threads in separate processes, but not
-** threads within the same process.
-**
-** To work around the problem, SQLite has to manage file locks internally
-** on its own. Whenever a new database is opened, we have to find the
-** specific inode of the database file (the inode is determined by the
-** st_dev and st_ino fields of the stat structure that fstat() fills in)
-** and check for locks already existing on that inode. When locks are
-** created or removed, we have to look at our own internal record of the
-** locks to see if another thread has previously set a lock on that same
-** inode.
-**
-** The OsFile structure for POSIX is no longer just an integer file
-** descriptor. It is now a structure that holds the integer file
-** descriptor and a pointer to a structure that describes the internal
-** locks on the corresponding inode. There is one locking structure
-** per inode, so if the same inode is opened twice, both OsFile structures
-** point to the same locking structure. The locking structure keeps
-** a reference count (so we will know when to delete it) and a "cnt"
-** field that tells us its internal lock status. cnt==0 means the
-** file is unlocked. cnt==-1 means the file has an exclusive lock.
-** cnt>0 means there are cnt shared locks on the file.
-**
-** Any attempt to lock or unlock a file first checks the locking
-** structure. The fcntl() system call is only invoked to set a
-** POSIX lock if the internal lock structure transitions between
-** a locked and an unlocked state.
-**
-** 2004-Jan-11:
-** More recent discoveries about POSIX advisory locks. (The more
-** I discover, the more I realize the a POSIX advisory locks are
-** an abomination.)
-**
-** If you close a file descriptor that points to a file that has locks,
-** all locks on that file that are owned by the current process are
-** released. To work around this problem, each OsFile structure contains
-** a pointer to an openCnt structure. There is one openCnt structure
-** per open inode, which means that multiple OsFiles can point to a single
-** openCnt. When an attempt is made to close an OsFile, if there are
-** other OsFiles open on the same inode that are holding locks, the call
-** to close() the file descriptor is deferred until all of the locks clear.
-** The openCnt structure keeps a list of file descriptors that need to
-** be closed and that list is walked (and cleared) when the last lock
-** clears.
-**
-** First, under Linux threads, because each thread has a separate
-** process ID, lock operations in one thread do not override locks
-** to the same file in other threads. Linux threads behave like
-** separate processes in this respect. But, if you close a file
-** descriptor in linux threads, all locks are cleared, even locks
-** on other threads and even though the other threads have different
-** process IDs. Linux threads is inconsistent in this respect.
-** (I'm beginning to think that linux threads is an abomination too.)
-** The consequence of this all is that the hash table for the lockInfo
-** structure has to include the process id as part of its key because
-** locks in different threads are treated as distinct. But the
-** openCnt structure should not include the process id in its
-** key because close() clears lock on all threads, not just the current
-** thread. Were it not for this goofiness in linux threads, we could
-** combine the lockInfo and openCnt structures into a single structure.
-**
-** 2004-Jun-28:
-** On some versions of linux, threads can override each others locks.
-** On others not. Sometimes you can change the behavior on the same
-** system by setting the LD_ASSUME_KERNEL environment variable. The
-** POSIX standard is silent as to which behavior is correct, as far
-** as I can tell, so other versions of unix might show the same
-** inconsistency. There is no little doubt in my mind that posix
-** advisory locks and linux threads are profoundly broken.
-**
-** To work around the inconsistencies, we have to test at runtime
-** whether or not threads can override each others locks. This test
-** is run once, the first time any lock is attempted. A static
-** variable is set to record the results of this test for future
-** use.
-*/
-
-/*
-** An instance of the following structure serves as the key used
-** to locate a particular lockInfo structure given its inode.
-**
-** If threads cannot override each others locks, then we set the
-** lockKey.tid field to the thread ID. If threads can override
-** each others locks then tid is always set to zero. tid is also
-** set to zero if we compile without threading support.
-*/
-struct lockKey {
- dev_t dev; /* Device number */
- ino_t ino; /* Inode number */
-#ifdef SQLITE_UNIX_THREADS
- pthread_t tid; /* Thread ID or zero if threads cannot override each other */
-#endif
-};
-
-/*
-** An instance of the following structure is allocated for each open
-** inode on each thread with a different process ID. (Threads have
-** different process IDs on linux, but not on most other unixes.)
-**
-** A single inode can have multiple file descriptors, so each OsFile
-** structure contains a pointer to an instance of this object and this
-** object keeps a count of the number of OsFiles pointing to it.
-*/
-struct lockInfo {
- struct lockKey key; /* The lookup key */
- int cnt; /* Number of SHARED locks held */
- int locktype; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
- int nRef; /* Number of pointers to this structure */
-};
-
-/*
-** An instance of the following structure serves as the key used
-** to locate a particular openCnt structure given its inode. This
-** is the same as the lockKey except that the thread ID is omitted.
-*/
-struct openKey {
- dev_t dev; /* Device number */
- ino_t ino; /* Inode number */
-};
-
-/*
-** An instance of the following structure is allocated for each open
-** inode. This structure keeps track of the number of locks on that
-** inode. If a close is attempted against an inode that is holding
-** locks, the close is deferred until all locks clear by adding the
-** file descriptor to be closed to the pending list.
-*/
-struct openCnt {
- struct openKey key; /* The lookup key */
- int nRef; /* Number of pointers to this structure */
- int nLock; /* Number of outstanding locks */
- int nPending; /* Number of pending close() operations */
- int *aPending; /* Malloced space holding fd's awaiting a close() */
-};
-
-/*
-** These hash table maps inodes and process IDs into lockInfo and openCnt
-** structures. Access to these hash tables must be protected by a mutex.
-*/
-static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
-static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
-
-
-#ifdef SQLITE_UNIX_THREADS
-/*
-** This variable records whether or not threads can override each others
-** locks.
-**
-** 0: No. Threads cannot override each others locks.
-** 1: Yes. Threads can override each others locks.
-** -1: We don't know yet.
-*/
-static int threadsOverrideEachOthersLocks = -1;
-
-/*
-** This structure holds information passed into individual test
-** threads by the testThreadLockingBehavior() routine.
-*/
-struct threadTestData {
- int fd; /* File to be locked */
- struct flock lock; /* The locking operation */
- int result; /* Result of the locking operation */
-};
-
-/*
-** The testThreadLockingBehavior() routine launches two separate
-** threads on this routine. This routine attempts to lock a file
-** descriptor then returns. The success or failure of that attempt
-** allows the testThreadLockingBehavior() procedure to determine
-** whether or not threads can override each others locks.
-*/
-static void *threadLockingTest(void *pArg){
- struct threadTestData *pData = (struct threadTestData*)pArg;
- pData->result = fcntl(pData->fd, F_SETLK, &pData->lock);
- return pArg;
-}
-
-/*
-** This procedure attempts to determine whether or not threads
-** can override each others locks then sets the
-** threadsOverrideEachOthersLocks variable appropriately.
-*/
-static void testThreadLockingBehavior(fd_orig){
- int fd;
- struct threadTestData d[2];
- pthread_t t[2];
-
- fd = dup(fd_orig);
- if( fd<0 ) return;
- memset(d, 0, sizeof(d));
- d[0].fd = fd;
- d[0].lock.l_type = F_RDLCK;
- d[0].lock.l_len = 1;
- d[0].lock.l_start = 0;
- d[0].lock.l_whence = SEEK_SET;
- d[1] = d[0];
- d[1].lock.l_type = F_WRLCK;
- pthread_create(&t[0], 0, threadLockingTest, &d[0]);
- pthread_create(&t[1], 0, threadLockingTest, &d[1]);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
- close(fd);
- threadsOverrideEachOthersLocks = d[0].result==0 && d[1].result==0;
-}
-#endif /* SQLITE_UNIX_THREADS */
-
-/*
-** Release a lockInfo structure previously allocated by findLockInfo().
-*/
-static void releaseLockInfo(struct lockInfo *pLock){
- pLock->nRef--;
- if( pLock->nRef==0 ){
- sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
- sqliteFree(pLock);
- }
-}
-
-/*
-** Release a openCnt structure previously allocated by findLockInfo().
-*/
-static void releaseOpenCnt(struct openCnt *pOpen){
- pOpen->nRef--;
- if( pOpen->nRef==0 ){
- sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
- sqliteFree(pOpen->aPending);
- sqliteFree(pOpen);
- }
-}
-
-/*
-** Given a file descriptor, locate lockInfo and openCnt structures that
-** describes that file descriptor. Create a new ones if necessary. The
-** return values might be unset if an error occurs.
-**
-** Return the number of errors.
-*/
-static int findLockInfo(
- int fd, /* The file descriptor used in the key */
- struct lockInfo **ppLock, /* Return the lockInfo structure here */
- struct openCnt **ppOpen /* Return the openCnt structure here */
-){
- int rc;
- struct lockKey key1;
- struct openKey key2;
- struct stat statbuf;
- struct lockInfo *pLock;
- struct openCnt *pOpen;
- rc = fstat(fd, &statbuf);
- if( rc!=0 ) return 1;
- memset(&key1, 0, sizeof(key1));
- key1.dev = statbuf.st_dev;
- key1.ino = statbuf.st_ino;
-#ifdef SQLITE_UNIX_THREADS
- if( threadsOverrideEachOthersLocks<0 ){
- testThreadLockingBehavior(fd);
- }
- key1.tid = threadsOverrideEachOthersLocks ? 0 : pthread_self();
-#endif
- memset(&key2, 0, sizeof(key2));
- key2.dev = statbuf.st_dev;
- key2.ino = statbuf.st_ino;
- pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1));
- if( pLock==0 ){
- struct lockInfo *pOld;
- pLock = sqliteMallocRaw( sizeof(*pLock) );
- if( pLock==0 ) return 1;
- pLock->key = key1;
- pLock->nRef = 1;
- pLock->cnt = 0;
- pLock->locktype = 0;
- pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock);
- if( pOld!=0 ){
- assert( pOld==pLock );
- sqliteFree(pLock);
- return 1;
- }
- }else{
- pLock->nRef++;
- }
- *ppLock = pLock;
- pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
- if( pOpen==0 ){
- struct openCnt *pOld;
- pOpen = sqliteMallocRaw( sizeof(*pOpen) );
- if( pOpen==0 ){
- releaseLockInfo(pLock);
- return 1;
- }
- pOpen->key = key2;
- pOpen->nRef = 1;
- pOpen->nLock = 0;
- pOpen->nPending = 0;
- pOpen->aPending = 0;
- pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
- if( pOld!=0 ){
- assert( pOld==pOpen );
- sqliteFree(pOpen);
- releaseLockInfo(pLock);
- return 1;
- }
- }else{
- pOpen->nRef++;
- }
- *ppOpen = pOpen;
- return 0;
-}
-
-/*
-** Delete the named file
-*/
-int sqlite3OsDelete(const char *zFilename){
- unlink(zFilename);
- return SQLITE_OK;
-}
-
-/*
-** Return TRUE if the named file exists.
-*/
-int sqlite3OsFileExists(const char *zFilename){
- return access(zFilename, 0)==0;
-}
-
-/*
-** Attempt to open a file for both reading and writing. If that
-** fails, try opening it read-only. If the file does not exist,
-** try to create it.
-**
-** On success, a handle for the open file is written to *id
-** and *pReadonly is set to 0 if the file was opened for reading and
-** writing or 1 if the file was opened read-only. The function returns
-** SQLITE_OK.
-**
-** On failure, the function returns SQLITE_CANTOPEN and leaves
-** *id and *pReadonly unchanged.
-*/
-int sqlite3OsOpenReadWrite(
- const char *zFilename,
- OsFile *id,
- int *pReadonly
-){
- int rc;
- assert( !id->isOpen );
- id->dirfd = -1;
- id->h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644);
- if( id->h<0 ){
-#ifdef EISDIR
- if( errno==EISDIR ){
- return SQLITE_CANTOPEN;
- }
-#endif
- id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
- if( id->h<0 ){
- return SQLITE_CANTOPEN;
- }
- *pReadonly = 1;
- }else{
- *pReadonly = 0;
- }
- sqlite3OsEnterMutex();
- rc = findLockInfo(id->h, &id->pLock, &id->pOpen);
- sqlite3OsLeaveMutex();
- if( rc ){
- close(id->h);
- return SQLITE_NOMEM;
- }
- id->locktype = 0;
- id->isOpen = 1;
- TRACE3("OPEN %-3d %s\n", id->h, zFilename);
- OpenCounter(+1);
- return SQLITE_OK;
-}
-
-
-/*
-** Attempt to open a new file for exclusive access by this process.
-** The file will be opened for both reading and writing. To avoid
-** a potential security problem, we do not allow the file to have
-** previously existed. Nor do we allow the file to be a symbolic
-** link.
-**
-** If delFlag is true, then make arrangements to automatically delete
-** the file when it is closed.
-**
-** On success, write the file handle into *id and return SQLITE_OK.
-**
-** On failure, return SQLITE_CANTOPEN.
-*/
-int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
- int rc;
- assert( !id->isOpen );
- if( access(zFilename, 0)==0 ){
- return SQLITE_CANTOPEN;
- }
- id->dirfd = -1;
- id->h = open(zFilename,
- O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600);
- if( id->h<0 ){
- return SQLITE_CANTOPEN;
- }
- sqlite3OsEnterMutex();
- rc = findLockInfo(id->h, &id->pLock, &id->pOpen);
- sqlite3OsLeaveMutex();
- if( rc ){
- close(id->h);
- unlink(zFilename);
- return SQLITE_NOMEM;
- }
- id->locktype = 0;
- id->isOpen = 1;
- if( delFlag ){
- unlink(zFilename);
- }
- TRACE3("OPEN-EX %-3d %s\n", id->h, zFilename);
- OpenCounter(+1);
- return SQLITE_OK;
-}
-
-/*
-** Attempt to open a new file for read-only access.
-**
-** On success, write the file handle into *id and return SQLITE_OK.
-**
-** On failure, return SQLITE_CANTOPEN.
-*/
-int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
- int rc;
- assert( !id->isOpen );
- id->dirfd = -1;
- id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
- if( id->h<0 ){
- return SQLITE_CANTOPEN;
- }
- sqlite3OsEnterMutex();
- rc = findLockInfo(id->h, &id->pLock, &id->pOpen);
- sqlite3OsLeaveMutex();
- if( rc ){
- close(id->h);
- return SQLITE_NOMEM;
- }
- id->locktype = 0;
- id->isOpen = 1;
- TRACE3("OPEN-RO %-3d %s\n", id->h, zFilename);
- OpenCounter(+1);
- return SQLITE_OK;
-}
-
-/*
-** Attempt to open a file descriptor for the directory that contains a
-** file. This file descriptor can be used to fsync() the directory
-** in order to make sure the creation of a new file is actually written
-** to disk.
-**
-** This routine is only meaningful for Unix. It is a no-op under
-** windows since windows does not support hard links.
-**
-** On success, a handle for a previously open file is at *id is
-** updated with the new directory file descriptor and SQLITE_OK is
-** returned.
-**
-** On failure, the function returns SQLITE_CANTOPEN and leaves
-** *id unchanged.
-*/
-int sqlite3OsOpenDirectory(
- const char *zDirname,
- OsFile *id
-){
- if( !id->isOpen ){
- /* Do not open the directory if the corresponding file is not already
- ** open. */
- return SQLITE_CANTOPEN;
- }
- assert( id->dirfd<0 );
- id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0644);
- if( id->dirfd<0 ){
- return SQLITE_CANTOPEN;
- }
- TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname);
- return SQLITE_OK;
-}
-
-/*
-** If the following global variable points to a string which is the
-** name of a directory, then that directory will be used to store
-** temporary files.
-*/
-const char *sqlite3_temp_directory = 0;
-
-/*
-** Create a temporary file name in zBuf. zBuf must be big enough to
-** hold at least SQLITE_TEMPNAME_SIZE characters.
-*/
-int sqlite3OsTempFileName(char *zBuf){
- static const char *azDirs[] = {
- 0,
- "/var/tmp",
- "/usr/tmp",
- "/tmp",
- ".",
- };
- static const unsigned char zChars[] =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789";
- int i, j;
- struct stat buf;
- const char *zDir = ".";
- azDirs[0] = sqlite3_temp_directory;
- for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
- if( azDirs[i]==0 ) continue;
- if( stat(azDirs[i], &buf) ) continue;
- if( !S_ISDIR(buf.st_mode) ) continue;
- if( access(azDirs[i], 07) ) continue;
- zDir = azDirs[i];
- break;
- }
- do{
- sprintf(zBuf, "%s/"TEMP_FILE_PREFIX, zDir);
- j = strlen(zBuf);
- sqlite3Randomness(15, &zBuf[j]);
- for(i=0; i<15; i++, j++){
- zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
- }
- zBuf[j] = 0;
- }while( access(zBuf,0)==0 );
- return SQLITE_OK;
-}
-
-/*
-** Read data from a file into a buffer. Return SQLITE_OK if all
-** bytes were read successfully and SQLITE_IOERR if anything goes
-** wrong.
-*/
-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
- int got;
- assert( id->isOpen );
- SimulateIOError(SQLITE_IOERR);
- TIMER_START;
- got = read(id->h, pBuf, amt);
- TIMER_END;
- TRACE4("READ %-3d %7d %d\n", id->h, last_page, TIMER_ELAPSED);
- SEEK(0);
- /* if( got<0 ) got = 0; */
- if( got==amt ){
- return SQLITE_OK;
- }else{
- return SQLITE_IOERR;
- }
-}
-
-/*
-** Write data from a buffer into a file. Return SQLITE_OK on success
-** or some other error code on failure.
-*/
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
- int wrote = 0;
- assert( id->isOpen );
- SimulateIOError(SQLITE_IOERR);
- SimulateDiskfullError;
- TIMER_START;
- while( amt>0 && (wrote = write(id->h, pBuf, amt))>0 ){
- amt -= wrote;
- pBuf = &((char*)pBuf)[wrote];
- }
- TIMER_END;
- TRACE4("WRITE %-3d %7d %d\n", id->h, last_page, TIMER_ELAPSED);
- SEEK(0);
- if( amt>0 ){
- return SQLITE_FULL;
- }
- return SQLITE_OK;
-}
-
-/*
-** Move the read/write pointer in a file.
-*/
-int sqlite3OsSeek(OsFile *id, i64 offset){
- assert( id->isOpen );
- SEEK(offset/1024 + 1);
- lseek(id->h, offset, SEEK_SET);
- return SQLITE_OK;
-}
-
-/*
-** The fsync() system call does not work as advertised on many
-** unix systems. The following procedure is an attempt to make
-** it work better.
-*/
-static int full_fsync(int fd){
- int rc;
-#ifdef F_FULLFSYNC
- rc = fcntl(fd, F_FULLFSYNC, 0);
- if( rc ) rc = fsync(fd);
-#else
- rc = fsync(fd);
-#endif
- return rc;
-}
-
-/*
-** Make sure all writes to a particular file are committed to disk.
-**
-** Under Unix, also make sure that the directory entry for the file
-** has been created by fsync-ing the directory that contains the file.
-** If we do not do this and we encounter a power failure, the directory
-** entry for the journal might not exist after we reboot. The next
-** SQLite to access the file will not know that the journal exists (because
-** the directory entry for the journal was never created) and the transaction
-** will not roll back - possibly leading to database corruption.
-*/
-int sqlite3OsSync(OsFile *id){
- assert( id->isOpen );
- SimulateIOError(SQLITE_IOERR);
- TRACE2("SYNC %-3d\n", id->h);
- if( full_fsync(id->h) ){
- return SQLITE_IOERR;
- }
- if( id->dirfd>=0 ){
- TRACE2("DIRSYNC %-3d\n", id->dirfd);
- full_fsync(id->dirfd);
- close(id->dirfd); /* Only need to sync once, so close the directory */
- id->dirfd = -1; /* when we are done. */
- }
- return SQLITE_OK;
-}
-
-/*
-** Sync the directory zDirname. This is a no-op on operating systems other
-** than UNIX.
-*/
-int sqlite3OsSyncDirectory(const char *zDirname){
- int fd;
- int r;
- SimulateIOError(SQLITE_IOERR);
- fd = open(zDirname, O_RDONLY|O_BINARY, 0644);
- TRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname);
- if( fd<0 ){
- return SQLITE_CANTOPEN;
- }
- r = fsync(fd);
- close(fd);
- return ((r==0)?SQLITE_OK:SQLITE_IOERR);
-}
-
-/*
-** Truncate an open file to a specified size
-*/
-int sqlite3OsTruncate(OsFile *id, i64 nByte){
- assert( id->isOpen );
- SimulateIOError(SQLITE_IOERR);
- return ftruncate(id->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
-}
-
-/*
-** Determine the current size of a file in bytes
-*/
-int sqlite3OsFileSize(OsFile *id, i64 *pSize){
- struct stat buf;
- assert( id->isOpen );
- SimulateIOError(SQLITE_IOERR);
- if( fstat(id->h, &buf)!=0 ){
- return SQLITE_IOERR;
- }
- *pSize = buf.st_size;
- return SQLITE_OK;
-}
-
-/*
-** This routine checks if there is a RESERVED lock held on the specified
-** file by this or any other process. If such a lock is held, return
-** non-zero. If the file is unlocked or holds only SHARED locks, then
-** return zero.
-*/
-int sqlite3OsCheckReservedLock(OsFile *id){
- int r = 0;
-
- assert( id->isOpen );
- sqlite3OsEnterMutex(); /* Needed because id->pLock is shared across threads */
-
- /* Check if a thread in this process holds such a lock */
- if( id->pLock->locktype>SHARED_LOCK ){
- r = 1;
- }
-
- /* Otherwise see if some other process holds it.
- */
- if( !r ){
- struct flock lock;
- lock.l_whence = SEEK_SET;
- lock.l_start = RESERVED_BYTE;
- lock.l_len = 1;
- lock.l_type = F_WRLCK;
- fcntl(id->h, F_GETLK, &lock);
- if( lock.l_type!=F_UNLCK ){
- r = 1;
- }
- }
-
- sqlite3OsLeaveMutex();
- TRACE3("TEST WR-LOCK %d %d\n", id->h, r);
-
- return r;
-}
-
-#ifdef SQLITE_DEBUG
-/*
-** Helper function for printing out trace information from debugging
-** binaries. This returns the string represetation of the supplied
-** integer lock-type.
-*/
-static const char * locktypeName(int locktype){
- switch( locktype ){
- case NO_LOCK: return "NONE";
- case SHARED_LOCK: return "SHARED";
- case RESERVED_LOCK: return "RESERVED";
- case PENDING_LOCK: return "PENDING";
- case EXCLUSIVE_LOCK: return "EXCLUSIVE";
- }
- return "ERROR";
-}
-#endif
-
-/*
-** Lock the file with the lock specified by parameter locktype - one
-** of the following:
-**
-** (1) SHARED_LOCK
-** (2) RESERVED_LOCK
-** (3) PENDING_LOCK
-** (4) EXCLUSIVE_LOCK
-**
-** Sometimes when requesting one lock state, additional lock states
-** are inserted in between. The locking might fail on one of the later
-** transitions leaving the lock state different from what it started but
-** still short of its goal. The following chart shows the allowed
-** transitions and the inserted intermediate states:
-**
-** UNLOCKED -> SHARED
-** SHARED -> RESERVED
-** SHARED -> (PENDING) -> EXCLUSIVE
-** RESERVED -> (PENDING) -> EXCLUSIVE
-** PENDING -> EXCLUSIVE
-**
-** This routine will only increase a lock. Use the sqlite3OsUnlock()
-** routine to lower a locking level.
-*/
-int sqlite3OsLock(OsFile *id, int locktype){
- /* The following describes the implementation of the various locks and
- ** lock transitions in terms of the POSIX advisory shared and exclusive
- ** lock primitives (called read-locks and write-locks below, to avoid
- ** confusion with SQLite lock names). The algorithms are complicated
- ** slightly in order to be compatible with windows systems simultaneously
- ** accessing the same database file, in case that is ever required.
- **
- ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
- ** byte', each single bytes at well known offsets, and the 'shared byte
- ** range', a range of 510 bytes at a well known offset.
- **
- ** To obtain a SHARED lock, a read-lock is obtained on the 'pending
- ** byte'. If this is successful, a random byte from the 'shared byte
- ** range' is read-locked and the lock on the 'pending byte' released.
- **
- ** A process may only obtain a RESERVED lock after it has a SHARED lock.
- ** A RESERVED lock is implemented by grabbing a write-lock on the
- ** 'reserved byte'.
- **
- ** A process may only obtain a PENDING lock after it has obtained a
- ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock
- ** on the 'pending byte'. This ensures that no new SHARED locks can be
- ** obtained, but existing SHARED locks are allowed to persist. A process
- ** does not have to obtain a RESERVED lock on the way to a PENDING lock.
- ** This property is used by the algorithm for rolling back a journal file
- ** after a crash.
- **
- ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is
- ** implemented by obtaining a write-lock on the entire 'shared byte
- ** range'. Since all other locks require a read-lock on one of the bytes
- ** within this range, this ensures that no other locks are held on the
- ** database.
- **
- ** The reason a single byte cannot be used instead of the 'shared byte
- ** range' is that some versions of windows do not support read-locks. By
- ** locking a random byte from a range, concurrent SHARED locks may exist
- ** even if the locking primitive used is always a write-lock.
- */
- int rc = SQLITE_OK;
- struct lockInfo *pLock = id->pLock;
- struct flock lock;
- int s;
-
- assert( id->isOpen );
- TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype),
- locktypeName(id->locktype), locktypeName(pLock->locktype), pLock->cnt
- ,getpid() );
-
- /* If there is already a lock of this type or more restrictive on the
- ** OsFile, do nothing. Don't use the end_lock: exit path, as
- ** sqlite3OsEnterMutex() hasn't been called yet.
- */
- if( id->locktype>=locktype ){
- TRACE3("LOCK %d %s ok (already held)\n", id->h, locktypeName(locktype));
- return SQLITE_OK;
- }
-
- /* Make sure the locking sequence is correct
- */
- assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK );
- assert( locktype!=PENDING_LOCK );
- assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK );
-
- /* This mutex is needed because id->pLock is shared across threads
- */
- sqlite3OsEnterMutex();
-
- /* If some thread using this PID has a lock via a different OsFile*
- ** handle that precludes the requested lock, return BUSY.
- */
- if( (id->locktype!=pLock->locktype &&
- (pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK))
- ){
- rc = SQLITE_BUSY;
- goto end_lock;
- }
-
- /* If a SHARED lock is requested, and some thread using this PID already
- ** has a SHARED or RESERVED lock, then increment reference counts and
- ** return SQLITE_OK.
- */
- if( locktype==SHARED_LOCK &&
- (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){
- assert( locktype==SHARED_LOCK );
- assert( id->locktype==0 );
- assert( pLock->cnt>0 );
- id->locktype = SHARED_LOCK;
- pLock->cnt++;
- id->pOpen->nLock++;
- goto end_lock;
- }
-
- lock.l_len = 1L;
- lock.l_whence = SEEK_SET;
-
- /* A PENDING lock is needed before acquiring a SHARED lock and before
- ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
- ** be released.
- */
- if( locktype==SHARED_LOCK
- || (locktype==EXCLUSIVE_LOCK && id->locktype<PENDING_LOCK)
- ){
- lock.l_type = (locktype==SHARED_LOCK?F_RDLCK:F_WRLCK);
- lock.l_start = PENDING_BYTE;
- s = fcntl(id->h, F_SETLK, &lock);
- if( s ){
- rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
- goto end_lock;
- }
- }
-
-
- /* If control gets to this point, then actually go ahead and make
- ** operating system calls for the specified lock.
- */
- if( locktype==SHARED_LOCK ){
- assert( pLock->cnt==0 );
- assert( pLock->locktype==0 );
-
- /* Now get the read-lock */
- lock.l_start = SHARED_FIRST;
- lock.l_len = SHARED_SIZE;
- s = fcntl(id->h, F_SETLK, &lock);
-
- /* Drop the temporary PENDING lock */
- lock.l_start = PENDING_BYTE;
- lock.l_len = 1L;
- lock.l_type = F_UNLCK;
- fcntl(id->h, F_SETLK, &lock);
- if( s ){
- rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
- }else{
- id->locktype = SHARED_LOCK;
- id->pOpen->nLock++;
- pLock->cnt = 1;
- }
- }else if( locktype==EXCLUSIVE_LOCK && pLock->cnt>1 ){
- /* We are trying for an exclusive lock but another thread in this
- ** same process is still holding a shared lock. */
- rc = SQLITE_BUSY;
- }else{
- /* The request was for a RESERVED or EXCLUSIVE lock. It is
- ** assumed that there is a SHARED or greater lock on the file
- ** already.
- */
- assert( 0!=id->locktype );
- lock.l_type = F_WRLCK;
- switch( locktype ){
- case RESERVED_LOCK:
- lock.l_start = RESERVED_BYTE;
- break;
- case EXCLUSIVE_LOCK:
- lock.l_start = SHARED_FIRST;
- lock.l_len = SHARED_SIZE;
- break;
- default:
- assert(0);
- }
- s = fcntl(id->h, F_SETLK, &lock);
- if( s ){
- rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
- }
- }
-
- if( rc==SQLITE_OK ){
- id->locktype = locktype;
- pLock->locktype = locktype;
- }else if( locktype==EXCLUSIVE_LOCK ){
- id->locktype = PENDING_LOCK;
- pLock->locktype = PENDING_LOCK;
- }
-
-end_lock:
- sqlite3OsLeaveMutex();
- TRACE4("LOCK %d %s %s\n", id->h, locktypeName(locktype),
- rc==SQLITE_OK ? "ok" : "failed");
- return rc;
-}
-
-/*
-** Lower the locking level on file descriptor id to locktype. locktype
-** must be either NO_LOCK or SHARED_LOCK.
-**
-** If the locking level of the file descriptor is already at or below
-** the requested locking level, this routine is a no-op.
-**
-** It is not possible for this routine to fail if the second argument
-** is NO_LOCK. If the second argument is SHARED_LOCK, this routine
-** might return SQLITE_IOERR instead of SQLITE_OK.
-*/
-int sqlite3OsUnlock(OsFile *id, int locktype){
- struct lockInfo *pLock;
- struct flock lock;
- int rc = SQLITE_OK;
-
- assert( id->isOpen );
- TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype,
- id->pLock->locktype, id->pLock->cnt, getpid());
-
- assert( locktype<=SHARED_LOCK );
- if( id->locktype<=locktype ){
- return SQLITE_OK;
- }
- sqlite3OsEnterMutex();
- pLock = id->pLock;
- assert( pLock->cnt!=0 );
- if( id->locktype>SHARED_LOCK ){
- assert( pLock->locktype==id->locktype );
- if( locktype==SHARED_LOCK ){
- lock.l_type = F_RDLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = SHARED_FIRST;
- lock.l_len = SHARED_SIZE;
- if( fcntl(id->h, F_SETLK, &lock)!=0 ){
- /* This should never happen */
- rc = SQLITE_IOERR;
- }
- }
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = PENDING_BYTE;
- lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
- fcntl(id->h, F_SETLK, &lock);
- pLock->locktype = SHARED_LOCK;
- }
- if( locktype==NO_LOCK ){
- struct openCnt *pOpen;
-
- /* Decrement the shared lock counter. Release the lock using an
- ** OS call only when all threads in this same process have released
- ** the lock.
- */
- pLock->cnt--;
- if( pLock->cnt==0 ){
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = lock.l_len = 0L;
- fcntl(id->h, F_SETLK, &lock);
- pLock->locktype = NO_LOCK;
- }
-
- /* Decrement the count of locks against this same file. When the
- ** count reaches zero, close any other file descriptors whose close
- ** was deferred because of outstanding locks.
- */
- pOpen = id->pOpen;
- pOpen->nLock--;
- assert( pOpen->nLock>=0 );
- if( pOpen->nLock==0 && pOpen->nPending>0 ){
- int i;
- for(i=0; i<pOpen->nPending; i++){
- close(pOpen->aPending[i]);
- }
- sqliteFree(pOpen->aPending);
- pOpen->nPending = 0;
- pOpen->aPending = 0;
- }
- }
- sqlite3OsLeaveMutex();
- id->locktype = locktype;
- return rc;
-}
-
-/*
-** Close a file.
-*/
-int sqlite3OsClose(OsFile *id){
- if( !id->isOpen ) return SQLITE_OK;
- sqlite3OsUnlock(id, NO_LOCK);
- if( id->dirfd>=0 ) close(id->dirfd);
- id->dirfd = -1;
- sqlite3OsEnterMutex();
- if( id->pOpen->nLock ){
- /* If there are outstanding locks, do not actually close the file just
- ** yet because that would clear those locks. Instead, add the file
- ** descriptor to pOpen->aPending. It will be automatically closed when
- ** the last lock is cleared.
- */
- int *aNew;
- struct openCnt *pOpen = id->pOpen;
- pOpen->nPending++;
- aNew = sqliteRealloc( pOpen->aPending, pOpen->nPending*sizeof(int) );
- if( aNew==0 ){
- /* If a malloc fails, just leak the file descriptor */
- }else{
- pOpen->aPending = aNew;
- pOpen->aPending[pOpen->nPending-1] = id->h;
- }
- }else{
- /* There are no outstanding locks so we can close the file immediately */
- close(id->h);
- }
- releaseLockInfo(id->pLock);
- releaseOpenCnt(id->pOpen);
- sqlite3OsLeaveMutex();
- id->isOpen = 0;
- TRACE2("CLOSE %-3d\n", id->h);
- OpenCounter(-1);
- return SQLITE_OK;
-}
-
-/*
-** Get information to seed the random number generator. The seed
-** is written into the buffer zBuf[256]. The calling function must
-** supply a sufficiently large buffer.
-*/
-int sqlite3OsRandomSeed(char *zBuf){
- /* We have to initialize zBuf to prevent valgrind from reporting
- ** errors. The reports issued by valgrind are incorrect - we would
- ** prefer that the randomness be increased by making use of the
- ** uninitialized space in zBuf - but valgrind errors tend to worry
- ** some users. Rather than argue, it seems easier just to initialize
- ** the whole array and silence valgrind, even if that means less randomness
- ** in the random seed.
- **
- ** When testing, initializing zBuf[] to zero is all we do. That means
- ** that we always use the same random number sequence.* This makes the
- ** tests repeatable.
- */
- memset(zBuf, 0, 256);
-#if !defined(SQLITE_TEST)
- {
- int pid;
- time((time_t*)zBuf);
- pid = getpid();
- memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
- }
-#endif
- return SQLITE_OK;
-}
-
-/*
-** Sleep for a little while. Return the amount of time slept.
-*/
-int sqlite3OsSleep(int ms){
-#if defined(HAVE_USLEEP) && HAVE_USLEEP
- usleep(ms*1000);
- return ms;
-#else
- sleep((ms+999)/1000);
- return 1000*((ms+999)/1000);
-#endif
-}
-
-/*
-** Static variables used for thread synchronization
-*/
-static int inMutex = 0;
-#ifdef SQLITE_UNIX_THREADS
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-/*
-** The following pair of routine implement mutual exclusion for
-** multi-threaded processes. Only a single thread is allowed to
-** executed code that is surrounded by EnterMutex() and LeaveMutex().
-**
-** SQLite uses only a single Mutex. There is not much critical
-** code and what little there is executes quickly and without blocking.
-*/
-void sqlite3OsEnterMutex(){
-#ifdef SQLITE_UNIX_THREADS
- pthread_mutex_lock(&mutex);
-#endif
- assert( !inMutex );
- inMutex = 1;
-}
-void sqlite3OsLeaveMutex(){
- assert( inMutex );
- inMutex = 0;
-#ifdef SQLITE_UNIX_THREADS
- pthread_mutex_unlock(&mutex);
-#endif
-}
-
-/*
-** Turn a relative pathname into a full pathname. Return a pointer
-** to the full pathname stored in space obtained from sqliteMalloc().
-** The calling function is responsible for freeing this space once it
-** is no longer needed.
-*/
-char *sqlite3OsFullPathname(const char *zRelative){
- char *zFull = 0;
- if( zRelative[0]=='/' ){
- sqlite3SetString(&zFull, zRelative, (char*)0);
- }else{
- char zBuf[5000];
- sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), "/", zRelative,
- (char*)0);
- }
- return zFull;
-}
-
-/*
-** The following variable, if set to a non-zero value, becomes the result
-** returned from sqlite3OsCurrentTime(). This is used for testing.
-*/
-#ifdef SQLITE_TEST
-int sqlite3_current_time = 0;
-#endif
-
-/*
-** Find the current time (in Universal Coordinated Time). Write the
-** current time and date as a Julian Day number into *prNow and
-** return 0. Return 1 if the time and date cannot be found.
-*/
-int sqlite3OsCurrentTime(double *prNow){
- time_t t;
- time(&t);
- *prNow = t/86400.0 + 2440587.5;
-#ifdef SQLITE_TEST
- if( sqlite3_current_time ){
- *prNow = sqlite3_current_time/86400.0 + 2440587.5;
- }
-#endif
- return 0;
-}
-
-#if 0 /* NOT USED */
-/*
-** Find the time that the file was last modified. Write the
-** modification time and date as a Julian Day number into *prNow and
-** return SQLITE_OK. Return SQLITE_ERROR if the modification
-** time cannot be found.
-*/
-int sqlite3OsFileModTime(OsFile *id, double *prNow){
- int rc;
- struct stat statbuf;
- if( fstat(id->h, &statbuf)==0 ){
- *prNow = statbuf.st_mtime/86400.0 + 2440587.5;
- rc = SQLITE_OK;
- }else{
- rc = SQLITE_ERROR;
- }
- return rc;
-}
-#endif /* NOT USED */
-
-#endif /* OS_UNIX */
diff --git a/kopete/plugins/statistics/sqlite/os_unix.h b/kopete/plugins/statistics/sqlite/os_unix.h
deleted file mode 100644
index 72f818be..00000000
--- a/kopete/plugins/statistics/sqlite/os_unix.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-** 2004 May 22
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This header file defined OS-specific features for Unix.
-*/
-#ifndef _SQLITE_OS_UNIX_H_
-#define _SQLITE_OS_UNIX_H_
-
-/*
-** Helpful hint: To get this to compile on HP/UX, add -D_INCLUDE_POSIX_SOURCE
-** to the compiler command line.
-*/
-
-/*
-** These #defines should enable >2GB file support on Posix if the
-** underlying operating system supports it. If the OS lacks
-** large file support, or if the OS is windows, these should be no-ops.
-**
-** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
-** on the compiler command line. This is necessary if you are compiling
-** on a recent machine (ex: RedHat 7.2) but you want your code to work
-** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2
-** without this option, LFS is enable. But LFS does not exist in the kernel
-** in RedHat 6.0, so the code won't work. Hence, for maximum binary
-** portability you should omit LFS.
-**
-** Similar is true for MacOS. LFS is only supported on MacOS 9 and later.
-*/
-#ifndef SQLITE_DISABLE_LFS
-# define _LARGE_FILE 1
-# ifndef _FILE_OFFSET_BITS
-# define _FILE_OFFSET_BITS 64
-# endif
-# define _LARGEFILE_SOURCE 1
-#endif
-
-/*
-** standard include files.
-*/
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-/*
-** The OsFile structure is a operating-system independing representation
-** of an open file handle. It is defined differently for each architecture.
-**
-** This is the definition for Unix.
-**
-** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK,
-** PENDING_LOCK or EXCLUSIVE_LOCK.
-*/
-typedef struct OsFile OsFile;
-struct OsFile {
- struct Pager *pPager; /* The pager that owns this OsFile. Might be 0 */
- struct openCnt *pOpen; /* Info about all open fd's on this inode */
- struct lockInfo *pLock; /* Info about locks on this inode */
- int h; /* The file descriptor */
- unsigned char locktype; /* The type of lock held on this fd */
- unsigned char isOpen; /* True if needs to be closed */
- int dirfd; /* File descriptor for the directory */
-};
-
-/*
-** Maximum number of characters in a temporary file name
-*/
-#define SQLITE_TEMPNAME_SIZE 200
-
-/*
-** Minimum interval supported by sqlite3OsSleep().
-*/
-#if defined(HAVE_USLEEP) && HAVE_USLEEP
-# define SQLITE_MIN_SLEEP_MS 1
-#else
-# define SQLITE_MIN_SLEEP_MS 1000
-#endif
-
-
-#endif /* _SQLITE_OS_UNIX_H_ */
diff --git a/kopete/plugins/statistics/sqlite/os_win.c b/kopete/plugins/statistics/sqlite/os_win.c
deleted file mode 100644
index f6e3e3ea..00000000
--- a/kopete/plugins/statistics/sqlite/os_win.c
+++ /dev/null
@@ -1,747 +0,0 @@
-/*
-** 2004 May 22
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This file contains code that is specific to windows.
-*/
-#include "sqliteInt.h"
-#include "os.h"
-#if OS_WIN /* This file is used for windows only */
-
-#include <winbase.h>
-
-/*
-** Macros used to determine whether or not to use threads.
-*/
-#if defined(THREADSAFE) && THREADSAFE
-# define SQLITE_W32_THREADS 1
-#endif
-
-/*
-** Include code that is common to all os_*.c files
-*/
-#include "os_common.h"
-
-/*
-** Delete the named file
-*/
-int sqlite3OsDelete(const char *zFilename){
- DeleteFileA(zFilename);
- TRACE2("DELETE \"%s\"\n", zFilename);
- return SQLITE_OK;
-}
-
-/*
-** Return TRUE if the named file exists.
-*/
-int sqlite3OsFileExists(const char *zFilename){
- return GetFileAttributesA(zFilename) != 0xffffffff;
-}
-
-/*
-** Attempt to open a file for both reading and writing. If that
-** fails, try opening it read-only. If the file does not exist,
-** try to create it.
-**
-** On success, a handle for the open file is written to *id
-** and *pReadonly is set to 0 if the file was opened for reading and
-** writing or 1 if the file was opened read-only. The function returns
-** SQLITE_OK.
-**
-** On failure, the function returns SQLITE_CANTOPEN and leaves
-** *id and *pReadonly unchanged.
-*/
-int sqlite3OsOpenReadWrite(
- const char *zFilename,
- OsFile *id,
- int *pReadonly
-){
- HANDLE h;
- assert( !id->isOpen );
- h = CreateFileA(zFilename,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- h = CreateFileA(zFilename,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- return SQLITE_CANTOPEN;
- }
- *pReadonly = 1;
- }else{
- *pReadonly = 0;
- }
- id->h = h;
- id->locktype = NO_LOCK;
- id->sharedLockByte = 0;
- id->isOpen = 1;
- OpenCounter(+1);
- TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
- return SQLITE_OK;
-}
-
-
-/*
-** Attempt to open a new file for exclusive access by this process.
-** The file will be opened for both reading and writing. To avoid
-** a potential security problem, we do not allow the file to have
-** previously existed. Nor do we allow the file to be a symbolic
-** link.
-**
-** If delFlag is true, then make arrangements to automatically delete
-** the file when it is closed.
-**
-** On success, write the file handle into *id and return SQLITE_OK.
-**
-** On failure, return SQLITE_CANTOPEN.
-*/
-int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
- HANDLE h;
- int fileflags;
- assert( !id->isOpen );
- if( delFlag ){
- fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS
- | FILE_FLAG_DELETE_ON_CLOSE;
- }else{
- fileflags = FILE_FLAG_RANDOM_ACCESS;
- }
- h = CreateFileA(zFilename,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- CREATE_ALWAYS,
- fileflags,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- return SQLITE_CANTOPEN;
- }
- id->h = h;
- id->locktype = NO_LOCK;
- id->sharedLockByte = 0;
- id->isOpen = 1;
- OpenCounter(+1);
- TRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
- return SQLITE_OK;
-}
-
-/*
-** Attempt to open a new file for read-only access.
-**
-** On success, write the file handle into *id and return SQLITE_OK.
-**
-** On failure, return SQLITE_CANTOPEN.
-*/
-int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
- HANDLE h;
- assert( !id->isOpen );
- h = CreateFileA(zFilename,
- GENERIC_READ,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- return SQLITE_CANTOPEN;
- }
- id->h = h;
- id->locktype = NO_LOCK;
- id->sharedLockByte = 0;
- id->isOpen = 1;
- OpenCounter(+1);
- TRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
- return SQLITE_OK;
-}
-
-/*
-** Attempt to open a file descriptor for the directory that contains a
-** file. This file descriptor can be used to fsync() the directory
-** in order to make sure the creation of a new file is actually written
-** to disk.
-**
-** This routine is only meaningful for Unix. It is a no-op under
-** windows since windows does not support hard links.
-**
-** On success, a handle for a previously open file is at *id is
-** updated with the new directory file descriptor and SQLITE_OK is
-** returned.
-**
-** On failure, the function returns SQLITE_CANTOPEN and leaves
-** *id unchanged.
-*/
-int sqlite3OsOpenDirectory(
- const char *zDirname,
- OsFile *id
-){
- return SQLITE_OK;
-}
-
-/*
-** If the following global variable points to a string which is the
-** name of a directory, then that directory will be used to store
-** temporary files.
-*/
-const char *sqlite3_temp_directory = 0;
-
-/*
-** Create a temporary file name in zBuf. zBuf must be big enough to
-** hold at least SQLITE_TEMPNAME_SIZE characters.
-*/
-int sqlite3OsTempFileName(char *zBuf){
- static char zChars[] =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789";
- int i, j;
- char zTempPath[SQLITE_TEMPNAME_SIZE];
- if( sqlite3_temp_directory ){
- strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30);
- zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
- }else{
- GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath);
- }
- for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
- zTempPath[i] = 0;
- for(;;){
- sprintf(zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath);
- j = strlen(zBuf);
- sqlite3Randomness(15, &zBuf[j]);
- for(i=0; i<15; i++, j++){
- zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
- }
- zBuf[j] = 0;
- if( !sqlite3OsFileExists(zBuf) ) break;
- }
- TRACE2("TEMP FILENAME: %s\n", zBuf);
- return SQLITE_OK;
-}
-
-/*
-** Close a file.
-*/
-int sqlite3OsClose(OsFile *id){
- if( id->isOpen ){
- TRACE2("CLOSE %d\n", id->h);
- CloseHandle(id->h);
- OpenCounter(-1);
- id->isOpen = 0;
- }
- return SQLITE_OK;
-}
-
-/*
-** Read data from a file into a buffer. Return SQLITE_OK if all
-** bytes were read successfully and SQLITE_IOERR if anything goes
-** wrong.
-*/
-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
- DWORD got;
- assert( id->isOpen );
- SimulateIOError(SQLITE_IOERR);
- TRACE3("READ %d lock=%d\n", id->h, id->locktype);
- if( !ReadFile(id->h, pBuf, amt, &got, 0) ){
- got = 0;
- }
- if( got==(DWORD)amt ){
- return SQLITE_OK;
- }else{
- return SQLITE_IOERR;
- }
-}
-
-/*
-** Write data from a buffer into a file. Return SQLITE_OK on success
-** or some other error code on failure.
-*/
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
- int rc;
- DWORD wrote;
- assert( id->isOpen );
- SimulateIOError(SQLITE_IOERR);
- SimulateDiskfullError;
- TRACE3("WRITE %d lock=%d\n", id->h, id->locktype);
- while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){
- amt -= wrote;
- pBuf = &((char*)pBuf)[wrote];
- }
- if( !rc || amt>(int)wrote ){
- return SQLITE_FULL;
- }
- return SQLITE_OK;
-}
-
-/*
-** Move the read/write pointer in a file.
-*/
-int sqlite3OsSeek(OsFile *id, i64 offset){
- LONG upperBits = offset>>32;
- LONG lowerBits = offset & 0xffffffff;
- DWORD rc;
- assert( id->isOpen );
- SEEK(offset/1024 + 1);
- rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
- TRACE3("SEEK %d %lld\n", id->h, offset);
- return SQLITE_OK;
-}
-
-/*
-** Make sure all writes to a particular file are committed to disk.
-*/
-int sqlite3OsSync(OsFile *id){
- assert( id->isOpen );
- TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
- if( FlushFileBuffers(id->h) ){
- return SQLITE_OK;
- }else{
- return SQLITE_IOERR;
- }
-}
-
-/*
-** Sync the directory zDirname. This is a no-op on operating systems other
-** than UNIX.
-*/
-int sqlite3OsSyncDirectory(const char *zDirname){
- SimulateIOError(SQLITE_IOERR);
- return SQLITE_OK;
-}
-
-/*
-** Truncate an open file to a specified size
-*/
-int sqlite3OsTruncate(OsFile *id, i64 nByte){
- LONG upperBits = nByte>>32;
- assert( id->isOpen );
- TRACE3("TRUNCATE %d %lld\n", id->h, nByte);
- SimulateIOError(SQLITE_IOERR);
- SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN);
- SetEndOfFile(id->h);
- return SQLITE_OK;
-}
-
-/*
-** Determine the current size of a file in bytes
-*/
-int sqlite3OsFileSize(OsFile *id, i64 *pSize){
- DWORD upperBits, lowerBits;
- assert( id->isOpen );
- SimulateIOError(SQLITE_IOERR);
- lowerBits = GetFileSize(id->h, &upperBits);
- *pSize = (((i64)upperBits)<<32) + lowerBits;
- return SQLITE_OK;
-}
-
-/*
-** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
-** Return false (zero) for Win95, Win98, or WinME.
-**
-** Here is an interesting observation: Win95, Win98, and WinME lack
-** the LockFileEx() API. But we can still statically link against that
-** API as long as we don't call it win running Win95/98/ME. A call to
-** this routine is used to determine if the host is Win95/98/ME or
-** WinNT/2K/XP so that we will know whether or not we can safely call
-** the LockFileEx() API.
-*/
-static int isNT(void){
- static int osType = 0; /* 0=unknown 1=win95 2=winNT */
- if( osType==0 ){
- OSVERSIONINFO sInfo;
- sInfo.dwOSVersionInfoSize = sizeof(sInfo);
- GetVersionEx(&sInfo);
- osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
- }
- return osType==2;
-}
-
-/*
-** Acquire a reader lock.
-** Different API routines are called depending on whether or not this
-** is Win95 or WinNT.
-*/
-static int getReadLock(OsFile *id){
- int res;
- if( isNT() ){
- OVERLAPPED ovlp;
- ovlp.Offset = SHARED_FIRST;
- ovlp.OffsetHigh = 0;
- ovlp.hEvent = 0;
- res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, 0, SHARED_SIZE,0,&ovlp);
- }else{
- int lk;
- sqlite3Randomness(sizeof(lk), &lk);
- id->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
- res = LockFile(id->h, SHARED_FIRST+id->sharedLockByte, 0, 1, 0);
- }
- return res;
-}
-
-/*
-** Undo a readlock
-*/
-static int unlockReadLock(OsFile *id){
- int res;
- if( isNT() ){
- res = UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
- }else{
- res = UnlockFile(id->h, SHARED_FIRST + id->sharedLockByte, 0, 1, 0);
- }
- return res;
-}
-
-/*
-** Lock the file with the lock specified by parameter locktype - one
-** of the following:
-**
-** (1) SHARED_LOCK
-** (2) RESERVED_LOCK
-** (3) PENDING_LOCK
-** (4) EXCLUSIVE_LOCK
-**
-** Sometimes when requesting one lock state, additional lock states
-** are inserted in between. The locking might fail on one of the later
-** transitions leaving the lock state different from what it started but
-** still short of its goal. The following chart shows the allowed
-** transitions and the inserted intermediate states:
-**
-** UNLOCKED -> SHARED
-** SHARED -> RESERVED
-** SHARED -> (PENDING) -> EXCLUSIVE
-** RESERVED -> (PENDING) -> EXCLUSIVE
-** PENDING -> EXCLUSIVE
-**
-** This routine will only increase a lock. The sqlite3OsUnlock() routine
-** erases all locks at once and returns us immediately to locking level 0.
-** It is not possible to lower the locking level one step at a time. You
-** must go straight to locking level 0.
-*/
-int sqlite3OsLock(OsFile *id, int locktype){
- int rc = SQLITE_OK; /* Return code from subroutines */
- int res = 1; /* Result of a windows lock call */
- int newLocktype; /* Set id->locktype to this value before exiting */
- int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
-
- assert( id->isOpen );
- TRACE5("LOCK %d %d was %d(%d)\n",
- id->h, locktype, id->locktype, id->sharedLockByte);
-
- /* If there is already a lock of this type or more restrictive on the
- ** OsFile, do nothing. Don't use the end_lock: exit path, as
- ** sqlite3OsEnterMutex() hasn't been called yet.
- */
- if( id->locktype>=locktype ){
- return SQLITE_OK;
- }
-
- /* Make sure the locking sequence is correct
- */
- assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK );
- assert( locktype!=PENDING_LOCK );
- assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK );
-
- /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
- ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
- ** the PENDING_LOCK byte is temporary.
- */
- newLocktype = id->locktype;
- if( id->locktype==NO_LOCK
- || (locktype==EXCLUSIVE_LOCK && id->locktype==RESERVED_LOCK)
- ){
- int cnt = 3;
- while( cnt-->0 && (res = LockFile(id->h, PENDING_BYTE, 0, 1, 0))==0 ){
- /* Try 3 times to get the pending lock. The pending lock might be
- ** held by another reader process who will release it momentarily.
- */
- TRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
- Sleep(1);
- }
- gotPendingLock = res;
- }
-
- /* Acquire a shared lock
- */
- if( locktype==SHARED_LOCK && res ){
- assert( id->locktype==NO_LOCK );
- res = getReadLock(id);
- if( res ){
- newLocktype = SHARED_LOCK;
- }
- }
-
- /* Acquire a RESERVED lock
- */
- if( locktype==RESERVED_LOCK && res ){
- assert( id->locktype==SHARED_LOCK );
- res = LockFile(id->h, RESERVED_BYTE, 0, 1, 0);
- if( res ){
- newLocktype = RESERVED_LOCK;
- }
- }
-
- /* Acquire a PENDING lock
- */
- if( locktype==EXCLUSIVE_LOCK && res ){
- newLocktype = PENDING_LOCK;
- gotPendingLock = 0;
- }
-
- /* Acquire an EXCLUSIVE lock
- */
- if( locktype==EXCLUSIVE_LOCK && res ){
- assert( id->locktype>=SHARED_LOCK );
- res = unlockReadLock(id);
- TRACE2("unreadlock = %d\n", res);
- res = LockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
- if( res ){
- newLocktype = EXCLUSIVE_LOCK;
- }else{
- TRACE2("error-code = %d\n", GetLastError());
- }
- }
-
- /* If we are holding a PENDING lock that ought to be released, then
- ** release it now.
- */
- if( gotPendingLock && locktype==SHARED_LOCK ){
- UnlockFile(id->h, PENDING_BYTE, 0, 1, 0);
- }
-
- /* Update the state of the lock has held in the file descriptor then
- ** return the appropriate result code.
- */
- if( res ){
- rc = SQLITE_OK;
- }else{
- TRACE4("LOCK FAILED %d trying for %d but got %d\n", id->h,
- locktype, newLocktype);
- rc = SQLITE_BUSY;
- }
- id->locktype = newLocktype;
- return rc;
-}
-
-/*
-** This routine checks if there is a RESERVED lock held on the specified
-** file by this or any other process. If such a lock is held, return
-** non-zero, otherwise zero.
-*/
-int sqlite3OsCheckReservedLock(OsFile *id){
- int rc;
- assert( id->isOpen );
- if( id->locktype>=RESERVED_LOCK ){
- rc = 1;
- TRACE3("TEST WR-LOCK %d %d (local)\n", id->h, rc);
- }else{
- rc = LockFile(id->h, RESERVED_BYTE, 0, 1, 0);
- if( rc ){
- UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);
- }
- rc = !rc;
- TRACE3("TEST WR-LOCK %d %d (remote)\n", id->h, rc);
- }
- return rc;
-}
-
-/*
-** Lower the locking level on file descriptor id to locktype. locktype
-** must be either NO_LOCK or SHARED_LOCK.
-**
-** If the locking level of the file descriptor is already at or below
-** the requested locking level, this routine is a no-op.
-**
-** It is not possible for this routine to fail if the second argument
-** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
-** might return SQLITE_IOERR;
-*/
-int sqlite3OsUnlock(OsFile *id, int locktype){
- int type;
- int rc = SQLITE_OK;
- assert( id->isOpen );
- assert( locktype<=SHARED_LOCK );
- TRACE5("UNLOCK %d to %d was %d(%d)\n", id->h, locktype,
- id->locktype, id->sharedLockByte);
- type = id->locktype;
- if( type>=EXCLUSIVE_LOCK ){
- UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
- if( locktype==SHARED_LOCK && !getReadLock(id) ){
- /* This should never happen. We should always be able to
- ** reacquire the read lock */
- rc = SQLITE_IOERR;
- }
- }
- if( type>=RESERVED_LOCK ){
- UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);
- }
- if( locktype==NO_LOCK && type>=SHARED_LOCK ){
- unlockReadLock(id);
- }
- if( type>=PENDING_LOCK ){
- UnlockFile(id->h, PENDING_BYTE, 0, 1, 0);
- }
- id->locktype = locktype;
- return rc;
-}
-
-/*
-** Get information to seed the random number generator. The seed
-** is written into the buffer zBuf[256]. The calling function must
-** supply a sufficiently large buffer.
-*/
-int sqlite3OsRandomSeed(char *zBuf){
- /* We have to initialize zBuf to prevent valgrind from reporting
- ** errors. The reports issued by valgrind are incorrect - we would
- ** prefer that the randomness be increased by making use of the
- ** uninitialized space in zBuf - but valgrind errors tend to worry
- ** some users. Rather than argue, it seems easier just to initialize
- ** the whole array and silence valgrind, even if that means less randomness
- ** in the random seed.
- **
- ** When testing, initializing zBuf[] to zero is all we do. That means
- ** that we always use the same random number sequence.* This makes the
- ** tests repeatable.
- */
- memset(zBuf, 0, 256);
- GetSystemTime((LPSYSTEMTIME)zBuf);
- return SQLITE_OK;
-}
-
-/*
-** Sleep for a little while. Return the amount of time slept.
-*/
-int sqlite3OsSleep(int ms){
- Sleep(ms);
- return ms;
-}
-
-/*
-** Static variables used for thread synchronization
-*/
-static int inMutex = 0;
-#ifdef SQLITE_W32_THREADS
- static CRITICAL_SECTION cs;
-#endif
-
-/*
-** The following pair of routine implement mutual exclusion for
-** multi-threaded processes. Only a single thread is allowed to
-** executed code that is surrounded by EnterMutex() and LeaveMutex().
-**
-** SQLite uses only a single Mutex. There is not much critical
-** code and what little there is executes quickly and without blocking.
-*/
-void sqlite3OsEnterMutex(){
-#ifdef SQLITE_W32_THREADS
- static int isInit = 0;
- while( !isInit ){
- static long lock = 0;
- if( InterlockedIncrement(&lock)==1 ){
- InitializeCriticalSection(&cs);
- isInit = 1;
- }else{
- Sleep(1);
- }
- }
- EnterCriticalSection(&cs);
-#endif
- assert( !inMutex );
- inMutex = 1;
-}
-void sqlite3OsLeaveMutex(){
- assert( inMutex );
- inMutex = 0;
-#ifdef SQLITE_W32_THREADS
- LeaveCriticalSection(&cs);
-#endif
-}
-
-/*
-** Turn a relative pathname into a full pathname. Return a pointer
-** to the full pathname stored in space obtained from sqliteMalloc().
-** The calling function is responsible for freeing this space once it
-** is no longer needed.
-*/
-char *sqlite3OsFullPathname(const char *zRelative){
- char *zNotUsed;
- char *zFull;
- int nByte;
- nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
- zFull = sqliteMalloc( nByte );
- if( zFull==0 ) return 0;
- GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
- return zFull;
-}
-
-/*
-** The following variable, if set to a non-zero value, becomes the result
-** returned from sqlite3OsCurrentTime(). This is used for testing.
-*/
-#ifdef SQLITE_TEST
-int sqlite3_current_time = 0;
-#endif
-
-/*
-** Find the current time (in Universal Coordinated Time). Write the
-** current time and date as a Julian Day number into *prNow and
-** return 0. Return 1 if the time and date cannot be found.
-*/
-int sqlite3OsCurrentTime(double *prNow){
- FILETIME ft;
- /* FILETIME structure is a 64-bit value representing the number of
- 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
- */
- double now;
- GetSystemTimeAsFileTime( &ft );
- now = ((double)ft.dwHighDateTime) * 4294967296.0;
- *prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
-#ifdef SQLITE_TEST
- if( sqlite3_current_time ){
- *prNow = sqlite3_current_time/86400.0 + 2440587.5;
- }
-#endif
- return 0;
-}
-
-/*
-** Find the time that the file was last modified. Write the
-** modification time and date as a Julian Day number into *prNow and
-** return SQLITE_OK. Return SQLITE_ERROR if the modification
-** time cannot be found.
-*/
-int sqlite3OsFileModTime(OsFile *id, double *prMTime){
- int rc;
- FILETIME ft;
- /* FILETIME structure is a 64-bit value representing the number of
- ** 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
- */
- if( GetFileTime(id->h, 0, 0, &ft) ){
- double t;
- t = ((double)ft.dwHighDateTime) * 4294967296.0;
- *prMTime = (t + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
- rc = SQLITE_OK;
- }else{
- rc = SQLITE_ERROR;
- }
- return rc;
-}
-
-#endif /* OS_WIN */
diff --git a/kopete/plugins/statistics/sqlite/os_win.h b/kopete/plugins/statistics/sqlite/os_win.h
deleted file mode 100644
index baf937b2..00000000
--- a/kopete/plugins/statistics/sqlite/os_win.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-** 2004 May 22
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This header file defines OS-specific features for Win32
-*/
-#ifndef _SQLITE_OS_WIN_H_
-#define _SQLITE_OS_WIN_H_
-
-#include <windows.h>
-#include <winbase.h>
-
-/*
-** The OsFile structure is a operating-system independing representation
-** of an open file handle. It is defined differently for each architecture.
-**
-** This is the definition for Win32.
-*/
-typedef struct OsFile OsFile;
-struct OsFile {
- HANDLE h; /* Handle for accessing the file */
- unsigned char locktype; /* Type of lock currently held on this file */
- unsigned char isOpen; /* True if needs to be closed */
- short sharedLockByte; /* Randomly chosen byte used as a shared lock */
-};
-
-
-#define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
-#define SQLITE_MIN_SLEEP_MS 1
-
-
-#endif /* _SQLITE_OS_WIN_H_ */
diff --git a/kopete/plugins/statistics/sqlite/pager.c b/kopete/plugins/statistics/sqlite/pager.c
deleted file mode 100644
index a374562b..00000000
--- a/kopete/plugins/statistics/sqlite/pager.c
+++ /dev/null
@@ -1,3205 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This is the implementation of the page cache subsystem or "pager".
-**
-** The pager is used to access a database disk file. It implements
-** atomic commit and rollback through the use of a journal file that
-** is separate from the database file. The pager also implements file
-** locking to prevent two processes from writing the same database
-** file simultaneously, or one process from reading the database while
-** another is writing.
-**
-** @(#) $Id$
-*/
-#include "sqliteInt.h"
-#include "os.h"
-#include "pager.h"
-#include <assert.h>
-#include <string.h>
-
-/*
-** Macros for troubleshooting. Normally turned off
-*/
-#if 0
-#define TRACE1(X) sqlite3DebugPrintf(X)
-#define TRACE2(X,Y) sqlite3DebugPrintf(X,Y)
-#define TRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z)
-#define TRACE4(X,Y,Z,W) sqlite3DebugPrintf(X,Y,Z,W)
-#else
-#define TRACE1(X)
-#define TRACE2(X,Y)
-#define TRACE3(X,Y,Z)
-#define TRACE4(X,Y,Z,W)
-#endif
-
-
-/*
-** The page cache as a whole is always in one of the following
-** states:
-**
-** PAGER_UNLOCK The page cache is not currently reading or
-** writing the database file. There is no
-** data held in memory. This is the initial
-** state.
-**
-** PAGER_SHARED The page cache is reading the database.
-** Writing is not permitted. There can be
-** multiple readers accessing the same database
-** file at the same time.
-**
-** PAGER_RESERVED This process has reserved the database for writing
-** but has not yet made any changes. Only one process
-** at a time can reserve the database. The original
-** database file has not been modified so other
-** processes may still be reading the on-disk
-** database file.
-**
-** PAGER_EXCLUSIVE The page cache is writing the database.
-** Access is exclusive. No other processes or
-** threads can be reading or writing while one
-** process is writing.
-**
-** PAGER_SYNCED The pager moves to this state from PAGER_EXCLUSIVE
-** after all dirty pages have been written to the
-** database file and the file has been synced to
-** disk. All that remains to do is to remove the
-** journal file and the transaction will be
-** committed.
-**
-** The page cache comes up in PAGER_UNLOCK. The first time a
-** sqlite3pager_get() occurs, the state transitions to PAGER_SHARED.
-** After all pages have been released using sqlite_page_unref(),
-** the state transitions back to PAGER_UNLOCK. The first time
-** that sqlite3pager_write() is called, the state transitions to
-** PAGER_RESERVED. (Note that sqlite_page_write() can only be
-** called on an outstanding page which means that the pager must
-** be in PAGER_SHARED before it transitions to PAGER_RESERVED.)
-** The transition to PAGER_EXCLUSIVE occurs when before any changes
-** are made to the database file. After an sqlite3pager_rollback()
-** or sqlite_pager_commit(), the state goes back to PAGER_SHARED.
-*/
-#define PAGER_UNLOCK 0
-#define PAGER_SHARED 1 /* same as SHARED_LOCK */
-#define PAGER_RESERVED 2 /* same as RESERVED_LOCK */
-#define PAGER_EXCLUSIVE 4 /* same as EXCLUSIVE_LOCK */
-#define PAGER_SYNCED 5
-
-/*
-** If the SQLITE_BUSY_RESERVED_LOCK macro is set to true at compile-time,
-** then failed attempts to get a reserved lock will invoke the busy callback.
-** This is off by default. To see why, consider the following scenario:
-**
-** Suppose thread A already has a shared lock and wants a reserved lock.
-** Thread B already has a reserved lock and wants an exclusive lock. If
-** both threads are using their busy callbacks, it might be a long time
-** be for one of the threads give up and allows the other to proceed.
-** But if the thread trying to get the reserved lock gives up quickly
-** (if it never invokes its busy callback) then the contention will be
-** resolved quickly.
-*/
-#ifndef SQLITE_BUSY_RESERVED_LOCK
-# define SQLITE_BUSY_RESERVED_LOCK 0
-#endif
-
-/*
-** Each in-memory image of a page begins with the following header.
-** This header is only visible to this pager module. The client
-** code that calls pager sees only the data that follows the header.
-**
-** Client code should call sqlite3pager_write() on a page prior to making
-** any modifications to that page. The first time sqlite3pager_write()
-** is called, the original page contents are written into the rollback
-** journal and PgHdr.inJournal and PgHdr.needSync are set. Later, once
-** the journal page has made it onto the disk surface, PgHdr.needSync
-** is cleared. The modified page cannot be written back into the original
-** database file until the journal pages has been synced to disk and the
-** PgHdr.needSync has been cleared.
-**
-** The PgHdr.dirty flag is set when sqlite3pager_write() is called and
-** is cleared again when the page content is written back to the original
-** database file.
-*/
-typedef struct PgHdr PgHdr;
-struct PgHdr {
- Pager *pPager; /* The pager to which this page belongs */
- Pgno pgno; /* The page number for this page */
- PgHdr *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */
- PgHdr *pNextFree, *pPrevFree; /* Freelist of pages where nRef==0 */
- PgHdr *pNextAll; /* A list of all pages */
- PgHdr *pNextStmt, *pPrevStmt; /* List of pages in the statement journal */
- u8 inJournal; /* TRUE if has been written to journal */
- u8 inStmt; /* TRUE if in the statement subjournal */
- u8 dirty; /* TRUE if we need to write back changes */
- u8 needSync; /* Sync journal before writing this page */
- u8 alwaysRollback; /* Disable dont_rollback() for this page */
- short int nRef; /* Number of users of this page */
- PgHdr *pDirty; /* Dirty pages sorted by PgHdr.pgno */
- /* pPager->pageSize bytes of page data follow this header */
- /* Pager.nExtra bytes of local data follow the page data */
-};
-
-/*
-** For an in-memory only database, some extra information is recorded about
-** each page so that changes can be rolled back. (Journal files are not
-** used for in-memory databases.) The following information is added to
-** the end of every EXTRA block for in-memory databases.
-**
-** This information could have been added directly to the PgHdr structure.
-** But then it would take up an extra 8 bytes of storage on every PgHdr
-** even for disk-based databases. Splitting it out saves 8 bytes. This
-** is only a savings of 0.8% but those percentages add up.
-*/
-typedef struct PgHistory PgHistory;
-struct PgHistory {
- u8 *pOrig; /* Original page text. Restore to this on a full rollback */
- u8 *pStmt; /* Text as it was at the beginning of the current statement */
-};
-
-/*
-** A macro used for invoking the codec if there is one
-*/
-#ifdef SQLITE_HAS_CODEC
-# define CODEC(P,D,N,X) if( P->xCodec ){ P->xCodec(P->pCodecArg,D,N,X); }
-#else
-# define CODEC(P,D,N,X)
-#endif
-
-/*
-** Convert a pointer to a PgHdr into a pointer to its data
-** and back again.
-*/
-#define PGHDR_TO_DATA(P) ((void*)(&(P)[1]))
-#define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1])
-#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->pageSize])
-#define PGHDR_TO_HIST(P,PGR) \
- ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra])
-
-/*
-** How big to make the hash table used for locating in-memory pages
-** by page number.
-*/
-#define N_PG_HASH 2048
-
-/*
-** Hash a page number
-*/
-#define pager_hash(PN) ((PN)&(N_PG_HASH-1))
-
-/*
-** A open page cache is an instance of the following structure.
-*/
-struct Pager {
- char *zFilename; /* Name of the database file */
- char *zJournal; /* Name of the journal file */
- char *zDirectory; /* Directory hold database and journal files */
- OsFile fd, jfd; /* File descriptors for database and journal */
- OsFile stfd; /* File descriptor for the statement subjournal*/
- int dbSize; /* Number of pages in the file */
- int origDbSize; /* dbSize before the current change */
- int stmtSize; /* Size of database (in pages) at stmt_begin() */
- i64 stmtJSize; /* Size of journal at stmt_begin() */
- int nRec; /* Number of pages written to the journal */
- u32 cksumInit; /* Quasi-random value added to every checksum */
- int stmtNRec; /* Number of records in stmt subjournal */
- int nExtra; /* Add this many bytes to each in-memory page */
- void (*xDestructor)(void*,int); /* Call this routine when freeing pages */
- void (*xReiniter)(void*,int); /* Call this routine when reloading pages */
- int pageSize; /* Number of bytes in a page */
- int nPage; /* Total number of in-memory pages */
- int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */
- int mxPage; /* Maximum number of pages to hold in cache */
- int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */
- void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
- void *pCodecArg; /* First argument to xCodec() */
- u8 journalOpen; /* True if journal file descriptors is valid */
- u8 journalStarted; /* True if header of journal is synced */
- u8 useJournal; /* Use a rollback journal on this file */
- u8 stmtOpen; /* True if the statement subjournal is open */
- u8 stmtInUse; /* True we are in a statement subtransaction */
- u8 stmtAutoopen; /* Open stmt journal when main journal is opened*/
- u8 noSync; /* Do not sync the journal if true */
- u8 fullSync; /* Do extra syncs of the journal for robustness */
- u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
- u8 errMask; /* One of several kinds of errors */
- u8 tempFile; /* zFilename is a temporary file */
- u8 readOnly; /* True for a read-only database */
- u8 needSync; /* True if an fsync() is needed on the journal */
- u8 dirtyCache; /* True if cached pages have changed */
- u8 alwaysRollback; /* Disable dont_rollback() for all pages */
- u8 memDb; /* True to inhibit all file I/O */
- u8 *aInJournal; /* One bit for each page in the database file */
- u8 *aInStmt; /* One bit for each page in the database */
- u8 setMaster; /* True if a m-j name has been written to jrnl */
- BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */
- PgHdr *pFirst, *pLast; /* List of free pages */
- PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */
- PgHdr *pAll; /* List of all pages */
- PgHdr *pStmt; /* List of pages in the statement subjournal */
- i64 journalOff; /* Current byte offset in the journal file */
- i64 journalHdr; /* Byte offset to previous journal header */
- i64 stmtHdrOff; /* First journal header written this statement */
- i64 stmtCksum; /* cksumInit when statement was started */
- int sectorSize; /* Assumed sector size during rollback */
- PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */
-};
-
-/*
-** These are bits that can be set in Pager.errMask.
-*/
-#define PAGER_ERR_FULL 0x01 /* a write() failed */
-#define PAGER_ERR_MEM 0x02 /* malloc() failed */
-#define PAGER_ERR_LOCK 0x04 /* error in the locking protocol */
-#define PAGER_ERR_CORRUPT 0x08 /* database or journal corruption */
-#define PAGER_ERR_DISK 0x10 /* general disk I/O error - bad hard drive? */
-
-/*
-** Journal files begin with the following magic string. The data
-** was obtained from /dev/random. It is used only as a sanity check.
-**
-** Since version 2.8.0, the journal format contains additional sanity
-** checking information. If the power fails while the journal is begin
-** written, semi-random garbage data might appear in the journal
-** file after power is restored. If an attempt is then made
-** to roll the journal back, the database could be corrupted. The additional
-** sanity checking data is an attempt to discover the garbage in the
-** journal and ignore it.
-**
-** The sanity checking information for the new journal format consists
-** of a 32-bit checksum on each page of data. The checksum covers both
-** the page number and the pPager->pageSize bytes of data for the page.
-** This cksum is initialized to a 32-bit random value that appears in the
-** journal file right after the header. The random initializer is important,
-** because garbage data that appears at the end of a journal is likely
-** data that was once in other files that have now been deleted. If the
-** garbage data came from an obsolete journal file, the checksums might
-** be correct. But by initializing the checksum to random value which
-** is different for every journal, we minimize that risk.
-*/
-static const unsigned char aJournalMagic[] = {
- 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7,
-};
-
-/*
-** The size of the header and of each page in the journal is determined
-** by the following macros.
-*/
-#define JOURNAL_PG_SZ(pPager) ((pPager->pageSize) + 8)
-
-/*
-** The journal header size for this pager. In the future, this could be
-** set to some value read from the disk controller. The important
-** characteristic is that it is the same size as a disk sector.
-*/
-#define JOURNAL_HDR_SZ(pPager) (pPager->sectorSize)
-
-#define PAGER_SECTOR_SIZE 512
-
-/*
-** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
-** reserved for working around a windows/posix incompatibility). It is
-** used in the journal to signify that the remainder of the journal file
-** is devoted to storing a master journal name - there are no more pages to
-** roll back. See comments for function writeMasterJournal() for details.
-*/
-#define PAGER_MJ_PGNO(x) (PENDING_BYTE/((x)->pageSize))
-
-/*
-** Enable reference count tracking (for debugging) here:
-*/
-#ifdef SQLITE_TEST
- int pager3_refinfo_enable = 0;
- static void pager_refinfo(PgHdr *p){
- static int cnt = 0;
- if( !pager3_refinfo_enable ) return;
- sqlite3DebugPrintf(
- "REFCNT: %4d addr=%p nRef=%d\n",
- p->pgno, PGHDR_TO_DATA(p), p->nRef
- );
- cnt++; /* Something to set a breakpoint on */
- }
-# define REFINFO(X) pager_refinfo(X)
-#else
-# define REFINFO(X)
-#endif
-
-/*
-** Read a 32-bit integer from the given file descriptor. Store the integer
-** that is read in *pRes. Return SQLITE_OK if everything worked, or an
-** error code is something goes wrong.
-**
-** All values are stored on disk as big-endian.
-*/
-static int read32bits(OsFile *fd, u32 *pRes){
- u32 res;
- int rc;
- rc = sqlite3OsRead(fd, &res, sizeof(res));
- if( rc==SQLITE_OK ){
- unsigned char ac[4];
- memcpy(ac, &res, 4);
- res = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3];
- }
- *pRes = res;
- return rc;
-}
-
-/*
-** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK
-** on success or an error code is something goes wrong.
-*/
-static int write32bits(OsFile *fd, u32 val){
- unsigned char ac[4];
- ac[0] = (val>>24) & 0xff;
- ac[1] = (val>>16) & 0xff;
- ac[2] = (val>>8) & 0xff;
- ac[3] = val & 0xff;
- return sqlite3OsWrite(fd, ac, 4);
-}
-
-/*
-** Write the 32-bit integer 'val' into the page identified by page header
-** 'p' at offset 'offset'.
-*/
-static void store32bits(u32 val, PgHdr *p, int offset){
- unsigned char *ac;
- ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset];
- ac[0] = (val>>24) & 0xff;
- ac[1] = (val>>16) & 0xff;
- ac[2] = (val>>8) & 0xff;
- ac[3] = val & 0xff;
-}
-
-/*
-** Read a 32-bit integer at offset 'offset' from the page identified by
-** page header 'p'.
-*/
-static u32 retrieve32bits(PgHdr *p, int offset){
- unsigned char *ac;
- ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset];
- return (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3];
-}
-
-
-/*
-** Convert the bits in the pPager->errMask into an approprate
-** return code.
-*/
-static int pager_errcode(Pager *pPager){
- int rc = SQLITE_OK;
- if( pPager->errMask & PAGER_ERR_LOCK ) rc = SQLITE_PROTOCOL;
- if( pPager->errMask & PAGER_ERR_DISK ) rc = SQLITE_IOERR;
- if( pPager->errMask & PAGER_ERR_FULL ) rc = SQLITE_FULL;
- if( pPager->errMask & PAGER_ERR_MEM ) rc = SQLITE_NOMEM;
- if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT;
- return rc;
-}
-
-/*
-** When this is called the journal file for pager pPager must be open.
-** The master journal file name is read from the end of the file and
-** written into memory obtained from sqliteMalloc(). *pzMaster is
-** set to point at the memory and SQLITE_OK returned. The caller must
-** sqliteFree() *pzMaster.
-**
-** If no master journal file name is present *pzMaster is set to 0 and
-** SQLITE_OK returned.
-*/
-static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
- int rc;
- u32 len;
- i64 szJ;
- u32 cksum;
- int i;
- unsigned char aMagic[8]; /* A buffer to hold the magic header */
-
- *pzMaster = 0;
-
- rc = sqlite3OsFileSize(pJrnl, &szJ);
- if( rc!=SQLITE_OK || szJ<16 ) return rc;
-
- rc = sqlite3OsSeek(pJrnl, szJ-16);
- if( rc!=SQLITE_OK ) return rc;
-
- rc = read32bits(pJrnl, &len);
- if( rc!=SQLITE_OK ) return rc;
-
- rc = read32bits(pJrnl, &cksum);
- if( rc!=SQLITE_OK ) return rc;
-
- rc = sqlite3OsRead(pJrnl, aMagic, 8);
- if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, 8) ) return rc;
-
- rc = sqlite3OsSeek(pJrnl, szJ-16-len);
- if( rc!=SQLITE_OK ) return rc;
-
- *pzMaster = (char *)sqliteMalloc(len+1);
- if( !*pzMaster ){
- return SQLITE_NOMEM;
- }
- rc = sqlite3OsRead(pJrnl, *pzMaster, len);
- if( rc!=SQLITE_OK ){
- sqliteFree(*pzMaster);
- *pzMaster = 0;
- return rc;
- }
-
- /* See if the checksum matches the master journal name */
- for(i=0; i<len; i++){
- cksum -= (*pzMaster)[i];
- }
- if( cksum ){
- /* If the checksum doesn't add up, then one or more of the disk sectors
- ** containing the master journal filename is corrupted. This means
- ** definitely roll back, so just return SQLITE_OK and report a (nul)
- ** master-journal filename.
- */
- sqliteFree(*pzMaster);
- *pzMaster = 0;
- }
- (*pzMaster)[len] = '\0';
-
- return SQLITE_OK;
-}
-
-/*
-** Seek the journal file descriptor to the next sector boundary where a
-** journal header may be read or written. Pager.journalOff is updated with
-** the new seek offset.
-**
-** i.e for a sector size of 512:
-**
-** Input Offset Output Offset
-** ---------------------------------------
-** 0 0
-** 512 512
-** 100 512
-** 2000 2048
-**
-*/
-static int seekJournalHdr(Pager *pPager){
- i64 offset = 0;
- i64 c = pPager->journalOff;
- if( c ){
- offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager);
- }
- assert( offset%JOURNAL_HDR_SZ(pPager)==0 );
- assert( offset>=c );
- assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
- pPager->journalOff = offset;
- return sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
-}
-
-/*
-** The journal file must be open when this routine is called. A journal
-** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the
-** current location.
-**
-** The format for the journal header is as follows:
-** - 8 bytes: Magic identifying journal format.
-** - 4 bytes: Number of records in journal, or -1 no-sync mode is on.
-** - 4 bytes: Random number used for page hash.
-** - 4 bytes: Initial database page count.
-** - 4 bytes: Sector size used by the process that wrote this journal.
-**
-** Followed by (JOURNAL_HDR_SZ - 24) bytes of unused space.
-*/
-static int writeJournalHdr(Pager *pPager){
-
- int rc = seekJournalHdr(pPager);
- if( rc ) return rc;
-
- pPager->journalHdr = pPager->journalOff;
- if( pPager->stmtHdrOff==0 ){
- pPager->stmtHdrOff = pPager->journalHdr;
- }
- pPager->journalOff += JOURNAL_HDR_SZ(pPager);
-
- /* FIX ME:
- **
- ** Possibly for a pager not in no-sync mode, the journal magic should not
- ** be written until nRec is filled in as part of next syncJournal().
- **
- ** Actually maybe the whole journal header should be delayed until that
- ** point. Think about this.
- */
- rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
-
- if( rc==SQLITE_OK ){
- /* The nRec Field. 0xFFFFFFFF for no-sync journals. */
- rc = write32bits(&pPager->jfd, pPager->noSync ? 0xffffffff : 0);
- }
- if( rc==SQLITE_OK ){
- /* The random check-hash initialiser */
- sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
- rc = write32bits(&pPager->jfd, pPager->cksumInit);
- }
- if( rc==SQLITE_OK ){
- /* The initial database size */
- rc = write32bits(&pPager->jfd, pPager->dbSize);
- }
- if( rc==SQLITE_OK ){
- /* The assumed sector size for this process */
- rc = write32bits(&pPager->jfd, pPager->sectorSize);
- }
-
- /* The journal header has been written successfully. Seek the journal
- ** file descriptor to the end of the journal header sector.
- */
- if( rc==SQLITE_OK ){
- sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1);
- rc = sqlite3OsWrite(&pPager->jfd, "\000", 1);
- }
- return rc;
-}
-
-/*
-** The journal file must be open when this is called. A journal header file
-** (JOURNAL_HDR_SZ bytes) is read from the current location in the journal
-** file. See comments above function writeJournalHdr() for a description of
-** the journal header format.
-**
-** If the header is read successfully, *nRec is set to the number of
-** page records following this header and *dbSize is set to the size of the
-** database before the transaction began, in pages. Also, pPager->cksumInit
-** is set to the value read from the journal header. SQLITE_OK is returned
-** in this case.
-**
-** If the journal header file appears to be corrupted, SQLITE_DONE is
-** returned and *nRec and *dbSize are not set. If JOURNAL_HDR_SZ bytes
-** cannot be read from the journal file an error code is returned.
-*/
-static int readJournalHdr(
- Pager *pPager,
- i64 journalSize,
- u32 *pNRec,
- u32 *pDbSize
-){
- int rc;
- unsigned char aMagic[8]; /* A buffer to hold the magic header */
-
- rc = seekJournalHdr(pPager);
- if( rc ) return rc;
-
- if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){
- return SQLITE_DONE;
- }
-
- rc = sqlite3OsRead(&pPager->jfd, aMagic, sizeof(aMagic));
- if( rc ) return rc;
-
- if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){
- return SQLITE_DONE;
- }
-
- rc = read32bits(&pPager->jfd, pNRec);
- if( rc ) return rc;
-
- rc = read32bits(&pPager->jfd, &pPager->cksumInit);
- if( rc ) return rc;
-
- rc = read32bits(&pPager->jfd, pDbSize);
- if( rc ) return rc;
-
- /* Update the assumed sector-size to match the value used by
- ** the process that created this journal. If this journal was
- ** created by a process other than this one, then this routine
- ** is being called from within pager_playback(). The local value
- ** of Pager.sectorSize is restored at the end of that routine.
- */
- rc = read32bits(&pPager->jfd, (u32 *)&pPager->sectorSize);
- if( rc ) return rc;
-
- pPager->journalOff += JOURNAL_HDR_SZ(pPager);
- rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
- return rc;
-}
-
-
-/*
-** Write the supplied master journal name into the journal file for pager
-** pPager at the current location. The master journal name must be the last
-** thing written to a journal file. If the pager is in full-sync mode, the
-** journal file descriptor is advanced to the next sector boundary before
-** anything is written. The format is:
-**
-** + 4 bytes: PAGER_MJ_PGNO.
-** + N bytes: length of master journal name.
-** + 4 bytes: N
-** + 4 bytes: Master journal name checksum.
-** + 8 bytes: aJournalMagic[].
-**
-** The master journal page checksum is the sum of the bytes in the master
-** journal name.
-*/
-static int writeMasterJournal(Pager *pPager, const char *zMaster){
- int rc;
- int len;
- int i;
- u32 cksum = 0;
-
- if( !zMaster || pPager->setMaster) return SQLITE_OK;
- pPager->setMaster = 1;
-
- len = strlen(zMaster);
- for(i=0; i<len; i++){
- cksum += zMaster[i];
- }
-
- /* If in full-sync mode, advance to the next disk sector before writing
- ** the master journal name. This is in case the previous page written to
- ** the journal has already been synced.
- */
- if( pPager->fullSync ){
- rc = seekJournalHdr(pPager);
- if( rc!=SQLITE_OK ) return rc;
- }
- pPager->journalOff += (len+20);
-
- rc = write32bits(&pPager->jfd, PAGER_MJ_PGNO(pPager));
- if( rc!=SQLITE_OK ) return rc;
-
- rc = sqlite3OsWrite(&pPager->jfd, zMaster, len);
- if( rc!=SQLITE_OK ) return rc;
-
- rc = write32bits(&pPager->jfd, len);
- if( rc!=SQLITE_OK ) return rc;
-
- rc = write32bits(&pPager->jfd, cksum);
- if( rc!=SQLITE_OK ) return rc;
-
- rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
- pPager->needSync = 1;
- return rc;
-}
-
-/*
-** Add or remove a page from the list of all pages that are in the
-** statement journal.
-**
-** The Pager keeps a separate list of pages that are currently in
-** the statement journal. This helps the sqlite3pager_stmt_commit()
-** routine run MUCH faster for the common case where there are many
-** pages in memory but only a few are in the statement journal.
-*/
-static void page_add_to_stmt_list(PgHdr *pPg){
- Pager *pPager = pPg->pPager;
- if( pPg->inStmt ) return;
- assert( pPg->pPrevStmt==0 && pPg->pNextStmt==0 );
- pPg->pPrevStmt = 0;
- if( pPager->pStmt ){
- pPager->pStmt->pPrevStmt = pPg;
- }
- pPg->pNextStmt = pPager->pStmt;
- pPager->pStmt = pPg;
- pPg->inStmt = 1;
-}
-static void page_remove_from_stmt_list(PgHdr *pPg){
- if( !pPg->inStmt ) return;
- if( pPg->pPrevStmt ){
- assert( pPg->pPrevStmt->pNextStmt==pPg );
- pPg->pPrevStmt->pNextStmt = pPg->pNextStmt;
- }else{
- assert( pPg->pPager->pStmt==pPg );
- pPg->pPager->pStmt = pPg->pNextStmt;
- }
- if( pPg->pNextStmt ){
- assert( pPg->pNextStmt->pPrevStmt==pPg );
- pPg->pNextStmt->pPrevStmt = pPg->pPrevStmt;
- }
- pPg->pNextStmt = 0;
- pPg->pPrevStmt = 0;
- pPg->inStmt = 0;
-}
-
-/*
-** Find a page in the hash table given its page number. Return
-** a pointer to the page or NULL if not found.
-*/
-static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
- PgHdr *p = pPager->aHash[pager_hash(pgno)];
- while( p && p->pgno!=pgno ){
- p = p->pNextHash;
- }
- return p;
-}
-
-/*
-** Unlock the database and clear the in-memory cache. This routine
-** sets the state of the pager back to what it was when it was first
-** opened. Any outstanding pages are invalidated and subsequent attempts
-** to access those pages will likely result in a coredump.
-*/
-static void pager_reset(Pager *pPager){
- PgHdr *pPg, *pNext;
- for(pPg=pPager->pAll; pPg; pPg=pNext){
- pNext = pPg->pNextAll;
- sqliteFree(pPg);
- }
- pPager->pFirst = 0;
- pPager->pFirstSynced = 0;
- pPager->pLast = 0;
- pPager->pAll = 0;
- memset(pPager->aHash, 0, sizeof(pPager->aHash));
- pPager->nPage = 0;
- if( pPager->state>=PAGER_RESERVED ){
- sqlite3pager_rollback(pPager);
- }
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
- pPager->dbSize = -1;
- pPager->nRef = 0;
- assert( pPager->journalOpen==0 );
-}
-
-/*
-** When this routine is called, the pager has the journal file open and
-** a RESERVED or EXCLUSIVE lock on the database. This routine releases
-** the database lock and acquires a SHARED lock in its place. The journal
-** file is deleted and closed.
-**
-** TODO: Consider keeping the journal file open for temporary databases.
-** This might give a performance improvement on windows where opening
-** a file is an expensive operation.
-*/
-static int pager_unwritelock(Pager *pPager){
- PgHdr *pPg;
- int rc;
- assert( !pPager->memDb );
- if( pPager->state<PAGER_RESERVED ){
- return SQLITE_OK;
- }
- sqlite3pager_stmt_commit(pPager);
- if( pPager->stmtOpen ){
- sqlite3OsClose(&pPager->stfd);
- pPager->stmtOpen = 0;
- }
- if( pPager->journalOpen ){
- sqlite3OsClose(&pPager->jfd);
- pPager->journalOpen = 0;
- sqlite3OsDelete(pPager->zJournal);
- sqliteFree( pPager->aInJournal );
- pPager->aInJournal = 0;
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- pPg->inJournal = 0;
- pPg->dirty = 0;
- pPg->needSync = 0;
- }
- pPager->dirtyCache = 0;
- pPager->nRec = 0;
- }else{
- assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
- }
- rc = sqlite3OsUnlock(&pPager->fd, SHARED_LOCK);
- pPager->state = PAGER_SHARED;
- pPager->origDbSize = 0;
- pPager->setMaster = 0;
- return rc;
-}
-
-/*
-** Compute and return a checksum for the page of data.
-**
-** This is not a real checksum. It is really just the sum of the
-** random initial value and the page number. We experimented with
-** a checksum of the entire data, but that was found to be too slow.
-**
-** Note that the page number is stored at the beginning of data and
-** the checksum is stored at the end. This is important. If journal
-** corruption occurs due to a power failure, the most likely scenario
-** is that one end or the other of the record will be changed. It is
-** much less likely that the two ends of the journal record will be
-** correct and the middle be corrupt. Thus, this "checksum" scheme,
-** though fast and simple, catches the mostly likely kind of corruption.
-**
-** FIX ME: Consider adding every 200th (or so) byte of the data to the
-** checksum. That way if a single page spans 3 or more disk sectors and
-** only the middle sector is corrupt, we will still have a reasonable
-** chance of failing the checksum and thus detecting the problem.
-*/
-static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){
- u32 cksum = pPager->cksumInit;
- int i = pPager->pageSize-200;
- while( i>0 ){
- cksum += aData[i];
- i -= 200;
- }
- return cksum;
-}
-
-/*
-** Read a single page from the journal file opened on file descriptor
-** jfd. Playback this one page.
-**
-** If useCksum==0 it means this journal does not use checksums. Checksums
-** are not used in statement journals because statement journals do not
-** need to survive power failures.
-*/
-static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
- int rc;
- PgHdr *pPg; /* An existing page in the cache */
- Pgno pgno; /* The page number of a page in journal */
- u32 cksum; /* Checksum used for sanity checking */
- u8 aData[SQLITE_MAX_PAGE_SIZE]; /* Temp storage for a page */
-
- rc = read32bits(jfd, &pgno);
- if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsRead(jfd, &aData, pPager->pageSize);
- if( rc!=SQLITE_OK ) return rc;
- pPager->journalOff += pPager->pageSize + 4;
-
- /* Sanity checking on the page. This is more important that I originally
- ** thought. If a power failure occurs while the journal is being written,
- ** it could cause invalid data to be written into the journal. We need to
- ** detect this invalid data (with high probability) and ignore it.
- */
- if( pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){
- return SQLITE_DONE;
- }
- if( pgno>(unsigned)pPager->dbSize ){
- return SQLITE_OK;
- }
- if( useCksum ){
- rc = read32bits(jfd, &cksum);
- if( rc ) return rc;
- pPager->journalOff += 4;
- if( pager_cksum(pPager, pgno, aData)!=cksum ){
- return SQLITE_DONE;
- }
- }
-
- assert( pPager->state==PAGER_RESERVED || pPager->state>=PAGER_EXCLUSIVE );
-
- /* If the pager is in RESERVED state, then there must be a copy of this
- ** page in the pager cache. In this case just update the pager cache,
- ** not the database file. The page is left marked dirty in this case.
- **
- ** If in EXCLUSIVE state, then we update the pager cache if it exists
- ** and the main file. The page is then marked not dirty.
- */
- pPg = pager_lookup(pPager, pgno);
- assert( pPager->state>=PAGER_EXCLUSIVE || pPg );
- TRACE3("PLAYBACK %d page %d\n", pPager->fd.h, pgno);
- if( pPager->state>=PAGER_EXCLUSIVE ){
- sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
- rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
- }
- if( pPg ){
- /* No page should ever be rolled back that is in use, except for page
- ** 1 which is held in use in order to keep the lock on the database
- ** active.
- */
- void *pData;
- assert( pPg->nRef==0 || pPg->pgno==1 );
- pData = PGHDR_TO_DATA(pPg);
- memcpy(pData, aData, pPager->pageSize);
- if( pPager->xDestructor ){ /*** FIX ME: Should this be xReinit? ***/
- pPager->xDestructor(pData, pPager->pageSize);
- }
- if( pPager->state>=PAGER_EXCLUSIVE ){
- pPg->dirty = 0;
- pPg->needSync = 0;
- }
- CODEC(pPager, pData, pPg->pgno, 3);
- }
- return rc;
-}
-
-/*
-** Parameter zMaster is the name of a master journal file. A single journal
-** file that referred to the master journal file has just been rolled back.
-** This routine checks if it is possible to delete the master journal file,
-** and does so if it is.
-**
-** The master journal file contains the names of all child journals.
-** To tell if a master journal can be deleted, check to each of the
-** children. If all children are either missing or do not refer to
-** a different master journal, then this master journal can be deleted.
-*/
-static int pager_delmaster(const char *zMaster){
- int rc;
- int master_open = 0;
- OsFile master;
- char *zMasterJournal = 0; /* Contents of master journal file */
- i64 nMasterJournal; /* Size of master journal file */
-
- /* Open the master journal file exclusively in case some other process
- ** is running this routine also. Not that it makes too much difference.
- */
- memset(&master, 0, sizeof(master));
- rc = sqlite3OsOpenReadOnly(zMaster, &master);
- if( rc!=SQLITE_OK ) goto delmaster_out;
- master_open = 1;
- rc = sqlite3OsFileSize(&master, &nMasterJournal);
- if( rc!=SQLITE_OK ) goto delmaster_out;
-
- if( nMasterJournal>0 ){
- char *zJournal;
- char *zMasterPtr = 0;
-
- /* Load the entire master journal file into space obtained from
- ** sqliteMalloc() and pointed to by zMasterJournal.
- */
- zMasterJournal = (char *)sqliteMalloc(nMasterJournal);
- if( !zMasterJournal ){
- rc = SQLITE_NOMEM;
- goto delmaster_out;
- }
- rc = sqlite3OsRead(&master, zMasterJournal, nMasterJournal);
- if( rc!=SQLITE_OK ) goto delmaster_out;
-
- zJournal = zMasterJournal;
- while( (zJournal-zMasterJournal)<nMasterJournal ){
- if( sqlite3OsFileExists(zJournal) ){
- /* One of the journals pointed to by the master journal exists.
- ** Open it and check if it points at the master journal. If
- ** so, return without deleting the master journal file.
- */
- OsFile journal;
-
- memset(&journal, 0, sizeof(journal));
- rc = sqlite3OsOpenReadOnly(zJournal, &journal);
- if( rc!=SQLITE_OK ){
- goto delmaster_out;
- }
-
- rc = readMasterJournal(&journal, &zMasterPtr);
- sqlite3OsClose(&journal);
- if( rc!=SQLITE_OK ){
- goto delmaster_out;
- }
-
- if( zMasterPtr && !strcmp(zMasterPtr, zMaster) ){
- /* We have a match. Do not delete the master journal file. */
- goto delmaster_out;
- }
- }
- zJournal += (strlen(zJournal)+1);
- }
- }
-
- sqlite3OsDelete(zMaster);
-
-delmaster_out:
- if( zMasterJournal ){
- sqliteFree(zMasterJournal);
- }
- if( master_open ){
- sqlite3OsClose(&master);
- }
- return rc;
-}
-
-/*
-** Make every page in the cache agree with what is on disk. In other words,
-** reread the disk to reset the state of the cache.
-**
-** This routine is called after a rollback in which some of the dirty cache
-** pages had never been written out to disk. We need to roll back the
-** cache content and the easiest way to do that is to reread the old content
-** back from the disk.
-*/
-static int pager_reload_cache(Pager *pPager){
- PgHdr *pPg;
- int rc = SQLITE_OK;
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- char zBuf[SQLITE_MAX_PAGE_SIZE];
- if( !pPg->dirty ) continue;
- if( (int)pPg->pgno <= pPager->origDbSize ){
- sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
- rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
- TRACE3("REFETCH %d page %d\n", pPager->fd.h, pPg->pgno);
- if( rc ) break;
- CODEC(pPager, zBuf, pPg->pgno, 2);
- }else{
- memset(zBuf, 0, pPager->pageSize);
- }
- if( pPg->nRef==0 || memcmp(zBuf, PGHDR_TO_DATA(pPg), pPager->pageSize) ){
- memcpy(PGHDR_TO_DATA(pPg), zBuf, pPager->pageSize);
- if( pPager->xReiniter ){
- pPager->xReiniter(PGHDR_TO_DATA(pPg), pPager->pageSize);
- }else{
- memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
- }
- }
- pPg->needSync = 0;
- pPg->dirty = 0;
- }
- return rc;
-}
-
-/*
-** Truncate the main file of the given pager to the number of pages
-** indicated.
-*/
-static int pager_truncate(Pager *pPager, int nPage){
- return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(i64)nPage);
-}
-
-/*
-** Playback the journal and thus restore the database file to
-** the state it was in before we started making changes.
-**
-** The journal file format is as follows:
-**
-** (1) 8 byte prefix. A copy of aJournalMagic[].
-** (2) 4 byte big-endian integer which is the number of valid page records
-** in the journal. If this value is 0xffffffff, then compute the
-** number of page records from the journal size.
-** (3) 4 byte big-endian integer which is the initial value for the
-** sanity checksum.
-** (4) 4 byte integer which is the number of pages to truncate the
-** database to during a rollback.
-** (5) 4 byte integer which is the number of bytes in the master journal
-** name. The value may be zero (indicate that there is no master
-** journal.)
-** (6) N bytes of the master journal name. The name will be nul-terminated
-** and might be shorter than the value read from (5). If the first byte
-** of the name is \000 then there is no master journal. The master
-** journal name is stored in UTF-8.
-** (7) Zero or more pages instances, each as follows:
-** + 4 byte page number.
-** + pPager->pageSize bytes of data.
-** + 4 byte checksum
-**
-** When we speak of the journal header, we mean the first 6 items above.
-** Each entry in the journal is an instance of the 7th item.
-**
-** Call the value from the second bullet "nRec". nRec is the number of
-** valid page entries in the journal. In most cases, you can compute the
-** value of nRec from the size of the journal file. But if a power
-** failure occurred while the journal was being written, it could be the
-** case that the size of the journal file had already been increased but
-** the extra entries had not yet made it safely to disk. In such a case,
-** the value of nRec computed from the file size would be too large. For
-** that reason, we always use the nRec value in the header.
-**
-** If the nRec value is 0xffffffff it means that nRec should be computed
-** from the file size. This value is used when the user selects the
-** no-sync option for the journal. A power failure could lead to corruption
-** in this case. But for things like temporary table (which will be
-** deleted when the power is restored) we don't care.
-**
-** If the file opened as the journal file is not a well-formed
-** journal file then all pages up to the first corrupted page are rolled
-** back (or no pages if the journal header is corrupted). The journal file
-** is then deleted and SQLITE_OK returned, just as if no corruption had
-** been encountered.
-**
-** If an I/O or malloc() error occurs, the journal-file is not deleted
-** and an error code is returned.
-*/
-static int pager_playback(Pager *pPager){
- i64 szJ; /* Size of the journal file in bytes */
- u32 nRec; /* Number of Records in the journal */
- int i; /* Loop counter */
- Pgno mxPg = 0; /* Size of the original file in pages */
- int rc; /* Result code of a subroutine */
- char *zMaster = 0; /* Name of master journal file if any */
-
- /* Figure out how many records are in the journal. Abort early if
- ** the journal is empty.
- */
- assert( pPager->journalOpen );
- rc = sqlite3OsFileSize(&pPager->jfd, &szJ);
- if( rc!=SQLITE_OK ){
- goto end_playback;
- }
-
- /* Read the master journal name from the journal, if it is present.
- ** If a master journal file name is specified, but the file is not
- ** present on disk, then the journal is not hot and does not need to be
- ** played back.
- */
- rc = readMasterJournal(&pPager->jfd, &zMaster);
- assert( rc!=SQLITE_DONE );
- if( rc!=SQLITE_OK || (zMaster && !sqlite3OsFileExists(zMaster)) ){
- sqliteFree(zMaster);
- zMaster = 0;
- if( rc==SQLITE_DONE ) rc = SQLITE_OK;
- goto end_playback;
- }
- sqlite3OsSeek(&pPager->jfd, 0);
- pPager->journalOff = 0;
-
- /* This loop terminates either when the readJournalHdr() call returns
- ** SQLITE_DONE or an IO error occurs. */
- while( 1 ){
-
- /* Read the next journal header from the journal file. If there are
- ** not enough bytes left in the journal file for a complete header, or
- ** it is corrupted, then a process must of failed while writing it.
- ** This indicates nothing more needs to be rolled back.
- */
- rc = readJournalHdr(pPager, szJ, &nRec, &mxPg);
- if( rc!=SQLITE_OK ){
- if( rc==SQLITE_DONE ){
- rc = SQLITE_OK;
- }
- goto end_playback;
- }
-
- /* If nRec is 0xffffffff, then this journal was created by a process
- ** working in no-sync mode. This means that the rest of the journal
- ** file consists of pages, there are no more journal headers. Compute
- ** the value of nRec based on this assumption.
- */
- if( nRec==0xffffffff ){
- assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) );
- nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager);
- }
-
- /* If this is the first header read from the journal, truncate the
- ** database file back to it's original size.
- */
- if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
- assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg );
- rc = pager_truncate(pPager, mxPg);
- if( rc!=SQLITE_OK ){
- goto end_playback;
- }
- pPager->dbSize = mxPg;
- }
-
- /* rc = sqlite3OsSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */
- if( rc!=SQLITE_OK ) goto end_playback;
-
- /* Copy original pages out of the journal and back into the database file.
- */
- for(i=0; i<nRec; i++){
- rc = pager_playback_one_page(pPager, &pPager->jfd, 1);
- if( rc!=SQLITE_OK ){
- if( rc==SQLITE_DONE ){
- rc = SQLITE_OK;
- pPager->journalOff = szJ;
- break;
- }else{
- goto end_playback;
- }
- }
- }
- }
-
- /* Pages that have been written to the journal but never synced
- ** where not restored by the loop above. We have to restore those
- ** pages by reading them back from the original database.
- */
- assert( rc==SQLITE_OK );
- pager_reload_cache(pPager);
-
-end_playback:
- if( rc==SQLITE_OK ){
- rc = pager_unwritelock(pPager);
- }
- if( zMaster ){
- /* If there was a master journal and this routine will return true,
- ** see if it is possible to delete the master journal. If errors
- ** occur during this process, ignore them.
- */
- if( rc==SQLITE_OK ){
- pager_delmaster(zMaster);
- }
- sqliteFree(zMaster);
- }
-
- /* The Pager.sectorSize variable may have been updated while rolling
- ** back a journal created by a process with a different PAGER_SECTOR_SIZE
- ** value. Reset it to the correct value for this process.
- */
- pPager->sectorSize = PAGER_SECTOR_SIZE;
- return rc;
-}
-
-/*
-** Playback the statement journal.
-**
-** This is similar to playing back the transaction journal but with
-** a few extra twists.
-**
-** (1) The number of pages in the database file at the start of
-** the statement is stored in pPager->stmtSize, not in the
-** journal file itself.
-**
-** (2) In addition to playing back the statement journal, also
-** playback all pages of the transaction journal beginning
-** at offset pPager->stmtJSize.
-*/
-static int pager_stmt_playback(Pager *pPager){
- i64 szJ; /* Size of the full journal */
- i64 hdrOff;
- int nRec; /* Number of Records */
- int i; /* Loop counter */
- int rc;
-
- szJ = pPager->journalOff;
-#ifndef NDEBUG
- {
- i64 os_szJ;
- rc = sqlite3OsFileSize(&pPager->jfd, &os_szJ);
- if( rc!=SQLITE_OK ) return rc;
- assert( szJ==os_szJ );
- }
-#endif
-
- /* Set hdrOff to be the offset to the first journal header written
- ** this statement transaction, or the end of the file if no journal
- ** header was written.
- */
- hdrOff = pPager->stmtHdrOff;
- assert( pPager->fullSync || !hdrOff );
- if( !hdrOff ){
- hdrOff = szJ;
- }
-
-
- /* Truncate the database back to its original size.
- */
- rc = pager_truncate(pPager, pPager->stmtSize);
- pPager->dbSize = pPager->stmtSize;
-
- /* Figure out how many records are in the statement journal.
- */
- assert( pPager->stmtInUse && pPager->journalOpen );
- sqlite3OsSeek(&pPager->stfd, 0);
- nRec = pPager->stmtNRec;
-
- /* Copy original pages out of the statement journal and back into the
- ** database file. Note that the statement journal omits checksums from
- ** each record since power-failure recovery is not important to statement
- ** journals.
- */
- for(i=nRec-1; i>=0; i--){
- rc = pager_playback_one_page(pPager, &pPager->stfd, 0);
- assert( rc!=SQLITE_DONE );
- if( rc!=SQLITE_OK ) goto end_stmt_playback;
- }
-
- /* Now roll some pages back from the transaction journal. Pager.stmtJSize
- ** was the size of the journal file when this statement was started, so
- ** everything after that needs to be rolled back, either into the
- ** database, the memory cache, or both.
- **
- ** If it is not zero, then Pager.stmtHdrOff is the offset to the start
- ** of the first journal header written during this statement transaction.
- */
- rc = sqlite3OsSeek(&pPager->jfd, pPager->stmtJSize);
- if( rc!=SQLITE_OK ){
- goto end_stmt_playback;
- }
- pPager->journalOff = pPager->stmtJSize;
- pPager->cksumInit = pPager->stmtCksum;
- assert( JOURNAL_HDR_SZ(pPager)<(pPager->pageSize+8) );
- while( pPager->journalOff <= (hdrOff-(pPager->pageSize+8)) ){
- rc = pager_playback_one_page(pPager, &pPager->jfd, 1);
- assert( rc!=SQLITE_DONE );
- if( rc!=SQLITE_OK ) goto end_stmt_playback;
- }
-
- while( pPager->journalOff < szJ ){
- u32 nRec;
- u32 dummy;
- rc = readJournalHdr(pPager, szJ, &nRec, &dummy);
- if( rc!=SQLITE_OK ){
- assert( rc!=SQLITE_DONE );
- goto end_stmt_playback;
- }
- if( nRec==0 ){
- nRec = (szJ - pPager->journalOff) / (pPager->pageSize+8);
- }
- for(i=nRec-1; i>=0 && pPager->journalOff < szJ; i--){
- rc = pager_playback_one_page(pPager, &pPager->jfd, 1);
- assert( rc!=SQLITE_DONE );
- if( rc!=SQLITE_OK ) goto end_stmt_playback;
- }
- }
-
- pPager->journalOff = szJ;
-
-end_stmt_playback:
- if( rc!=SQLITE_OK ){
- pPager->errMask |= PAGER_ERR_CORRUPT;
- rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */
- }else{
- pPager->journalOff = szJ;
- /* pager_reload_cache(pPager); */
- }
- return rc;
-}
-
-/*
-** Change the maximum number of in-memory pages that are allowed.
-**
-** The maximum number is the absolute value of the mxPage parameter.
-** If mxPage is negative, the noSync flag is also set. noSync bypasses
-** calls to sqlite3OsSync(). The pager runs much faster with noSync on,
-** but if the operating system crashes or there is an abrupt power
-** failure, the database file might be left in an inconsistent and
-** unrepairable state.
-*/
-void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
- if( mxPage>=0 ){
- pPager->noSync = pPager->tempFile;
- if( pPager->noSync ) pPager->needSync = 0;
- }else{
- pPager->noSync = 1;
- mxPage = -mxPage;
- }
- if( mxPage>10 ){
- pPager->mxPage = mxPage;
- }else{
- pPager->mxPage = 10;
- }
-}
-
-/*
-** Adjust the robustness of the database to damage due to OS crashes
-** or power failures by changing the number of syncs()s when writing
-** the rollback journal. There are three levels:
-**
-** OFF sqlite3OsSync() is never called. This is the default
-** for temporary and transient files.
-**
-** NORMAL The journal is synced once before writes begin on the
-** database. This is normally adequate protection, but
-** it is theoretically possible, though very unlikely,
-** that an inopertune power failure could leave the journal
-** in a state which would cause damage to the database
-** when it is rolled back.
-**
-** FULL The journal is synced twice before writes begin on the
-** database (with some additional information - the nRec field
-** of the journal header - being written in between the two
-** syncs). If we assume that writing a
-** single disk sector is atomic, then this mode provides
-** assurance that the journal will not be corrupted to the
-** point of causing damage to the database during rollback.
-**
-** Numeric values associated with these states are OFF==1, NORMAL=2,
-** and FULL=3.
-*/
-void sqlite3pager_set_safety_level(Pager *pPager, int level){
- pPager->noSync = level==1 || pPager->tempFile;
- pPager->fullSync = level==3 && !pPager->tempFile;
- if( pPager->noSync ) pPager->needSync = 0;
-}
-
-/*
-** Open a temporary file. Write the name of the file into zName
-** (zName must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write
-** the file descriptor into *fd. Return SQLITE_OK on success or some
-** other error code if we fail.
-**
-** The OS will automatically delete the temporary file when it is
-** closed.
-*/
-static int sqlite3pager_opentemp(char *zFile, OsFile *fd){
- int cnt = 8;
- int rc;
- do{
- cnt--;
- sqlite3OsTempFileName(zFile);
- rc = sqlite3OsOpenExclusive(zFile, fd, 1);
- }while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM );
- return rc;
-}
-
-/*
-** Create a new page cache and put a pointer to the page cache in *ppPager.
-** The file to be cached need not exist. The file is not locked until
-** the first call to sqlite3pager_get() and is only held open until the
-** last page is released using sqlite3pager_unref().
-**
-** If zFilename is NULL then a randomly-named temporary file is created
-** and used as the file to be cached. The file will be deleted
-** automatically when it is closed.
-**
-** If zFilename is ":memory:" then all information is held in cache.
-** It is never written to disk. This can be used to implement an
-** in-memory database.
-*/
-int sqlite3pager_open(
- Pager **ppPager, /* Return the Pager structure here */
- const char *zFilename, /* Name of the database file to open */
- int nExtra, /* Extra bytes append to each in-memory page */
- int useJournal /* TRUE to use a rollback journal on this file */
-){
- Pager *pPager;
- char *zFullPathname = 0;
- int nameLen;
- OsFile fd;
- int rc = SQLITE_OK;
- int i;
- int tempFile = 0;
- int memDb = 0;
- int readOnly = 0;
- char zTemp[SQLITE_TEMPNAME_SIZE];
-
- *ppPager = 0;
- memset(&fd, 0, sizeof(fd));
- if( sqlite3_malloc_failed ){
- return SQLITE_NOMEM;
- }
- if( zFilename && zFilename[0] ){
- if( strcmp(zFilename,":memory:")==0 ){
- memDb = 1;
- zFullPathname = sqliteStrDup("");
- rc = SQLITE_OK;
- }else{
- zFullPathname = sqlite3OsFullPathname(zFilename);
- if( zFullPathname ){
- rc = sqlite3OsOpenReadWrite(zFullPathname, &fd, &readOnly);
- }
- }
- }else{
- rc = sqlite3pager_opentemp(zTemp, &fd);
- zFilename = zTemp;
- zFullPathname = sqlite3OsFullPathname(zFilename);
- if( rc==SQLITE_OK ){
- tempFile = 1;
- }
- }
- if( !zFullPathname ){
- sqlite3OsClose(&fd);
- return SQLITE_NOMEM;
- }
- if( rc!=SQLITE_OK ){
- sqlite3OsClose(&fd);
- sqliteFree(zFullPathname);
- return rc;
- }
- nameLen = strlen(zFullPathname);
- pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
- if( pPager==0 ){
- sqlite3OsClose(&fd);
- sqliteFree(zFullPathname);
- return SQLITE_NOMEM;
- }
- TRACE3("OPEN %d %s\n", fd.h, zFullPathname);
- pPager->zFilename = (char*)&pPager[1];
- pPager->zDirectory = &pPager->zFilename[nameLen+1];
- pPager->zJournal = &pPager->zDirectory[nameLen+1];
- strcpy(pPager->zFilename, zFullPathname);
- strcpy(pPager->zDirectory, zFullPathname);
- for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){}
- if( i>0 ) pPager->zDirectory[i-1] = 0;
- strcpy(pPager->zJournal, zFullPathname);
- sqliteFree(zFullPathname);
- strcpy(&pPager->zJournal[nameLen], "-journal");
- pPager->fd = fd;
-#if OS_UNIX
- pPager->fd.pPager = pPager;
-#endif
- pPager->journalOpen = 0;
- pPager->useJournal = useJournal && !memDb;
- pPager->stmtOpen = 0;
- pPager->stmtInUse = 0;
- pPager->nRef = 0;
- pPager->dbSize = memDb-1;
- pPager->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
- pPager->stmtSize = 0;
- pPager->stmtJSize = 0;
- pPager->nPage = 0;
- pPager->mxPage = 100;
- pPager->state = PAGER_UNLOCK;
- pPager->errMask = 0;
- pPager->tempFile = tempFile;
- pPager->memDb = memDb;
- pPager->readOnly = readOnly;
- pPager->needSync = 0;
- pPager->noSync = pPager->tempFile || !useJournal;
- pPager->fullSync = (pPager->noSync?0:1);
- pPager->pFirst = 0;
- pPager->pFirstSynced = 0;
- pPager->pLast = 0;
- pPager->nExtra = nExtra;
- pPager->sectorSize = PAGER_SECTOR_SIZE;
- pPager->pBusyHandler = 0;
- memset(pPager->aHash, 0, sizeof(pPager->aHash));
- *ppPager = pPager;
- return SQLITE_OK;
-}
-
-/*
-** Set the busy handler function.
-*/
-void sqlite3pager_set_busyhandler(Pager *pPager, BusyHandler *pBusyHandler){
- pPager->pBusyHandler = pBusyHandler;
-}
-
-/*
-** Set the destructor for this pager. If not NULL, the destructor is called
-** when the reference count on each page reaches zero. The destructor can
-** be used to clean up information in the extra segment appended to each page.
-**
-** The destructor is not called as a result sqlite3pager_close().
-** Destructors are only called by sqlite3pager_unref().
-*/
-void sqlite3pager_set_destructor(Pager *pPager, void (*xDesc)(void*,int)){
- pPager->xDestructor = xDesc;
-}
-
-/*
-** Set the reinitializer for this pager. If not NULL, the reinitializer
-** is called when the content of a page in cache is restored to its original
-** value as a result of a rollback. The callback gives higher-level code
-** an opportunity to restore the EXTRA section to agree with the restored
-** page data.
-*/
-void sqlite3pager_set_reiniter(Pager *pPager, void (*xReinit)(void*,int)){
- pPager->xReiniter = xReinit;
-}
-
-/*
-** Set the page size.
-**
-** The page size must only be changed when the cache is empty.
-*/
-void sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
- assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE );
- pPager->pageSize = pageSize;
-}
-
-/*
-** Read the first N bytes from the beginning of the file into memory
-** that pDest points to. No error checking is done.
-*/
-void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
- memset(pDest, 0, N);
- if( pPager->memDb==0 ){
- sqlite3OsSeek(&pPager->fd, 0);
- sqlite3OsRead(&pPager->fd, pDest, N);
- }
-}
-
-/*
-** Return the total number of pages in the disk file associated with
-** pPager.
-*/
-int sqlite3pager_pagecount(Pager *pPager){
- i64 n;
- assert( pPager!=0 );
- if( pPager->dbSize>=0 ){
- return pPager->dbSize;
- }
- if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
- pPager->errMask |= PAGER_ERR_DISK;
- return 0;
- }
- n /= pPager->pageSize;
- if( !pPager->memDb && n==PENDING_BYTE/pPager->pageSize ){
- n++;
- }
- if( pPager->state!=PAGER_UNLOCK ){
- pPager->dbSize = n;
- }
- return n;
-}
-
-/*
-** Forward declaration
-*/
-static int syncJournal(Pager*);
-
-
-/*
-** Unlink a page from the free list (the list of all pages where nRef==0)
-** and from its hash collision chain.
-*/
-static void unlinkPage(PgHdr *pPg){
- Pager *pPager = pPg->pPager;
-
- /* Keep the pFirstSynced pointer pointing at the first synchronized page */
- if( pPg==pPager->pFirstSynced ){
- PgHdr *p = pPg->pNextFree;
- while( p && p->needSync ){ p = p->pNextFree; }
- pPager->pFirstSynced = p;
- }
-
- /* Unlink from the freelist */
- if( pPg->pPrevFree ){
- pPg->pPrevFree->pNextFree = pPg->pNextFree;
- }else{
- assert( pPager->pFirst==pPg );
- pPager->pFirst = pPg->pNextFree;
- }
- if( pPg->pNextFree ){
- pPg->pNextFree->pPrevFree = pPg->pPrevFree;
- }else{
- assert( pPager->pLast==pPg );
- pPager->pLast = pPg->pPrevFree;
- }
- pPg->pNextFree = pPg->pPrevFree = 0;
-
- /* Unlink from the pgno hash table */
- if( pPg->pNextHash ){
- pPg->pNextHash->pPrevHash = pPg->pPrevHash;
- }
- if( pPg->pPrevHash ){
- pPg->pPrevHash->pNextHash = pPg->pNextHash;
- }else{
- int h = pager_hash(pPg->pgno);
- assert( pPager->aHash[h]==pPg );
- pPager->aHash[h] = pPg->pNextHash;
- }
- pPg->pNextHash = pPg->pPrevHash = 0;
-}
-
-/*
-** This routine is used to truncate an in-memory database. Delete
-** all pages whose pgno is larger than pPager->dbSize and is unreferenced.
-** Referenced pages larger than pPager->dbSize are zeroed.
-*/
-static void memoryTruncate(Pager *pPager){
- PgHdr *pPg;
- PgHdr **ppPg;
- int dbSize = pPager->dbSize;
-
- ppPg = &pPager->pAll;
- while( (pPg = *ppPg)!=0 ){
- if( pPg->pgno<=dbSize ){
- ppPg = &pPg->pNextAll;
- }else if( pPg->nRef>0 ){
- memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
- ppPg = &pPg->pNextAll;
- }else{
- *ppPg = pPg->pNextAll;
- unlinkPage(pPg);
- sqliteFree(pPg);
- pPager->nPage--;
- }
- }
-}
-
-/*
-** Truncate the file to the number of pages specified.
-*/
-int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
- int rc;
- sqlite3pager_pagecount(pPager);
- if( pPager->errMask!=0 ){
- rc = pager_errcode(pPager);
- return rc;
- }
- if( nPage>=(unsigned)pPager->dbSize ){
- return SQLITE_OK;
- }
- if( pPager->memDb ){
- pPager->dbSize = nPage;
- memoryTruncate(pPager);
- return SQLITE_OK;
- }
- rc = syncJournal(pPager);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- rc = pager_truncate(pPager, nPage);
- if( rc==SQLITE_OK ){
- pPager->dbSize = nPage;
- }
- return rc;
-}
-
-/*
-** Shutdown the page cache. Free all memory and close all files.
-**
-** If a transaction was in progress when this routine is called, that
-** transaction is rolled back. All outstanding pages are invalidated
-** and their memory is freed. Any attempt to use a page associated
-** with this page cache after this function returns will likely
-** result in a coredump.
-*/
-int sqlite3pager_close(Pager *pPager){
- PgHdr *pPg, *pNext;
- switch( pPager->state ){
- case PAGER_RESERVED:
- case PAGER_SYNCED:
- case PAGER_EXCLUSIVE: {
- sqlite3pager_rollback(pPager);
- if( !pPager->memDb ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
- }
- assert( pPager->journalOpen==0 );
- break;
- }
- case PAGER_SHARED: {
- if( !pPager->memDb ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
- }
- break;
- }
- default: {
- /* Do nothing */
- break;
- }
- }
- for(pPg=pPager->pAll; pPg; pPg=pNext){
-#ifndef NDEBUG
- if( pPager->memDb ){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- assert( !pPg->alwaysRollback );
- assert( !pHist->pOrig );
- assert( !pHist->pStmt );
- }
-#endif
- pNext = pPg->pNextAll;
- sqliteFree(pPg);
- }
- TRACE2("CLOSE %d\n", pPager->fd.h);
- sqlite3OsClose(&pPager->fd);
- assert( pPager->journalOpen==0 );
- /* Temp files are automatically deleted by the OS
- ** if( pPager->tempFile ){
- ** sqlite3OsDelete(pPager->zFilename);
- ** }
- */
- if( pPager->zFilename!=(char*)&pPager[1] ){
- assert( 0 ); /* Cannot happen */
- sqliteFree(pPager->zFilename);
- sqliteFree(pPager->zJournal);
- sqliteFree(pPager->zDirectory);
- }
- sqliteFree(pPager);
- return SQLITE_OK;
-}
-
-/*
-** Return the page number for the given page data.
-*/
-Pgno sqlite3pager_pagenumber(void *pData){
- PgHdr *p = DATA_TO_PGHDR(pData);
- return p->pgno;
-}
-
-/*
-** The page_ref() function increments the reference count for a page.
-** If the page is currently on the freelist (the reference count is zero) then
-** remove it from the freelist.
-**
-** For non-test systems, page_ref() is a macro that calls _page_ref()
-** online of the reference count is zero. For test systems, page_ref()
-** is a real function so that we can set breakpoints and trace it.
-*/
-static void _page_ref(PgHdr *pPg){
- if( pPg->nRef==0 ){
- /* The page is currently on the freelist. Remove it. */
- if( pPg==pPg->pPager->pFirstSynced ){
- PgHdr *p = pPg->pNextFree;
- while( p && p->needSync ){ p = p->pNextFree; }
- pPg->pPager->pFirstSynced = p;
- }
- if( pPg->pPrevFree ){
- pPg->pPrevFree->pNextFree = pPg->pNextFree;
- }else{
- pPg->pPager->pFirst = pPg->pNextFree;
- }
- if( pPg->pNextFree ){
- pPg->pNextFree->pPrevFree = pPg->pPrevFree;
- }else{
- pPg->pPager->pLast = pPg->pPrevFree;
- }
- pPg->pPager->nRef++;
- }
- pPg->nRef++;
- REFINFO(pPg);
-}
-#ifdef SQLITE_TEST
- static void page_ref(PgHdr *pPg){
- if( pPg->nRef==0 ){
- _page_ref(pPg);
- }else{
- pPg->nRef++;
- REFINFO(pPg);
- }
- }
-#else
-# define page_ref(P) ((P)->nRef==0?_page_ref(P):(void)(P)->nRef++)
-#endif
-
-/*
-** Increment the reference count for a page. The input pointer is
-** a reference to the page data.
-*/
-int sqlite3pager_ref(void *pData){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
- page_ref(pPg);
- return SQLITE_OK;
-}
-
-/*
-** Sync the journal. In other words, make sure all the pages that have
-** been written to the journal have actually reached the surface of the
-** disk. It is not safe to modify the original database file until after
-** the journal has been synced. If the original database is modified before
-** the journal is synced and a power failure occurs, the unsynced journal
-** data would be lost and we would be unable to completely rollback the
-** database changes. Database corruption would occur.
-**
-** This routine also updates the nRec field in the header of the journal.
-** (See comments on the pager_playback() routine for additional information.)
-** If the sync mode is FULL, two syncs will occur. First the whole journal
-** is synced, then the nRec field is updated, then a second sync occurs.
-**
-** For temporary databases, we do not care if we are able to rollback
-** after a power failure, so sync occurs.
-**
-** This routine clears the needSync field of every page current held in
-** memory.
-*/
-static int syncJournal(Pager *pPager){
- PgHdr *pPg;
- int rc = SQLITE_OK;
-
- /* Sync the journal before modifying the main database
- ** (assuming there is a journal and it needs to be synced.)
- */
- if( pPager->needSync ){
- if( !pPager->tempFile ){
- assert( pPager->journalOpen );
- /* assert( !pPager->noSync ); // noSync might be set if synchronous
- ** was turned off after the transaction was started. Ticket #615 */
-#ifndef NDEBUG
- {
- /* Make sure the pPager->nRec counter we are keeping agrees
- ** with the nRec computed from the size of the journal file.
- */
- i64 jSz;
- rc = sqlite3OsFileSize(&pPager->jfd, &jSz);
- if( rc!=0 ) return rc;
- assert( pPager->journalOff==jSz );
- }
-#endif
- {
- /* Write the nRec value into the journal file header. If in
- ** full-synchronous mode, sync the journal first. This ensures that
- ** all data has really hit the disk before nRec is updated to mark
- ** it as a candidate for rollback.
- */
- if( pPager->fullSync ){
- TRACE2("SYNC journal of %d\n", pPager->fd.h);
- rc = sqlite3OsSync(&pPager->jfd);
- if( rc!=0 ) return rc;
- }
- sqlite3OsSeek(&pPager->jfd, pPager->journalHdr + sizeof(aJournalMagic));
- rc = write32bits(&pPager->jfd, pPager->nRec);
- if( rc ) return rc;
-
- sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
- }
- TRACE2("SYNC journal of %d\n", pPager->fd.h);
- rc = sqlite3OsSync(&pPager->jfd);
- if( rc!=0 ) return rc;
- pPager->journalStarted = 1;
- }
- pPager->needSync = 0;
-
- /* Erase the needSync flag from every page.
- */
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- pPg->needSync = 0;
- }
- pPager->pFirstSynced = pPager->pFirst;
- }
-
-#ifndef NDEBUG
- /* If the Pager.needSync flag is clear then the PgHdr.needSync
- ** flag must also be clear for all pages. Verify that this
- ** invariant is true.
- */
- else{
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- assert( pPg->needSync==0 );
- }
- assert( pPager->pFirstSynced==pPager->pFirst );
- }
-#endif
-
- return rc;
-}
-
-/*
-** Try to obtain a lock on a file. Invoke the busy callback if the lock
-** is currently not available. Repeate until the busy callback returns
-** false or until the lock succeeds.
-**
-** Return SQLITE_OK on success and an error code if we cannot obtain
-** the lock.
-*/
-static int pager_wait_on_lock(Pager *pPager, int locktype){
- int rc;
- assert( PAGER_SHARED==SHARED_LOCK );
- assert( PAGER_RESERVED==RESERVED_LOCK );
- assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK );
- if( pPager->state>=locktype ){
- rc = SQLITE_OK;
- }else{
- int busy = 1;
- do {
- rc = sqlite3OsLock(&pPager->fd, locktype);
- }while( rc==SQLITE_BUSY &&
- pPager->pBusyHandler &&
- pPager->pBusyHandler->xFunc &&
- pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
- );
- if( rc==SQLITE_OK ){
- pPager->state = locktype;
- }
- }
- return rc;
-}
-
-/*
-** Given a list of pages (connected by the PgHdr.pDirty pointer) write
-** every one of those pages out to the database file and mark them all
-** as clean.
-*/
-static int pager_write_pagelist(PgHdr *pList){
- Pager *pPager;
- int rc;
-
- if( pList==0 ) return SQLITE_OK;
- pPager = pList->pPager;
-
- /* At this point there may be either a RESERVED or EXCLUSIVE lock on the
- ** database file. If there is already an EXCLUSIVE lock, the following
- ** calls to sqlite3OsLock() are no-ops.
- **
- ** Moving the lock from RESERVED to EXCLUSIVE actually involves going
- ** through an intermediate state PENDING. A PENDING lock prevents new
- ** readers from attaching to the database but is unsufficient for us to
- ** write. The idea of a PENDING lock is to prevent new readers from
- ** coming in while we wait for existing readers to clear.
- **
- ** While the pager is in the RESERVED state, the original database file
- ** is unchanged and we can rollback without having to playback the
- ** journal into the original database file. Once we transition to
- ** EXCLUSIVE, it means the database file has been changed and any rollback
- ** will require a journal playback.
- */
- rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
- if( rc!=SQLITE_OK ){
- return rc;
- }
-
- while( pList ){
- assert( pList->dirty );
- sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
- CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
- TRACE3("STORE %d page %d\n", pPager->fd.h, pList->pgno);
- rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize);
- CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
- if( rc ) return rc;
- pList->dirty = 0;
- pList = pList->pDirty;
- }
- return SQLITE_OK;
-}
-
-/*
-** Collect every dirty page into a dirty list and
-** return a pointer to the head of that list. All pages are
-** collected even if they are still in use.
-*/
-static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
- PgHdr *p, *pList;
- pList = 0;
- for(p=pPager->pAll; p; p=p->pNextAll){
- if( p->dirty ){
- p->pDirty = pList;
- pList = p;
- }
- }
- return pList;
-}
-
-/*
-** Acquire a page.
-**
-** A read lock on the disk file is obtained when the first page is acquired.
-** This read lock is dropped when the last page is released.
-**
-** A _get works for any page number greater than 0. If the database
-** file is smaller than the requested page, then no actual disk
-** read occurs and the memory image of the page is initialized to
-** all zeros. The extra data appended to a page is always initialized
-** to zeros the first time a page is loaded into memory.
-**
-** The acquisition might fail for several reasons. In all cases,
-** an appropriate error code is returned and *ppPage is set to NULL.
-**
-** See also sqlite3pager_lookup(). Both this routine and _lookup() attempt
-** to find a page in the in-memory cache first. If the page is not already
-** in memory, this routine goes to disk to read it in whereas _lookup()
-** just returns 0. This routine acquires a read-lock the first time it
-** has to go to disk, and could also playback an old journal if necessary.
-** Since _lookup() never goes to disk, it never has to deal with locks
-** or journal files.
-*/
-int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
- PgHdr *pPg;
- int rc;
-
- /* Make sure we have not hit any critical errors.
- */
- assert( pPager!=0 );
- assert( pgno!=0 );
- *ppPage = 0;
- if( pPager->errMask & ~(PAGER_ERR_FULL) ){
- return pager_errcode(pPager);
- }
-
- /* If this is the first page accessed, then get a SHARED lock
- ** on the database file.
- */
- if( pPager->nRef==0 && !pPager->memDb ){
- rc = pager_wait_on_lock(pPager, SHARED_LOCK);
- if( rc!=SQLITE_OK ){
- return rc;
- }
-
- /* If a journal file exists, and there is no RESERVED lock on the
- ** database file, then it either needs to be played back or deleted.
- */
- if( pPager->useJournal &&
- sqlite3OsFileExists(pPager->zJournal) &&
- !sqlite3OsCheckReservedLock(&pPager->fd)
- ){
- int rc;
-
- /* Get an EXCLUSIVE lock on the database file. At this point it is
- ** important that a RESERVED lock is not obtained on the way to the
- ** EXCLUSIVE lock. If it were, another process might open the
- ** database file, detect the RESERVED lock, and conclude that the
- ** database is safe to read while this process is still rolling it
- ** back.
- **
- ** Because the intermediate RESERVED lock is not requested, the
- ** second process will get to this point in the code and fail to
- ** obtain it's own EXCLUSIVE lock on the database file.
- */
- rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK);
- if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
- return rc;
- }
- pPager->state = PAGER_EXCLUSIVE;
-
- /* Open the journal for reading only. Return SQLITE_BUSY if
- ** we are unable to open the journal file.
- **
- ** The journal file does not need to be locked itself. The
- ** journal file is never open unless the main database file holds
- ** a write lock, so there is never any chance of two or more
- ** processes opening the journal at the same time.
- */
- rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
- if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
- return SQLITE_BUSY;
- }
- pPager->journalOpen = 1;
- pPager->journalStarted = 0;
- pPager->journalOff = 0;
- pPager->setMaster = 0;
- pPager->journalHdr = 0;
-
- /* Playback and delete the journal. Drop the database write
- ** lock and reacquire the read lock.
- */
- rc = pager_playback(pPager);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- }
- pPg = 0;
- }else{
- /* Search for page in cache */
- pPg = pager_lookup(pPager, pgno);
- if( pPager->memDb && pPager->state==PAGER_UNLOCK ){
- pPager->state = PAGER_SHARED;
- }
- }
- if( pPg==0 ){
- /* The requested page is not in the page cache. */
- int h;
- pPager->nMiss++;
- if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || pPager->memDb ){
- /* Create a new page */
- pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize
- + sizeof(u32) + pPager->nExtra
- + pPager->memDb*sizeof(PgHistory) );
- if( pPg==0 ){
- if( !pPager->memDb ){
- pager_unwritelock(pPager);
- }
- pPager->errMask |= PAGER_ERR_MEM;
- return SQLITE_NOMEM;
- }
- memset(pPg, 0, sizeof(*pPg));
- if( pPager->memDb ){
- memset(PGHDR_TO_HIST(pPg, pPager), 0, sizeof(PgHistory));
- }
- pPg->pPager = pPager;
- pPg->pNextAll = pPager->pAll;
- pPager->pAll = pPg;
- pPager->nPage++;
- }else{
- /* Find a page to recycle. Try to locate a page that does not
- ** require us to do an fsync() on the journal.
- */
- pPg = pPager->pFirstSynced;
-
- /* If we could not find a page that does not require an fsync()
- ** on the journal file then fsync the journal file. This is a
- ** very slow operation, so we work hard to avoid it. But sometimes
- ** it can't be helped.
- */
- if( pPg==0 ){
- int rc = syncJournal(pPager);
- if( rc!=0 ){
- sqlite3pager_rollback(pPager);
- return SQLITE_IOERR;
- }
- if( pPager->fullSync ){
- /* If in full-sync mode, write a new journal header into the
- ** journal file. This is done to avoid ever modifying a journal
- ** header that is involved in the rollback of pages that have
- ** already been written to the database (in case the header is
- ** trashed when the nRec field is updated).
- */
- pPager->nRec = 0;
- assert( pPager->journalOff > 0 );
- rc = writeJournalHdr(pPager);
- if( rc!=0 ){
- sqlite3pager_rollback(pPager);
- return SQLITE_IOERR;
- }
- }
- pPg = pPager->pFirst;
- }
- assert( pPg->nRef==0 );
-
- /* Write the page to the database file if it is dirty.
- */
- if( pPg->dirty ){
- assert( pPg->needSync==0 );
- pPg->pDirty = 0;
- rc = pager_write_pagelist( pPg );
- if( rc!=SQLITE_OK ){
- sqlite3pager_rollback(pPager);
- return SQLITE_IOERR;
- }
- }
- assert( pPg->dirty==0 );
-
- /* If the page we are recycling is marked as alwaysRollback, then
- ** set the global alwaysRollback flag, thus disabling the
- ** sqlite_dont_rollback() optimization for the rest of this transaction.
- ** It is necessary to do this because the page marked alwaysRollback
- ** might be reloaded at a later time but at that point we won't remember
- ** that is was marked alwaysRollback. This means that all pages must
- ** be marked as alwaysRollback from here on out.
- */
- if( pPg->alwaysRollback ){
- pPager->alwaysRollback = 1;
- }
-
- /* Unlink the old page from the free list and the hash table
- */
- unlinkPage(pPg);
- pPager->nOvfl++;
- }
- pPg->pgno = pgno;
- if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
- sqlite3CheckMemory(pPager->aInJournal, pgno/8);
- assert( pPager->journalOpen );
- pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0;
- pPg->needSync = 0;
- }else{
- pPg->inJournal = 0;
- pPg->needSync = 0;
- }
- if( pPager->aInStmt && (int)pgno<=pPager->stmtSize
- && (pPager->aInStmt[pgno/8] & (1<<(pgno&7)))!=0 ){
- page_add_to_stmt_list(pPg);
- }else{
- page_remove_from_stmt_list(pPg);
- }
- pPg->dirty = 0;
- pPg->nRef = 1;
- REFINFO(pPg);
- pPager->nRef++;
- h = pager_hash(pgno);
- pPg->pNextHash = pPager->aHash[h];
- pPager->aHash[h] = pPg;
- if( pPg->pNextHash ){
- assert( pPg->pNextHash->pPrevHash==0 );
- pPg->pNextHash->pPrevHash = pPg;
- }
- if( pPager->nExtra>0 ){
- memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
- }
- sqlite3pager_pagecount(pPager);
- if( pPager->errMask!=0 ){
- sqlite3pager_unref(PGHDR_TO_DATA(pPg));
- rc = pager_errcode(pPager);
- return rc;
- }
- if( pPager->dbSize<(int)pgno ){
- memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
- }else{
- int rc;
- assert( pPager->memDb==0 );
- sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
- rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
- TRACE3("FETCH %d page %d\n", pPager->fd.h, pPg->pgno);
- CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
- if( rc!=SQLITE_OK ){
- i64 fileSize;
- if( sqlite3OsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
- || fileSize>=pgno*pPager->pageSize ){
- sqlite3pager_unref(PGHDR_TO_DATA(pPg));
- return rc;
- }else{
- memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
- }
- }
- }
- }else{
- /* The requested page is in the page cache. */
- pPager->nHit++;
- page_ref(pPg);
- }
- *ppPage = PGHDR_TO_DATA(pPg);
- return SQLITE_OK;
-}
-
-/*
-** Acquire a page if it is already in the in-memory cache. Do
-** not read the page from disk. Return a pointer to the page,
-** or 0 if the page is not in cache.
-**
-** See also sqlite3pager_get(). The difference between this routine
-** and sqlite3pager_get() is that _get() will go to the disk and read
-** in the page if the page is not already in cache. This routine
-** returns NULL if the page is not in cache or if a disk I/O error
-** has ever happened.
-*/
-void *sqlite3pager_lookup(Pager *pPager, Pgno pgno){
- PgHdr *pPg;
-
- assert( pPager!=0 );
- assert( pgno!=0 );
- if( pPager->errMask & ~(PAGER_ERR_FULL) ){
- return 0;
- }
- pPg = pager_lookup(pPager, pgno);
- if( pPg==0 ) return 0;
- page_ref(pPg);
- return PGHDR_TO_DATA(pPg);
-}
-
-/*
-** Release a page.
-**
-** If the number of references to the page drop to zero, then the
-** page is added to the LRU list. When all references to all pages
-** are released, a rollback occurs and the lock on the database is
-** removed.
-*/
-int sqlite3pager_unref(void *pData){
- PgHdr *pPg;
-
- /* Decrement the reference count for this page
- */
- pPg = DATA_TO_PGHDR(pData);
- assert( pPg->nRef>0 );
- pPg->nRef--;
- REFINFO(pPg);
-
- /* When the number of references to a page reach 0, call the
- ** destructor and add the page to the freelist.
- */
- if( pPg->nRef==0 ){
- Pager *pPager;
- pPager = pPg->pPager;
- pPg->pNextFree = 0;
- pPg->pPrevFree = pPager->pLast;
- pPager->pLast = pPg;
- if( pPg->pPrevFree ){
- pPg->pPrevFree->pNextFree = pPg;
- }else{
- pPager->pFirst = pPg;
- }
- if( pPg->needSync==0 && pPager->pFirstSynced==0 ){
- pPager->pFirstSynced = pPg;
- }
- if( pPager->xDestructor ){
- pPager->xDestructor(pData, pPager->pageSize);
- }
-
- /* When all pages reach the freelist, drop the read lock from
- ** the database file.
- */
- pPager->nRef--;
- assert( pPager->nRef>=0 );
- if( pPager->nRef==0 && !pPager->memDb ){
- pager_reset(pPager);
- }
- }
- return SQLITE_OK;
-}
-
-/*
-** Create a journal file for pPager. There should already be a RESERVED
-** or EXCLUSIVE lock on the database file when this routine is called.
-**
-** Return SQLITE_OK if everything. Return an error code and release the
-** write lock if anything goes wrong.
-*/
-static int pager_open_journal(Pager *pPager){
- int rc;
- assert( !pPager->memDb );
- assert( pPager->state>=PAGER_RESERVED );
- assert( pPager->journalOpen==0 );
- assert( pPager->useJournal );
- sqlite3pager_pagecount(pPager);
- pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
- if( pPager->aInJournal==0 ){
- rc = SQLITE_NOMEM;
- goto failed_to_open_journal;
- }
- rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile);
- pPager->journalOff = 0;
- pPager->setMaster = 0;
- pPager->journalHdr = 0;
- if( rc!=SQLITE_OK ){
- goto failed_to_open_journal;
- }
- sqlite3OsOpenDirectory(pPager->zDirectory, &pPager->jfd);
- pPager->journalOpen = 1;
- pPager->journalStarted = 0;
- pPager->needSync = 0;
- pPager->alwaysRollback = 0;
- pPager->nRec = 0;
- if( pPager->errMask!=0 ){
- rc = pager_errcode(pPager);
- return rc;
- }
- pPager->origDbSize = pPager->dbSize;
-
- rc = writeJournalHdr(pPager);
-
- if( pPager->stmtAutoopen && rc==SQLITE_OK ){
- rc = sqlite3pager_stmt_begin(pPager);
- }
- if( rc!=SQLITE_OK ){
- rc = pager_unwritelock(pPager);
- if( rc==SQLITE_OK ){
- rc = SQLITE_FULL;
- }
- }
- return rc;
-
-failed_to_open_journal:
- sqliteFree(pPager->aInJournal);
- pPager->aInJournal = 0;
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
- return rc;
-}
-
-/*
-** Acquire a write-lock on the database. The lock is removed when
-** the any of the following happen:
-**
-** * sqlite3pager_commit() is called.
-** * sqlite3pager_rollback() is called.
-** * sqlite3pager_close() is called.
-** * sqlite3pager_unref() is called to on every outstanding page.
-**
-** The first parameter to this routine is a pointer to any open page of the
-** database file. Nothing changes about the page - it is used merely to
-** acquire a pointer to the Pager structure and as proof that there is
-** already a read-lock on the database.
-**
-** The second parameter indicates how much space in bytes to reserve for a
-** master journal file-name at the start of the journal when it is created.
-**
-** A journal file is opened if this is not a temporary file. For temporary
-** files, the opening of the journal file is deferred until there is an
-** actual need to write to the journal.
-**
-** If the database is already reserved for writing, this routine is a no-op.
-**
-** If exFlag is true, go ahead and get an EXCLUSIVE lock on the file
-** immediately instead of waiting until we try to flush the cache. The
-** exFlag is ignored if a transaction is already active.
-*/
-int sqlite3pager_begin(void *pData, int exFlag){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
- Pager *pPager = pPg->pPager;
- int rc = SQLITE_OK;
- assert( pPg->nRef>0 );
- assert( pPager->state!=PAGER_UNLOCK );
- if( pPager->state==PAGER_SHARED ){
- assert( pPager->aInJournal==0 );
- if( pPager->memDb ){
- pPager->state = PAGER_EXCLUSIVE;
- pPager->origDbSize = pPager->dbSize;
- }else{
- if( SQLITE_BUSY_RESERVED_LOCK || exFlag ){
- rc = pager_wait_on_lock(pPager, RESERVED_LOCK);
- }else{
- rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
- }
- if( rc==SQLITE_OK ){
- pPager->state = PAGER_RESERVED;
- if( exFlag ){
- rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
- }
- }
- if( rc!=SQLITE_OK ){
- return rc;
- }
- pPager->dirtyCache = 0;
- TRACE2("TRANSACTION %d\n", pPager->fd.h);
- if( pPager->useJournal && !pPager->tempFile ){
- rc = pager_open_journal(pPager);
- }
- }
- }
- return rc;
-}
-
-/*
-** Mark a data page as writeable. The page is written into the journal
-** if it is not there already. This routine must be called before making
-** changes to a page.
-**
-** The first time this routine is called, the pager creates a new
-** journal and acquires a RESERVED lock on the database. If the RESERVED
-** lock could not be acquired, this routine returns SQLITE_BUSY. The
-** calling routine must check for that return value and be careful not to
-** change any page data until this routine returns SQLITE_OK.
-**
-** If the journal file could not be written because the disk is full,
-** then this routine returns SQLITE_FULL and does an immediate rollback.
-** All subsequent write attempts also return SQLITE_FULL until there
-** is a call to sqlite3pager_commit() or sqlite3pager_rollback() to
-** reset.
-*/
-int sqlite3pager_write(void *pData){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
- Pager *pPager = pPg->pPager;
- int rc = SQLITE_OK;
-
- /* Check for errors
- */
- if( pPager->errMask ){
- return pager_errcode(pPager);
- }
- if( pPager->readOnly ){
- return SQLITE_PERM;
- }
-
- assert( !pPager->setMaster );
-
- /* Mark the page as dirty. If the page has already been written
- ** to the journal then we can return right away.
- */
- pPg->dirty = 1;
- if( pPg->inJournal && (pPg->inStmt || pPager->stmtInUse==0) ){
- pPager->dirtyCache = 1;
- return SQLITE_OK;
- }
-
- /* If we get this far, it means that the page needs to be
- ** written to the transaction journal or the ckeckpoint journal
- ** or both.
- **
- ** First check to see that the transaction journal exists and
- ** create it if it does not.
- */
- assert( pPager->state!=PAGER_UNLOCK );
- rc = sqlite3pager_begin(pData, 0);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- assert( pPager->state>=PAGER_RESERVED );
- if( !pPager->journalOpen && pPager->useJournal ){
- rc = pager_open_journal(pPager);
- if( rc!=SQLITE_OK ) return rc;
- }
- assert( pPager->journalOpen || !pPager->useJournal );
- pPager->dirtyCache = 1;
-
- /* The transaction journal now exists and we have a RESERVED or an
- ** EXCLUSIVE lock on the main database file. Write the current page to
- ** the transaction journal if it is not there already.
- */
- if( !pPg->inJournal && (pPager->useJournal || pPager->memDb) ){
- if( (int)pPg->pgno <= pPager->origDbSize ){
- int szPg;
- u32 saved;
- if( pPager->memDb ){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- TRACE3("JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
- assert( pHist->pOrig==0 );
- pHist->pOrig = sqliteMallocRaw( pPager->pageSize );
- if( pHist->pOrig ){
- memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
- }
- }else{
- u32 cksum;
- CODEC(pPager, pData, pPg->pgno, 7);
- cksum = pager_cksum(pPager, pPg->pgno, pData);
- saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
- store32bits(cksum, pPg, pPager->pageSize);
- szPg = pPager->pageSize+8;
- store32bits(pPg->pgno, pPg, -4);
- rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
- pPager->journalOff += szPg;
- TRACE4("JOURNAL %d page %d needSync=%d\n",
- pPager->fd.h, pPg->pgno, pPg->needSync);
- CODEC(pPager, pData, pPg->pgno, 0);
- *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved;
- if( rc!=SQLITE_OK ){
- sqlite3pager_rollback(pPager);
- pPager->errMask |= PAGER_ERR_FULL;
- return rc;
- }
- pPager->nRec++;
- assert( pPager->aInJournal!=0 );
- pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- pPg->needSync = !pPager->noSync;
- if( pPager->stmtInUse ){
- pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- page_add_to_stmt_list(pPg);
- }
- }
- }else{
- pPg->needSync = !pPager->journalStarted && !pPager->noSync;
- TRACE4("APPEND %d page %d needSync=%d\n",
- pPager->fd.h, pPg->pgno, pPg->needSync);
- }
- if( pPg->needSync ){
- pPager->needSync = 1;
- }
- pPg->inJournal = 1;
- }
-
- /* If the statement journal is open and the page is not in it,
- ** then write the current page to the statement journal. Note that
- ** the statement journal format differs from the standard journal format
- ** in that it omits the checksums and the header.
- */
- if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
- assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
- if( pPager->memDb ){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- assert( pHist->pStmt==0 );
- pHist->pStmt = sqliteMallocRaw( pPager->pageSize );
- if( pHist->pStmt ){
- memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize);
- }
- TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
- }else{
- store32bits(pPg->pgno, pPg, -4);
- CODEC(pPager, pData, pPg->pgno, 7);
- rc = sqlite3OsWrite(&pPager->stfd, ((char*)pData)-4, pPager->pageSize+4);
- TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
- CODEC(pPager, pData, pPg->pgno, 0);
- if( rc!=SQLITE_OK ){
- sqlite3pager_rollback(pPager);
- pPager->errMask |= PAGER_ERR_FULL;
- return rc;
- }
- pPager->stmtNRec++;
- assert( pPager->aInStmt!=0 );
- pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- }
- page_add_to_stmt_list(pPg);
- }
-
- /* Update the database size and return.
- */
- if( pPager->dbSize<(int)pPg->pgno ){
- pPager->dbSize = pPg->pgno;
- if( !pPager->memDb && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){
- pPager->dbSize++;
- }
- }
- return rc;
-}
-
-/*
-** Return TRUE if the page given in the argument was previously passed
-** to sqlite3pager_write(). In other words, return TRUE if it is ok
-** to change the content of the page.
-*/
-int sqlite3pager_iswriteable(void *pData){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
- return pPg->dirty;
-}
-
-/*
-** Replace the content of a single page with the information in the third
-** argument.
-*/
-int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void *pData){
- void *pPage;
- int rc;
-
- rc = sqlite3pager_get(pPager, pgno, &pPage);
- if( rc==SQLITE_OK ){
- rc = sqlite3pager_write(pPage);
- if( rc==SQLITE_OK ){
- memcpy(pPage, pData, pPager->pageSize);
- }
- sqlite3pager_unref(pPage);
- }
- return rc;
-}
-
-/*
-** A call to this routine tells the pager that it is not necessary to
-** write the information on page "pgno" back to the disk, even though
-** that page might be marked as dirty.
-**
-** The overlying software layer calls this routine when all of the data
-** on the given page is unused. The pager marks the page as clean so
-** that it does not get written to disk.
-**
-** Tests show that this optimization, together with the
-** sqlite3pager_dont_rollback() below, more than double the speed
-** of large INSERT operations and quadruple the speed of large DELETEs.
-**
-** When this routine is called, set the alwaysRollback flag to true.
-** Subsequent calls to sqlite3pager_dont_rollback() for the same page
-** will thereafter be ignored. This is necessary to avoid a problem
-** where a page with data is added to the freelist during one part of
-** a transaction then removed from the freelist during a later part
-** of the same transaction and reused for some other purpose. When it
-** is first added to the freelist, this routine is called. When reused,
-** the dont_rollback() routine is called. But because the page contains
-** critical data, we still need to be sure it gets rolled back in spite
-** of the dont_rollback() call.
-*/
-void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
- PgHdr *pPg;
-
- if( pPager->memDb ) return;
-
- pPg = pager_lookup(pPager, pgno);
- pPg->alwaysRollback = 1;
- if( pPg && pPg->dirty ){
- if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){
- /* If this pages is the last page in the file and the file has grown
- ** during the current transaction, then do NOT mark the page as clean.
- ** When the database file grows, we must make sure that the last page
- ** gets written at least once so that the disk file will be the correct
- ** size. If you do not write this page and the size of the file
- ** on the disk ends up being too small, that can lead to database
- ** corruption during the next transaction.
- */
- }else{
- TRACE3("DONT_WRITE page %d of %d\n", pgno, pPager->fd.h);
- pPg->dirty = 0;
- }
- }
-}
-
-/*
-** A call to this routine tells the pager that if a rollback occurs,
-** it is not necessary to restore the data on the given page. This
-** means that the pager does not have to record the given page in the
-** rollback journal.
-*/
-void sqlite3pager_dont_rollback(void *pData){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
- Pager *pPager = pPg->pPager;
-
- if( pPager->state!=PAGER_EXCLUSIVE || pPager->journalOpen==0 ) return;
- if( pPg->alwaysRollback || pPager->alwaysRollback || pPager->memDb ) return;
- if( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ){
- assert( pPager->aInJournal!=0 );
- pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- pPg->inJournal = 1;
- if( pPager->stmtInUse ){
- pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- page_add_to_stmt_list(pPg);
- }
- TRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, pPager->fd.h);
- }
- if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
- assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
- assert( pPager->aInStmt!=0 );
- pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- page_add_to_stmt_list(pPg);
- }
-}
-
-
-/*
-** Clear a PgHistory block
-*/
-static void clearHistory(PgHistory *pHist){
- sqliteFree(pHist->pOrig);
- sqliteFree(pHist->pStmt);
- pHist->pOrig = 0;
- pHist->pStmt = 0;
-}
-
-/*
-** Commit all changes to the database and release the write lock.
-**
-** If the commit fails for any reason, a rollback attempt is made
-** and an error code is returned. If the commit worked, SQLITE_OK
-** is returned.
-*/
-int sqlite3pager_commit(Pager *pPager){
- int rc;
- PgHdr *pPg;
-
- if( pPager->errMask==PAGER_ERR_FULL ){
- rc = sqlite3pager_rollback(pPager);
- if( rc==SQLITE_OK ){
- rc = SQLITE_FULL;
- }
- return rc;
- }
- if( pPager->errMask!=0 ){
- rc = pager_errcode(pPager);
- return rc;
- }
- if( pPager->state<PAGER_RESERVED ){
- return SQLITE_ERROR;
- }
- TRACE2("COMMIT %d\n", pPager->fd.h);
- if( pPager->memDb ){
- pPg = pager_get_all_dirty_pages(pPager);
- while( pPg ){
- clearHistory(PGHDR_TO_HIST(pPg, pPager));
- pPg->dirty = 0;
- pPg->inJournal = 0;
- pPg->inStmt = 0;
- pPg->pPrevStmt = pPg->pNextStmt = 0;
- pPg = pPg->pDirty;
- }
-#ifndef NDEBUG
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- assert( !pPg->alwaysRollback );
- assert( !pHist->pOrig );
- assert( !pHist->pStmt );
- }
-#endif
- pPager->pStmt = 0;
- pPager->state = PAGER_SHARED;
- return SQLITE_OK;
- }
- if( pPager->dirtyCache==0 ){
- /* Exit early (without doing the time-consuming sqlite3OsSync() calls)
- ** if there have been no changes to the database file. */
- assert( pPager->needSync==0 );
- rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
- return rc;
- }
- assert( pPager->journalOpen );
- rc = sqlite3pager_sync(pPager, 0);
- if( rc!=SQLITE_OK ){
- goto commit_abort;
- }
- rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
- return rc;
-
- /* Jump here if anything goes wrong during the commit process.
- */
-commit_abort:
- sqlite3pager_rollback(pPager);
- return rc;
-}
-
-/*
-** Rollback all changes. The database falls back to PAGER_SHARED mode.
-** All in-memory cache pages revert to their original data contents.
-** The journal is deleted.
-**
-** This routine cannot fail unless some other process is not following
-** the correct locking protocol (SQLITE_PROTOCOL) or unless some other
-** process is writing trash into the journal file (SQLITE_CORRUPT) or
-** unless a prior malloc() failed (SQLITE_NOMEM). Appropriate error
-** codes are returned for all these occasions. Otherwise,
-** SQLITE_OK is returned.
-*/
-int sqlite3pager_rollback(Pager *pPager){
- int rc;
- TRACE2("ROLLBACK %d\n", pPager->fd.h);
- if( pPager->memDb ){
- PgHdr *p;
- for(p=pPager->pAll; p; p=p->pNextAll){
- PgHistory *pHist;
- assert( !p->alwaysRollback );
- if( !p->dirty ){
- assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig );
- assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt );
- continue;
- }
-
- pHist = PGHDR_TO_HIST(p, pPager);
- if( pHist->pOrig ){
- memcpy(PGHDR_TO_DATA(p), pHist->pOrig, pPager->pageSize);
- TRACE3("ROLLBACK-PAGE %d of %d\n", p->pgno, pPager->fd.h);
- }else{
- TRACE3("PAGE %d is clean on %d\n", p->pgno, pPager->fd.h);
- }
- clearHistory(pHist);
- p->dirty = 0;
- p->inJournal = 0;
- p->inStmt = 0;
- p->pPrevStmt = p->pNextStmt = 0;
-
- if( pPager->xReiniter ){
- pPager->xReiniter(PGHDR_TO_DATA(p), pPager->pageSize);
- }
-
- }
- pPager->pStmt = 0;
- pPager->dbSize = pPager->origDbSize;
- memoryTruncate(pPager);
- pPager->stmtInUse = 0;
- pPager->state = PAGER_SHARED;
- return SQLITE_OK;
- }
-
- if( !pPager->dirtyCache || !pPager->journalOpen ){
- rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
- return rc;
- }
-
- if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){
- if( pPager->state>=PAGER_EXCLUSIVE ){
- pager_playback(pPager);
- }
- return pager_errcode(pPager);
- }
- if( pPager->state==PAGER_RESERVED ){
- int rc2, rc3;
- rc = pager_reload_cache(pPager);
- rc2 = pager_truncate(pPager, pPager->origDbSize);
- rc3 = pager_unwritelock(pPager);
- if( rc==SQLITE_OK ){
- rc = rc2;
- if( rc3 ) rc = rc3;
- }
- }else{
- rc = pager_playback(pPager);
- }
- if( rc!=SQLITE_OK ){
- rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */
- pPager->errMask |= PAGER_ERR_CORRUPT;
- }
- pPager->dbSize = -1;
- return rc;
-}
-
-/*
-** Return TRUE if the database file is opened read-only. Return FALSE
-** if the database is (in theory) writable.
-*/
-int sqlite3pager_isreadonly(Pager *pPager){
- return pPager->readOnly;
-}
-
-/*
-** This routine is used for testing and analysis only.
-*/
-int *sqlite3pager_stats(Pager *pPager){
- static int a[9];
- a[0] = pPager->nRef;
- a[1] = pPager->nPage;
- a[2] = pPager->mxPage;
- a[3] = pPager->dbSize;
- a[4] = pPager->state;
- a[5] = pPager->errMask;
- a[6] = pPager->nHit;
- a[7] = pPager->nMiss;
- a[8] = pPager->nOvfl;
- return a;
-}
-
-/*
-** Set the statement rollback point.
-**
-** This routine should be called with the transaction journal already
-** open. A new statement journal is created that can be used to rollback
-** changes of a single SQL command within a larger transaction.
-*/
-int sqlite3pager_stmt_begin(Pager *pPager){
- int rc;
- char zTemp[SQLITE_TEMPNAME_SIZE];
- assert( !pPager->stmtInUse );
- assert( pPager->dbSize>=0 );
- TRACE2("STMT-BEGIN %d\n", pPager->fd.h);
- if( pPager->memDb ){
- pPager->stmtInUse = 1;
- pPager->stmtSize = pPager->dbSize;
- return SQLITE_OK;
- }
- if( !pPager->journalOpen ){
- pPager->stmtAutoopen = 1;
- return SQLITE_OK;
- }
- assert( pPager->journalOpen );
- pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 );
- if( pPager->aInStmt==0 ){
- sqlite3OsLock(&pPager->fd, SHARED_LOCK);
- return SQLITE_NOMEM;
- }
-#ifndef NDEBUG
- rc = sqlite3OsFileSize(&pPager->jfd, &pPager->stmtJSize);
- if( rc ) goto stmt_begin_failed;
- assert( pPager->stmtJSize == pPager->journalOff );
-#endif
- pPager->stmtJSize = pPager->journalOff;
- pPager->stmtSize = pPager->dbSize;
- pPager->stmtHdrOff = 0;
- pPager->stmtCksum = pPager->cksumInit;
- if( !pPager->stmtOpen ){
- rc = sqlite3pager_opentemp(zTemp, &pPager->stfd);
- if( rc ) goto stmt_begin_failed;
- pPager->stmtOpen = 1;
- pPager->stmtNRec = 0;
- }
- pPager->stmtInUse = 1;
- return SQLITE_OK;
-
-stmt_begin_failed:
- if( pPager->aInStmt ){
- sqliteFree(pPager->aInStmt);
- pPager->aInStmt = 0;
- }
- return rc;
-}
-
-/*
-** Commit a statement.
-*/
-int sqlite3pager_stmt_commit(Pager *pPager){
- if( pPager->stmtInUse ){
- PgHdr *pPg, *pNext;
- TRACE2("STMT-COMMIT %d\n", pPager->fd.h);
- if( !pPager->memDb ){
- sqlite3OsSeek(&pPager->stfd, 0);
- /* sqlite3OsTruncate(&pPager->stfd, 0); */
- sqliteFree( pPager->aInStmt );
- pPager->aInStmt = 0;
- }
- for(pPg=pPager->pStmt; pPg; pPg=pNext){
- pNext = pPg->pNextStmt;
- assert( pPg->inStmt );
- pPg->inStmt = 0;
- pPg->pPrevStmt = pPg->pNextStmt = 0;
- if( pPager->memDb ){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- sqliteFree(pHist->pStmt);
- pHist->pStmt = 0;
- }
- }
- pPager->stmtNRec = 0;
- pPager->stmtInUse = 0;
- pPager->pStmt = 0;
- }
- pPager->stmtAutoopen = 0;
- return SQLITE_OK;
-}
-
-/*
-** Rollback a statement.
-*/
-int sqlite3pager_stmt_rollback(Pager *pPager){
- int rc;
- if( pPager->stmtInUse ){
- TRACE2("STMT-ROLLBACK %d\n", pPager->fd.h);
- if( pPager->memDb ){
- PgHdr *pPg;
- for(pPg=pPager->pStmt; pPg; pPg=pPg->pNextStmt){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- if( pHist->pStmt ){
- memcpy(PGHDR_TO_DATA(pPg), pHist->pStmt, pPager->pageSize);
- sqliteFree(pHist->pStmt);
- pHist->pStmt = 0;
- }
- }
- pPager->dbSize = pPager->stmtSize;
- memoryTruncate(pPager);
- rc = SQLITE_OK;
- }else{
- rc = pager_stmt_playback(pPager);
- }
- sqlite3pager_stmt_commit(pPager);
- }else{
- rc = SQLITE_OK;
- }
- pPager->stmtAutoopen = 0;
- return rc;
-}
-
-/*
-** Return the full pathname of the database file.
-*/
-const char *sqlite3pager_filename(Pager *pPager){
- return pPager->zFilename;
-}
-
-/*
-** Return the directory of the database file.
-*/
-const char *sqlite3pager_dirname(Pager *pPager){
- return pPager->zDirectory;
-}
-
-/*
-** Return the full pathname of the journal file.
-*/
-const char *sqlite3pager_journalname(Pager *pPager){
- return pPager->zJournal;
-}
-
-/*
-** Set the codec for this pager
-*/
-void sqlite3pager_set_codec(
- Pager *pPager,
- void (*xCodec)(void*,void*,Pgno,int),
- void *pCodecArg
-){
- pPager->xCodec = xCodec;
- pPager->pCodecArg = pCodecArg;
-}
-
-/*
-** This routine is called to increment the database file change-counter,
-** stored at byte 24 of the pager file.
-*/
-static int pager_incr_changecounter(Pager *pPager){
- void *pPage;
- PgHdr *pPgHdr;
- u32 change_counter;
- int rc;
-
- /* Open page 1 of the file for writing. */
- rc = sqlite3pager_get(pPager, 1, &pPage);
- if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3pager_write(pPage);
- if( rc!=SQLITE_OK ) return rc;
-
- /* Read the current value at byte 24. */
- pPgHdr = DATA_TO_PGHDR(pPage);
- change_counter = retrieve32bits(pPgHdr, 24);
-
- /* Increment the value just read and write it back to byte 24. */
- change_counter++;
- store32bits(change_counter, pPgHdr, 24);
-
- /* Release the page reference. */
- sqlite3pager_unref(pPage);
- return SQLITE_OK;
-}
-
-/*
-** Sync the database file for the pager pPager. zMaster points to the name
-** of a master journal file that should be written into the individual
-** journal file. zMaster may be NULL, which is interpreted as no master
-** journal (a single database transaction).
-**
-** This routine ensures that the journal is synced, all dirty pages written
-** to the database file and the database file synced. The only thing that
-** remains to commit the transaction is to delete the journal file (or
-** master journal file if specified).
-**
-** Note that if zMaster==NULL, this does not overwrite a previous value
-** passed to an sqlite3pager_sync() call.
-*/
-int sqlite3pager_sync(Pager *pPager, const char *zMaster){
- int rc = SQLITE_OK;
-
- /* If this is an in-memory db, or no pages have been written to, or this
- ** function has already been called, it is a no-op.
- */
- if( pPager->state!=PAGER_SYNCED && !pPager->memDb && pPager->dirtyCache ){
- PgHdr *pPg;
- assert( pPager->journalOpen );
-
- /* If a master journal file name has already been written to the
- ** journal file, then no sync is required. This happens when it is
- ** written, then the process fails to upgrade from a RESERVED to an
- ** EXCLUSIVE lock. The next time the process tries to commit the
- ** transaction the m-j name will have already been written.
- */
- if( !pPager->setMaster ){
- rc = pager_incr_changecounter(pPager);
- if( rc!=SQLITE_OK ) goto sync_exit;
- rc = writeMasterJournal(pPager, zMaster);
- if( rc!=SQLITE_OK ) goto sync_exit;
- rc = syncJournal(pPager);
- if( rc!=SQLITE_OK ) goto sync_exit;
- }
-
- /* Write all dirty pages to the database file */
- pPg = pager_get_all_dirty_pages(pPager);
- rc = pager_write_pagelist(pPg);
- if( rc!=SQLITE_OK ) goto sync_exit;
-
- /* Sync the database file. */
- if( !pPager->noSync ){
- rc = sqlite3OsSync(&pPager->fd);
- }
-
- pPager->state = PAGER_SYNCED;
- }
-
-sync_exit:
- return rc;
-}
-
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
-/*
-** Return the current state of the file lock for the given pager.
-** The return value is one of NO_LOCK, SHARED_LOCK, RESERVED_LOCK,
-** PENDING_LOCK, or EXCLUSIVE_LOCK.
-*/
-int sqlite3pager_lockstate(Pager *pPager){
-#ifdef OS_TEST
- return pPager->fd->fd.locktype;
-#else
- return pPager->fd.locktype;
-#endif
-}
-#endif
-
-#ifdef SQLITE_TEST
-/*
-** Print a listing of all referenced pages and their ref count.
-*/
-void sqlite3pager_refdump(Pager *pPager){
- PgHdr *pPg;
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- if( pPg->nRef<=0 ) continue;
- sqlite3DebugPrintf("PAGE %3d addr=%p nRef=%d\n",
- pPg->pgno, PGHDR_TO_DATA(pPg), pPg->nRef);
- }
-}
-#endif
diff --git a/kopete/plugins/statistics/sqlite/pager.h b/kopete/plugins/statistics/sqlite/pager.h
deleted file mode 100644
index 0231e27a..00000000
--- a/kopete/plugins/statistics/sqlite/pager.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This header file defines the interface that the sqlite page cache
-** subsystem. The page cache subsystem reads and writes a file a page
-** at a time and provides a journal for rollback.
-**
-** @(#) $Id$
-*/
-
-/*
-** The default size of a database page.
-*/
-#ifndef SQLITE_DEFAULT_PAGE_SIZE
-# define SQLITE_DEFAULT_PAGE_SIZE 1024
-#endif
-
-/* Maximum page size. The upper bound on this value is 65536 (a limit
-** imposed by the 2-byte size of cell array pointers.) The
-** maximum page size determines the amount of stack space allocated
-** by many of the routines in pager.c and btree.c On embedded architectures
-** or any machine where memory and especially stack memory is limited,
-** one may wish to chose a smaller value for the maximum page size.
-*/
-#ifndef SQLITE_MAX_PAGE_SIZE
-# define SQLITE_MAX_PAGE_SIZE 8192
-#endif
-
-/*
-** Maximum number of pages in one database.
-*/
-#define SQLITE_MAX_PAGE 1073741823
-
-/*
-** The type used to represent a page number. The first page in a file
-** is called page 1. 0 is used to represent "not a page".
-*/
-typedef unsigned int Pgno;
-
-/*
-** Each open file is managed by a separate instance of the "Pager" structure.
-*/
-typedef struct Pager Pager;
-
-
-/*
-** See source code comments for a detailed description of the following
-** routines:
-*/
-int sqlite3pager_open(Pager **ppPager, const char *zFilename,
- int nExtra, int useJournal);
-void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler);
-void sqlite3pager_set_destructor(Pager*, void(*)(void*,int));
-void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int));
-void sqlite3pager_set_pagesize(Pager*, int);
-void sqlite3pager_read_fileheader(Pager*, int, unsigned char*);
-void sqlite3pager_set_cachesize(Pager*, int);
-int sqlite3pager_close(Pager *pPager);
-int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage);
-void *sqlite3pager_lookup(Pager *pPager, Pgno pgno);
-int sqlite3pager_ref(void*);
-int sqlite3pager_unref(void*);
-Pgno sqlite3pager_pagenumber(void*);
-int sqlite3pager_write(void*);
-int sqlite3pager_iswriteable(void*);
-int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void*);
-int sqlite3pager_pagecount(Pager*);
-int sqlite3pager_truncate(Pager*,Pgno);
-int sqlite3pager_begin(void*, int exFlag);
-int sqlite3pager_commit(Pager*);
-int sqlite3pager_sync(Pager*,const char *zMaster);
-int sqlite3pager_rollback(Pager*);
-int sqlite3pager_isreadonly(Pager*);
-int sqlite3pager_stmt_begin(Pager*);
-int sqlite3pager_stmt_commit(Pager*);
-int sqlite3pager_stmt_rollback(Pager*);
-void sqlite3pager_dont_rollback(void*);
-void sqlite3pager_dont_write(Pager*, Pgno);
-int *sqlite3pager_stats(Pager*);
-void sqlite3pager_set_safety_level(Pager*,int);
-const char *sqlite3pager_filename(Pager*);
-const char *sqlite3pager_dirname(Pager*);
-const char *sqlite3pager_journalname(Pager*);
-int sqlite3pager_rename(Pager*, const char *zNewName);
-void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
-
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
-int sqlite3pager_lockstate(Pager*);
-#endif
-
-#ifdef SQLITE_TEST
-void sqlite3pager_refdump(Pager*);
-int pager3_refinfo_enable;
-#endif
diff --git a/kopete/plugins/statistics/sqlite/parse.c b/kopete/plugins/statistics/sqlite/parse.c
deleted file mode 100644
index d3e68e02..00000000
--- a/kopete/plugins/statistics/sqlite/parse.c
+++ /dev/null
@@ -1,3143 +0,0 @@
-/* Driver template for the LEMON parser generator.
-** The author disclaims copyright to this source code.
-*/
-/* First off, code is include which follows the "include" declaration
-** in the input file. */
-#include <stdio.h>
-#line 33 "parse.y"
-
-#include "sqliteInt.h"
-#include "parse.h"
-
-/*
-** An instance of this structure holds information about the
-** LIMIT clause of a SELECT statement.
-*/
-struct LimitVal {
- int limit; /* The LIMIT value. -1 if there is no limit */
- int offset; /* The OFFSET. 0 if there is none */
-};
-
-/*
-** An instance of this structure is used to store the LIKE,
-** GLOB, NOT LIKE, and NOT GLOB operators.
-*/
-struct LikeOp {
- int opcode; /* Either TK_GLOB or TK_LIKE */
- int not; /* True if the NOT keyword is present */
-};
-
-/*
-** An instance of the following structure describes the event of a
-** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT,
-** TK_DELETE, or TK_INSTEAD. If the event is of the form
-**
-** UPDATE ON (a,b,c)
-**
-** Then the "b" IdList records the list "a,b,c".
-*/
-struct TrigEvent { int a; IdList * b; };
-
-/*
-** An instance of this structure holds the ATTACH key and the key type.
-*/
-struct AttachKey { int type; Token key; };
-
-#line 48 "parse.c"
-/* Next is all token values, in a form suitable for use by makeheaders.
-** This section will be null unless lemon is run with the -m switch.
-*/
-/*
-** These constants (all generated automatically by the parser generator)
-** specify the various kinds of tokens (terminals) that the parser
-** understands.
-**
-** Each symbol here is a terminal symbol in the grammar.
-*/
-/* Make sure the INTERFACE macro is defined.
-*/
-#ifndef INTERFACE
-# define INTERFACE 1
-#endif
-/* The next thing included is series of defines which control
-** various aspects of the generated parser.
-** YYCODETYPE is the data type used for storing terminal
-** and nonterminal numbers. "unsigned char" is
-** used if there are fewer than 250 terminals
-** and nonterminals. "int" is used otherwise.
-** YYNOCODE is a number of type YYCODETYPE which corresponds
-** to no legal terminal or nonterminal number. This
-** number is used to fill in empty slots of the hash
-** table.
-** YYFALLBACK If defined, this indicates that one or more tokens
-** have fall-back values which should be used if the
-** original value of the token will not parse.
-** YYACTIONTYPE is the data type used for storing terminal
-** and nonterminal numbers. "unsigned char" is
-** used if there are fewer than 250 rules and
-** states combined. "int" is used otherwise.
-** sqlite3ParserTOKENTYPE is the data type used for minor tokens given
-** directly to the parser from the tokenizer.
-** YYMINORTYPE is the data type used for all minor tokens.
-** This is typically a union of many types, one of
-** which is sqlite3ParserTOKENTYPE. The entry in the union
-** for base tokens is called "yy0".
-** YYSTACKDEPTH is the maximum depth of the parser's stack.
-** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument
-** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument
-** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser
-** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser
-** YYNSTATE the combined number of states.
-** YYNRULE the number of rules in the grammar
-** YYERRORSYMBOL is the code number of the error symbol. If not
-** defined, then do no error processing.
-*/
-#define YYCODETYPE unsigned char
-#define YYNOCODE 225
-#define YYACTIONTYPE unsigned short int
-#define sqlite3ParserTOKENTYPE Token
-typedef union {
- sqlite3ParserTOKENTYPE yy0;
- struct {int value; int mask;} yy47;
- TriggerStep* yy91;
- Token yy98;
- Select* yy107;
- struct TrigEvent yy146;
- ExprList* yy210;
- Expr* yy258;
- SrcList* yy259;
- IdList* yy272;
- int yy284;
- struct AttachKey yy292;
- struct LikeOp yy342;
- struct LimitVal yy404;
- int yy449;
-} YYMINORTYPE;
-#define YYSTACKDEPTH 100
-#define sqlite3ParserARG_SDECL Parse *pParse;
-#define sqlite3ParserARG_PDECL ,Parse *pParse
-#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
-#define sqlite3ParserARG_STORE yypParser->pParse = pParse
-#define YYNSTATE 537
-#define YYNRULE 292
-#define YYERRORSYMBOL 130
-#define YYERRSYMDT yy449
-#define YYFALLBACK 1
-#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
-#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
-#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
-
-/* Next are that tables used to determine what action to take based on the
-** current state and lookahead token. These tables are used to implement
-** functions that take a state number and lookahead value and return an
-** action integer.
-**
-** Suppose the action integer is N. Then the action is determined as
-** follows
-**
-** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
-** token onto the stack and goto state N.
-**
-** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
-**
-** N == YYNSTATE+YYNRULE A syntax error has occurred.
-**
-** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
-**
-** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
-** slots in the yy_action[] table.
-**
-** The action table is constructed as a single large table named yy_action[].
-** Given state S and lookahead X, the action is computed as
-**
-** yy_action[ yy_shift_ofst[S] + X ]
-**
-** If the index value yy_shift_ofst[S]+X is out of range or if the value
-** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
-** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
-** and that yy_default[S] should be used instead.
-**
-** The formula above is for computing the action when the lookahead is
-** a terminal symbol. If the lookahead is a non-terminal (as occurs after
-** a reduce action) then the yy_reduce_ofst[] array is used in place of
-** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
-** YY_SHIFT_USE_DFLT.
-**
-** The following are the tables generated in this section:
-**
-** yy_action[] A single table containing all actions.
-** yy_lookahead[] A table containing the lookahead for each entry in
-** yy_action. Used to detect hash collisions.
-** yy_shift_ofst[] For each state, the offset into yy_action for
-** shifting terminals.
-** yy_reduce_ofst[] For each state, the offset into yy_action for
-** shifting non-terminals after a reduce.
-** yy_default[] Default action for each state.
-*/
-static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 257, 325, 255, 138, 140, 142, 144, 146, 148, 150,
- /* 10 */ 152, 154, 156, 89, 87, 88, 159, 12, 4, 6,
- /* 20 */ 158, 537, 38, 24, 830, 1, 536, 3, 329, 488,
- /* 30 */ 534, 535, 319, 50, 124, 112, 160, 169, 174, 179,
- /* 40 */ 168, 173, 134, 136, 128, 130, 126, 132, 138, 140,
- /* 50 */ 142, 144, 146, 148, 150, 152, 154, 156, 26, 73,
- /* 60 */ 384, 256, 39, 58, 64, 66, 299, 330, 612, 611,
- /* 70 */ 351, 30, 92, 332, 326, 159, 13, 14, 353, 158,
- /* 80 */ 5, 355, 361, 366, 499, 146, 148, 150, 152, 154,
- /* 90 */ 156, 12, 369, 124, 112, 160, 169, 174, 179, 168,
- /* 100 */ 173, 134, 136, 128, 130, 126, 132, 138, 140, 142,
- /* 110 */ 144, 146, 148, 150, 152, 154, 156, 128, 130, 126,
- /* 120 */ 132, 138, 140, 142, 144, 146, 148, 150, 152, 154,
- /* 130 */ 156, 659, 353, 244, 62, 355, 361, 366, 79, 12,
- /* 140 */ 63, 98, 96, 289, 159, 280, 369, 349, 158, 181,
- /* 150 */ 13, 14, 27, 12, 546, 383, 32, 10, 368, 273,
- /* 160 */ 515, 765, 124, 112, 160, 169, 174, 179, 168, 173,
- /* 170 */ 134, 136, 128, 130, 126, 132, 138, 140, 142, 144,
- /* 180 */ 146, 148, 150, 152, 154, 156, 810, 349, 47, 73,
- /* 190 */ 222, 763, 223, 114, 246, 31, 32, 48, 13, 14,
- /* 200 */ 74, 274, 252, 166, 175, 180, 275, 304, 49, 8,
- /* 210 */ 255, 45, 13, 14, 159, 290, 350, 382, 158, 245,
- /* 220 */ 441, 46, 378, 183, 247, 185, 186, 15, 16, 17,
- /* 230 */ 73, 205, 124, 112, 160, 169, 174, 179, 168, 173,
- /* 240 */ 134, 136, 128, 130, 126, 132, 138, 140, 142, 144,
- /* 250 */ 146, 148, 150, 152, 154, 156, 542, 306, 438, 159,
- /* 260 */ 98, 96, 332, 158, 272, 475, 447, 437, 12, 256,
- /* 270 */ 288, 12, 304, 339, 287, 50, 77, 124, 112, 160,
- /* 280 */ 169, 174, 179, 168, 173, 134, 136, 128, 130, 126,
- /* 290 */ 132, 138, 140, 142, 144, 146, 148, 150, 152, 154,
- /* 300 */ 156, 547, 36, 335, 39, 58, 64, 66, 299, 330,
- /* 310 */ 35, 334, 291, 545, 114, 332, 114, 329, 12, 625,
- /* 320 */ 353, 187, 306, 355, 361, 366, 422, 13, 14, 159,
- /* 330 */ 13, 14, 184, 158, 369, 636, 188, 259, 188, 764,
- /* 340 */ 91, 87, 88, 100, 87, 88, 219, 124, 112, 160,
- /* 350 */ 169, 174, 179, 168, 173, 134, 136, 128, 130, 126,
- /* 360 */ 132, 138, 140, 142, 144, 146, 148, 150, 152, 154,
- /* 370 */ 156, 297, 282, 114, 292, 51, 237, 13, 14, 150,
- /* 380 */ 152, 154, 156, 114, 12, 225, 53, 225, 159, 166,
- /* 390 */ 175, 180, 158, 380, 303, 111, 433, 658, 69, 92,
- /* 400 */ 379, 183, 92, 185, 186, 111, 124, 112, 160, 169,
- /* 410 */ 174, 179, 168, 173, 134, 136, 128, 130, 126, 132,
- /* 420 */ 138, 140, 142, 144, 146, 148, 150, 152, 154, 156,
- /* 430 */ 103, 230, 561, 159, 773, 12, 286, 158, 631, 534,
- /* 440 */ 535, 105, 815, 13, 14, 166, 175, 180, 203, 808,
- /* 450 */ 215, 124, 112, 160, 169, 174, 179, 168, 173, 134,
- /* 460 */ 136, 128, 130, 126, 132, 138, 140, 142, 144, 146,
- /* 470 */ 148, 150, 152, 154, 156, 2, 3, 183, 159, 185,
- /* 480 */ 186, 813, 158, 43, 44, 569, 33, 633, 41, 348,
- /* 490 */ 340, 413, 415, 414, 13, 14, 124, 112, 160, 169,
- /* 500 */ 174, 179, 168, 173, 134, 136, 128, 130, 126, 132,
- /* 510 */ 138, 140, 142, 144, 146, 148, 150, 152, 154, 156,
- /* 520 */ 249, 336, 697, 159, 337, 338, 183, 158, 185, 186,
- /* 530 */ 56, 57, 183, 11, 185, 186, 183, 416, 185, 186,
- /* 540 */ 402, 124, 112, 160, 169, 174, 179, 168, 173, 134,
- /* 550 */ 136, 128, 130, 126, 132, 138, 140, 142, 144, 146,
- /* 560 */ 148, 150, 152, 154, 156, 342, 87, 88, 159, 345,
- /* 570 */ 87, 88, 158, 98, 96, 183, 404, 185, 186, 240,
- /* 580 */ 9, 183, 92, 185, 186, 802, 124, 177, 160, 169,
- /* 590 */ 174, 179, 168, 173, 134, 136, 128, 130, 126, 132,
- /* 600 */ 138, 140, 142, 144, 146, 148, 150, 152, 154, 156,
- /* 610 */ 787, 341, 257, 159, 255, 255, 183, 158, 185, 186,
- /* 620 */ 94, 95, 480, 518, 92, 307, 314, 316, 92, 548,
- /* 630 */ 325, 171, 112, 160, 169, 174, 179, 168, 173, 134,
- /* 640 */ 136, 128, 130, 126, 132, 138, 140, 142, 144, 146,
- /* 650 */ 148, 150, 152, 154, 156, 255, 25, 486, 159, 482,
- /* 660 */ 170, 358, 158, 19, 241, 242, 252, 266, 513, 267,
- /* 670 */ 259, 553, 72, 256, 256, 402, 68, 244, 160, 169,
- /* 680 */ 174, 179, 168, 173, 134, 136, 128, 130, 126, 132,
- /* 690 */ 138, 140, 142, 144, 146, 148, 150, 152, 154, 156,
- /* 700 */ 207, 255, 72, 326, 780, 260, 68, 267, 514, 47,
- /* 710 */ 189, 428, 388, 385, 256, 325, 259, 21, 48, 162,
- /* 720 */ 395, 12, 114, 161, 516, 517, 195, 193, 294, 49,
- /* 730 */ 207, 484, 209, 312, 191, 70, 71, 387, 246, 113,
- /* 740 */ 189, 164, 165, 73, 198, 114, 363, 396, 114, 391,
- /* 750 */ 73, 277, 529, 313, 436, 182, 195, 193, 72, 467,
- /* 760 */ 256, 623, 68, 245, 191, 70, 71, 188, 163, 113,
- /* 770 */ 188, 119, 120, 121, 122, 197, 114, 803, 691, 72,
- /* 780 */ 13, 14, 92, 68, 73, 73, 207, 77, 326, 73,
- /* 790 */ 199, 807, 99, 436, 452, 293, 189, 223, 474, 325,
- /* 800 */ 309, 119, 120, 121, 122, 197, 423, 207, 221, 460,
- /* 810 */ 434, 419, 195, 193, 418, 90, 224, 189, 77, 225,
- /* 820 */ 191, 70, 71, 73, 442, 113, 420, 114, 325, 444,
- /* 830 */ 372, 468, 114, 195, 193, 283, 325, 311, 310, 402,
- /* 840 */ 470, 191, 70, 71, 114, 7, 113, 41, 460, 474,
- /* 850 */ 18, 20, 22, 386, 296, 114, 457, 119, 120, 121,
- /* 860 */ 122, 197, 766, 446, 521, 554, 123, 430, 444, 23,
- /* 870 */ 531, 114, 326, 114, 114, 481, 114, 125, 119, 120,
- /* 880 */ 121, 122, 197, 510, 72, 441, 114, 238, 68, 114,
- /* 890 */ 508, 506, 114, 127, 114, 129, 131, 114, 133, 411,
- /* 900 */ 412, 322, 114, 114, 114, 114, 407, 114, 135, 326,
- /* 910 */ 660, 137, 207, 114, 139, 114, 141, 451, 114, 143,
- /* 920 */ 114, 114, 189, 114, 145, 147, 149, 151, 114, 153,
- /* 930 */ 489, 493, 437, 114, 114, 155, 479, 157, 195, 193,
- /* 940 */ 167, 77, 176, 178, 114, 190, 191, 70, 71, 114,
- /* 950 */ 192, 113, 114, 114, 114, 194, 196, 114, 691, 114,
- /* 960 */ 269, 320, 343, 321, 344, 269, 204, 114, 359, 284,
- /* 970 */ 321, 206, 114, 555, 216, 218, 220, 114, 364, 234,
- /* 980 */ 321, 239, 660, 119, 120, 121, 122, 197, 373, 271,
- /* 990 */ 321, 281, 114, 114, 367, 227, 227, 269, 431, 408,
- /* 1000 */ 321, 503, 439, 44, 465, 473, 267, 471, 114, 77,
- /* 1010 */ 402, 402, 402, 402, 455, 459, 265, 457, 402, 402,
- /* 1020 */ 823, 417, 504, 507, 556, 471, 28, 29, 560, 37,
- /* 1030 */ 472, 73, 34, 55, 40, 41, 42, 54, 59, 67,
- /* 1040 */ 570, 571, 52, 75, 60, 78, 483, 485, 487, 491,
- /* 1050 */ 61, 65, 76, 464, 495, 501, 101, 527, 77, 238,
- /* 1060 */ 233, 235, 85, 93, 86, 80, 97, 238, 102, 81,
- /* 1070 */ 104, 82, 108, 107, 109, 110, 83, 115, 497, 84,
- /* 1080 */ 117, 116, 156, 172, 637, 217, 638, 118, 202, 226,
- /* 1090 */ 639, 208, 106, 211, 227, 210, 213, 214, 212, 229,
- /* 1100 */ 228, 231, 236, 223, 200, 243, 201, 251, 248, 250,
- /* 1110 */ 254, 253, 232, 258, 261, 270, 264, 263, 262, 268,
- /* 1120 */ 276, 278, 285, 295, 318, 279, 300, 303, 301, 305,
- /* 1130 */ 333, 346, 298, 323, 327, 356, 357, 362, 370, 302,
- /* 1140 */ 371, 53, 374, 394, 399, 354, 331, 375, 401, 409,
- /* 1150 */ 308, 347, 315, 324, 406, 317, 405, 328, 795, 390,
- /* 1160 */ 389, 392, 397, 410, 421, 800, 360, 381, 365, 393,
- /* 1170 */ 398, 352, 376, 403, 801, 377, 400, 425, 426, 424,
- /* 1180 */ 427, 429, 771, 432, 772, 435, 440, 698, 443, 794,
- /* 1190 */ 445, 438, 809, 449, 699, 450, 453, 448, 454, 456,
- /* 1200 */ 811, 458, 461, 462, 463, 469, 812, 814, 476, 630,
- /* 1210 */ 478, 632, 779, 821, 490, 477, 690, 492, 494, 496,
- /* 1220 */ 498, 693, 500, 505, 696, 509, 781, 511, 782, 783,
- /* 1230 */ 466, 784, 785, 502, 512, 786, 520, 822, 519, 530,
- /* 1240 */ 524, 824, 523, 825, 525, 528, 533, 828, 518, 518,
- /* 1250 */ 518, 518, 518, 518, 522, 518, 526, 518, 518, 532,
-};
-static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 24, 139, 26, 72, 73, 74, 75, 76, 77, 78,
- /* 10 */ 79, 80, 81, 154, 155, 156, 40, 26, 135, 136,
- /* 20 */ 44, 0, 158, 140, 131, 132, 133, 134, 164, 146,
- /* 30 */ 9, 10, 170, 60, 58, 59, 60, 61, 62, 63,
- /* 40 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
- /* 50 */ 74, 75, 76, 77, 78, 79, 80, 81, 22, 176,
- /* 60 */ 24, 85, 89, 90, 91, 92, 93, 94, 23, 23,
- /* 70 */ 25, 25, 213, 100, 212, 40, 85, 86, 87, 44,
- /* 80 */ 9, 90, 91, 92, 201, 76, 77, 78, 79, 80,
- /* 90 */ 81, 26, 101, 58, 59, 60, 61, 62, 63, 64,
- /* 100 */ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
- /* 110 */ 75, 76, 77, 78, 79, 80, 81, 68, 69, 70,
- /* 120 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- /* 130 */ 81, 23, 87, 25, 29, 90, 91, 92, 179, 26,
- /* 140 */ 35, 76, 77, 23, 40, 186, 101, 139, 44, 22,
- /* 150 */ 85, 86, 144, 26, 9, 147, 148, 12, 159, 146,
- /* 160 */ 95, 126, 58, 59, 60, 61, 62, 63, 64, 65,
- /* 170 */ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
- /* 180 */ 76, 77, 78, 79, 80, 81, 17, 139, 18, 176,
- /* 190 */ 23, 17, 25, 139, 86, 147, 148, 27, 85, 86,
- /* 200 */ 146, 188, 189, 204, 205, 206, 193, 45, 38, 137,
- /* 210 */ 26, 41, 85, 86, 40, 161, 168, 169, 44, 111,
- /* 220 */ 51, 51, 60, 103, 111, 105, 106, 13, 14, 15,
- /* 230 */ 176, 127, 58, 59, 60, 61, 62, 63, 64, 65,
- /* 240 */ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
- /* 250 */ 76, 77, 78, 79, 80, 81, 9, 95, 58, 40,
- /* 260 */ 76, 77, 100, 44, 22, 96, 97, 98, 26, 85,
- /* 270 */ 104, 26, 45, 89, 108, 60, 107, 58, 59, 60,
- /* 280 */ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
- /* 290 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- /* 300 */ 81, 9, 87, 88, 89, 90, 91, 92, 93, 94,
- /* 310 */ 157, 158, 23, 9, 139, 100, 139, 164, 26, 119,
- /* 320 */ 87, 23, 95, 90, 91, 92, 21, 85, 86, 40,
- /* 330 */ 85, 86, 104, 44, 101, 107, 161, 152, 161, 17,
- /* 340 */ 154, 155, 156, 154, 155, 156, 127, 58, 59, 60,
- /* 350 */ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
- /* 360 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- /* 370 */ 81, 23, 187, 139, 199, 89, 199, 85, 86, 78,
- /* 380 */ 79, 80, 81, 139, 26, 210, 100, 210, 40, 204,
- /* 390 */ 205, 206, 44, 164, 165, 161, 91, 23, 22, 213,
- /* 400 */ 171, 103, 213, 105, 106, 161, 58, 59, 60, 61,
- /* 410 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
- /* 420 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
- /* 430 */ 196, 197, 9, 40, 129, 26, 78, 44, 9, 9,
- /* 440 */ 10, 197, 9, 85, 86, 204, 205, 206, 126, 11,
- /* 450 */ 128, 58, 59, 60, 61, 62, 63, 64, 65, 66,
- /* 460 */ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
- /* 470 */ 77, 78, 79, 80, 81, 133, 134, 103, 40, 105,
- /* 480 */ 106, 9, 44, 173, 174, 109, 149, 9, 95, 152,
- /* 490 */ 153, 96, 97, 98, 85, 86, 58, 59, 60, 61,
- /* 500 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
- /* 510 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
- /* 520 */ 111, 152, 9, 40, 155, 156, 103, 44, 105, 106,
- /* 530 */ 13, 14, 103, 139, 105, 106, 103, 47, 105, 106,
- /* 540 */ 139, 58, 59, 60, 61, 62, 63, 64, 65, 66,
- /* 550 */ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
- /* 560 */ 77, 78, 79, 80, 81, 154, 155, 156, 40, 154,
- /* 570 */ 155, 156, 44, 76, 77, 103, 175, 105, 106, 25,
- /* 580 */ 138, 103, 213, 105, 106, 95, 58, 59, 60, 61,
- /* 590 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
- /* 600 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
- /* 610 */ 9, 22, 24, 40, 26, 26, 103, 44, 105, 106,
- /* 620 */ 121, 122, 20, 22, 213, 96, 97, 98, 213, 9,
- /* 630 */ 139, 60, 59, 60, 61, 62, 63, 64, 65, 66,
- /* 640 */ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
- /* 650 */ 77, 78, 79, 80, 81, 26, 141, 55, 40, 57,
- /* 660 */ 89, 170, 44, 138, 110, 188, 189, 23, 67, 25,
- /* 670 */ 152, 9, 22, 85, 85, 139, 26, 25, 60, 61,
- /* 680 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
- /* 690 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
- /* 700 */ 50, 26, 22, 212, 9, 187, 26, 25, 139, 18,
- /* 710 */ 60, 175, 20, 146, 85, 139, 152, 138, 27, 40,
- /* 720 */ 146, 26, 139, 44, 155, 156, 76, 77, 78, 38,
- /* 730 */ 50, 129, 41, 32, 84, 85, 86, 142, 86, 89,
- /* 740 */ 60, 62, 63, 176, 161, 139, 170, 55, 139, 57,
- /* 750 */ 176, 187, 123, 52, 146, 146, 76, 77, 22, 146,
- /* 760 */ 85, 9, 26, 111, 84, 85, 86, 161, 89, 89,
- /* 770 */ 161, 121, 122, 123, 124, 125, 139, 95, 9, 22,
- /* 780 */ 85, 86, 213, 26, 176, 176, 50, 107, 212, 176,
- /* 790 */ 207, 11, 25, 146, 25, 23, 60, 25, 161, 139,
- /* 800 */ 99, 121, 122, 123, 124, 125, 211, 50, 199, 201,
- /* 810 */ 215, 28, 76, 77, 31, 48, 210, 60, 107, 210,
- /* 820 */ 84, 85, 86, 176, 216, 89, 43, 139, 139, 221,
- /* 830 */ 170, 120, 139, 76, 77, 78, 139, 88, 89, 139,
- /* 840 */ 203, 84, 85, 86, 139, 11, 89, 95, 201, 161,
- /* 850 */ 16, 17, 18, 19, 161, 139, 139, 121, 122, 123,
- /* 860 */ 124, 125, 126, 216, 30, 9, 161, 170, 221, 138,
- /* 870 */ 36, 139, 212, 139, 139, 175, 139, 161, 121, 122,
- /* 880 */ 123, 124, 125, 49, 22, 51, 139, 118, 26, 139,
- /* 890 */ 56, 203, 139, 161, 139, 161, 161, 139, 161, 53,
- /* 900 */ 54, 212, 139, 139, 139, 139, 126, 139, 161, 212,
- /* 910 */ 24, 161, 50, 139, 161, 139, 161, 200, 139, 161,
- /* 920 */ 139, 139, 60, 139, 161, 161, 161, 161, 139, 161,
- /* 930 */ 96, 97, 98, 139, 139, 161, 102, 161, 76, 77,
- /* 940 */ 161, 107, 161, 161, 139, 161, 84, 85, 86, 139,
- /* 950 */ 161, 89, 139, 139, 139, 161, 161, 139, 9, 139,
- /* 960 */ 139, 23, 23, 25, 25, 139, 161, 139, 23, 139,
- /* 970 */ 25, 161, 139, 9, 161, 161, 161, 139, 23, 161,
- /* 980 */ 25, 161, 95, 121, 122, 123, 124, 125, 23, 161,
- /* 990 */ 25, 161, 139, 139, 161, 109, 109, 139, 23, 161,
- /* 1000 */ 25, 146, 173, 174, 23, 23, 25, 25, 139, 107,
- /* 1010 */ 139, 139, 139, 139, 161, 161, 195, 139, 139, 139,
- /* 1020 */ 9, 195, 120, 23, 9, 25, 145, 23, 9, 139,
- /* 1030 */ 161, 176, 150, 42, 159, 95, 33, 167, 46, 22,
- /* 1040 */ 109, 109, 159, 177, 160, 178, 175, 175, 175, 175,
- /* 1050 */ 159, 159, 176, 195, 175, 175, 113, 46, 107, 118,
- /* 1060 */ 116, 115, 185, 214, 117, 180, 214, 118, 114, 181,
- /* 1070 */ 25, 182, 94, 160, 26, 151, 183, 109, 200, 184,
- /* 1080 */ 109, 139, 81, 89, 107, 126, 107, 139, 17, 139,
- /* 1090 */ 107, 22, 198, 174, 109, 23, 139, 23, 25, 143,
- /* 1100 */ 139, 198, 114, 25, 208, 190, 209, 111, 139, 139,
- /* 1110 */ 143, 139, 160, 139, 191, 95, 22, 112, 192, 139,
- /* 1120 */ 23, 191, 109, 23, 22, 192, 139, 165, 162, 139,
- /* 1130 */ 167, 23, 159, 198, 198, 46, 22, 22, 46, 163,
- /* 1140 */ 22, 100, 93, 24, 217, 139, 151, 139, 95, 39,
- /* 1150 */ 166, 152, 166, 160, 220, 166, 219, 160, 11, 143,
- /* 1160 */ 139, 139, 139, 37, 47, 95, 159, 169, 159, 143,
- /* 1170 */ 143, 169, 162, 143, 95, 163, 218, 139, 143, 129,
- /* 1180 */ 95, 22, 9, 159, 129, 11, 172, 119, 17, 9,
- /* 1190 */ 9, 58, 17, 139, 119, 99, 139, 172, 67, 181,
- /* 1200 */ 9, 67, 119, 139, 22, 22, 9, 9, 110, 9,
- /* 1210 */ 181, 9, 9, 9, 110, 139, 9, 181, 172, 99,
- /* 1220 */ 181, 9, 119, 22, 9, 139, 9, 139, 9, 9,
- /* 1230 */ 202, 9, 9, 202, 143, 9, 23, 9, 139, 34,
- /* 1240 */ 24, 9, 152, 9, 139, 152, 139, 9, 224, 224,
- /* 1250 */ 224, 224, 224, 224, 222, 224, 223, 224, 224, 222,
-};
-#define YY_SHIFT_USE_DFLT (-70)
-static const short yy_shift_ofst[] = {
- /* 0 */ 430, 21, -70, 834, 71, -70, 247, 214, 145, 304,
- /* 10 */ 292, 620, -70, -70, -70, -70, -70, -70, 145, 662,
- /* 20 */ 145, 856, 145, 964, 36, 1015, 245, 46, 1004, 1019,
- /* 30 */ -9, -70, 675, -70, 215, -70, 245, -27, -70, 940,
- /* 40 */ -70, 1003, 170, -70, -70, -70, -70, -70, -70, -70,
- /* 50 */ 286, 940, -70, 991, -70, 517, -70, -70, 992, 105,
- /* 60 */ 940, -70, -70, -70, 940, -70, 1017, 862, 376, 650,
- /* 70 */ 931, 932, 680, -70, 120, 951, -70, 166, -70, 554,
- /* 80 */ 941, 946, 944, 943, 947, -70, 497, -70, -70, 767,
- /* 90 */ 497, -70, 499, -70, -70, -70, 499, -70, -70, 497,
- /* 100 */ -70, 954, 862, 1045, 862, 978, 105, -70, 1048, -70,
- /* 110 */ -70, 483, 862, -70, 968, 245, 971, 245, -70, -70,
- /* 120 */ -70, -70, -70, 618, 862, 573, 862, -69, 862, -69,
- /* 130 */ 862, -69, 862, -69, 862, 49, 862, 49, 862, 9,
- /* 140 */ 862, 9, 862, 9, 862, 9, 862, 301, 862, 301,
- /* 150 */ 862, 1001, 862, 1001, 862, 1001, 862, -70, -70, -70,
- /* 160 */ 679, -70, -70, -70, -70, -70, 862, 49, -70, 571,
- /* 170 */ -70, 994, -70, -70, -70, 862, 528, 862, 49, -70,
- /* 180 */ 127, 680, 298, 228, 977, 979, 983, -70, 483, 862,
- /* 190 */ 618, 862, -70, 862, -70, 862, -70, 736, 35, 959,
- /* 200 */ 322, 1071, -70, 862, 104, 862, 483, 1069, 691, 1072,
- /* 210 */ -70, 1073, 245, 1074, -70, 862, 174, 862, 219, 862,
- /* 220 */ 483, 167, -70, 862, -70, -70, 985, 245, -70, -70,
- /* 230 */ 978, 105, -70, 862, 483, 988, 862, 1078, 862, 483,
- /* 240 */ -70, -70, 652, -70, -70, -70, 113, -70, 409, -70,
- /* 250 */ 996, -70, 242, 985, 588, -70, -70, 245, -70, -70,
- /* 260 */ 1020, 1005, -70, 1094, 245, 644, -70, 245, -70, -70,
- /* 270 */ 862, 483, 951, 374, 108, 1097, 588, 1020, 1005, -70,
- /* 280 */ 757, -24, -70, -70, 1013, 358, -70, -70, -70, -70,
- /* 290 */ 289, -70, 772, -70, 1100, -70, 348, 940, -70, 245,
- /* 300 */ 1102, -70, 227, -70, 245, -70, 529, 701, -70, 749,
- /* 310 */ -70, -70, -70, -70, 701, -70, 701, -70, 245, 938,
- /* 320 */ -70, 245, 978, 105, -70, -70, 978, 105, -70, -70,
- /* 330 */ 1048, -70, 991, -70, -70, 184, -70, -70, -70, -70,
- /* 340 */ 589, 497, 939, -70, 497, 1108, -70, -70, -70, -70,
- /* 350 */ 45, 233, -70, 245, -70, 1089, 1114, 245, 945, 940,
- /* 360 */ -70, 1115, 245, 955, 940, -70, 862, 393, -70, 1092,
- /* 370 */ 1118, 245, 965, 1049, 245, 1102, -70, 162, 1041, -70,
- /* 380 */ -70, -70, -70, -70, 951, 423, 305, 692, 245, 985,
- /* 390 */ -70, 245, 886, 1119, 951, 429, 245, 985, 783, 395,
- /* 400 */ 1053, 245, 985, -70, 1110, 780, 1147, 862, 438, 1126,
- /* 410 */ 846, -70, -70, 1070, 1079, 490, 245, 682, -70, -70,
- /* 420 */ 1117, -70, -70, 1050, 245, 887, 1085, 245, 1159, 245,
- /* 430 */ 975, 752, 1173, 1055, 1174, 169, 433, 200, 170, -70,
- /* 440 */ 1068, 1075, 1171, 1180, 1181, 169, 1175, 1133, 245, 1096,
- /* 450 */ 245, 769, 245, 1131, 862, 483, 1191, 1134, 862, 483,
- /* 460 */ 1083, 245, 1182, 245, 981, -70, 711, 472, 1183, 862,
- /* 470 */ 982, 862, 483, 1197, 483, 1098, 245, 949, 1198, 602,
- /* 480 */ 245, 1200, 245, 1202, 245, 1203, 245, 1204, 478, 1104,
- /* 490 */ 245, 949, 1207, 1133, 245, 1120, 245, 769, 1212, 1103,
- /* 500 */ 245, 1182, 902, 513, 1201, 862, 1000, 1215, 695, 1217,
- /* 510 */ 245, 985, 601, 65, 1219, 1220, 1222, 1223, 245, 1213,
- /* 520 */ 1226, 1205, 675, 1216, 245, 1011, 1228, 629, 1232, 1234,
- /* 530 */ -70, 1205, 245, 1238, -70, -70, -70,
-};
-#define YY_REDUCE_USE_DFLT (-142)
-static const short yy_reduce_ofst[] = {
- /* 0 */ -107, 342, -142, -117, -142, -142, -142, 72, 442, -142,
- /* 10 */ 394, -142, -142, -142, -142, -142, -142, -142, 525, -142,
- /* 20 */ 579, -142, 731, -142, 515, -142, 8, 881, -142, -142,
- /* 30 */ 48, -142, 337, 882, 153, -142, 890, -136, -142, 875,
- /* 40 */ -142, -142, 310, -142, -142, -142, -142, -142, -142, -142,
- /* 50 */ -142, 883, -142, 870, -142, -142, -142, -142, -142, 884,
- /* 60 */ 891, -142, -142, -142, 892, -142, -142, 693, -142, 175,
- /* 70 */ -142, -142, 54, -142, 866, 876, -142, 867, -41, 885,
- /* 80 */ 888, 889, 893, 895, 877, -142, -141, -142, -142, -142,
- /* 90 */ 186, -142, 849, -142, -142, -142, 852, -142, -142, 189,
- /* 100 */ -142, -142, 234, -142, 244, 894, 913, -142, 924, -142,
- /* 110 */ -142, 241, 705, -142, -142, 942, -142, 948, -142, -142,
- /* 120 */ -142, -142, -142, 241, 716, 241, 732, 241, 734, 241,
- /* 130 */ 735, 241, 737, 241, 747, 241, 750, 241, 753, 241,
- /* 140 */ 755, 241, 758, 241, 763, 241, 764, 241, 765, 241,
- /* 150 */ 766, 241, 768, 241, 774, 241, 776, 241, -142, -142,
- /* 160 */ -142, -142, -142, -142, -142, -142, 779, 241, -142, -142,
- /* 170 */ -142, -142, -142, -142, -142, 781, 241, 782, 241, -142,
- /* 180 */ 950, 609, 866, -142, -142, -142, -142, -142, 241, 784,
- /* 190 */ 241, 789, 241, 794, 241, 795, 241, 583, 241, 896,
- /* 200 */ 897, -142, -142, 805, 241, 810, 241, -142, 919, -142,
- /* 210 */ -142, -142, 957, -142, -142, 813, 241, 814, 241, 815,
- /* 220 */ 241, -142, -142, 606, -142, -142, 956, 961, -142, -142,
- /* 230 */ 903, 952, -142, 818, 241, -142, 177, -142, 820, 241,
- /* 240 */ -142, 477, 915, -142, -142, -142, 969, -142, 970, -142,
- /* 250 */ -142, -142, 972, 967, 518, -142, -142, 974, -142, -142,
- /* 260 */ 923, 926, -142, -142, 821, -142, -142, 980, -142, -142,
- /* 270 */ 828, 241, 13, 866, 915, -142, 564, 930, 933, -142,
- /* 280 */ 830, 185, -142, -142, -142, 942, -142, -142, -142, -142,
- /* 290 */ 241, -142, -142, -142, -142, -142, 241, 973, -142, 987,
- /* 300 */ 966, 976, 962, -142, 990, -142, -142, 984, -142, -142,
- /* 310 */ -142, -142, -142, -142, 986, -142, 989, -142, -138, -142,
- /* 320 */ -142, 689, 935, 993, -142, -142, 936, 997, -142, -142,
- /* 330 */ 995, -142, 963, -142, -142, 369, -142, -142, -142, -142,
- /* 340 */ 999, 411, -142, -142, 415, -142, -142, -142, -142, -142,
- /* 350 */ 998, 1002, -142, 1006, -142, -142, -142, 491, -142, 1007,
- /* 360 */ -142, -142, 576, -142, 1009, -142, 833, -1, -142, -142,
- /* 370 */ -142, 660, -142, -142, 1008, 1010, 1012, 229, -142, -142,
- /* 380 */ -142, -142, -142, -142, 567, 866, 595, -142, 1021, 1016,
- /* 390 */ -142, 1022, 1026, -142, 574, 866, 1023, 1027, 927, 958,
- /* 400 */ -142, 401, 1030, -142, 937, 934, -142, 838, 241, -142,
- /* 410 */ -142, -142, -142, -142, -142, -142, 826, -142, -142, -142,
- /* 420 */ -142, -142, -142, -142, 1038, 1035, -142, 536, -142, 697,
- /* 430 */ -142, 1024, -142, -142, -142, 608, 866, 1014, 829, -142,
- /* 440 */ -142, -142, -142, -142, -142, 647, -142, 1025, 1054, -142,
- /* 450 */ 717, 1018, 1057, -142, 853, 241, -142, -142, 854, 241,
- /* 460 */ -142, 1064, 1028, 858, -142, -142, 613, 866, -142, 637,
- /* 470 */ -142, 869, 241, -142, 241, -142, 1076, 1029, -142, -142,
- /* 480 */ 700, -142, 871, -142, 872, -142, 873, -142, 866, -142,
- /* 490 */ 874, 1036, -142, 1046, 879, -142, 878, 1039, -142, -142,
- /* 500 */ 880, 1031, 855, 866, -142, 688, -142, -142, 1086, -142,
- /* 510 */ 1088, 1091, -142, 569, -142, -142, -142, -142, 1099, -142,
- /* 520 */ -142, 1032, 1090, -142, 1105, 1033, -142, 1093, -142, -142,
- /* 530 */ -142, 1037, 1107, -142, -142, -142, -142,
-};
-static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 544, 544, 538, 829, 829, 540, 829, 549, 829, 829,
- /* 10 */ 829, 829, 569, 570, 571, 550, 551, 552, 829, 829,
- /* 20 */ 829, 829, 829, 829, 829, 829, 829, 829, 829, 829,
- /* 30 */ 829, 562, 572, 581, 564, 580, 829, 829, 582, 623,
- /* 40 */ 588, 829, 829, 624, 627, 628, 629, 818, 819, 820,
- /* 50 */ 829, 623, 589, 608, 606, 829, 609, 610, 829, 679,
- /* 60 */ 623, 590, 677, 678, 623, 591, 829, 829, 708, 770,
- /* 70 */ 714, 709, 829, 634, 829, 829, 635, 643, 645, 652,
- /* 80 */ 691, 682, 684, 672, 686, 640, 793, 578, 579, 687,
- /* 90 */ 793, 688, 829, 788, 790, 791, 829, 789, 792, 793,
- /* 100 */ 689, 829, 829, 673, 829, 680, 679, 674, 829, 566,
- /* 110 */ 681, 676, 829, 707, 829, 829, 710, 829, 711, 712,
- /* 120 */ 713, 715, 716, 719, 829, 720, 829, 721, 829, 722,
- /* 130 */ 829, 723, 829, 724, 829, 725, 829, 726, 829, 727,
- /* 140 */ 829, 728, 829, 729, 829, 730, 829, 731, 829, 732,
- /* 150 */ 829, 733, 829, 734, 829, 735, 829, 736, 737, 738,
- /* 160 */ 829, 739, 740, 745, 753, 756, 829, 741, 742, 829,
- /* 170 */ 743, 829, 746, 744, 752, 829, 829, 829, 754, 755,
- /* 180 */ 829, 770, 829, 829, 829, 829, 829, 758, 769, 829,
- /* 190 */ 747, 829, 748, 829, 749, 829, 750, 829, 829, 829,
- /* 200 */ 829, 829, 760, 829, 829, 829, 761, 829, 829, 829,
- /* 210 */ 816, 829, 829, 829, 817, 829, 829, 829, 829, 829,
- /* 220 */ 762, 829, 757, 770, 767, 768, 660, 829, 661, 759,
- /* 230 */ 680, 679, 675, 829, 685, 829, 770, 683, 829, 692,
- /* 240 */ 644, 655, 653, 654, 663, 664, 829, 665, 829, 666,
- /* 250 */ 829, 667, 829, 660, 651, 567, 568, 829, 649, 650,
- /* 260 */ 669, 671, 656, 829, 829, 829, 670, 829, 704, 705,
- /* 270 */ 829, 668, 655, 829, 829, 829, 651, 669, 671, 657,
- /* 280 */ 829, 651, 646, 647, 829, 829, 648, 641, 642, 751,
- /* 290 */ 829, 706, 829, 717, 829, 718, 829, 623, 592, 829,
- /* 300 */ 774, 596, 593, 597, 829, 598, 829, 829, 599, 829,
- /* 310 */ 602, 603, 604, 605, 829, 600, 829, 601, 829, 829,
- /* 320 */ 775, 829, 680, 679, 776, 778, 680, 679, 777, 594,
- /* 330 */ 829, 595, 608, 607, 583, 793, 584, 585, 586, 587,
- /* 340 */ 573, 793, 829, 574, 793, 829, 575, 577, 576, 565,
- /* 350 */ 829, 829, 613, 829, 616, 829, 829, 829, 829, 623,
- /* 360 */ 617, 829, 829, 829, 623, 618, 829, 623, 619, 829,
- /* 370 */ 829, 829, 829, 829, 829, 774, 596, 621, 829, 620,
- /* 380 */ 622, 614, 615, 563, 829, 829, 559, 829, 829, 660,
- /* 390 */ 557, 829, 829, 829, 829, 829, 829, 660, 799, 829,
- /* 400 */ 829, 829, 660, 662, 804, 829, 829, 829, 829, 829,
- /* 410 */ 829, 805, 806, 829, 829, 829, 829, 829, 796, 797,
- /* 420 */ 829, 798, 558, 829, 829, 829, 829, 829, 829, 829,
- /* 430 */ 829, 829, 829, 829, 829, 829, 829, 829, 829, 626,
- /* 440 */ 829, 829, 829, 829, 829, 829, 829, 625, 829, 829,
- /* 450 */ 829, 829, 829, 829, 829, 694, 829, 829, 829, 695,
- /* 460 */ 829, 829, 702, 829, 829, 703, 829, 829, 829, 829,
- /* 470 */ 829, 829, 700, 829, 701, 829, 829, 829, 829, 829,
- /* 480 */ 829, 829, 829, 829, 829, 829, 829, 829, 829, 829,
- /* 490 */ 829, 829, 829, 625, 829, 829, 829, 829, 829, 829,
- /* 500 */ 829, 702, 829, 829, 829, 829, 829, 829, 829, 829,
- /* 510 */ 829, 660, 829, 793, 829, 829, 829, 829, 829, 829,
- /* 520 */ 829, 827, 829, 829, 829, 829, 829, 829, 829, 829,
- /* 530 */ 826, 827, 829, 829, 541, 543, 539,
-};
-#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
-
-/* The next table maps tokens into fallback tokens. If a construct
-** like the following:
-**
-** %fallback ID X Y Z.
-**
-** appears in the grammer, then ID becomes a fallback token for X, Y,
-** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
-** but it does not parse, the type of the token is changed to ID and
-** the parse is retried before an error is thrown.
-*/
-#ifdef YYFALLBACK
-static const YYCODETYPE yyFallback[] = {
- 0, /* $ => nothing */
- 0, /* END_OF_FILE => nothing */
- 0, /* ILLEGAL => nothing */
- 0, /* SPACE => nothing */
- 0, /* UNCLOSED_STRING => nothing */
- 0, /* COMMENT => nothing */
- 0, /* FUNCTION => nothing */
- 0, /* COLUMN => nothing */
- 0, /* AGG_FUNCTION => nothing */
- 0, /* SEMI => nothing */
- 26, /* EXPLAIN => ID */
- 26, /* BEGIN => ID */
- 0, /* TRANSACTION => nothing */
- 26, /* DEFERRED => ID */
- 26, /* IMMEDIATE => ID */
- 26, /* EXCLUSIVE => ID */
- 0, /* COMMIT => nothing */
- 26, /* END => ID */
- 0, /* ROLLBACK => nothing */
- 0, /* CREATE => nothing */
- 0, /* TABLE => nothing */
- 26, /* TEMP => ID */
- 0, /* LP => nothing */
- 0, /* RP => nothing */
- 0, /* AS => nothing */
- 0, /* COMMA => nothing */
- 0, /* ID => nothing */
- 26, /* ABORT => ID */
- 26, /* AFTER => ID */
- 26, /* ASC => ID */
- 26, /* ATTACH => ID */
- 26, /* BEFORE => ID */
- 26, /* CASCADE => ID */
- 26, /* CONFLICT => ID */
- 26, /* DATABASE => ID */
- 26, /* DESC => ID */
- 26, /* DETACH => ID */
- 26, /* EACH => ID */
- 26, /* FAIL => ID */
- 26, /* FOR => ID */
- 26, /* GLOB => ID */
- 26, /* IGNORE => ID */
- 26, /* INITIALLY => ID */
- 26, /* INSTEAD => ID */
- 26, /* LIKE => ID */
- 26, /* MATCH => ID */
- 26, /* KEY => ID */
- 26, /* OF => ID */
- 26, /* OFFSET => ID */
- 26, /* PRAGMA => ID */
- 26, /* RAISE => ID */
- 26, /* REPLACE => ID */
- 26, /* RESTRICT => ID */
- 26, /* ROW => ID */
- 26, /* STATEMENT => ID */
- 26, /* TRIGGER => ID */
- 26, /* VACUUM => ID */
- 26, /* VIEW => ID */
- 0, /* OR => nothing */
- 0, /* AND => nothing */
- 0, /* NOT => nothing */
- 0, /* IS => nothing */
- 0, /* BETWEEN => nothing */
- 0, /* IN => nothing */
- 0, /* ISNULL => nothing */
- 0, /* NOTNULL => nothing */
- 0, /* NE => nothing */
- 0, /* EQ => nothing */
- 0, /* GT => nothing */
- 0, /* LE => nothing */
- 0, /* LT => nothing */
- 0, /* GE => nothing */
- 0, /* BITAND => nothing */
- 0, /* BITOR => nothing */
- 0, /* LSHIFT => nothing */
- 0, /* RSHIFT => nothing */
- 0, /* PLUS => nothing */
- 0, /* MINUS => nothing */
- 0, /* STAR => nothing */
- 0, /* SLASH => nothing */
- 0, /* REM => nothing */
- 0, /* CONCAT => nothing */
- 0, /* UMINUS => nothing */
- 0, /* UPLUS => nothing */
- 0, /* BITNOT => nothing */
- 0, /* STRING => nothing */
- 0, /* JOIN_KW => nothing */
- 0, /* CONSTRAINT => nothing */
- 0, /* DEFAULT => nothing */
- 0, /* NULL => nothing */
- 0, /* PRIMARY => nothing */
- 0, /* UNIQUE => nothing */
- 0, /* CHECK => nothing */
- 0, /* REFERENCES => nothing */
- 0, /* COLLATE => nothing */
- 0, /* ON => nothing */
- 0, /* DELETE => nothing */
- 0, /* UPDATE => nothing */
- 0, /* INSERT => nothing */
- 0, /* SET => nothing */
- 0, /* DEFERRABLE => nothing */
- 0, /* FOREIGN => nothing */
- 0, /* DROP => nothing */
- 0, /* UNION => nothing */
- 0, /* ALL => nothing */
- 0, /* INTERSECT => nothing */
- 0, /* EXCEPT => nothing */
- 0, /* SELECT => nothing */
- 0, /* DISTINCT => nothing */
- 0, /* DOT => nothing */
- 0, /* FROM => nothing */
- 0, /* JOIN => nothing */
- 0, /* USING => nothing */
- 0, /* ORDER => nothing */
- 0, /* BY => nothing */
- 0, /* GROUP => nothing */
- 0, /* HAVING => nothing */
- 0, /* LIMIT => nothing */
- 0, /* WHERE => nothing */
- 0, /* INTO => nothing */
- 0, /* VALUES => nothing */
- 0, /* INTEGER => nothing */
- 0, /* FLOAT => nothing */
- 0, /* BLOB => nothing */
- 0, /* VARIABLE => nothing */
- 0, /* CASE => nothing */
- 0, /* WHEN => nothing */
- 0, /* THEN => nothing */
- 0, /* ELSE => nothing */
- 0, /* INDEX => nothing */
-};
-#endif /* YYFALLBACK */
-
-/* The following structure represents a single element of the
-** parser's stack. Information stored includes:
-**
-** + The state number for the parser at this level of the stack.
-**
-** + The value of the token stored at this level of the stack.
-** (In other words, the "major" token.)
-**
-** + The semantic value stored at this level of the stack. This is
-** the information used by the action routines in the grammar.
-** It is sometimes called the "minor" token.
-*/
-struct yyStackEntry {
- int stateno; /* The state-number */
- int major; /* The major token value. This is the code
- ** number for the token at this stack level */
- YYMINORTYPE minor; /* The user-supplied minor token value. This
- ** is the value of the token */
-};
-typedef struct yyStackEntry yyStackEntry;
-
-/* The state of the parser is completely contained in an instance of
-** the following structure */
-struct yyParser {
- int yyidx; /* Index of top element in stack */
- int yyerrcnt; /* Shifts left before out of the error */
- sqlite3ParserARG_SDECL /* A place to hold %extra_argument */
- yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
-};
-typedef struct yyParser yyParser;
-
-#ifndef NDEBUG
-#include <stdio.h>
-static FILE *yyTraceFILE = 0;
-static char *yyTracePrompt = 0;
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/*
-** Turn parser tracing on by giving a stream to which to write the trace
-** and a prompt to preface each trace message. Tracing is turned off
-** by making either argument NULL
-**
-** Inputs:
-** <ul>
-** <li> A FILE* to which trace output should be written.
-** If NULL, then tracing is turned off.
-** <li> A prefix string written at the beginning of every
-** line of trace output. If NULL, then tracing is
-** turned off.
-** </ul>
-**
-** Outputs:
-** None.
-*/
-void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){
- yyTraceFILE = TraceFILE;
- yyTracePrompt = zTracePrompt;
- if( yyTraceFILE==0 ) yyTracePrompt = 0;
- else if( yyTracePrompt==0 ) yyTraceFILE = 0;
-}
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/* For tracing shifts, the names of all terminals and nonterminals
-** are required. The following table supplies these names */
-static const char *const yyTokenName[] = {
- "$", "END_OF_FILE", "ILLEGAL", "SPACE",
- "UNCLOSED_STRING", "COMMENT", "FUNCTION", "COLUMN",
- "AGG_FUNCTION", "SEMI", "EXPLAIN", "BEGIN",
- "TRANSACTION", "DEFERRED", "IMMEDIATE", "EXCLUSIVE",
- "COMMIT", "END", "ROLLBACK", "CREATE",
- "TABLE", "TEMP", "LP", "RP",
- "AS", "COMMA", "ID", "ABORT",
- "AFTER", "ASC", "ATTACH", "BEFORE",
- "CASCADE", "CONFLICT", "DATABASE", "DESC",
- "DETACH", "EACH", "FAIL", "FOR",
- "GLOB", "IGNORE", "INITIALLY", "INSTEAD",
- "LIKE", "MATCH", "KEY", "OF",
- "OFFSET", "PRAGMA", "RAISE", "REPLACE",
- "RESTRICT", "ROW", "STATEMENT", "TRIGGER",
- "VACUUM", "VIEW", "OR", "AND",
- "NOT", "IS", "BETWEEN", "IN",
- "ISNULL", "NOTNULL", "NE", "EQ",
- "GT", "LE", "LT", "GE",
- "BITAND", "BITOR", "LSHIFT", "RSHIFT",
- "PLUS", "MINUS", "STAR", "SLASH",
- "REM", "CONCAT", "UMINUS", "UPLUS",
- "BITNOT", "STRING", "JOIN_KW", "CONSTRAINT",
- "DEFAULT", "NULL", "PRIMARY", "UNIQUE",
- "CHECK", "REFERENCES", "COLLATE", "ON",
- "DELETE", "UPDATE", "INSERT", "SET",
- "DEFERRABLE", "FOREIGN", "DROP", "UNION",
- "ALL", "INTERSECT", "EXCEPT", "SELECT",
- "DISTINCT", "DOT", "FROM", "JOIN",
- "USING", "ORDER", "BY", "GROUP",
- "HAVING", "LIMIT", "WHERE", "INTO",
- "VALUES", "INTEGER", "FLOAT", "BLOB",
- "VARIABLE", "CASE", "WHEN", "THEN",
- "ELSE", "INDEX", "error", "input",
- "cmdlist", "ecmd", "explain", "cmdx",
- "cmd", "transtype", "trans_opt", "nm",
- "create_table", "create_table_args", "temp", "dbnm",
- "columnlist", "conslist_opt", "select", "column",
- "columnid", "type", "carglist", "id",
- "ids", "typename", "signed", "plus_num",
- "minus_num", "carg", "ccons", "onconf",
- "sortorder", "expr", "idxlist_opt", "refargs",
- "defer_subclause", "refarg", "refact", "init_deferred_pred_opt",
- "conslist", "tcons", "idxlist", "defer_subclause_opt",
- "orconf", "resolvetype", "raisetype", "fullname",
- "oneselect", "multiselect_op", "distinct", "selcollist",
- "from", "where_opt", "groupby_opt", "having_opt",
- "orderby_opt", "limit_opt", "sclp", "as",
- "seltablist", "stl_prefix", "joinop", "on_opt",
- "using_opt", "seltablist_paren", "joinop2", "inscollist",
- "sortlist", "sortitem", "collate", "exprlist",
- "setlist", "insert_cmd", "inscollist_opt", "itemlist",
- "likeop", "between_op", "in_op", "case_operand",
- "case_exprlist", "case_else", "expritem", "uniqueflag",
- "idxitem", "plus_opt", "number", "trigger_decl",
- "trigger_cmd_list", "trigger_time", "trigger_event", "foreach_clause",
- "when_clause", "trigger_cmd", "database_kw_opt", "key_opt",
-};
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/* For tracing reduce actions, the names of all rules are required.
-*/
-static const char *const yyRuleName[] = {
- /* 0 */ "input ::= cmdlist",
- /* 1 */ "cmdlist ::= cmdlist ecmd",
- /* 2 */ "cmdlist ::= ecmd",
- /* 3 */ "ecmd ::= explain cmdx SEMI",
- /* 4 */ "ecmd ::= SEMI",
- /* 5 */ "cmdx ::= cmd",
- /* 6 */ "explain ::= EXPLAIN",
- /* 7 */ "explain ::=",
- /* 8 */ "cmd ::= BEGIN transtype trans_opt",
- /* 9 */ "trans_opt ::=",
- /* 10 */ "trans_opt ::= TRANSACTION",
- /* 11 */ "trans_opt ::= TRANSACTION nm",
- /* 12 */ "transtype ::=",
- /* 13 */ "transtype ::= DEFERRED",
- /* 14 */ "transtype ::= IMMEDIATE",
- /* 15 */ "transtype ::= EXCLUSIVE",
- /* 16 */ "cmd ::= COMMIT trans_opt",
- /* 17 */ "cmd ::= END trans_opt",
- /* 18 */ "cmd ::= ROLLBACK trans_opt",
- /* 19 */ "cmd ::= create_table create_table_args",
- /* 20 */ "create_table ::= CREATE temp TABLE nm dbnm",
- /* 21 */ "temp ::= TEMP",
- /* 22 */ "temp ::=",
- /* 23 */ "create_table_args ::= LP columnlist conslist_opt RP",
- /* 24 */ "create_table_args ::= AS select",
- /* 25 */ "columnlist ::= columnlist COMMA column",
- /* 26 */ "columnlist ::= column",
- /* 27 */ "column ::= columnid type carglist",
- /* 28 */ "columnid ::= nm",
- /* 29 */ "id ::= ID",
- /* 30 */ "ids ::= ID",
- /* 31 */ "ids ::= STRING",
- /* 32 */ "nm ::= ID",
- /* 33 */ "nm ::= STRING",
- /* 34 */ "nm ::= JOIN_KW",
- /* 35 */ "type ::=",
- /* 36 */ "type ::= typename",
- /* 37 */ "type ::= typename LP signed RP",
- /* 38 */ "type ::= typename LP signed COMMA signed RP",
- /* 39 */ "typename ::= ids",
- /* 40 */ "typename ::= typename ids",
- /* 41 */ "signed ::= plus_num",
- /* 42 */ "signed ::= minus_num",
- /* 43 */ "carglist ::= carglist carg",
- /* 44 */ "carglist ::=",
- /* 45 */ "carg ::= CONSTRAINT nm ccons",
- /* 46 */ "carg ::= ccons",
- /* 47 */ "carg ::= DEFAULT ids",
- /* 48 */ "carg ::= DEFAULT plus_num",
- /* 49 */ "carg ::= DEFAULT minus_num",
- /* 50 */ "carg ::= DEFAULT NULL",
- /* 51 */ "ccons ::= NULL onconf",
- /* 52 */ "ccons ::= NOT NULL onconf",
- /* 53 */ "ccons ::= PRIMARY KEY sortorder onconf",
- /* 54 */ "ccons ::= UNIQUE onconf",
- /* 55 */ "ccons ::= CHECK LP expr RP onconf",
- /* 56 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
- /* 57 */ "ccons ::= defer_subclause",
- /* 58 */ "ccons ::= COLLATE id",
- /* 59 */ "refargs ::=",
- /* 60 */ "refargs ::= refargs refarg",
- /* 61 */ "refarg ::= MATCH nm",
- /* 62 */ "refarg ::= ON DELETE refact",
- /* 63 */ "refarg ::= ON UPDATE refact",
- /* 64 */ "refarg ::= ON INSERT refact",
- /* 65 */ "refact ::= SET NULL",
- /* 66 */ "refact ::= SET DEFAULT",
- /* 67 */ "refact ::= CASCADE",
- /* 68 */ "refact ::= RESTRICT",
- /* 69 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
- /* 70 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
- /* 71 */ "init_deferred_pred_opt ::=",
- /* 72 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
- /* 73 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
- /* 74 */ "conslist_opt ::=",
- /* 75 */ "conslist_opt ::= COMMA conslist",
- /* 76 */ "conslist ::= conslist COMMA tcons",
- /* 77 */ "conslist ::= conslist tcons",
- /* 78 */ "conslist ::= tcons",
- /* 79 */ "tcons ::= CONSTRAINT nm",
- /* 80 */ "tcons ::= PRIMARY KEY LP idxlist RP onconf",
- /* 81 */ "tcons ::= UNIQUE LP idxlist RP onconf",
- /* 82 */ "tcons ::= CHECK expr onconf",
- /* 83 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt",
- /* 84 */ "defer_subclause_opt ::=",
- /* 85 */ "defer_subclause_opt ::= defer_subclause",
- /* 86 */ "onconf ::=",
- /* 87 */ "onconf ::= ON CONFLICT resolvetype",
- /* 88 */ "orconf ::=",
- /* 89 */ "orconf ::= OR resolvetype",
- /* 90 */ "resolvetype ::= raisetype",
- /* 91 */ "resolvetype ::= IGNORE",
- /* 92 */ "resolvetype ::= REPLACE",
- /* 93 */ "cmd ::= DROP TABLE fullname",
- /* 94 */ "cmd ::= CREATE temp VIEW nm dbnm AS select",
- /* 95 */ "cmd ::= DROP VIEW fullname",
- /* 96 */ "cmd ::= select",
- /* 97 */ "select ::= oneselect",
- /* 98 */ "select ::= select multiselect_op oneselect",
- /* 99 */ "multiselect_op ::= UNION",
- /* 100 */ "multiselect_op ::= UNION ALL",
- /* 101 */ "multiselect_op ::= INTERSECT",
- /* 102 */ "multiselect_op ::= EXCEPT",
- /* 103 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
- /* 104 */ "distinct ::= DISTINCT",
- /* 105 */ "distinct ::= ALL",
- /* 106 */ "distinct ::=",
- /* 107 */ "sclp ::= selcollist COMMA",
- /* 108 */ "sclp ::=",
- /* 109 */ "selcollist ::= sclp expr as",
- /* 110 */ "selcollist ::= sclp STAR",
- /* 111 */ "selcollist ::= sclp nm DOT STAR",
- /* 112 */ "as ::= AS nm",
- /* 113 */ "as ::= ids",
- /* 114 */ "as ::=",
- /* 115 */ "from ::=",
- /* 116 */ "from ::= FROM seltablist",
- /* 117 */ "stl_prefix ::= seltablist joinop",
- /* 118 */ "stl_prefix ::=",
- /* 119 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt",
- /* 120 */ "seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt",
- /* 121 */ "seltablist_paren ::= select",
- /* 122 */ "seltablist_paren ::= seltablist",
- /* 123 */ "dbnm ::=",
- /* 124 */ "dbnm ::= DOT nm",
- /* 125 */ "fullname ::= nm dbnm",
- /* 126 */ "joinop ::= COMMA",
- /* 127 */ "joinop ::= JOIN",
- /* 128 */ "joinop ::= JOIN_KW JOIN",
- /* 129 */ "joinop ::= JOIN_KW nm JOIN",
- /* 130 */ "joinop ::= JOIN_KW nm nm JOIN",
- /* 131 */ "on_opt ::= ON expr",
- /* 132 */ "on_opt ::=",
- /* 133 */ "using_opt ::= USING LP inscollist RP",
- /* 134 */ "using_opt ::=",
- /* 135 */ "orderby_opt ::=",
- /* 136 */ "orderby_opt ::= ORDER BY sortlist",
- /* 137 */ "sortlist ::= sortlist COMMA sortitem collate sortorder",
- /* 138 */ "sortlist ::= sortitem collate sortorder",
- /* 139 */ "sortitem ::= expr",
- /* 140 */ "sortorder ::= ASC",
- /* 141 */ "sortorder ::= DESC",
- /* 142 */ "sortorder ::=",
- /* 143 */ "collate ::=",
- /* 144 */ "collate ::= COLLATE id",
- /* 145 */ "groupby_opt ::=",
- /* 146 */ "groupby_opt ::= GROUP BY exprlist",
- /* 147 */ "having_opt ::=",
- /* 148 */ "having_opt ::= HAVING expr",
- /* 149 */ "limit_opt ::=",
- /* 150 */ "limit_opt ::= LIMIT signed",
- /* 151 */ "limit_opt ::= LIMIT signed OFFSET signed",
- /* 152 */ "limit_opt ::= LIMIT signed COMMA signed",
- /* 153 */ "cmd ::= DELETE FROM fullname where_opt",
- /* 154 */ "where_opt ::=",
- /* 155 */ "where_opt ::= WHERE expr",
- /* 156 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt",
- /* 157 */ "setlist ::= setlist COMMA nm EQ expr",
- /* 158 */ "setlist ::= nm EQ expr",
- /* 159 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP",
- /* 160 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select",
- /* 161 */ "insert_cmd ::= INSERT orconf",
- /* 162 */ "insert_cmd ::= REPLACE",
- /* 163 */ "itemlist ::= itemlist COMMA expr",
- /* 164 */ "itemlist ::= expr",
- /* 165 */ "inscollist_opt ::=",
- /* 166 */ "inscollist_opt ::= LP inscollist RP",
- /* 167 */ "inscollist ::= inscollist COMMA nm",
- /* 168 */ "inscollist ::= nm",
- /* 169 */ "expr ::= LP expr RP",
- /* 170 */ "expr ::= NULL",
- /* 171 */ "expr ::= ID",
- /* 172 */ "expr ::= JOIN_KW",
- /* 173 */ "expr ::= nm DOT nm",
- /* 174 */ "expr ::= nm DOT nm DOT nm",
- /* 175 */ "expr ::= INTEGER",
- /* 176 */ "expr ::= FLOAT",
- /* 177 */ "expr ::= STRING",
- /* 178 */ "expr ::= BLOB",
- /* 179 */ "expr ::= VARIABLE",
- /* 180 */ "expr ::= ID LP exprlist RP",
- /* 181 */ "expr ::= ID LP STAR RP",
- /* 182 */ "expr ::= expr AND expr",
- /* 183 */ "expr ::= expr OR expr",
- /* 184 */ "expr ::= expr LT expr",
- /* 185 */ "expr ::= expr GT expr",
- /* 186 */ "expr ::= expr LE expr",
- /* 187 */ "expr ::= expr GE expr",
- /* 188 */ "expr ::= expr NE expr",
- /* 189 */ "expr ::= expr EQ expr",
- /* 190 */ "expr ::= expr BITAND expr",
- /* 191 */ "expr ::= expr BITOR expr",
- /* 192 */ "expr ::= expr LSHIFT expr",
- /* 193 */ "expr ::= expr RSHIFT expr",
- /* 194 */ "expr ::= expr PLUS expr",
- /* 195 */ "expr ::= expr MINUS expr",
- /* 196 */ "expr ::= expr STAR expr",
- /* 197 */ "expr ::= expr SLASH expr",
- /* 198 */ "expr ::= expr REM expr",
- /* 199 */ "expr ::= expr CONCAT expr",
- /* 200 */ "likeop ::= LIKE",
- /* 201 */ "likeop ::= GLOB",
- /* 202 */ "likeop ::= NOT LIKE",
- /* 203 */ "likeop ::= NOT GLOB",
- /* 204 */ "expr ::= expr likeop expr",
- /* 205 */ "expr ::= expr ISNULL",
- /* 206 */ "expr ::= expr IS NULL",
- /* 207 */ "expr ::= expr NOTNULL",
- /* 208 */ "expr ::= expr NOT NULL",
- /* 209 */ "expr ::= expr IS NOT NULL",
- /* 210 */ "expr ::= NOT expr",
- /* 211 */ "expr ::= BITNOT expr",
- /* 212 */ "expr ::= MINUS expr",
- /* 213 */ "expr ::= PLUS expr",
- /* 214 */ "expr ::= LP select RP",
- /* 215 */ "between_op ::= BETWEEN",
- /* 216 */ "between_op ::= NOT BETWEEN",
- /* 217 */ "expr ::= expr between_op expr AND expr",
- /* 218 */ "in_op ::= IN",
- /* 219 */ "in_op ::= NOT IN",
- /* 220 */ "expr ::= expr in_op LP exprlist RP",
- /* 221 */ "expr ::= expr in_op LP select RP",
- /* 222 */ "expr ::= expr in_op nm dbnm",
- /* 223 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 224 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 225 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 226 */ "case_else ::= ELSE expr",
- /* 227 */ "case_else ::=",
- /* 228 */ "case_operand ::= expr",
- /* 229 */ "case_operand ::=",
- /* 230 */ "exprlist ::= exprlist COMMA expritem",
- /* 231 */ "exprlist ::= expritem",
- /* 232 */ "expritem ::= expr",
- /* 233 */ "expritem ::=",
- /* 234 */ "cmd ::= CREATE uniqueflag INDEX nm dbnm ON fullname LP idxlist RP onconf",
- /* 235 */ "uniqueflag ::= UNIQUE",
- /* 236 */ "uniqueflag ::=",
- /* 237 */ "idxlist_opt ::=",
- /* 238 */ "idxlist_opt ::= LP idxlist RP",
- /* 239 */ "idxlist ::= idxlist COMMA idxitem collate sortorder",
- /* 240 */ "idxlist ::= idxitem collate sortorder",
- /* 241 */ "idxitem ::= nm",
- /* 242 */ "cmd ::= DROP INDEX fullname",
- /* 243 */ "cmd ::= VACUUM",
- /* 244 */ "cmd ::= VACUUM nm",
- /* 245 */ "cmd ::= PRAGMA nm dbnm EQ nm",
- /* 246 */ "cmd ::= PRAGMA nm dbnm EQ ON",
- /* 247 */ "cmd ::= PRAGMA nm dbnm EQ plus_num",
- /* 248 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 249 */ "cmd ::= PRAGMA nm dbnm LP nm RP",
- /* 250 */ "cmd ::= PRAGMA nm dbnm",
- /* 251 */ "plus_num ::= plus_opt number",
- /* 252 */ "minus_num ::= MINUS number",
- /* 253 */ "number ::= INTEGER",
- /* 254 */ "number ::= FLOAT",
- /* 255 */ "plus_opt ::= PLUS",
- /* 256 */ "plus_opt ::=",
- /* 257 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END",
- /* 258 */ "trigger_decl ::= temp TRIGGER nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 259 */ "trigger_time ::= BEFORE",
- /* 260 */ "trigger_time ::= AFTER",
- /* 261 */ "trigger_time ::= INSTEAD OF",
- /* 262 */ "trigger_time ::=",
- /* 263 */ "trigger_event ::= DELETE",
- /* 264 */ "trigger_event ::= INSERT",
- /* 265 */ "trigger_event ::= UPDATE",
- /* 266 */ "trigger_event ::= UPDATE OF inscollist",
- /* 267 */ "foreach_clause ::=",
- /* 268 */ "foreach_clause ::= FOR EACH ROW",
- /* 269 */ "foreach_clause ::= FOR EACH STATEMENT",
- /* 270 */ "when_clause ::=",
- /* 271 */ "when_clause ::= WHEN expr",
- /* 272 */ "trigger_cmd_list ::= trigger_cmd SEMI trigger_cmd_list",
- /* 273 */ "trigger_cmd_list ::=",
- /* 274 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt",
- /* 275 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP",
- /* 276 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select",
- /* 277 */ "trigger_cmd ::= DELETE FROM nm where_opt",
- /* 278 */ "trigger_cmd ::= select",
- /* 279 */ "expr ::= RAISE LP IGNORE RP",
- /* 280 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 281 */ "raisetype ::= ROLLBACK",
- /* 282 */ "raisetype ::= ABORT",
- /* 283 */ "raisetype ::= FAIL",
- /* 284 */ "cmd ::= DROP TRIGGER fullname",
- /* 285 */ "cmd ::= ATTACH database_kw_opt ids AS nm key_opt",
- /* 286 */ "key_opt ::=",
- /* 287 */ "key_opt ::= KEY ids",
- /* 288 */ "key_opt ::= KEY BLOB",
- /* 289 */ "database_kw_opt ::= DATABASE",
- /* 290 */ "database_kw_opt ::=",
- /* 291 */ "cmd ::= DETACH database_kw_opt nm",
-};
-#endif /* NDEBUG */
-
-/*
-** This function returns the symbolic name associated with a token
-** value.
-*/
-const char *sqlite3ParserTokenName(int tokenType){
-#ifndef NDEBUG
- if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
- return yyTokenName[tokenType];
- }else{
- return "Unknown";
- }
-#else
- return "";
-#endif
-}
-
-/*
-** This function allocates a new parser.
-** The only argument is a pointer to a function which works like
-** malloc.
-**
-** Inputs:
-** A pointer to the function used to allocate memory.
-**
-** Outputs:
-** A pointer to a parser. This pointer is used in subsequent calls
-** to sqlite3Parser and sqlite3ParserFree.
-*/
-void *sqlite3ParserAlloc(void *(*mallocProc)(size_t)){
- yyParser *pParser;
- pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
- if( pParser ){
- pParser->yyidx = -1;
- }
- return pParser;
-}
-
-/* The following function deletes the value associated with a
-** symbol. The symbol can be either a terminal or nonterminal.
-** "yymajor" is the symbol code, and "yypminor" is a pointer to
-** the value.
-*/
-static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
- switch( yymajor ){
- /* Here is inserted the actions which take place when a
- ** terminal or non-terminal is destroyed. This can happen
- ** when the symbol is popped from the stack during a
- ** reduce or during error processing or when a parser is
- ** being destroyed before it is finished parsing.
- **
- ** Note: during a reduce, the only symbols destroyed are those
- ** which appear on the RHS of the rule, but which are not used
- ** inside the C code.
- */
- case 146:
- case 176:
- case 193:
-#line 303 "parse.y"
-{sqlite3SelectDelete((yypminor->yy107));}
-#line 1236 "parse.c"
- break;
- case 161:
- case 181:
- case 183:
- case 191:
- case 197:
- case 210:
-#line 552 "parse.y"
-{sqlite3ExprDelete((yypminor->yy258));}
-#line 1246 "parse.c"
- break;
- case 162:
- case 170:
- case 179:
- case 182:
- case 184:
- case 186:
- case 196:
- case 199:
- case 200:
- case 203:
- case 208:
-#line 744 "parse.y"
-{sqlite3ExprListDelete((yypminor->yy210));}
-#line 1261 "parse.c"
- break;
- case 175:
- case 180:
- case 188:
- case 189:
-#line 428 "parse.y"
-{sqlite3SrcListDelete((yypminor->yy259));}
-#line 1269 "parse.c"
- break;
- case 192:
- case 195:
- case 202:
-#line 446 "parse.y"
-{sqlite3IdListDelete((yypminor->yy272));}
-#line 1276 "parse.c"
- break;
- case 216:
- case 221:
-#line 833 "parse.y"
-{sqlite3DeleteTriggerStep((yypminor->yy91));}
-#line 1282 "parse.c"
- break;
- case 218:
-#line 817 "parse.y"
-{sqlite3IdListDelete((yypminor->yy146).b);}
-#line 1287 "parse.c"
- break;
- default: break; /* If no destructor action specified: do nothing */
- }
-}
-
-/*
-** Pop the parser's stack once.
-**
-** If there is a destructor routine associated with the token which
-** is popped from the stack, then call it.
-**
-** Return the major token number for the symbol popped.
-*/
-static int yy_pop_parser_stack(yyParser *pParser){
- YYCODETYPE yymajor;
- yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
-
- if( pParser->yyidx<0 ) return 0;
-#ifndef NDEBUG
- if( yyTraceFILE && pParser->yyidx>=0 ){
- fprintf(yyTraceFILE,"%sPopping %s\n",
- yyTracePrompt,
- yyTokenName[yytos->major]);
- }
-#endif
- yymajor = yytos->major;
- yy_destructor( yymajor, &yytos->minor);
- pParser->yyidx--;
- return yymajor;
-}
-
-/*
-** Deallocate and destroy a parser. Destructors are all called for
-** all stack elements before shutting the parser down.
-**
-** Inputs:
-** <ul>
-** <li> A pointer to the parser. This should be a pointer
-** obtained from sqlite3ParserAlloc.
-** <li> A pointer to a function used to reclaim memory obtained
-** from malloc.
-** </ul>
-*/
-void sqlite3ParserFree(
- void *p, /* The parser to be deleted */
- void (*freeProc)(void*) /* Function used to reclaim memory */
-){
- yyParser *pParser = (yyParser*)p;
- if( pParser==0 ) return;
- while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
- (*freeProc)((void*)pParser);
-}
-
-/*
-** Find the appropriate action for a parser given the terminal
-** look-ahead token iLookAhead.
-**
-** If the look-ahead token is YYNOCODE, then check to see if the action is
-** independent of the look-ahead. If it is, return the action, otherwise
-** return YY_NO_ACTION.
-*/
-static int yy_find_shift_action(
- yyParser *pParser, /* The parser */
- int iLookAhead /* The look-ahead token */
-){
- int i;
- int stateno = pParser->yystack[pParser->yyidx].stateno;
-
- /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
- i = yy_shift_ofst[stateno];
- if( i==YY_SHIFT_USE_DFLT ){
- return yy_default[stateno];
- }
- if( iLookAhead==YYNOCODE ){
- return YY_NO_ACTION;
- }
- i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
-#ifdef YYFALLBACK
- int iFallback; /* Fallback token */
- if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
- && (iFallback = yyFallback[iLookAhead])!=0 ){
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
- yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
- }
-#endif
- return yy_find_shift_action(pParser, iFallback);
- }
-#endif
- return yy_default[stateno];
- }else{
- return yy_action[i];
- }
-}
-
-/*
-** Find the appropriate action for a parser given the non-terminal
-** look-ahead token iLookAhead.
-**
-** If the look-ahead token is YYNOCODE, then check to see if the action is
-** independent of the look-ahead. If it is, return the action, otherwise
-** return YY_NO_ACTION.
-*/
-static int yy_find_reduce_action(
- yyParser *pParser, /* The parser */
- int iLookAhead /* The look-ahead token */
-){
- int i;
- int stateno = pParser->yystack[pParser->yyidx].stateno;
-
- i = yy_reduce_ofst[stateno];
- if( i==YY_REDUCE_USE_DFLT ){
- return yy_default[stateno];
- }
- if( iLookAhead==YYNOCODE ){
- return YY_NO_ACTION;
- }
- i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
- return yy_default[stateno];
- }else{
- return yy_action[i];
- }
-}
-
-/*
-** Perform a shift action.
-*/
-static void yy_shift(
- yyParser *yypParser, /* The parser to be shifted */
- int yyNewState, /* The new state to shift in */
- int yyMajor, /* The major token to shift in */
- YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
-){
- yyStackEntry *yytos;
- yypParser->yyidx++;
- if( yypParser->yyidx>=YYSTACKDEPTH ){
- sqlite3ParserARG_FETCH;
- yypParser->yyidx--;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will execute if the parser
- ** stack every overflows */
- sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
- return;
- }
- yytos = &yypParser->yystack[yypParser->yyidx];
- yytos->stateno = yyNewState;
- yytos->major = yyMajor;
- yytos->minor = *yypMinor;
-#ifndef NDEBUG
- if( yyTraceFILE && yypParser->yyidx>0 ){
- int i;
- fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
- fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
- for(i=1; i<=yypParser->yyidx; i++)
- fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
- fprintf(yyTraceFILE,"\n");
- }
-#endif
-}
-
-/* The following table contains information about every rule that
-** is used during the reduce.
-*/
-static const struct {
- YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
- unsigned char nrhs; /* Number of right-hand side symbols in the rule */
-} yyRuleInfo[] = {
- { 131, 1 },
- { 132, 2 },
- { 132, 1 },
- { 133, 3 },
- { 133, 1 },
- { 135, 1 },
- { 134, 1 },
- { 134, 0 },
- { 136, 3 },
- { 138, 0 },
- { 138, 1 },
- { 138, 2 },
- { 137, 0 },
- { 137, 1 },
- { 137, 1 },
- { 137, 1 },
- { 136, 2 },
- { 136, 2 },
- { 136, 2 },
- { 136, 2 },
- { 140, 5 },
- { 142, 1 },
- { 142, 0 },
- { 141, 4 },
- { 141, 2 },
- { 144, 3 },
- { 144, 1 },
- { 147, 3 },
- { 148, 1 },
- { 151, 1 },
- { 152, 1 },
- { 152, 1 },
- { 139, 1 },
- { 139, 1 },
- { 139, 1 },
- { 149, 0 },
- { 149, 1 },
- { 149, 4 },
- { 149, 6 },
- { 153, 1 },
- { 153, 2 },
- { 154, 1 },
- { 154, 1 },
- { 150, 2 },
- { 150, 0 },
- { 157, 3 },
- { 157, 1 },
- { 157, 2 },
- { 157, 2 },
- { 157, 2 },
- { 157, 2 },
- { 158, 2 },
- { 158, 3 },
- { 158, 4 },
- { 158, 2 },
- { 158, 5 },
- { 158, 4 },
- { 158, 1 },
- { 158, 2 },
- { 163, 0 },
- { 163, 2 },
- { 165, 2 },
- { 165, 3 },
- { 165, 3 },
- { 165, 3 },
- { 166, 2 },
- { 166, 2 },
- { 166, 1 },
- { 166, 1 },
- { 164, 3 },
- { 164, 2 },
- { 167, 0 },
- { 167, 2 },
- { 167, 2 },
- { 145, 0 },
- { 145, 2 },
- { 168, 3 },
- { 168, 2 },
- { 168, 1 },
- { 169, 2 },
- { 169, 6 },
- { 169, 5 },
- { 169, 3 },
- { 169, 10 },
- { 171, 0 },
- { 171, 1 },
- { 159, 0 },
- { 159, 3 },
- { 172, 0 },
- { 172, 2 },
- { 173, 1 },
- { 173, 1 },
- { 173, 1 },
- { 136, 3 },
- { 136, 7 },
- { 136, 3 },
- { 136, 1 },
- { 146, 1 },
- { 146, 3 },
- { 177, 1 },
- { 177, 2 },
- { 177, 1 },
- { 177, 1 },
- { 176, 9 },
- { 178, 1 },
- { 178, 1 },
- { 178, 0 },
- { 186, 2 },
- { 186, 0 },
- { 179, 3 },
- { 179, 2 },
- { 179, 4 },
- { 187, 2 },
- { 187, 1 },
- { 187, 0 },
- { 180, 0 },
- { 180, 2 },
- { 189, 2 },
- { 189, 0 },
- { 188, 6 },
- { 188, 7 },
- { 193, 1 },
- { 193, 1 },
- { 143, 0 },
- { 143, 2 },
- { 175, 2 },
- { 190, 1 },
- { 190, 1 },
- { 190, 2 },
- { 190, 3 },
- { 190, 4 },
- { 191, 2 },
- { 191, 0 },
- { 192, 4 },
- { 192, 0 },
- { 184, 0 },
- { 184, 3 },
- { 196, 5 },
- { 196, 3 },
- { 197, 1 },
- { 160, 1 },
- { 160, 1 },
- { 160, 0 },
- { 198, 0 },
- { 198, 2 },
- { 182, 0 },
- { 182, 3 },
- { 183, 0 },
- { 183, 2 },
- { 185, 0 },
- { 185, 2 },
- { 185, 4 },
- { 185, 4 },
- { 136, 4 },
- { 181, 0 },
- { 181, 2 },
- { 136, 6 },
- { 200, 5 },
- { 200, 3 },
- { 136, 8 },
- { 136, 5 },
- { 201, 2 },
- { 201, 1 },
- { 203, 3 },
- { 203, 1 },
- { 202, 0 },
- { 202, 3 },
- { 195, 3 },
- { 195, 1 },
- { 161, 3 },
- { 161, 1 },
- { 161, 1 },
- { 161, 1 },
- { 161, 3 },
- { 161, 5 },
- { 161, 1 },
- { 161, 1 },
- { 161, 1 },
- { 161, 1 },
- { 161, 1 },
- { 161, 4 },
- { 161, 4 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 161, 3 },
- { 204, 1 },
- { 204, 1 },
- { 204, 2 },
- { 204, 2 },
- { 161, 3 },
- { 161, 2 },
- { 161, 3 },
- { 161, 2 },
- { 161, 3 },
- { 161, 4 },
- { 161, 2 },
- { 161, 2 },
- { 161, 2 },
- { 161, 2 },
- { 161, 3 },
- { 205, 1 },
- { 205, 2 },
- { 161, 5 },
- { 206, 1 },
- { 206, 2 },
- { 161, 5 },
- { 161, 5 },
- { 161, 4 },
- { 161, 5 },
- { 208, 5 },
- { 208, 4 },
- { 209, 2 },
- { 209, 0 },
- { 207, 1 },
- { 207, 0 },
- { 199, 3 },
- { 199, 1 },
- { 210, 1 },
- { 210, 0 },
- { 136, 11 },
- { 211, 1 },
- { 211, 0 },
- { 162, 0 },
- { 162, 3 },
- { 170, 5 },
- { 170, 3 },
- { 212, 1 },
- { 136, 3 },
- { 136, 1 },
- { 136, 2 },
- { 136, 5 },
- { 136, 5 },
- { 136, 5 },
- { 136, 5 },
- { 136, 6 },
- { 136, 3 },
- { 155, 2 },
- { 156, 2 },
- { 214, 1 },
- { 214, 1 },
- { 213, 1 },
- { 213, 0 },
- { 136, 5 },
- { 215, 10 },
- { 217, 1 },
- { 217, 1 },
- { 217, 2 },
- { 217, 0 },
- { 218, 1 },
- { 218, 1 },
- { 218, 1 },
- { 218, 3 },
- { 219, 0 },
- { 219, 3 },
- { 219, 3 },
- { 220, 0 },
- { 220, 2 },
- { 216, 3 },
- { 216, 0 },
- { 221, 6 },
- { 221, 8 },
- { 221, 5 },
- { 221, 4 },
- { 221, 1 },
- { 161, 4 },
- { 161, 6 },
- { 174, 1 },
- { 174, 1 },
- { 174, 1 },
- { 136, 3 },
- { 136, 6 },
- { 223, 0 },
- { 223, 2 },
- { 223, 2 },
- { 222, 1 },
- { 222, 0 },
- { 136, 3 },
-};
-
-static void yy_accept(yyParser*); /* Forward Declaration */
-
-/*
-** Perform a reduce action and the shift that must immediately
-** follow the reduce.
-*/
-static void yy_reduce(
- yyParser *yypParser, /* The parser */
- int yyruleno /* Number of the rule by which to reduce */
-){
- int yygoto; /* The next state */
- int yyact; /* The next action */
- YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
- yyStackEntry *yymsp; /* The top of the parser's stack */
- int yysize; /* Amount to pop the stack */
- sqlite3ParserARG_FETCH;
- yymsp = &yypParser->yystack[yypParser->yyidx];
-#ifndef NDEBUG
- if( yyTraceFILE && yyruleno>=0
- && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
- fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
- yyRuleName[yyruleno]);
- }
-#endif /* NDEBUG */
-
- switch( yyruleno ){
- /* Beginning here are the reduction cases. A typical example
- ** follows:
- ** case 0:
- ** #line <lineno> <grammarfile>
- ** { ... } // User supplied code
- ** #line <lineno> <thisfile>
- ** break;
- */
- case 5:
-#line 86 "parse.y"
-{ sqlite3FinishCoding(pParse); }
-#line 1794 "parse.c"
- break;
- case 6:
-#line 87 "parse.y"
-{ sqlite3BeginParse(pParse, 1); }
-#line 1799 "parse.c"
- break;
- case 7:
-#line 88 "parse.y"
-{ sqlite3BeginParse(pParse, 0); }
-#line 1804 "parse.c"
- break;
- case 8:
-#line 93 "parse.y"
-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy284);}
-#line 1809 "parse.c"
- break;
- case 12:
-#line 98 "parse.y"
-{yygotominor.yy284 = TK_DEFERRED;}
-#line 1814 "parse.c"
- break;
- case 13:
- case 14:
- case 15:
- case 99:
- case 101:
- case 102:
-#line 99 "parse.y"
-{yygotominor.yy284 = yymsp[0].major;}
-#line 1824 "parse.c"
- break;
- case 16:
- case 17:
-#line 102 "parse.y"
-{sqlite3CommitTransaction(pParse);}
-#line 1830 "parse.c"
- break;
- case 18:
-#line 104 "parse.y"
-{sqlite3RollbackTransaction(pParse);}
-#line 1835 "parse.c"
- break;
- case 20:
-#line 109 "parse.y"
-{
- sqlite3StartTable(pParse,&yymsp[-4].minor.yy0,&yymsp[-1].minor.yy98,&yymsp[0].minor.yy98,yymsp[-3].minor.yy284,0);
-}
-#line 1842 "parse.c"
- break;
- case 21:
- case 72:
- case 104:
- case 216:
- case 219:
-#line 113 "parse.y"
-{yygotominor.yy284 = 1;}
-#line 1851 "parse.c"
- break;
- case 22:
- case 71:
- case 73:
- case 84:
- case 105:
- case 106:
- case 215:
- case 218:
-#line 114 "parse.y"
-{yygotominor.yy284 = 0;}
-#line 1863 "parse.c"
- break;
- case 23:
-#line 115 "parse.y"
-{
- sqlite3EndTable(pParse,&yymsp[0].minor.yy0,0);
-}
-#line 1870 "parse.c"
- break;
- case 24:
-#line 118 "parse.y"
-{
- sqlite3EndTable(pParse,0,yymsp[0].minor.yy107);
- sqlite3SelectDelete(yymsp[0].minor.yy107);
-}
-#line 1878 "parse.c"
- break;
- case 28:
-#line 130 "parse.y"
-{sqlite3AddColumn(pParse,&yymsp[0].minor.yy98);}
-#line 1883 "parse.c"
- break;
- case 29:
- case 30:
- case 31:
- case 32:
- case 33:
- case 34:
- case 253:
- case 254:
-#line 136 "parse.y"
-{yygotominor.yy98 = yymsp[0].minor.yy0;}
-#line 1895 "parse.c"
- break;
- case 36:
-#line 185 "parse.y"
-{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy98,&yymsp[0].minor.yy98);}
-#line 1900 "parse.c"
- break;
- case 37:
-#line 186 "parse.y"
-{sqlite3AddColumnType(pParse,&yymsp[-3].minor.yy98,&yymsp[0].minor.yy0);}
-#line 1905 "parse.c"
- break;
- case 38:
-#line 188 "parse.y"
-{sqlite3AddColumnType(pParse,&yymsp[-5].minor.yy98,&yymsp[0].minor.yy0);}
-#line 1910 "parse.c"
- break;
- case 39:
- case 112:
- case 113:
- case 124:
- case 144:
- case 241:
- case 251:
- case 252:
-#line 190 "parse.y"
-{yygotominor.yy98 = yymsp[0].minor.yy98;}
-#line 1922 "parse.c"
- break;
- case 40:
-#line 191 "parse.y"
-{yygotominor.yy98.z=yymsp[-1].minor.yy98.z; yygotominor.yy98.n=yymsp[0].minor.yy98.n+(yymsp[0].minor.yy98.z-yymsp[-1].minor.yy98.z);}
-#line 1927 "parse.c"
- break;
- case 41:
-#line 193 "parse.y"
-{ yygotominor.yy284 = atoi(yymsp[0].minor.yy98.z); }
-#line 1932 "parse.c"
- break;
- case 42:
-#line 194 "parse.y"
-{ yygotominor.yy284 = -atoi(yymsp[0].minor.yy98.z); }
-#line 1937 "parse.c"
- break;
- case 47:
- case 48:
-#line 199 "parse.y"
-{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy98,0);}
-#line 1943 "parse.c"
- break;
- case 49:
-#line 201 "parse.y"
-{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy98,1);}
-#line 1948 "parse.c"
- break;
- case 52:
-#line 208 "parse.y"
-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy284);}
-#line 1953 "parse.c"
- break;
- case 53:
-#line 209 "parse.y"
-{sqlite3AddPrimaryKey(pParse,0,yymsp[0].minor.yy284);}
-#line 1958 "parse.c"
- break;
- case 54:
-#line 210 "parse.y"
-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy284,0,0);}
-#line 1963 "parse.c"
- break;
- case 56:
-#line 213 "parse.y"
-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy98,yymsp[-1].minor.yy210,yymsp[0].minor.yy284);}
-#line 1968 "parse.c"
- break;
- case 57:
-#line 214 "parse.y"
-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy284);}
-#line 1973 "parse.c"
- break;
- case 58:
-#line 215 "parse.y"
-{sqlite3AddCollateType(pParse, yymsp[0].minor.yy98.z, yymsp[0].minor.yy98.n);}
-#line 1978 "parse.c"
- break;
- case 59:
-#line 223 "parse.y"
-{ yygotominor.yy284 = OE_Restrict * 0x010101; }
-#line 1983 "parse.c"
- break;
- case 60:
-#line 224 "parse.y"
-{ yygotominor.yy284 = (yymsp[-1].minor.yy284 & yymsp[0].minor.yy47.mask) | yymsp[0].minor.yy47.value; }
-#line 1988 "parse.c"
- break;
- case 61:
-#line 226 "parse.y"
-{ yygotominor.yy47.value = 0; yygotominor.yy47.mask = 0x000000; }
-#line 1993 "parse.c"
- break;
- case 62:
-#line 227 "parse.y"
-{ yygotominor.yy47.value = yymsp[0].minor.yy284; yygotominor.yy47.mask = 0x0000ff; }
-#line 1998 "parse.c"
- break;
- case 63:
-#line 228 "parse.y"
-{ yygotominor.yy47.value = yymsp[0].minor.yy284<<8; yygotominor.yy47.mask = 0x00ff00; }
-#line 2003 "parse.c"
- break;
- case 64:
-#line 229 "parse.y"
-{ yygotominor.yy47.value = yymsp[0].minor.yy284<<16; yygotominor.yy47.mask = 0xff0000; }
-#line 2008 "parse.c"
- break;
- case 65:
-#line 231 "parse.y"
-{ yygotominor.yy284 = OE_SetNull; }
-#line 2013 "parse.c"
- break;
- case 66:
-#line 232 "parse.y"
-{ yygotominor.yy284 = OE_SetDflt; }
-#line 2018 "parse.c"
- break;
- case 67:
-#line 233 "parse.y"
-{ yygotominor.yy284 = OE_Cascade; }
-#line 2023 "parse.c"
- break;
- case 68:
-#line 234 "parse.y"
-{ yygotominor.yy284 = OE_Restrict; }
-#line 2028 "parse.c"
- break;
- case 69:
- case 70:
- case 85:
- case 87:
- case 89:
- case 90:
- case 161:
-#line 236 "parse.y"
-{yygotominor.yy284 = yymsp[0].minor.yy284;}
-#line 2039 "parse.c"
- break;
- case 80:
-#line 253 "parse.y"
-{sqlite3AddPrimaryKey(pParse,yymsp[-2].minor.yy210,yymsp[0].minor.yy284);}
-#line 2044 "parse.c"
- break;
- case 81:
-#line 255 "parse.y"
-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy210,yymsp[0].minor.yy284,0,0);}
-#line 2049 "parse.c"
- break;
- case 83:
-#line 258 "parse.y"
-{
- sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy210, &yymsp[-3].minor.yy98, yymsp[-2].minor.yy210, yymsp[-1].minor.yy284);
- sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy284);
-}
-#line 2057 "parse.c"
- break;
- case 86:
- case 88:
-#line 272 "parse.y"
-{yygotominor.yy284 = OE_Default;}
-#line 2063 "parse.c"
- break;
- case 91:
-#line 277 "parse.y"
-{yygotominor.yy284 = OE_Ignore;}
-#line 2068 "parse.c"
- break;
- case 92:
- case 162:
-#line 278 "parse.y"
-{yygotominor.yy284 = OE_Replace;}
-#line 2074 "parse.c"
- break;
- case 93:
-#line 282 "parse.y"
-{
- sqlite3DropTable(pParse, yymsp[0].minor.yy259, 0);
-}
-#line 2081 "parse.c"
- break;
- case 94:
-#line 288 "parse.y"
-{
- sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy98, &yymsp[-2].minor.yy98, yymsp[0].minor.yy107, yymsp[-5].minor.yy284);
-}
-#line 2088 "parse.c"
- break;
- case 95:
-#line 291 "parse.y"
-{
- sqlite3DropTable(pParse, yymsp[0].minor.yy259, 1);
-}
-#line 2095 "parse.c"
- break;
- case 96:
-#line 297 "parse.y"
-{
- sqlite3Select(pParse, yymsp[0].minor.yy107, SRT_Callback, 0, 0, 0, 0, 0);
- sqlite3SelectDelete(yymsp[0].minor.yy107);
-}
-#line 2103 "parse.c"
- break;
- case 97:
- case 121:
-#line 307 "parse.y"
-{yygotominor.yy107 = yymsp[0].minor.yy107;}
-#line 2109 "parse.c"
- break;
- case 98:
-#line 308 "parse.y"
-{
- if( yymsp[0].minor.yy107 ){
- yymsp[0].minor.yy107->op = yymsp[-1].minor.yy284;
- yymsp[0].minor.yy107->pPrior = yymsp[-2].minor.yy107;
- }
- yygotominor.yy107 = yymsp[0].minor.yy107;
-}
-#line 2120 "parse.c"
- break;
- case 100:
-#line 317 "parse.y"
-{yygotominor.yy284 = TK_ALL;}
-#line 2125 "parse.c"
- break;
- case 103:
-#line 321 "parse.y"
-{
- yygotominor.yy107 = sqlite3SelectNew(yymsp[-6].minor.yy210,yymsp[-5].minor.yy259,yymsp[-4].minor.yy258,yymsp[-3].minor.yy210,yymsp[-2].minor.yy258,yymsp[-1].minor.yy210,yymsp[-7].minor.yy284,yymsp[0].minor.yy404.limit,yymsp[0].minor.yy404.offset);
-}
-#line 2132 "parse.c"
- break;
- case 107:
- case 238:
-#line 342 "parse.y"
-{yygotominor.yy210 = yymsp[-1].minor.yy210;}
-#line 2138 "parse.c"
- break;
- case 108:
- case 135:
- case 145:
- case 237:
-#line 343 "parse.y"
-{yygotominor.yy210 = 0;}
-#line 2146 "parse.c"
- break;
- case 109:
-#line 344 "parse.y"
-{
- yygotominor.yy210 = sqlite3ExprListAppend(yymsp[-2].minor.yy210,yymsp[-1].minor.yy258,yymsp[0].minor.yy98.n?&yymsp[0].minor.yy98:0);
-}
-#line 2153 "parse.c"
- break;
- case 110:
-#line 347 "parse.y"
-{
- yygotominor.yy210 = sqlite3ExprListAppend(yymsp[-1].minor.yy210, sqlite3Expr(TK_ALL, 0, 0, 0), 0);
-}
-#line 2160 "parse.c"
- break;
- case 111:
-#line 350 "parse.y"
-{
- Expr *pRight = sqlite3Expr(TK_ALL, 0, 0, 0);
- Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy98);
- yygotominor.yy210 = sqlite3ExprListAppend(yymsp[-3].minor.yy210, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0);
-}
-#line 2169 "parse.c"
- break;
- case 114:
-#line 362 "parse.y"
-{yygotominor.yy98.n = 0;}
-#line 2174 "parse.c"
- break;
- case 115:
-#line 374 "parse.y"
-{yygotominor.yy259 = sqliteMalloc(sizeof(*yygotominor.yy259));}
-#line 2179 "parse.c"
- break;
- case 116:
-#line 375 "parse.y"
-{yygotominor.yy259 = yymsp[0].minor.yy259;}
-#line 2184 "parse.c"
- break;
- case 117:
-#line 380 "parse.y"
-{
- yygotominor.yy259 = yymsp[-1].minor.yy259;
- if( yygotominor.yy259 && yygotominor.yy259->nSrc>0 ) yygotominor.yy259->a[yygotominor.yy259->nSrc-1].jointype = yymsp[0].minor.yy284;
-}
-#line 2192 "parse.c"
- break;
- case 118:
-#line 384 "parse.y"
-{yygotominor.yy259 = 0;}
-#line 2197 "parse.c"
- break;
- case 119:
-#line 385 "parse.y"
-{
- yygotominor.yy259 = sqlite3SrcListAppend(yymsp[-5].minor.yy259,&yymsp[-4].minor.yy98,&yymsp[-3].minor.yy98);
- if( yymsp[-2].minor.yy98.n ) sqlite3SrcListAddAlias(yygotominor.yy259,&yymsp[-2].minor.yy98);
- if( yymsp[-1].minor.yy258 ){
- if( yygotominor.yy259 && yygotominor.yy259->nSrc>1 ){ yygotominor.yy259->a[yygotominor.yy259->nSrc-2].pOn = yymsp[-1].minor.yy258; }
- else { sqlite3ExprDelete(yymsp[-1].minor.yy258); }
- }
- if( yymsp[0].minor.yy272 ){
- if( yygotominor.yy259 && yygotominor.yy259->nSrc>1 ){ yygotominor.yy259->a[yygotominor.yy259->nSrc-2].pUsing = yymsp[0].minor.yy272; }
- else { sqlite3IdListDelete(yymsp[0].minor.yy272); }
- }
-}
-#line 2213 "parse.c"
- break;
- case 120:
-#line 398 "parse.y"
-{
- yygotominor.yy259 = sqlite3SrcListAppend(yymsp[-6].minor.yy259,0,0);
- yygotominor.yy259->a[yygotominor.yy259->nSrc-1].pSelect = yymsp[-4].minor.yy107;
- if( yymsp[-2].minor.yy98.n ) sqlite3SrcListAddAlias(yygotominor.yy259,&yymsp[-2].minor.yy98);
- if( yymsp[-1].minor.yy258 ){
- if( yygotominor.yy259 && yygotominor.yy259->nSrc>1 ){ yygotominor.yy259->a[yygotominor.yy259->nSrc-2].pOn = yymsp[-1].minor.yy258; }
- else { sqlite3ExprDelete(yymsp[-1].minor.yy258); }
- }
- if( yymsp[0].minor.yy272 ){
- if( yygotominor.yy259 && yygotominor.yy259->nSrc>1 ){ yygotominor.yy259->a[yygotominor.yy259->nSrc-2].pUsing = yymsp[0].minor.yy272; }
- else { sqlite3IdListDelete(yymsp[0].minor.yy272); }
- }
-}
-#line 2230 "parse.c"
- break;
- case 122:
-#line 419 "parse.y"
-{
- yygotominor.yy107 = sqlite3SelectNew(0,yymsp[0].minor.yy259,0,0,0,0,0,-1,0);
-}
-#line 2237 "parse.c"
- break;
- case 123:
-#line 424 "parse.y"
-{yygotominor.yy98.z=0; yygotominor.yy98.n=0;}
-#line 2242 "parse.c"
- break;
- case 125:
-#line 429 "parse.y"
-{yygotominor.yy259 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy98,&yymsp[0].minor.yy98);}
-#line 2247 "parse.c"
- break;
- case 126:
- case 127:
-#line 433 "parse.y"
-{ yygotominor.yy284 = JT_INNER; }
-#line 2253 "parse.c"
- break;
- case 128:
-#line 435 "parse.y"
-{ yygotominor.yy284 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
-#line 2258 "parse.c"
- break;
- case 129:
-#line 436 "parse.y"
-{ yygotominor.yy284 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy98,0); }
-#line 2263 "parse.c"
- break;
- case 130:
-#line 438 "parse.y"
-{ yygotominor.yy284 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy98,&yymsp[-1].minor.yy98); }
-#line 2268 "parse.c"
- break;
- case 131:
- case 139:
- case 148:
- case 155:
- case 226:
- case 228:
- case 232:
-#line 442 "parse.y"
-{yygotominor.yy258 = yymsp[0].minor.yy258;}
-#line 2279 "parse.c"
- break;
- case 132:
- case 147:
- case 154:
- case 227:
- case 229:
- case 233:
-#line 443 "parse.y"
-{yygotominor.yy258 = 0;}
-#line 2289 "parse.c"
- break;
- case 133:
- case 166:
-#line 447 "parse.y"
-{yygotominor.yy272 = yymsp[-1].minor.yy272;}
-#line 2295 "parse.c"
- break;
- case 134:
- case 165:
-#line 448 "parse.y"
-{yygotominor.yy272 = 0;}
-#line 2301 "parse.c"
- break;
- case 136:
- case 146:
-#line 459 "parse.y"
-{yygotominor.yy210 = yymsp[0].minor.yy210;}
-#line 2307 "parse.c"
- break;
- case 137:
-#line 460 "parse.y"
-{
- yygotominor.yy210 = sqlite3ExprListAppend(yymsp[-4].minor.yy210,yymsp[-2].minor.yy258,yymsp[-1].minor.yy98.n>0?&yymsp[-1].minor.yy98:0);
- if( yygotominor.yy210 ) yygotominor.yy210->a[yygotominor.yy210->nExpr-1].sortOrder = yymsp[0].minor.yy284;
-}
-#line 2315 "parse.c"
- break;
- case 138:
-#line 464 "parse.y"
-{
- yygotominor.yy210 = sqlite3ExprListAppend(0,yymsp[-2].minor.yy258,yymsp[-1].minor.yy98.n>0?&yymsp[-1].minor.yy98:0);
- if( yygotominor.yy210 && yygotominor.yy210->a ) yygotominor.yy210->a[0].sortOrder = yymsp[0].minor.yy284;
-}
-#line 2323 "parse.c"
- break;
- case 140:
- case 142:
-#line 473 "parse.y"
-{yygotominor.yy284 = SQLITE_SO_ASC;}
-#line 2329 "parse.c"
- break;
- case 141:
-#line 474 "parse.y"
-{yygotominor.yy284 = SQLITE_SO_DESC;}
-#line 2334 "parse.c"
- break;
- case 143:
-#line 476 "parse.y"
-{yygotominor.yy98.z = 0; yygotominor.yy98.n = 0;}
-#line 2339 "parse.c"
- break;
- case 149:
-#line 490 "parse.y"
-{yygotominor.yy404.limit = -1; yygotominor.yy404.offset = 0;}
-#line 2344 "parse.c"
- break;
- case 150:
-#line 491 "parse.y"
-{yygotominor.yy404.limit = yymsp[0].minor.yy284; yygotominor.yy404.offset = 0;}
-#line 2349 "parse.c"
- break;
- case 151:
-#line 493 "parse.y"
-{yygotominor.yy404.limit = yymsp[-2].minor.yy284; yygotominor.yy404.offset = yymsp[0].minor.yy284;}
-#line 2354 "parse.c"
- break;
- case 152:
-#line 495 "parse.y"
-{yygotominor.yy404.limit = yymsp[0].minor.yy284; yygotominor.yy404.offset = yymsp[-2].minor.yy284;}
-#line 2359 "parse.c"
- break;
- case 153:
-#line 499 "parse.y"
-{sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy259,yymsp[0].minor.yy258);}
-#line 2364 "parse.c"
- break;
- case 156:
-#line 513 "parse.y"
-{sqlite3Update(pParse,yymsp[-3].minor.yy259,yymsp[-1].minor.yy210,yymsp[0].minor.yy258,yymsp[-4].minor.yy284);}
-#line 2369 "parse.c"
- break;
- case 157:
-#line 516 "parse.y"
-{yygotominor.yy210 = sqlite3ExprListAppend(yymsp[-4].minor.yy210,yymsp[0].minor.yy258,&yymsp[-2].minor.yy98);}
-#line 2374 "parse.c"
- break;
- case 158:
-#line 517 "parse.y"
-{yygotominor.yy210 = sqlite3ExprListAppend(0,yymsp[0].minor.yy258,&yymsp[-2].minor.yy98);}
-#line 2379 "parse.c"
- break;
- case 159:
-#line 523 "parse.y"
-{sqlite3Insert(pParse, yymsp[-5].minor.yy259, yymsp[-1].minor.yy210, 0, yymsp[-4].minor.yy272, yymsp[-7].minor.yy284);}
-#line 2384 "parse.c"
- break;
- case 160:
-#line 525 "parse.y"
-{sqlite3Insert(pParse, yymsp[-2].minor.yy259, 0, yymsp[0].minor.yy107, yymsp[-1].minor.yy272, yymsp[-4].minor.yy284);}
-#line 2389 "parse.c"
- break;
- case 163:
- case 230:
-#line 535 "parse.y"
-{yygotominor.yy210 = sqlite3ExprListAppend(yymsp[-2].minor.yy210,yymsp[0].minor.yy258,0);}
-#line 2395 "parse.c"
- break;
- case 164:
- case 231:
-#line 536 "parse.y"
-{yygotominor.yy210 = sqlite3ExprListAppend(0,yymsp[0].minor.yy258,0);}
-#line 2401 "parse.c"
- break;
- case 167:
-#line 545 "parse.y"
-{yygotominor.yy272 = sqlite3IdListAppend(yymsp[-2].minor.yy272,&yymsp[0].minor.yy98);}
-#line 2406 "parse.c"
- break;
- case 168:
-#line 546 "parse.y"
-{yygotominor.yy272 = sqlite3IdListAppend(0,&yymsp[0].minor.yy98);}
-#line 2411 "parse.c"
- break;
- case 169:
-#line 554 "parse.y"
-{yygotominor.yy258 = yymsp[-1].minor.yy258; sqlite3ExprSpan(yygotominor.yy258,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); }
-#line 2416 "parse.c"
- break;
- case 170:
- case 175:
- case 176:
- case 177:
- case 178:
-#line 555 "parse.y"
-{yygotominor.yy258 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);}
-#line 2425 "parse.c"
- break;
- case 171:
- case 172:
-#line 556 "parse.y"
-{yygotominor.yy258 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);}
-#line 2431 "parse.c"
- break;
- case 173:
-#line 558 "parse.y"
-{
- Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy98);
- Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy98);
- yygotominor.yy258 = sqlite3Expr(TK_DOT, temp1, temp2, 0);
-}
-#line 2440 "parse.c"
- break;
- case 174:
-#line 563 "parse.y"
-{
- Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-4].minor.yy98);
- Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy98);
- Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy98);
- Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0);
- yygotominor.yy258 = sqlite3Expr(TK_DOT, temp1, temp4, 0);
-}
-#line 2451 "parse.c"
- break;
- case 179:
-#line 574 "parse.y"
-{
- Token *pToken = &yymsp[0].minor.yy0;
- Expr *pExpr = yygotominor.yy258 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
- sqlite3ExprAssignVarNumber(pParse, pExpr);
-}
-#line 2460 "parse.c"
- break;
- case 180:
-#line 579 "parse.y"
-{
- yygotominor.yy258 = sqlite3ExprFunction(yymsp[-1].minor.yy210, &yymsp[-3].minor.yy0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
-}
-#line 2468 "parse.c"
- break;
- case 181:
-#line 583 "parse.y"
-{
- yygotominor.yy258 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
-}
-#line 2476 "parse.c"
- break;
- case 182:
- case 183:
- case 184:
- case 185:
- case 186:
- case 187:
- case 188:
- case 189:
- case 190:
- case 191:
- case 192:
- case 193:
- case 194:
- case 195:
- case 196:
- case 197:
- case 198:
- case 199:
-#line 587 "parse.y"
-{yygotominor.yy258 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy258, yymsp[0].minor.yy258, 0);}
-#line 2498 "parse.c"
- break;
- case 200:
-#line 606 "parse.y"
-{yygotominor.yy342.opcode = TK_LIKE; yygotominor.yy342.not = 0;}
-#line 2503 "parse.c"
- break;
- case 201:
-#line 607 "parse.y"
-{yygotominor.yy342.opcode = TK_GLOB; yygotominor.yy342.not = 0;}
-#line 2508 "parse.c"
- break;
- case 202:
-#line 608 "parse.y"
-{yygotominor.yy342.opcode = TK_LIKE; yygotominor.yy342.not = 1;}
-#line 2513 "parse.c"
- break;
- case 203:
-#line 609 "parse.y"
-{yygotominor.yy342.opcode = TK_GLOB; yygotominor.yy342.not = 1;}
-#line 2518 "parse.c"
- break;
- case 204:
-#line 610 "parse.y"
-{
- ExprList *pList = sqlite3ExprListAppend(0, yymsp[0].minor.yy258, 0);
- pList = sqlite3ExprListAppend(pList, yymsp[-2].minor.yy258, 0);
- yygotominor.yy258 = sqlite3ExprFunction(pList, 0);
- if( yygotominor.yy258 ) yygotominor.yy258->op = yymsp[-1].minor.yy342.opcode;
- if( yymsp[-1].minor.yy342.not ) yygotominor.yy258 = sqlite3Expr(TK_NOT, yygotominor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258, &yymsp[-2].minor.yy258->span, &yymsp[0].minor.yy258->span);
-}
-#line 2530 "parse.c"
- break;
- case 205:
-#line 618 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_ISNULL, yymsp[-1].minor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-1].minor.yy258->span,&yymsp[0].minor.yy0);
-}
-#line 2538 "parse.c"
- break;
- case 206:
-#line 622 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-2].minor.yy258->span,&yymsp[0].minor.yy0);
-}
-#line 2546 "parse.c"
- break;
- case 207:
-#line 626 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_NOTNULL, yymsp[-1].minor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-1].minor.yy258->span,&yymsp[0].minor.yy0);
-}
-#line 2554 "parse.c"
- break;
- case 208:
-#line 630 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-2].minor.yy258->span,&yymsp[0].minor.yy0);
-}
-#line 2562 "parse.c"
- break;
- case 209:
-#line 634 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-3].minor.yy258->span,&yymsp[0].minor.yy0);
-}
-#line 2570 "parse.c"
- break;
- case 210:
- case 211:
-#line 638 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy258->span);
-}
-#line 2579 "parse.c"
- break;
- case 212:
-#line 646 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy258->span);
-}
-#line 2587 "parse.c"
- break;
- case 213:
-#line 650 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy258->span);
-}
-#line 2595 "parse.c"
- break;
- case 214:
-#line 654 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_SELECT, 0, 0, 0);
- if( yygotominor.yy258 ) yygotominor.yy258->pSelect = yymsp[-1].minor.yy107;
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
-}
-#line 2604 "parse.c"
- break;
- case 217:
-#line 662 "parse.y"
-{
- ExprList *pList = sqlite3ExprListAppend(0, yymsp[-2].minor.yy258, 0);
- pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy258, 0);
- yygotominor.yy258 = sqlite3Expr(TK_BETWEEN, yymsp[-4].minor.yy258, 0, 0);
- if( yygotominor.yy258 ) yygotominor.yy258->pList = pList;
- if( yymsp[-3].minor.yy284 ) yygotominor.yy258 = sqlite3Expr(TK_NOT, yygotominor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-4].minor.yy258->span,&yymsp[0].minor.yy258->span);
-}
-#line 2616 "parse.c"
- break;
- case 220:
-#line 673 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy258, 0, 0);
- if( yygotominor.yy258 ) yygotominor.yy258->pList = yymsp[-1].minor.yy210;
- if( yymsp[-3].minor.yy284 ) yygotominor.yy258 = sqlite3Expr(TK_NOT, yygotominor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-4].minor.yy258->span,&yymsp[0].minor.yy0);
-}
-#line 2626 "parse.c"
- break;
- case 221:
-#line 679 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy258, 0, 0);
- if( yygotominor.yy258 ) yygotominor.yy258->pSelect = yymsp[-1].minor.yy107;
- if( yymsp[-3].minor.yy284 ) yygotominor.yy258 = sqlite3Expr(TK_NOT, yygotominor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-4].minor.yy258->span,&yymsp[0].minor.yy0);
-}
-#line 2636 "parse.c"
- break;
- case 222:
-#line 685 "parse.y"
-{
- SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy98,&yymsp[0].minor.yy98);
- yygotominor.yy258 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy258, 0, 0);
- if( yygotominor.yy258 ) yygotominor.yy258->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,-1,0);
- if( yymsp[-2].minor.yy284 ) yygotominor.yy258 = sqlite3Expr(TK_NOT, yygotominor.yy258, 0, 0);
- sqlite3ExprSpan(yygotominor.yy258,&yymsp[-3].minor.yy258->span,yymsp[0].minor.yy98.z?&yymsp[0].minor.yy98:&yymsp[-1].minor.yy98);
-}
-#line 2647 "parse.c"
- break;
- case 223:
-#line 695 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy258, yymsp[-1].minor.yy258, 0);
- if( yygotominor.yy258 ) yygotominor.yy258->pList = yymsp[-2].minor.yy210;
- sqlite3ExprSpan(yygotominor.yy258, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0);
-}
-#line 2656 "parse.c"
- break;
- case 224:
-#line 702 "parse.y"
-{
- yygotominor.yy210 = sqlite3ExprListAppend(yymsp[-4].minor.yy210, yymsp[-2].minor.yy258, 0);
- yygotominor.yy210 = sqlite3ExprListAppend(yygotominor.yy210, yymsp[0].minor.yy258, 0);
-}
-#line 2664 "parse.c"
- break;
- case 225:
-#line 706 "parse.y"
-{
- yygotominor.yy210 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy258, 0);
- yygotominor.yy210 = sqlite3ExprListAppend(yygotominor.yy210, yymsp[0].minor.yy258, 0);
-}
-#line 2672 "parse.c"
- break;
- case 234:
-#line 731 "parse.y"
-{
- if( yymsp[-9].minor.yy284!=OE_None ) yymsp[-9].minor.yy284 = yymsp[0].minor.yy284;
- if( yymsp[-9].minor.yy284==OE_Default) yymsp[-9].minor.yy284 = OE_Abort;
- sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy98, &yymsp[-6].minor.yy98, yymsp[-4].minor.yy259, yymsp[-2].minor.yy210, yymsp[-9].minor.yy284, &yymsp[-10].minor.yy0, &yymsp[-1].minor.yy0);
-}
-#line 2681 "parse.c"
- break;
- case 235:
- case 282:
-#line 738 "parse.y"
-{yygotominor.yy284 = OE_Abort;}
-#line 2687 "parse.c"
- break;
- case 236:
-#line 739 "parse.y"
-{yygotominor.yy284 = OE_None;}
-#line 2692 "parse.c"
- break;
- case 239:
-#line 749 "parse.y"
-{
- Expr *p = 0;
- if( yymsp[-1].minor.yy98.n>0 ){
- p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
- if( p ) p->pColl = sqlite3LocateCollSeq(pParse, yymsp[-1].minor.yy98.z, yymsp[-1].minor.yy98.n);
- }
- yygotominor.yy210 = sqlite3ExprListAppend(yymsp[-4].minor.yy210, p, &yymsp[-2].minor.yy98);
-}
-#line 2704 "parse.c"
- break;
- case 240:
-#line 757 "parse.y"
-{
- Expr *p = 0;
- if( yymsp[-1].minor.yy98.n>0 ){
- p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
- if( p ) p->pColl = sqlite3LocateCollSeq(pParse, yymsp[-1].minor.yy98.z, yymsp[-1].minor.yy98.n);
- }
- yygotominor.yy210 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy98);
-}
-#line 2716 "parse.c"
- break;
- case 242:
-#line 770 "parse.y"
-{sqlite3DropIndex(pParse, yymsp[0].minor.yy259);}
-#line 2721 "parse.c"
- break;
- case 243:
- case 244:
-#line 774 "parse.y"
-{sqlite3Vacuum(pParse,0);}
-#line 2727 "parse.c"
- break;
- case 245:
- case 247:
-#line 779 "parse.y"
-{sqlite3Pragma(pParse,&yymsp[-3].minor.yy98,&yymsp[-2].minor.yy98,&yymsp[0].minor.yy98,0);}
-#line 2733 "parse.c"
- break;
- case 246:
-#line 780 "parse.y"
-{sqlite3Pragma(pParse,&yymsp[-3].minor.yy98,&yymsp[-2].minor.yy98,&yymsp[0].minor.yy0,0);}
-#line 2738 "parse.c"
- break;
- case 248:
-#line 782 "parse.y"
-{
- sqlite3Pragma(pParse,&yymsp[-3].minor.yy98,&yymsp[-2].minor.yy98,&yymsp[0].minor.yy98,1);
-}
-#line 2745 "parse.c"
- break;
- case 249:
-#line 785 "parse.y"
-{sqlite3Pragma(pParse,&yymsp[-4].minor.yy98,&yymsp[-3].minor.yy98,&yymsp[-1].minor.yy98,0);}
-#line 2750 "parse.c"
- break;
- case 250:
-#line 786 "parse.y"
-{sqlite3Pragma(pParse,&yymsp[-1].minor.yy98,&yymsp[0].minor.yy98,0,0);}
-#line 2755 "parse.c"
- break;
- case 257:
-#line 796 "parse.y"
-{
- Token all;
- all.z = yymsp[-3].minor.yy98.z;
- all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy98.z) + yymsp[0].minor.yy0.n;
- sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy91, &all);
-}
-#line 2765 "parse.c"
- break;
- case 258:
-#line 805 "parse.y"
-{
- sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy98, &yymsp[-6].minor.yy98, yymsp[-5].minor.yy284, yymsp[-4].minor.yy146.a, yymsp[-4].minor.yy146.b, yymsp[-2].minor.yy259, yymsp[-1].minor.yy284, yymsp[0].minor.yy258, yymsp[-9].minor.yy284);
- yygotominor.yy98 = (yymsp[-6].minor.yy98.n==0?yymsp[-7].minor.yy98:yymsp[-6].minor.yy98);
-}
-#line 2773 "parse.c"
- break;
- case 259:
- case 262:
-#line 811 "parse.y"
-{ yygotominor.yy284 = TK_BEFORE; }
-#line 2779 "parse.c"
- break;
- case 260:
-#line 812 "parse.y"
-{ yygotominor.yy284 = TK_AFTER; }
-#line 2784 "parse.c"
- break;
- case 261:
-#line 813 "parse.y"
-{ yygotominor.yy284 = TK_INSTEAD;}
-#line 2789 "parse.c"
- break;
- case 263:
- case 264:
- case 265:
-#line 818 "parse.y"
-{yygotominor.yy146.a = yymsp[0].major; yygotominor.yy146.b = 0;}
-#line 2796 "parse.c"
- break;
- case 266:
-#line 821 "parse.y"
-{yygotominor.yy146.a = TK_UPDATE; yygotominor.yy146.b = yymsp[0].minor.yy272;}
-#line 2801 "parse.c"
- break;
- case 267:
- case 268:
-#line 824 "parse.y"
-{ yygotominor.yy284 = TK_ROW; }
-#line 2807 "parse.c"
- break;
- case 269:
-#line 826 "parse.y"
-{ yygotominor.yy284 = TK_STATEMENT; }
-#line 2812 "parse.c"
- break;
- case 270:
-#line 829 "parse.y"
-{ yygotominor.yy258 = 0; }
-#line 2817 "parse.c"
- break;
- case 271:
-#line 830 "parse.y"
-{ yygotominor.yy258 = yymsp[0].minor.yy258; }
-#line 2822 "parse.c"
- break;
- case 272:
-#line 834 "parse.y"
-{
- yymsp[-2].minor.yy91->pNext = yymsp[0].minor.yy91;
- yygotominor.yy91 = yymsp[-2].minor.yy91;
-}
-#line 2830 "parse.c"
- break;
- case 273:
-#line 838 "parse.y"
-{ yygotominor.yy91 = 0; }
-#line 2835 "parse.c"
- break;
- case 274:
-#line 844 "parse.y"
-{ yygotominor.yy91 = sqlite3TriggerUpdateStep(&yymsp[-3].minor.yy98, yymsp[-1].minor.yy210, yymsp[0].minor.yy258, yymsp[-4].minor.yy284); }
-#line 2840 "parse.c"
- break;
- case 275:
-#line 849 "parse.y"
-{yygotominor.yy91 = sqlite3TriggerInsertStep(&yymsp[-5].minor.yy98, yymsp[-4].minor.yy272, yymsp[-1].minor.yy210, 0, yymsp[-7].minor.yy284);}
-#line 2845 "parse.c"
- break;
- case 276:
-#line 852 "parse.y"
-{yygotominor.yy91 = sqlite3TriggerInsertStep(&yymsp[-2].minor.yy98, yymsp[-1].minor.yy272, 0, yymsp[0].minor.yy107, yymsp[-4].minor.yy284);}
-#line 2850 "parse.c"
- break;
- case 277:
-#line 856 "parse.y"
-{yygotominor.yy91 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy98, yymsp[0].minor.yy258);}
-#line 2855 "parse.c"
- break;
- case 278:
-#line 859 "parse.y"
-{yygotominor.yy91 = sqlite3TriggerSelectStep(yymsp[0].minor.yy107); }
-#line 2860 "parse.c"
- break;
- case 279:
-#line 862 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_RAISE, 0, 0, 0);
- yygotominor.yy258->iColumn = OE_Ignore;
- sqlite3ExprSpan(yygotominor.yy258, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0);
-}
-#line 2869 "parse.c"
- break;
- case 280:
-#line 867 "parse.y"
-{
- yygotominor.yy258 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy98);
- yygotominor.yy258->iColumn = yymsp[-3].minor.yy284;
- sqlite3ExprSpan(yygotominor.yy258, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0);
-}
-#line 2878 "parse.c"
- break;
- case 281:
-#line 873 "parse.y"
-{yygotominor.yy284 = OE_Rollback;}
-#line 2883 "parse.c"
- break;
- case 283:
-#line 875 "parse.y"
-{yygotominor.yy284 = OE_Fail;}
-#line 2888 "parse.c"
- break;
- case 284:
-#line 879 "parse.y"
-{
- sqlite3DropTrigger(pParse,yymsp[0].minor.yy259);
-}
-#line 2895 "parse.c"
- break;
- case 285:
-#line 884 "parse.y"
-{
- sqlite3Attach(pParse, &yymsp[-3].minor.yy98, &yymsp[-1].minor.yy98, yymsp[0].minor.yy292.type, &yymsp[0].minor.yy292.key);
-}
-#line 2902 "parse.c"
- break;
- case 286:
-#line 888 "parse.y"
-{ yygotominor.yy292.type = 0; }
-#line 2907 "parse.c"
- break;
- case 287:
-#line 889 "parse.y"
-{ yygotominor.yy292.type=1; yygotominor.yy292.key = yymsp[0].minor.yy98; }
-#line 2912 "parse.c"
- break;
- case 288:
-#line 890 "parse.y"
-{ yygotominor.yy292.type=2; yygotominor.yy292.key = yymsp[0].minor.yy0; }
-#line 2917 "parse.c"
- break;
- case 291:
-#line 896 "parse.y"
-{
- sqlite3Detach(pParse, &yymsp[0].minor.yy98);
-}
-#line 2924 "parse.c"
- break;
- };
- yygoto = yyRuleInfo[yyruleno].lhs;
- yysize = yyRuleInfo[yyruleno].nrhs;
- yypParser->yyidx -= yysize;
- yyact = yy_find_reduce_action(yypParser,yygoto);
- if( yyact < YYNSTATE ){
- yy_shift(yypParser,yyact,yygoto,&yygotominor);
- }else if( yyact == YYNSTATE + YYNRULE + 1 ){
- yy_accept(yypParser);
- }
-}
-
-/*
-** The following code executes when the parse fails
-*/
-static void yy_parse_failed(
- yyParser *yypParser /* The parser */
-){
- sqlite3ParserARG_FETCH;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will be executed whenever the
- ** parser fails */
- sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-
-/*
-** The following code executes when a syntax error first occurs.
-*/
-static void yy_syntax_error(
- yyParser *yypParser, /* The parser */
- int yymajor, /* The major type of the error token */
- YYMINORTYPE yyminor /* The minor type of the error token */
-){
- sqlite3ParserARG_FETCH;
-#define TOKEN (yyminor.yy0)
-#line 23 "parse.y"
-
- if( pParse->zErrMsg==0 ){
- if( TOKEN.z[0] ){
- sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
- }else{
- sqlite3ErrorMsg(pParse, "incomplete SQL statement");
- }
- }
-#line 2976 "parse.c"
- sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-
-/*
-** The following is executed when the parser accepts
-*/
-static void yy_accept(
- yyParser *yypParser /* The parser */
-){
- sqlite3ParserARG_FETCH;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will be executed whenever the
- ** parser accepts */
- sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-
-/* The main parser program.
-** The first argument is a pointer to a structure obtained from
-** "sqlite3ParserAlloc" which describes the current state of the parser.
-** The second argument is the major token number. The third is
-** the minor token. The fourth optional argument is whatever the
-** user wants (and specified in the grammar) and is available for
-** use by the action routines.
-**
-** Inputs:
-** <ul>
-** <li> A pointer to the parser (an opaque structure.)
-** <li> The major token number.
-** <li> The minor token number.
-** <li> An option argument of a grammar-specified type.
-** </ul>
-**
-** Outputs:
-** None.
-*/
-void sqlite3Parser(
- void *yyp, /* The parser */
- int yymajor, /* The major token code number */
- sqlite3ParserTOKENTYPE yyminor /* The value for the token */
- sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */
-){
- YYMINORTYPE yyminorunion;
- int yyact; /* The parser action. */
- int yyendofinput; /* True if we are at the end of input */
- int yyerrorhit = 0; /* True if yymajor has invoked an error */
- yyParser *yypParser; /* The parser */
-
- /* (re)initialize the parser, if necessary */
- yypParser = (yyParser*)yyp;
- if( yypParser->yyidx<0 ){
- if( yymajor==0 ) return;
- yypParser->yyidx = 0;
- yypParser->yyerrcnt = -1;
- yypParser->yystack[0].stateno = 0;
- yypParser->yystack[0].major = 0;
- }
- yyminorunion.yy0 = yyminor;
- yyendofinput = (yymajor==0);
- sqlite3ParserARG_STORE;
-
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
- }
-#endif
-
- do{
- yyact = yy_find_shift_action(yypParser,yymajor);
- if( yyact<YYNSTATE ){
- yy_shift(yypParser,yyact,yymajor,&yyminorunion);
- yypParser->yyerrcnt--;
- if( yyendofinput && yypParser->yyidx>=0 ){
- yymajor = 0;
- }else{
- yymajor = YYNOCODE;
- }
- }else if( yyact < YYNSTATE + YYNRULE ){
- yy_reduce(yypParser,yyact-YYNSTATE);
- }else if( yyact == YY_ERROR_ACTION ){
- int yymx;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
- }
-#endif
-#ifdef YYERRORSYMBOL
- /* A syntax error has occurred.
- ** The response to an error depends upon whether or not the
- ** grammar defines an error token "ERROR".
- **
- ** This is what we do if the grammar does define ERROR:
- **
- ** * Call the %syntax_error function.
- **
- ** * Begin popping the stack until we enter a state where
- ** it is legal to shift the error symbol, then shift
- ** the error symbol.
- **
- ** * Set the error count to three.
- **
- ** * Begin accepting and shifting new tokens. No new error
- ** processing will occur until three tokens have been
- ** shifted successfully.
- **
- */
- if( yypParser->yyerrcnt<0 ){
- yy_syntax_error(yypParser,yymajor,yyminorunion);
- }
- yymx = yypParser->yystack[yypParser->yyidx].major;
- if( yymx==YYERRORSYMBOL || yyerrorhit ){
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sDiscard input token %s\n",
- yyTracePrompt,yyTokenName[yymajor]);
- }
-#endif
- yy_destructor(yymajor,&yyminorunion);
- yymajor = YYNOCODE;
- }else{
- while(
- yypParser->yyidx >= 0 &&
- yymx != YYERRORSYMBOL &&
- (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
- ){
- yy_pop_parser_stack(yypParser);
- }
- if( yypParser->yyidx < 0 || yymajor==0 ){
- yy_destructor(yymajor,&yyminorunion);
- yy_parse_failed(yypParser);
- yymajor = YYNOCODE;
- }else if( yymx!=YYERRORSYMBOL ){
- YYMINORTYPE u2;
- u2.YYERRSYMDT = 0;
- yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
- }
- }
- yypParser->yyerrcnt = 3;
- yyerrorhit = 1;
-#else /* YYERRORSYMBOL is not defined */
- /* This is what we do if the grammar does not define ERROR:
- **
- ** * Report an error message, and throw away the input token.
- **
- ** * If the input token is $, then fail the parse.
- **
- ** As before, subsequent error messages are suppressed until
- ** three input tokens have been successfully shifted.
- */
- if( yypParser->yyerrcnt<=0 ){
- yy_syntax_error(yypParser,yymajor,yyminorunion);
- }
- yypParser->yyerrcnt = 3;
- yy_destructor(yymajor,&yyminorunion);
- if( yyendofinput ){
- yy_parse_failed(yypParser);
- }
- yymajor = YYNOCODE;
-#endif
- }else{
- yy_accept(yypParser);
- yymajor = YYNOCODE;
- }
- }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
- return;
-}
diff --git a/kopete/plugins/statistics/sqlite/parse.h b/kopete/plugins/statistics/sqlite/parse.h
deleted file mode 100644
index 547319ed..00000000
--- a/kopete/plugins/statistics/sqlite/parse.h
+++ /dev/null
@@ -1,129 +0,0 @@
-#define TK_END_OF_FILE 1
-#define TK_ILLEGAL 2
-#define TK_SPACE 3
-#define TK_UNCLOSED_STRING 4
-#define TK_COMMENT 5
-#define TK_FUNCTION 6
-#define TK_COLUMN 7
-#define TK_AGG_FUNCTION 8
-#define TK_SEMI 9
-#define TK_EXPLAIN 10
-#define TK_BEGIN 11
-#define TK_TRANSACTION 12
-#define TK_DEFERRED 13
-#define TK_IMMEDIATE 14
-#define TK_EXCLUSIVE 15
-#define TK_COMMIT 16
-#define TK_END 17
-#define TK_ROLLBACK 18
-#define TK_CREATE 19
-#define TK_TABLE 20
-#define TK_TEMP 21
-#define TK_LP 22
-#define TK_RP 23
-#define TK_AS 24
-#define TK_COMMA 25
-#define TK_ID 26
-#define TK_ABORT 27
-#define TK_AFTER 28
-#define TK_ASC 29
-#define TK_ATTACH 30
-#define TK_BEFORE 31
-#define TK_CASCADE 32
-#define TK_CONFLICT 33
-#define TK_DATABASE 34
-#define TK_DESC 35
-#define TK_DETACH 36
-#define TK_EACH 37
-#define TK_FAIL 38
-#define TK_FOR 39
-#define TK_GLOB 40
-#define TK_IGNORE 41
-#define TK_INITIALLY 42
-#define TK_INSTEAD 43
-#define TK_LIKE 44
-#define TK_MATCH 45
-#define TK_KEY 46
-#define TK_OF 47
-#define TK_OFFSET 48
-#define TK_PRAGMA 49
-#define TK_RAISE 50
-#define TK_REPLACE 51
-#define TK_RESTRICT 52
-#define TK_ROW 53
-#define TK_STATEMENT 54
-#define TK_TRIGGER 55
-#define TK_VACUUM 56
-#define TK_VIEW 57
-#define TK_OR 58
-#define TK_AND 59
-#define TK_NOT 60
-#define TK_IS 61
-#define TK_BETWEEN 62
-#define TK_IN 63
-#define TK_ISNULL 64
-#define TK_NOTNULL 65
-#define TK_NE 66
-#define TK_EQ 67
-#define TK_GT 68
-#define TK_LE 69
-#define TK_LT 70
-#define TK_GE 71
-#define TK_BITAND 72
-#define TK_BITOR 73
-#define TK_LSHIFT 74
-#define TK_RSHIFT 75
-#define TK_PLUS 76
-#define TK_MINUS 77
-#define TK_STAR 78
-#define TK_SLASH 79
-#define TK_REM 80
-#define TK_CONCAT 81
-#define TK_UMINUS 82
-#define TK_UPLUS 83
-#define TK_BITNOT 84
-#define TK_STRING 85
-#define TK_JOIN_KW 86
-#define TK_CONSTRAINT 87
-#define TK_DEFAULT 88
-#define TK_NULL 89
-#define TK_PRIMARY 90
-#define TK_UNIQUE 91
-#define TK_CHECK 92
-#define TK_REFERENCES 93
-#define TK_COLLATE 94
-#define TK_ON 95
-#define TK_DELETE 96
-#define TK_UPDATE 97
-#define TK_INSERT 98
-#define TK_SET 99
-#define TK_DEFERRABLE 100
-#define TK_FOREIGN 101
-#define TK_DROP 102
-#define TK_UNION 103
-#define TK_ALL 104
-#define TK_INTERSECT 105
-#define TK_EXCEPT 106
-#define TK_SELECT 107
-#define TK_DISTINCT 108
-#define TK_DOT 109
-#define TK_FROM 110
-#define TK_JOIN 111
-#define TK_USING 112
-#define TK_ORDER 113
-#define TK_BY 114
-#define TK_GROUP 115
-#define TK_HAVING 116
-#define TK_LIMIT 117
-#define TK_WHERE 118
-#define TK_INTO 119
-#define TK_VALUES 120
-#define TK_INTEGER 121
-#define TK_FLOAT 122
-#define TK_BLOB 123
-#define TK_VARIABLE 124
-#define TK_CASE 125
-#define TK_WHEN 126
-#define TK_THEN 127
-#define TK_ELSE 128
-#define TK_INDEX 129
diff --git a/kopete/plugins/statistics/sqlite/pragma.c b/kopete/plugins/statistics/sqlite/pragma.c
deleted file mode 100644
index 94a21863..00000000
--- a/kopete/plugins/statistics/sqlite/pragma.c
+++ /dev/null
@@ -1,754 +0,0 @@
-/*
-** 2003 April 6
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains code used to implement the PRAGMA command.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-#include <ctype.h>
-
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
-# include "pager.h"
-# include "btree.h"
-#endif
-
-/*
-** Interpret the given string as a boolean value.
-*/
-static int getBoolean(const u8 *z){
- static const u8 *azTrue[] = { "yes", "on", "true" };
- int i;
- if( z[0]==0 ) return 0;
- if( sqlite3IsNumber(z, 0, SQLITE_UTF8) ){
- return atoi(z);
- }
- for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){
- if( sqlite3StrICmp(z,azTrue[i])==0 ) return 1;
- }
- return 0;
-}
-
-/*
-** Interpret the given string as a safety level. Return 0 for OFF,
-** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
-** unrecognized string argument.
-**
-** Note that the values returned are one less that the values that
-** should be passed into sqlite3BtreeSetSafetyLevel(). The is done
-** to support legacy SQL code. The safety level used to be boolean
-** and older scripts may have used numbers 0 for OFF and 1 for ON.
-*/
-static int getSafetyLevel(u8 *z){
- static const struct {
- const u8 *zWord;
- int val;
- } aKey[] = {
- { "no", 0 },
- { "off", 0 },
- { "false", 0 },
- { "yes", 1 },
- { "on", 1 },
- { "true", 1 },
- { "full", 2 },
- };
- int i;
- if( z[0]==0 ) return 1;
- if( sqlite3IsNumber(z, 0, SQLITE_UTF8) ){
- return atoi(z);
- }
- for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){
- if( sqlite3StrICmp(z,aKey[i].zWord)==0 ) return aKey[i].val;
- }
- return 1;
-}
-
-/*
-** Interpret the given string as a temp db location. Return 1 for file
-** backed temporary databases, 2 for the Red-Black tree in memory database
-** and 0 to use the compile-time default.
-*/
-static int getTempStore(const char *z){
- if( z[0]>='0' && z[0]<='2' ){
- return z[0] - '0';
- }else if( sqlite3StrICmp(z, "file")==0 ){
- return 1;
- }else if( sqlite3StrICmp(z, "memory")==0 ){
- return 2;
- }else{
- return 0;
- }
-}
-
-/*
-** If the TEMP database is open, close it and mark the database schema
-** as needing reloading. This must be done when using the TEMP_STORE
-** or DEFAULT_TEMP_STORE pragmas.
-*/
-static int changeTempStorage(Parse *pParse, const char *zStorageType){
- int ts = getTempStore(zStorageType);
- sqlite3 *db = pParse->db;
- if( db->temp_store==ts ) return SQLITE_OK;
- if( db->aDb[1].pBt!=0 ){
- if( db->flags & SQLITE_InTrans ){
- sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
- "from within a transaction");
- return SQLITE_ERROR;
- }
- sqlite3BtreeClose(db->aDb[1].pBt);
- db->aDb[1].pBt = 0;
- sqlite3ResetInternalSchema(db, 0);
- }
- db->temp_store = ts;
- return SQLITE_OK;
-}
-
-/*
-** Generate code to return a single integer value.
-*/
-static void returnSingleInt(Parse *pParse, const char *zLabel, int value){
- Vdbe *v = sqlite3GetVdbe(pParse);
- sqlite3VdbeAddOp(v, OP_Integer, value, 0);
- if( pParse->explain==0 ){
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, zLabel, P3_STATIC);
- }
- sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
-}
-
-/*
-** Check to see if zRight and zLeft refer to a pragma that queries
-** or changes one of the flags in db->flags. Return 1 if so and 0 if not.
-** Also, implement the pragma.
-*/
-static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
- static const struct {
- const char *zName; /* Name of the pragma */
- int mask; /* Mask for the db->flags value */
- } aPragma[] = {
- { "vdbe_trace", SQLITE_VdbeTrace },
- { "sql_trace", SQLITE_SqlTrace },
- { "vdbe_listing", SQLITE_VdbeListing },
-#if 1 /* FIX ME: Remove the following pragmas */
- { "full_column_names", SQLITE_FullColNames },
- { "short_column_names", SQLITE_ShortColNames },
- { "count_changes", SQLITE_CountRows },
- { "empty_result_callbacks", SQLITE_NullCallback },
-#endif
- };
- int i;
- for(i=0; i<sizeof(aPragma)/sizeof(aPragma[0]); i++){
- if( sqlite3StrICmp(zLeft, aPragma[i].zName)==0 ){
- sqlite3 *db = pParse->db;
- Vdbe *v;
- if( zRight==0 ){
- v = sqlite3GetVdbe(pParse);
- if( v ){
- returnSingleInt(pParse,
- aPragma[i].zName, (db->flags&aPragma[i].mask)!=0);
- }
- }else if( getBoolean(zRight) ){
- db->flags |= aPragma[i].mask;
- }else{
- db->flags &= ~aPragma[i].mask;
- }
- return 1;
- }
- }
- return 0;
-}
-
-/*
-** Process a pragma statement.
-**
-** Pragmas are of this form:
-**
-** PRAGMA [database.]id [= value]
-**
-** The identifier might also be a string. The value is a string, and
-** identifier, or a number. If minusFlag is true, then the value is
-** a number that was preceded by a minus sign.
-**
-** If the left side is "database.id" then pId1 is the database name
-** and pId2 is the id. If the left side is just "id" then pId1 is the
-** id and pId2 is any empty string.
-*/
-void sqlite3Pragma(
- Parse *pParse,
- Token *pId1, /* First part of [database.]id field */
- Token *pId2, /* Second part of [database.]id field, or NULL */
- Token *pValue, /* Token for <value>, or NULL */
- int minusFlag /* True if a '-' sign preceded <value> */
-){
- char *zLeft = 0; /* Nul-terminated UTF-8 string <id> */
- char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */
- const char *zDb = 0; /* The database name */
- Token *pId; /* Pointer to <id> token */
- int iDb; /* Database index for <database> */
- sqlite3 *db = pParse->db;
- Db *pDb;
- Vdbe *v = sqlite3GetVdbe(pParse);
- if( v==0 ) return;
-
- /* Interpret the [database.] part of the pragma statement. iDb is the
- ** index of the database this pragma is being applied to in db.aDb[]. */
- iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId);
- if( iDb<0 ) return;
- pDb = &db->aDb[iDb];
-
- zLeft = sqlite3NameFromToken(pId);
- if( !zLeft ) return;
- if( minusFlag ){
- zRight = sqlite3MPrintf("-%T", pValue);
- }else{
- zRight = sqlite3NameFromToken(pValue);
- }
-
- zDb = ((iDb>0)?pDb->zName:0);
- if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
- goto pragma_out;
- }
-
- /*
- ** PRAGMA [database.]default_cache_size
- ** PRAGMA [database.]default_cache_size=N
- **
- ** The first form reports the current persistent setting for the
- ** page cache size. The value returned is the maximum number of
- ** pages in the page cache. The second form sets both the current
- ** page cache size value and the persistent page cache size value
- ** stored in the database file.
- **
- ** The default cache size is stored in meta-value 2 of page 1 of the
- ** database file. The cache size is actually the absolute value of
- ** this memory location. The sign of meta-value 2 determines the
- ** synchronous setting. A negative value means synchronous is off
- ** and a positive value means synchronous is on.
- */
- if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
- static const VdbeOpList getCacheSize[] = {
- { OP_ReadCookie, 0, 2, 0}, /* 0 */
- { OP_AbsValue, 0, 0, 0},
- { OP_Dup, 0, 0, 0},
- { OP_Integer, 0, 0, 0},
- { OP_Ne, 0, 6, 0},
- { OP_Integer, 0, 0, 0}, /* 5 */
- { OP_Callback, 1, 0, 0},
- };
- int addr;
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
- if( !zRight ){
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, "cache_size", P3_STATIC);
- addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
- sqlite3VdbeChangeP1(v, addr, iDb);
- sqlite3VdbeChangeP1(v, addr+5, MAX_PAGES);
- }else{
- int size = atoi(zRight);
- if( size<0 ) size = -size;
- sqlite3BeginWriteOperation(pParse, 0, iDb);
- sqlite3VdbeAddOp(v, OP_Integer, size, 0);
- sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 2);
- addr = sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
- sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3);
- sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
- sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2);
- pDb->cache_size = size;
- sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
- }
- }else
-
- /*
- ** PRAGMA [database.]page_size
- ** PRAGMA [database.]page_size=N
- **
- ** The first form reports the current setting for the
- ** database page size in bytes. The second form sets the
- ** database page size value. The value can only be set if
- ** the database has not yet been created.
- */
- if( sqlite3StrICmp(zLeft,"page_size")==0 ){
- Btree *pBt = pDb->pBt;
- if( !zRight ){
- int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0;
- returnSingleInt(pParse, "page_size", size);
- }else{
- sqlite3BtreeSetPageSize(pBt, atoi(zRight), sqlite3BtreeGetReserve(pBt));
- }
- }else
-
- /*
- ** PRAGMA [database.]cache_size
- ** PRAGMA [database.]cache_size=N
- **
- ** The first form reports the current local setting for the
- ** page cache size. The local setting can be different from
- ** the persistent cache size value that is stored in the database
- ** file itself. The value returned is the maximum number of
- ** pages in the page cache. The second form sets the local
- ** page cache size value. It does not change the persistent
- ** cache size stored on the disk so the cache size will revert
- ** to its default value when the database is closed and reopened.
- ** N should be a positive integer.
- */
- if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
- if( !zRight ){
- returnSingleInt(pParse, "cache_size", pDb->cache_size);
- }else{
- int size = atoi(zRight);
- if( size<0 ) size = -size;
- pDb->cache_size = size;
- sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
- }
- }else
-
- /*
- ** PRAGMA temp_store
- ** PRAGMA temp_store = "default"|"memory"|"file"
- **
- ** Return or set the local value of the temp_store flag. Changing
- ** the local value does not make changes to the disk file and the default
- ** value will be restored the next time the database is opened.
- **
- ** Note that it is possible for the library compile-time options to
- ** override this setting
- */
- if( sqlite3StrICmp(zLeft, "temp_store")==0 ){
- if( !zRight ){
- returnSingleInt(pParse, "temp_store", db->temp_store);
- }else{
- changeTempStorage(pParse, zRight);
- }
- }else
-
- /*
- ** PRAGMA [database.]synchronous
- ** PRAGMA [database.]synchronous=OFF|ON|NORMAL|FULL
- **
- ** Return or set the local value of the synchronous flag. Changing
- ** the local value does not make changes to the disk file and the
- ** default value will be restored the next time the database is
- ** opened.
- */
- if( sqlite3StrICmp(zLeft,"synchronous")==0 ){
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
- if( !zRight ){
- returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
- }else{
- if( !db->autoCommit ){
- sqlite3ErrorMsg(pParse,
- "Safety level may not be changed inside a transaction");
- }else{
- pDb->safety_level = getSafetyLevel(zRight)+1;
- sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level);
- }
- }
- }else
-
-#if 0 /* Used once during development. No longer needed */
- if( sqlite3StrICmp(zLeft, "trigger_overhead_test")==0 ){
- if( getBoolean(zRight) ){
- sqlite3_always_code_trigger_setup = 1;
- }else{
- sqlite3_always_code_trigger_setup = 0;
- }
- }else
-#endif
-
- if( flagPragma(pParse, zLeft, zRight) ){
- /* The flagPragma() subroutine also generates any necessary code
- ** there is nothing more to do here */
- }else
-
- /*
- ** PRAGMA table_info(<table>)
- **
- ** Return a single row for each column of the named table. The columns of
- ** the returned data set are:
- **
- ** cid: Column id (numbered from left to right, starting at 0)
- ** name: Column name
- ** type: Column declaration type.
- ** notnull: True if 'NOT NULL' is part of column declaration
- ** dflt_value: The default value for the column, if any.
- */
- if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){
- Table *pTab;
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
- pTab = sqlite3FindTable(db, zRight, zDb);
- if( pTab ){
- int i;
- sqlite3VdbeSetNumCols(v, 6);
- sqlite3VdbeSetColName(v, 0, "cid", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, "type", P3_STATIC);
- sqlite3VdbeSetColName(v, 3, "notnull", P3_STATIC);
- sqlite3VdbeSetColName(v, 4, "dflt_value", P3_STATIC);
- sqlite3VdbeSetColName(v, 5, "pk", P3_STATIC);
- sqlite3ViewGetColumnNames(pParse, pTab);
- for(i=0; i<pTab->nCol; i++){
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zName, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0,
- pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
- sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0,
- pTab->aCol[i].zDflt, P3_STATIC);
- sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
- sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
- }
- }
- }else
-
- if( sqlite3StrICmp(zLeft, "index_info")==0 && zRight ){
- Index *pIdx;
- Table *pTab;
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
- pIdx = sqlite3FindIndex(db, zRight, zDb);
- if( pIdx ){
- int i;
- pTab = pIdx->pTable;
- sqlite3VdbeSetNumCols(v, 3);
- sqlite3VdbeSetColName(v, 0, "seqno", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "cid", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, "name", P3_STATIC);
- for(i=0; i<pIdx->nColumn; i++){
- int cnum = pIdx->aiColumn[i];
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- sqlite3VdbeAddOp(v, OP_Integer, cnum, 0);
- assert( pTab->nCol>cnum );
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[cnum].zName, 0);
- sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
- }
- }
- }else
-
- if( sqlite3StrICmp(zLeft, "index_list")==0 && zRight ){
- Index *pIdx;
- Table *pTab;
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
- pTab = sqlite3FindTable(db, zRight, zDb);
- if( pTab ){
- v = sqlite3GetVdbe(pParse);
- pIdx = pTab->pIndex;
- if( pIdx ){
- int i = 0;
- sqlite3VdbeSetNumCols(v, 3);
- sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, "unique", P3_STATIC);
- while(pIdx){
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
- sqlite3VdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
- sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
- ++i;
- pIdx = pIdx->pNext;
- }
- }
- }
- }else
-
- if( sqlite3StrICmp(zLeft, "foreign_key_list")==0 && zRight ){
- FKey *pFK;
- Table *pTab;
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
- pTab = sqlite3FindTable(db, zRight, zDb);
- if( pTab ){
- v = sqlite3GetVdbe(pParse);
- pFK = pTab->pFKey;
- if( pFK ){
- int i = 0;
- sqlite3VdbeSetNumCols(v, 5);
- sqlite3VdbeSetColName(v, 0, "id", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "seq", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, "table", P3_STATIC);
- sqlite3VdbeSetColName(v, 3, "from", P3_STATIC);
- sqlite3VdbeSetColName(v, 4, "to", P3_STATIC);
- while(pFK){
- int j;
- for(j=0; j<pFK->nCol; j++){
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- sqlite3VdbeAddOp(v, OP_Integer, j, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->zTo, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0,
- pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->aCol[j].zCol, 0);
- sqlite3VdbeAddOp(v, OP_Callback, 5, 0);
- }
- ++i;
- pFK = pFK->pNextFrom;
- }
- }
- }
- }else
-
- if( sqlite3StrICmp(zLeft, "database_list")==0 ){
- int i;
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
- sqlite3VdbeSetNumCols(v, 3);
- sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, "file", P3_STATIC);
- for(i=0; i<db->nDb; i++){
- if( db->aDb[i].pBt==0 ) continue;
- assert( db->aDb[i].zName!=0 );
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0,
- sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
- sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
- }
- }else
-
-#ifndef NDEBUG
- if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
- extern void sqlite3ParserTrace(FILE*, char *);
- if( getBoolean(zRight) ){
- sqlite3ParserTrace(stdout, "parser: ");
- }else{
- sqlite3ParserTrace(0, 0);
- }
- }else
-#endif
-
- if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
- int i, j, addr;
-
- /* Code that initializes the integrity check program. Set the
- ** error count 0
- */
- static const VdbeOpList initCode[] = {
- { OP_Integer, 0, 0, 0},
- { OP_MemStore, 0, 1, 0},
- };
-
- /* Code that appears at the end of the integrity check. If no error
- ** messages have been generated, output OK. Otherwise output the
- ** error message
- */
- static const VdbeOpList endCode[] = {
- { OP_MemLoad, 0, 0, 0},
- { OP_Integer, 0, 0, 0},
- { OP_Ne, 0, 0, 0}, /* 2 */
- { OP_String8, 0, 0, "ok"},
- { OP_Callback, 1, 0, 0},
- };
-
- /* Initialize the VDBE program */
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC);
- sqlite3VdbeAddOpList(v, ArraySize(initCode), initCode);
-
- /* Do an integrity check on each database file */
- for(i=0; i<db->nDb; i++){
- HashElem *x;
- int cnt = 0;
-
- sqlite3CodeVerifySchema(pParse, i);
-
- /* Do an integrity check of the B-Tree
- */
- for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
- Table *pTab = sqliteHashData(x);
- Index *pIdx;
- sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0);
- cnt++;
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto pragma_out;
- sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
- cnt++;
- }
- }
- assert( cnt>0 );
- sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 1);
- addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
- sqlite3VdbeAddOp(v, OP_Eq, 0, addr+6);
- sqlite3VdbeOp3(v, OP_String8, 0, 0,
- sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
- P3_DYNAMIC);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- sqlite3VdbeAddOp(v, OP_Concat, 0, 1);
- sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
-
- /* Make sure all the indices are constructed correctly.
- */
- sqlite3CodeVerifySchema(pParse, i);
- for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
- Table *pTab = sqliteHashData(x);
- Index *pIdx;
- int loopTop;
-
- if( pTab->pIndex==0 ) continue;
- sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, 1, 1);
- loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
- sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
- for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
- int jmp2;
- static const VdbeOpList idxErr[] = {
- { OP_MemIncr, 0, 0, 0},
- { OP_String8, 0, 0, "rowid "},
- { OP_Recno, 1, 0, 0},
- { OP_String8, 0, 0, " missing from index "},
- { OP_String8, 0, 0, 0}, /* 4 */
- { OP_Concat, 2, 0, 0},
- { OP_Callback, 1, 0, 0},
- };
- sqlite3GenerateIndexKey(v, pIdx, 1);
- jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
- addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
- sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
- sqlite3VdbeChangeP2(v, jmp2, sqlite3VdbeCurrentAddr(v));
- }
- sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1);
- sqlite3VdbeChangeP2(v, loopTop, sqlite3VdbeCurrentAddr(v));
- for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
- static const VdbeOpList cntIdx[] = {
- { OP_Integer, 0, 0, 0},
- { OP_MemStore, 2, 1, 0},
- { OP_Rewind, 0, 0, 0}, /* 2 */
- { OP_MemIncr, 2, 0, 0},
- { OP_Next, 0, 0, 0}, /* 4 */
- { OP_MemLoad, 1, 0, 0},
- { OP_MemLoad, 2, 0, 0},
- { OP_Eq, 0, 0, 0}, /* 7 */
- { OP_MemIncr, 0, 0, 0},
- { OP_String8, 0, 0, "wrong # of entries in index "},
- { OP_String8, 0, 0, 0}, /* 10 */
- { OP_Concat, 0, 0, 0},
- { OP_Callback, 1, 0, 0},
- };
- if( pIdx->tnum==0 ) continue;
- addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
- sqlite3VdbeChangeP1(v, addr+2, j+2);
- sqlite3VdbeChangeP2(v, addr+2, addr+5);
- sqlite3VdbeChangeP1(v, addr+4, j+2);
- sqlite3VdbeChangeP2(v, addr+4, addr+3);
- sqlite3VdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx));
- sqlite3VdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC);
- }
- }
- }
- addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
- sqlite3VdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
- }else
- /*
- ** PRAGMA encoding
- ** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be"
- **
- ** In it's first form, this pragma returns the encoding of the main
- ** database. If the database is not initialized, it is initialized now.
- **
- ** The second form of this pragma is a no-op if the main database file
- ** has not already been initialized. In this case it sets the default
- ** encoding that will be used for the main database file if a new file
- ** is created. If an existing main database file is opened, then the
- ** default text encoding for the existing database is used.
- **
- ** In all cases new databases created using the ATTACH command are
- ** created to use the same default text encoding as the main database. If
- ** the main database has not been initialized and/or created when ATTACH
- ** is executed, this is done before the ATTACH operation.
- **
- ** In the second form this pragma sets the text encoding to be used in
- ** new database files created using this database handle. It is only
- ** useful if invoked immediately after the main database i
- */
- if( sqlite3StrICmp(zLeft, "encoding")==0 ){
- static struct EncName {
- char *zName;
- u8 enc;
- } encnames[] = {
- { "UTF-8", SQLITE_UTF8 },
- { "UTF8", SQLITE_UTF8 },
- { "UTF-16le", SQLITE_UTF16LE },
- { "UTF16le", SQLITE_UTF16LE },
- { "UTF-16be", SQLITE_UTF16BE },
- { "UTF16be", SQLITE_UTF16BE },
- { "UTF-16", 0 /* Filled in at run-time */ },
- { "UTF16", 0 /* Filled in at run-time */ },
- { 0, 0 }
- };
- struct EncName *pEnc;
- encnames[6].enc = encnames[7].enc = SQLITE_UTF16NATIVE;
- if( !zRight ){ /* "PRAGMA encoding" */
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, "encoding", P3_STATIC);
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
- if( pEnc->enc==pParse->db->enc ){
- sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC);
- break;
- }
- }
- sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
- }else{ /* "PRAGMA encoding = XXX" */
- /* Only change the value of sqlite.enc if the database handle is not
- ** initialized. If the main database exists, the new sqlite.enc value
- ** will be overwritten when the schema is next loaded. If it does not
- ** already exists, it will be created to use the new encoding value.
- */
- if( !(pParse->db->flags&SQLITE_Initialized) ){
- for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
- if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
- pParse->db->enc = pEnc->enc;
- break;
- }
- }
- if( !pEnc->zName ){
- sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
- }
- }
- }
- }else
-
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
- /*
- ** Report the current state of file logs for all databases
- */
- if( sqlite3StrICmp(zLeft, "lock_status")==0 ){
- static const char *const azLockName[] = {
- "unlocked", "shared", "reserved", "pending", "exclusive"
- };
- int i;
- Vdbe *v = sqlite3GetVdbe(pParse);
- sqlite3VdbeSetNumCols(v, 2);
- sqlite3VdbeSetColName(v, 0, "database", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "status", P3_STATIC);
- for(i=0; i<db->nDb; i++){
- Btree *pBt;
- Pager *pPager;
- if( db->aDb[i].zName==0 ) continue;
- sqlite3VdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, P3_STATIC);
- pBt = db->aDb[i].pBt;
- if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
- sqlite3VdbeOp3(v, OP_String, 0, 0, "closed", P3_STATIC);
- }else{
- int j = sqlite3pager_lockstate(pPager);
- sqlite3VdbeOp3(v, OP_String, 0, 0,
- (j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
- }
- sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
- }
- }else
-#endif
-
- {}
-pragma_out:
- sqliteFree(zLeft);
- sqliteFree(zRight);
-}
diff --git a/kopete/plugins/statistics/sqlite/printf.c b/kopete/plugins/statistics/sqlite/printf.c
deleted file mode 100644
index 43e12863..00000000
--- a/kopete/plugins/statistics/sqlite/printf.c
+++ /dev/null
@@ -1,825 +0,0 @@
-/*
-** The "printf" code that follows dates from the 1980's. It is in
-** the public domain. The original comments are included here for
-** completeness. They are very out-of-date but might be useful as
-** an historical reference. Most of the "enhancements" have been backed
-** out so that the functionality is now the same as standard printf().
-**
-**************************************************************************
-**
-** The following modules is an enhanced replacement for the "printf" subroutines
-** found in the standard C library. The following enhancements are
-** supported:
-**
-** + Additional functions. The standard set of "printf" functions
-** includes printf, fprintf, sprintf, vprintf, vfprintf, and
-** vsprintf. This module adds the following:
-**
-** * snprintf -- Works like sprintf, but has an extra argument
-** which is the size of the buffer written to.
-**
-** * mprintf -- Similar to sprintf. Writes output to memory
-** obtained from malloc.
-**
-** * xprintf -- Calls a function to dispose of output.
-**
-** * nprintf -- No output, but returns the number of characters
-** that would have been output by printf.
-**
-** * A v- version (ex: vsnprintf) of every function is also
-** supplied.
-**
-** + A few extensions to the formatting notation are supported:
-**
-** * The "=" flag (similar to "-") causes the output to be
-** be centered in the appropriately sized field.
-**
-** * The %b field outputs an integer in binary notation.
-**
-** * The %c field now accepts a precision. The character output
-** is repeated by the number of times the precision specifies.
-**
-** * The %' field works like %c, but takes as its character the
-** next character of the format string, instead of the next
-** argument. For example, printf("%.78'-") prints 78 minus
-** signs, the same as printf("%.78c",'-').
-**
-** + When compiled using GCC on a SPARC, this version of printf is
-** faster than the library printf for SUN OS 4.1.
-**
-** + All functions are fully reentrant.
-**
-*/
-#include "sqliteInt.h"
-
-/*
-** Conversion types fall into various categories as defined by the
-** following enumeration.
-*/
-#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
-#define etFLOAT 2 /* Floating point. %f */
-#define etEXP 3 /* Exponentional notation. %e and %E */
-#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
-#define etSIZE 5 /* Return number of characters processed so far. %n */
-#define etSTRING 6 /* Strings. %s */
-#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
-#define etPERCENT 8 /* Percent symbol. %% */
-#define etCHARX 9 /* Characters. %c */
-#define etERROR 10 /* Used to indicate no such conversion type */
-/* The rest are extensions, not normally found in printf() */
-#define etCHARLIT 11 /* Literal characters. %' */
-#define etSQLESCAPE 12 /* Strings with '\'' doubled. %q */
-#define etSQLESCAPE2 13 /* Strings with '\'' doubled and enclosed in '',
- NULL pointers replaced by SQL NULL. %Q */
-#define etTOKEN 14 /* a pointer to a Token structure */
-#define etSRCLIST 15 /* a pointer to a SrcList */
-#define etPOINTER 16 /* The %p conversion */
-
-
-/*
-** An "etByte" is an 8-bit unsigned value.
-*/
-typedef unsigned char etByte;
-
-/*
-** Each builtin conversion character (ex: the 'd' in "%d") is described
-** by an instance of the following structure
-*/
-typedef struct et_info { /* Information about each format field */
- char fmttype; /* The format field code letter */
- etByte base; /* The base for radix conversion */
- etByte flags; /* One or more of FLAG_ constants below */
- etByte type; /* Conversion paradigm */
- etByte charset; /* Offset into aDigits[] of the digits string */
- etByte prefix; /* Offset into aPrefix[] of the prefix string */
-} et_info;
-
-/*
-** Allowed values for et_info.flags
-*/
-#define FLAG_SIGNED 1 /* True if the value to convert is signed */
-#define FLAG_INTERN 2 /* True if for internal use only */
-
-
-/*
-** The following table is searched linearly, so it is good to put the
-** most frequently used conversion types first.
-*/
-static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
-static const char aPrefix[] = "-x0\000X0";
-static const et_info fmtinfo[] = {
- { 'd', 10, 1, etRADIX, 0, 0 },
- { 's', 0, 0, etSTRING, 0, 0 },
- { 'z', 0, 2, etDYNSTRING, 0, 0 },
- { 'q', 0, 0, etSQLESCAPE, 0, 0 },
- { 'Q', 0, 0, etSQLESCAPE2, 0, 0 },
- { 'c', 0, 0, etCHARX, 0, 0 },
- { 'o', 8, 0, etRADIX, 0, 2 },
- { 'u', 10, 0, etRADIX, 0, 0 },
- { 'x', 16, 0, etRADIX, 16, 1 },
- { 'X', 16, 0, etRADIX, 0, 4 },
- { 'f', 0, 1, etFLOAT, 0, 0 },
- { 'e', 0, 1, etEXP, 30, 0 },
- { 'E', 0, 1, etEXP, 14, 0 },
- { 'g', 0, 1, etGENERIC, 30, 0 },
- { 'G', 0, 1, etGENERIC, 14, 0 },
- { 'i', 10, 1, etRADIX, 0, 0 },
- { 'n', 0, 0, etSIZE, 0, 0 },
- { '%', 0, 0, etPERCENT, 0, 0 },
- { 'p', 16, 0, etPOINTER, 0, 1 },
- { 'T', 0, 2, etTOKEN, 0, 0 },
- { 'S', 0, 2, etSRCLIST, 0, 0 },
-};
-#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
-
-/*
-** If NOFLOATINGPOINT is defined, then none of the floating point
-** conversions will work.
-*/
-#ifndef etNOFLOATINGPOINT
-/*
-** "*val" is a double such that 0.1 <= *val < 10.0
-** Return the ascii code for the leading digit of *val, then
-** multiply "*val" by 10.0 to renormalize.
-**
-** Example:
-** input: *val = 3.14159
-** output: *val = 1.4159 function return = '3'
-**
-** The counter *cnt is incremented each time. After counter exceeds
-** 16 (the number of significant digits in a 64-bit float) '0' is
-** always returned.
-*/
-static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
- int digit;
- LONGDOUBLE_TYPE d;
- if( (*cnt)++ >= 16 ) return '0';
- digit = (int)*val;
- d = digit;
- digit += '0';
- *val = (*val - d)*10.0;
- return digit;
-}
-#endif
-
-#define etBUFSIZE 1000 /* Size of the output buffer */
-
-/*
-** The root program. All variations call this core.
-**
-** INPUTS:
-** func This is a pointer to a function taking three arguments
-** 1. A pointer to anything. Same as the "arg" parameter.
-** 2. A pointer to the list of characters to be output
-** (Note, this list is NOT null terminated.)
-** 3. An integer number of characters to be output.
-** (Note: This number might be zero.)
-**
-** arg This is the pointer to anything which will be passed as the
-** first argument to "func". Use it for whatever you like.
-**
-** fmt This is the format string, as in the usual print.
-**
-** ap This is a pointer to a list of arguments. Same as in
-** vfprint.
-**
-** OUTPUTS:
-** The return value is the total number of characters sent to
-** the function "func". Returns -1 on a error.
-**
-** Note that the order in which automatic variables are declared below
-** seems to make a big difference in determining how fast this beast
-** will run.
-*/
-static int vxprintf(
- void (*func)(void*,const char*,int), /* Consumer of text */
- void *arg, /* First argument to the consumer */
- int useExtended, /* Allow extended %-conversions */
- const char *fmt, /* Format string */
- va_list ap /* arguments */
-){
- int c; /* Next character in the format string */
- char *bufpt; /* Pointer to the conversion buffer */
- int precision; /* Precision of the current field */
- int length; /* Length of the field */
- int idx; /* A general purpose loop counter */
- int count; /* Total number of characters output */
- int width; /* Width of the current field */
- etByte flag_leftjustify; /* True if "-" flag is present */
- etByte flag_plussign; /* True if "+" flag is present */
- etByte flag_blanksign; /* True if " " flag is present */
- etByte flag_alternateform; /* True if "#" flag is present */
- etByte flag_zeropad; /* True if field width constant starts with zero */
- etByte flag_long; /* True if "l" flag is present */
- etByte flag_longlong; /* True if the "ll" flag is present */
- UINT64_TYPE longvalue; /* Value for integer types */
- LONGDOUBLE_TYPE realvalue; /* Value for real types */
- const et_info *infop; /* Pointer to the appropriate info structure */
- char buf[etBUFSIZE]; /* Conversion buffer */
- char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
- etByte errorflag = 0; /* True if an error is encountered */
- etByte xtype; /* Conversion paradigm */
- char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
- static const char spaces[] =
- " ";
-#define etSPACESIZE (sizeof(spaces)-1)
-#ifndef etNOFLOATINGPOINT
- int exp; /* exponent of real numbers */
- double rounder; /* Used for rounding floating point values */
- etByte flag_dp; /* True if decimal point should be shown */
- etByte flag_rtz; /* True if trailing zeros should be removed */
- etByte flag_exp; /* True to force display of the exponent */
- int nsd; /* Number of significant digits returned */
-#endif
-
- func(arg,"",0);
- count = length = 0;
- bufpt = 0;
- for(; (c=(*fmt))!=0; ++fmt){
- if( c!='%' ){
- int amt;
- bufpt = (char *)fmt;
- amt = 1;
- while( (c=(*++fmt))!='%' && c!=0 ) amt++;
- (*func)(arg,bufpt,amt);
- count += amt;
- if( c==0 ) break;
- }
- if( (c=(*++fmt))==0 ){
- errorflag = 1;
- (*func)(arg,"%",1);
- count++;
- break;
- }
- /* Find out what flags are present */
- flag_leftjustify = flag_plussign = flag_blanksign =
- flag_alternateform = flag_zeropad = 0;
- do{
- switch( c ){
- case '-': flag_leftjustify = 1; c = 0; break;
- case '+': flag_plussign = 1; c = 0; break;
- case ' ': flag_blanksign = 1; c = 0; break;
- case '#': flag_alternateform = 1; c = 0; break;
- case '0': flag_zeropad = 1; c = 0; break;
- default: break;
- }
- }while( c==0 && (c=(*++fmt))!=0 );
- /* Get the field width */
- width = 0;
- if( c=='*' ){
- width = va_arg(ap,int);
- if( width<0 ){
- flag_leftjustify = 1;
- width = -width;
- }
- c = *++fmt;
- }else{
- while( c>='0' && c<='9' ){
- width = width*10 + c - '0';
- c = *++fmt;
- }
- }
- if( width > etBUFSIZE-10 ){
- width = etBUFSIZE-10;
- }
- /* Get the precision */
- if( c=='.' ){
- precision = 0;
- c = *++fmt;
- if( c=='*' ){
- precision = va_arg(ap,int);
- if( precision<0 ) precision = -precision;
- c = *++fmt;
- }else{
- while( c>='0' && c<='9' ){
- precision = precision*10 + c - '0';
- c = *++fmt;
- }
- }
- /* Limit the precision to prevent overflowing buf[] during conversion */
- if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40;
- }else{
- precision = -1;
- }
- /* Get the conversion type modifier */
- if( c=='l' ){
- flag_long = 1;
- c = *++fmt;
- if( c=='l' ){
- flag_longlong = 1;
- c = *++fmt;
- }else{
- flag_longlong = 0;
- }
- }else{
- flag_long = flag_longlong = 0;
- }
- /* Fetch the info entry for the field */
- infop = 0;
- xtype = etERROR;
- for(idx=0; idx<etNINFO; idx++){
- if( c==fmtinfo[idx].fmttype ){
- infop = &fmtinfo[idx];
- if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
- xtype = infop->type;
- }
- break;
- }
- }
- zExtra = 0;
-
- /*
- ** At this point, variables are initialized as follows:
- **
- ** flag_alternateform TRUE if a '#' is present.
- ** flag_plussign TRUE if a '+' is present.
- ** flag_leftjustify TRUE if a '-' is present or if the
- ** field width was negative.
- ** flag_zeropad TRUE if the width began with 0.
- ** flag_long TRUE if the letter 'l' (ell) prefixed
- ** the conversion character.
- ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed
- ** the conversion character.
- ** flag_blanksign TRUE if a ' ' is present.
- ** width The specified field width. This is
- ** always non-negative. Zero is the default.
- ** precision The specified precision. The default
- ** is -1.
- ** xtype The class of the conversion.
- ** infop Pointer to the appropriate info struct.
- */
- switch( xtype ){
- case etPOINTER:
- flag_longlong = sizeof(char*)==sizeof(i64);
- flag_long = sizeof(char*)==sizeof(long int);
- /* Fall through into the next case */
- case etRADIX:
- if( infop->flags & FLAG_SIGNED ){
- i64 v;
- if( flag_longlong ) v = va_arg(ap,i64);
- else if( flag_long ) v = va_arg(ap,long int);
- else v = va_arg(ap,int);
- if( v<0 ){
- longvalue = -v;
- prefix = '-';
- }else{
- longvalue = v;
- if( flag_plussign ) prefix = '+';
- else if( flag_blanksign ) prefix = ' ';
- else prefix = 0;
- }
- }else{
- if( flag_longlong ) longvalue = va_arg(ap,u64);
- else if( flag_long ) longvalue = va_arg(ap,unsigned long int);
- else longvalue = va_arg(ap,unsigned int);
- prefix = 0;
- }
- if( longvalue==0 ) flag_alternateform = 0;
- if( flag_zeropad && precision<width-(prefix!=0) ){
- precision = width-(prefix!=0);
- }
- bufpt = &buf[etBUFSIZE-1];
- {
- register const char *cset; /* Use registers for speed */
- register int base;
- cset = &aDigits[infop->charset];
- base = infop->base;
- do{ /* Convert to ascii */
- *(--bufpt) = cset[longvalue%base];
- longvalue = longvalue/base;
- }while( longvalue>0 );
- }
- length = &buf[etBUFSIZE-1]-bufpt;
- for(idx=precision-length; idx>0; idx--){
- *(--bufpt) = '0'; /* Zero pad */
- }
- if( prefix ) *(--bufpt) = prefix; /* Add sign */
- if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
- const char *pre;
- char x;
- pre = &aPrefix[infop->prefix];
- if( *bufpt!=pre[0] ){
- for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
- }
- }
- length = &buf[etBUFSIZE-1]-bufpt;
- break;
- case etFLOAT:
- case etEXP:
- case etGENERIC:
- realvalue = va_arg(ap,double);
-#ifndef etNOFLOATINGPOINT
- if( precision<0 ) precision = 6; /* Set default precision */
- if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10;
- if( realvalue<0.0 ){
- realvalue = -realvalue;
- prefix = '-';
- }else{
- if( flag_plussign ) prefix = '+';
- else if( flag_blanksign ) prefix = ' ';
- else prefix = 0;
- }
- if( infop->type==etGENERIC && precision>0 ) precision--;
- rounder = 0.0;
-#if 0
- /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
- for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
-#else
- /* It makes more sense to use 0.5 */
- for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
-#endif
- if( infop->type==etFLOAT ) realvalue += rounder;
- /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
- exp = 0;
- if( realvalue>0.0 ){
- while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
- while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
- while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
- while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
- if( exp>350 || exp<-350 ){
- bufpt = "NaN";
- length = 3;
- break;
- }
- }
- bufpt = buf;
- /*
- ** If the field type is etGENERIC, then convert to either etEXP
- ** or etFLOAT, as appropriate.
- */
- flag_exp = xtype==etEXP;
- if( xtype!=etFLOAT ){
- realvalue += rounder;
- if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
- }
- if( xtype==etGENERIC ){
- flag_rtz = !flag_alternateform;
- if( exp<-4 || exp>precision ){
- xtype = etEXP;
- }else{
- precision = precision - exp;
- xtype = etFLOAT;
- }
- }else{
- flag_rtz = 0;
- }
- /*
- ** The "exp+precision" test causes output to be of type etEXP if
- ** the precision is too large to fit in buf[].
- */
- nsd = 0;
- if( xtype==etFLOAT && exp+precision<etBUFSIZE-30 ){
- flag_dp = (precision>0 || flag_alternateform);
- if( prefix ) *(bufpt++) = prefix; /* Sign */
- if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */
- else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd);
- if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */
- for(exp++; exp<0 && precision>0; precision--, exp++){
- *(bufpt++) = '0';
- }
- while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
- *(bufpt--) = 0; /* Null terminate */
- if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */
- while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
- if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
- }
- bufpt++; /* point to next free slot */
- }else{ /* etEXP or etGENERIC */
- flag_dp = (precision>0 || flag_alternateform);
- if( prefix ) *(bufpt++) = prefix; /* Sign */
- *(bufpt++) = et_getdigit(&realvalue,&nsd); /* First digit */
- if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */
- while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
- bufpt--; /* point to last digit */
- if( flag_rtz && flag_dp ){ /* Remove tail zeros */
- while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
- if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
- }
- bufpt++; /* point to next free slot */
- if( exp || flag_exp ){
- *(bufpt++) = aDigits[infop->charset];
- if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */
- else { *(bufpt++) = '+'; }
- if( exp>=100 ){
- *(bufpt++) = (exp/100)+'0'; /* 100's digit */
- exp %= 100;
- }
- *(bufpt++) = exp/10+'0'; /* 10's digit */
- *(bufpt++) = exp%10+'0'; /* 1's digit */
- }
- }
- /* The converted number is in buf[] and zero terminated. Output it.
- ** Note that the number is in the usual order, not reversed as with
- ** integer conversions. */
- length = bufpt-buf;
- bufpt = buf;
-
- /* Special case: Add leading zeros if the flag_zeropad flag is
- ** set and we are not left justified */
- if( flag_zeropad && !flag_leftjustify && length < width){
- int i;
- int nPad = width - length;
- for(i=width; i>=nPad; i--){
- bufpt[i] = bufpt[i-nPad];
- }
- i = prefix!=0;
- while( nPad-- ) bufpt[i++] = '0';
- length = width;
- }
-#endif
- break;
- case etSIZE:
- *(va_arg(ap,int*)) = count;
- length = width = 0;
- break;
- case etPERCENT:
- buf[0] = '%';
- bufpt = buf;
- length = 1;
- break;
- case etCHARLIT:
- case etCHARX:
- c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
- if( precision>=0 ){
- for(idx=1; idx<precision; idx++) buf[idx] = c;
- length = precision;
- }else{
- length =1;
- }
- bufpt = buf;
- break;
- case etSTRING:
- case etDYNSTRING:
- bufpt = va_arg(ap,char*);
- if( bufpt==0 ){
- bufpt = "";
- }else if( xtype==etDYNSTRING ){
- zExtra = bufpt;
- }
- length = strlen(bufpt);
- if( precision>=0 && precision<length ) length = precision;
- break;
- case etSQLESCAPE:
- case etSQLESCAPE2:
- {
- int i, j, n, c, isnull;
- char *arg = va_arg(ap,char*);
- isnull = arg==0;
- if( isnull ) arg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
- for(i=n=0; (c=arg[i])!=0; i++){
- if( c=='\'' ) n++;
- }
- n += i + 1 + ((!isnull && xtype==etSQLESCAPE2) ? 2 : 0);
- if( n>etBUFSIZE ){
- bufpt = zExtra = sqliteMalloc( n );
- if( bufpt==0 ) return -1;
- }else{
- bufpt = buf;
- }
- j = 0;
- if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
- for(i=0; (c=arg[i])!=0; i++){
- bufpt[j++] = c;
- if( c=='\'' ) bufpt[j++] = c;
- }
- if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
- bufpt[j] = 0;
- length = j;
- if( precision>=0 && precision<length ) length = precision;
- }
- break;
- case etTOKEN: {
- Token *pToken = va_arg(ap, Token*);
- if( pToken && pToken->z ){
- (*func)(arg, pToken->z, pToken->n);
- }
- length = width = 0;
- break;
- }
- case etSRCLIST: {
- SrcList *pSrc = va_arg(ap, SrcList*);
- int k = va_arg(ap, int);
- struct SrcList_item *pItem = &pSrc->a[k];
- assert( k>=0 && k<pSrc->nSrc );
- if( pItem->zDatabase && pItem->zDatabase[0] ){
- (*func)(arg, pItem->zDatabase, strlen(pItem->zDatabase));
- (*func)(arg, ".", 1);
- }
- (*func)(arg, pItem->zName, strlen(pItem->zName));
- length = width = 0;
- break;
- }
- case etERROR:
- buf[0] = '%';
- buf[1] = c;
- errorflag = 0;
- idx = 1+(c!=0);
- (*func)(arg,"%",idx);
- count += idx;
- if( c==0 ) fmt--;
- break;
- }/* End switch over the format type */
- /*
- ** The text of the conversion is pointed to by "bufpt" and is
- ** "length" characters long. The field width is "width". Do
- ** the output.
- */
- if( !flag_leftjustify ){
- register int nspace;
- nspace = width-length;
- if( nspace>0 ){
- count += nspace;
- while( nspace>=etSPACESIZE ){
- (*func)(arg,spaces,etSPACESIZE);
- nspace -= etSPACESIZE;
- }
- if( nspace>0 ) (*func)(arg,spaces,nspace);
- }
- }
- if( length>0 ){
- (*func)(arg,bufpt,length);
- count += length;
- }
- if( flag_leftjustify ){
- register int nspace;
- nspace = width-length;
- if( nspace>0 ){
- count += nspace;
- while( nspace>=etSPACESIZE ){
- (*func)(arg,spaces,etSPACESIZE);
- nspace -= etSPACESIZE;
- }
- if( nspace>0 ) (*func)(arg,spaces,nspace);
- }
- }
- if( zExtra ){
- sqliteFree(zExtra);
- }
- }/* End for loop over the format string */
- return errorflag ? -1 : count;
-} /* End of function */
-
-
-/* This structure is used to store state information about the
-** write to memory that is currently in progress.
-*/
-struct sgMprintf {
- char *zBase; /* A base allocation */
- char *zText; /* The string collected so far */
- int nChar; /* Length of the string so far */
- int nTotal; /* Output size if unconstrained */
- int nAlloc; /* Amount of space allocated in zText */
- void *(*xRealloc)(void*,int); /* Function used to realloc memory */
-};
-
-/*
-** This function implements the callback from vxprintf.
-**
-** This routine add nNewChar characters of text in zNewText to
-** the sgMprintf structure pointed to by "arg".
-*/
-static void mout(void *arg, const char *zNewText, int nNewChar){
- struct sgMprintf *pM = (struct sgMprintf*)arg;
- pM->nTotal += nNewChar;
- if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
- if( pM->xRealloc==0 ){
- nNewChar = pM->nAlloc - pM->nChar - 1;
- }else{
- pM->nAlloc = pM->nChar + nNewChar*2 + 1;
- if( pM->zText==pM->zBase ){
- pM->zText = pM->xRealloc(0, pM->nAlloc);
- if( pM->zText && pM->nChar ){
- memcpy(pM->zText, pM->zBase, pM->nChar);
- }
- }else{
- pM->zText = pM->xRealloc(pM->zText, pM->nAlloc);
- }
- }
- }
- if( pM->zText ){
- if( nNewChar>0 ){
- memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
- pM->nChar += nNewChar;
- }
- pM->zText[pM->nChar] = 0;
- }
-}
-
-/*
-** This routine is a wrapper around xprintf() that invokes mout() as
-** the consumer.
-*/
-static char *base_vprintf(
- void *(*xRealloc)(void*,int), /* Routine to realloc memory. May be NULL */
- int useInternal, /* Use internal %-conversions if true */
- char *zInitBuf, /* Initially write here, before mallocing */
- int nInitBuf, /* Size of zInitBuf[] */
- const char *zFormat, /* format string */
- va_list ap /* arguments */
-){
- struct sgMprintf sM;
- sM.zBase = sM.zText = zInitBuf;
- sM.nChar = sM.nTotal = 0;
- sM.nAlloc = nInitBuf;
- sM.xRealloc = xRealloc;
- vxprintf(mout, &sM, useInternal, zFormat, ap);
- if( xRealloc ){
- if( sM.zText==sM.zBase ){
- sM.zText = xRealloc(0, sM.nChar+1);
- if( sM.zText ){
- memcpy(sM.zText, sM.zBase, sM.nChar+1);
- }
- }else if( sM.nAlloc>sM.nChar+10 ){
- sM.zText = xRealloc(sM.zText, sM.nChar+1);
- }
- }
- return sM.zText;
-}
-
-/*
-** Realloc that is a real function, not a macro.
-*/
-static void *printf_realloc(void *old, int size){
- return sqliteRealloc(old,size);
-}
-
-/*
-** Print into memory obtained from sqliteMalloc(). Use the internal
-** %-conversion extensions.
-*/
-char *sqlite3VMPrintf(const char *zFormat, va_list ap){
- char zBase[1000];
- return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
-}
-
-/*
-** Print into memory obtained from sqliteMalloc(). Use the internal
-** %-conversion extensions.
-*/
-char *sqlite3MPrintf(const char *zFormat, ...){
- va_list ap;
- char *z;
- char zBase[1000];
- va_start(ap, zFormat);
- z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
- va_end(ap);
- return z;
-}
-
-/*
-** Print into memory obtained from malloc(). Do not use the internal
-** %-conversion extensions. This routine is for use by external users.
-*/
-char *sqlite3_mprintf(const char *zFormat, ...){
- va_list ap;
- char *z;
- char zBuf[200];
-
- va_start(ap,zFormat);
- z = base_vprintf((void*(*)(void*,int))realloc, 0,
- zBuf, sizeof(zBuf), zFormat, ap);
- va_end(ap);
- return z;
-}
-
-/* This is the varargs version of sqlite3_mprintf.
-*/
-char *sqlite3_vmprintf(const char *zFormat, va_list ap){
- char zBuf[200];
- return base_vprintf((void*(*)(void*,int))realloc, 0,
- zBuf, sizeof(zBuf), zFormat, ap);
-}
-
-/*
-** sqlite3_snprintf() works like snprintf() except that it ignores the
-** current locale settings. This is important for SQLite because we
-** are not able to use a "," as the decimal point in place of "." as
-** specified by some locales.
-*/
-char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
- char *z;
- va_list ap;
-
- va_start(ap,zFormat);
- z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
- va_end(ap);
- return z;
-}
-
-#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
-/*
-** A version of printf() that understands %lld. Used for debugging.
-** The printf() built into some versions of windows does not understand %lld
-** and segfaults if you give it a long long int.
-*/
-void sqlite3DebugPrintf(const char *zFormat, ...){
- extern int getpid(void);
- va_list ap;
- char zBuf[500];
- va_start(ap, zFormat);
- base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap);
- va_end(ap);
- fprintf(stdout,"%d: %s", getpid(), zBuf);
- fflush(stdout);
-}
-#endif
diff --git a/kopete/plugins/statistics/sqlite/random.c b/kopete/plugins/statistics/sqlite/random.c
deleted file mode 100644
index de74e291..00000000
--- a/kopete/plugins/statistics/sqlite/random.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains code to implement a pseudo-random number
-** generator (PRNG) for SQLite.
-**
-** Random numbers are used by some of the database backends in order
-** to generate random integer keys for tables or random filenames.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-#include "os.h"
-
-
-/*
-** Get a single 8-bit random value from the RC4 PRNG. The Mutex
-** must be held while executing this routine.
-**
-** Why not just use a library random generator like lrand48() for this?
-** Because the OP_NewRecno opcode in the VDBE depends on having a very
-** good source of random numbers. The lrand48() library function may
-** well be good enough. But maybe not. Or maybe lrand48() has some
-** subtle problems on some systems that could cause problems. It is hard
-** to know. To minimize the risk of problems due to bad lrand48()
-** implementations, SQLite uses this random number generator based
-** on RC4, which we know works very well.
-*/
-static int randomByte(){
- unsigned char t;
-
- /* All threads share a single random number generator.
- ** This structure is the current state of the generator.
- */
- static struct {
- unsigned char isInit; /* True if initialized */
- unsigned char i, j; /* State variables */
- unsigned char s[256]; /* State variables */
- } prng;
-
- /* Initialize the state of the random number generator once,
- ** the first time this routine is called. The seed value does
- ** not need to contain a lot of randomness since we are not
- ** trying to do secure encryption or anything like that...
- **
- ** Nothing in this file or anywhere else in SQLite does any kind of
- ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
- ** number generator) not as an encryption device.
- */
- if( !prng.isInit ){
- int i;
- char k[256];
- prng.j = 0;
- prng.i = 0;
- sqlite3OsRandomSeed(k);
- for(i=0; i<256; i++){
- prng.s[i] = i;
- }
- for(i=0; i<256; i++){
- prng.j += prng.s[i] + k[i];
- t = prng.s[prng.j];
- prng.s[prng.j] = prng.s[i];
- prng.s[i] = t;
- }
- prng.isInit = 1;
- }
-
- /* Generate and return single random byte
- */
- prng.i++;
- t = prng.s[prng.i];
- prng.j += t;
- prng.s[prng.i] = prng.s[prng.j];
- prng.s[prng.j] = t;
- t += prng.s[prng.i];
- return prng.s[t];
-}
-
-/*
-** Return N random bytes.
-*/
-void sqlite3Randomness(int N, void *pBuf){
- unsigned char *zBuf = pBuf;
- sqlite3OsEnterMutex();
- while( N-- ){
- *(zBuf++) = randomByte();
- }
- sqlite3OsLeaveMutex();
-}
-
-
-
diff --git a/kopete/plugins/statistics/sqlite/select.c b/kopete/plugins/statistics/sqlite/select.c
deleted file mode 100644
index 8bee7897..00000000
--- a/kopete/plugins/statistics/sqlite/select.c
+++ /dev/null
@@ -1,2628 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains C code routines that are called by the parser
-** to handle SELECT statements in SQLite.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-
-
-/*
-** Allocate a new Select structure and return a pointer to that
-** structure.
-*/
-Select *sqlite3SelectNew(
- ExprList *pEList, /* which columns to include in the result */
- SrcList *pSrc, /* the FROM clause -- which tables to scan */
- Expr *pWhere, /* the WHERE clause */
- ExprList *pGroupBy, /* the GROUP BY clause */
- Expr *pHaving, /* the HAVING clause */
- ExprList *pOrderBy, /* the ORDER BY clause */
- int isDistinct, /* true if the DISTINCT keyword is present */
- int nLimit, /* LIMIT value. -1 means not used */
- int nOffset /* OFFSET value. 0 means no offset */
-){
- Select *pNew;
- pNew = sqliteMalloc( sizeof(*pNew) );
- if( pNew==0 ){
- sqlite3ExprListDelete(pEList);
- sqlite3SrcListDelete(pSrc);
- sqlite3ExprDelete(pWhere);
- sqlite3ExprListDelete(pGroupBy);
- sqlite3ExprDelete(pHaving);
- sqlite3ExprListDelete(pOrderBy);
- }else{
- if( pEList==0 ){
- pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0);
- }
- pNew->pEList = pEList;
- pNew->pSrc = pSrc;
- pNew->pWhere = pWhere;
- pNew->pGroupBy = pGroupBy;
- pNew->pHaving = pHaving;
- pNew->pOrderBy = pOrderBy;
- pNew->isDistinct = isDistinct;
- pNew->op = TK_SELECT;
- pNew->nLimit = nLimit;
- pNew->nOffset = nOffset;
- pNew->iLimit = -1;
- pNew->iOffset = -1;
- }
- return pNew;
-}
-
-/*
-** Given 1 to 3 identifiers preceeding the JOIN keyword, determine the
-** type of join. Return an integer constant that expresses that type
-** in terms of the following bit values:
-**
-** JT_INNER
-** JT_OUTER
-** JT_NATURAL
-** JT_LEFT
-** JT_RIGHT
-**
-** A full outer join is the combination of JT_LEFT and JT_RIGHT.
-**
-** If an illegal or unsupported join type is seen, then still return
-** a join type, but put an error in the pParse structure.
-*/
-int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
- int jointype = 0;
- Token *apAll[3];
- Token *p;
- static const struct {
- const char *zKeyword;
- u8 nChar;
- u8 code;
- } keywords[] = {
- { "natural", 7, JT_NATURAL },
- { "left", 4, JT_LEFT|JT_OUTER },
- { "right", 5, JT_RIGHT|JT_OUTER },
- { "full", 4, JT_LEFT|JT_RIGHT|JT_OUTER },
- { "outer", 5, JT_OUTER },
- { "inner", 5, JT_INNER },
- { "cross", 5, JT_INNER },
- };
- int i, j;
- apAll[0] = pA;
- apAll[1] = pB;
- apAll[2] = pC;
- for(i=0; i<3 && apAll[i]; i++){
- p = apAll[i];
- for(j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++){
- if( p->n==keywords[j].nChar
- && sqlite3StrNICmp(p->z, keywords[j].zKeyword, p->n)==0 ){
- jointype |= keywords[j].code;
- break;
- }
- }
- if( j>=sizeof(keywords)/sizeof(keywords[0]) ){
- jointype |= JT_ERROR;
- break;
- }
- }
- if(
- (jointype & (JT_INNER|JT_OUTER))==(JT_INNER|JT_OUTER) ||
- (jointype & JT_ERROR)!=0
- ){
- const char *zSp1 = " ";
- const char *zSp2 = " ";
- if( pB==0 ){ zSp1++; }
- if( pC==0 ){ zSp2++; }
- sqlite3ErrorMsg(pParse, "unknown or unsupported join type: "
- "%T%s%T%s%T", pA, zSp1, pB, zSp2, pC);
- jointype = JT_INNER;
- }else if( jointype & JT_RIGHT ){
- sqlite3ErrorMsg(pParse,
- "RIGHT and FULL OUTER JOINs are not currently supported");
- jointype = JT_INNER;
- }
- return jointype;
-}
-
-/*
-** Return the index of a column in a table. Return -1 if the column
-** is not contained in the table.
-*/
-static int columnIndex(Table *pTab, const char *zCol){
- int i;
- for(i=0; i<pTab->nCol; i++){
- if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
- }
- return -1;
-}
-
-/*
-** Set the value of a token to a '\000'-terminated string.
-*/
-static void setToken(Token *p, const char *z){
- p->z = z;
- p->n = strlen(z);
- p->dyn = 0;
-}
-
-
-/*
-** Add a term to the WHERE expression in *ppExpr that requires the
-** zCol column to be equal in the two tables pTab1 and pTab2.
-*/
-static void addWhereTerm(
- const char *zCol, /* Name of the column */
- const Table *pTab1, /* First table */
- const Table *pTab2, /* Second table */
- Expr **ppExpr /* Add the equality term to this expression */
-){
- Token dummy;
- Expr *pE1a, *pE1b, *pE1c;
- Expr *pE2a, *pE2b, *pE2c;
- Expr *pE;
-
- setToken(&dummy, zCol);
- pE1a = sqlite3Expr(TK_ID, 0, 0, &dummy);
- pE2a = sqlite3Expr(TK_ID, 0, 0, &dummy);
- setToken(&dummy, pTab1->zName);
- pE1b = sqlite3Expr(TK_ID, 0, 0, &dummy);
- setToken(&dummy, pTab2->zName);
- pE2b = sqlite3Expr(TK_ID, 0, 0, &dummy);
- pE1c = sqlite3Expr(TK_DOT, pE1b, pE1a, 0);
- pE2c = sqlite3Expr(TK_DOT, pE2b, pE2a, 0);
- pE = sqlite3Expr(TK_EQ, pE1c, pE2c, 0);
- ExprSetProperty(pE, EP_FromJoin);
- *ppExpr = sqlite3ExprAnd(*ppExpr, pE);
-}
-
-/*
-** Set the EP_FromJoin property on all terms of the given expression.
-**
-** The EP_FromJoin property is used on terms of an expression to tell
-** the LEFT OUTER JOIN processing logic that this term is part of the
-** join restriction specified in the ON or USING clause and not a part
-** of the more general WHERE clause. These terms are moved over to the
-** WHERE clause during join processing but we need to remember that they
-** originated in the ON or USING clause.
-*/
-static void setJoinExpr(Expr *p){
- while( p ){
- ExprSetProperty(p, EP_FromJoin);
- setJoinExpr(p->pLeft);
- p = p->pRight;
- }
-}
-
-/*
-** This routine processes the join information for a SELECT statement.
-** ON and USING clauses are converted into extra terms of the WHERE clause.
-** NATURAL joins also create extra WHERE clause terms.
-**
-** The terms of a FROM clause are contained in the Select.pSrc structure.
-** The left most table is the first entry in Select.pSrc. The right-most
-** table is the last entry. The join operator is held in the entry to
-** the left. Thus entry 0 contains the join operator for the join between
-** entries 0 and 1. Any ON or USING clauses associated with the join are
-** also attached to the left entry.
-**
-** This routine returns the number of errors encountered.
-*/
-static int sqliteProcessJoin(Parse *pParse, Select *p){
- SrcList *pSrc; /* All tables in the FROM clause */
- int i, j; /* Loop counters */
- struct SrcList_item *pLeft; /* Left table being joined */
- struct SrcList_item *pRight; /* Right table being joined */
-
- pSrc = p->pSrc;
- pLeft = &pSrc->a[0];
- pRight = &pLeft[1];
- for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
- Table *pLeftTab = pLeft->pTab;
- Table *pRightTab = pRight->pTab;
-
- if( pLeftTab==0 || pRightTab==0 ) continue;
-
- /* When the NATURAL keyword is present, add WHERE clause terms for
- ** every column that the two tables have in common.
- */
- if( pLeft->jointype & JT_NATURAL ){
- if( pLeft->pOn || pLeft->pUsing ){
- sqlite3ErrorMsg(pParse, "a NATURAL join may not have "
- "an ON or USING clause", 0);
- return 1;
- }
- for(j=0; j<pLeftTab->nCol; j++){
- char *zName = pLeftTab->aCol[j].zName;
- if( columnIndex(pRightTab, zName)>=0 ){
- addWhereTerm(zName, pLeftTab, pRightTab, &p->pWhere);
- }
- }
- }
-
- /* Disallow both ON and USING clauses in the same join
- */
- if( pLeft->pOn && pLeft->pUsing ){
- sqlite3ErrorMsg(pParse, "cannot have both ON and USING "
- "clauses in the same join");
- return 1;
- }
-
- /* Add the ON clause to the end of the WHERE clause, connected by
- ** an AND operator.
- */
- if( pLeft->pOn ){
- setJoinExpr(pLeft->pOn);
- p->pWhere = sqlite3ExprAnd(p->pWhere, pLeft->pOn);
- pLeft->pOn = 0;
- }
-
- /* Create extra terms on the WHERE clause for each column named
- ** in the USING clause. Example: If the two tables to be joined are
- ** A and B and the USING clause names X, Y, and Z, then add this
- ** to the WHERE clause: A.X=B.X AND A.Y=B.Y AND A.Z=B.Z
- ** Report an error if any column mentioned in the USING clause is
- ** not contained in both tables to be joined.
- */
- if( pLeft->pUsing ){
- IdList *pList = pLeft->pUsing;
- for(j=0; j<pList->nId; j++){
- char *zName = pList->a[j].zName;
- if( columnIndex(pLeftTab, zName)<0 || columnIndex(pRightTab, zName)<0 ){
- sqlite3ErrorMsg(pParse, "cannot join using column %s - column "
- "not present in both tables", zName);
- return 1;
- }
- addWhereTerm(zName, pLeftTab, pRightTab, &p->pWhere);
- }
- }
- }
- return 0;
-}
-
-/*
-** Delete the given Select structure and all of its substructures.
-*/
-void sqlite3SelectDelete(Select *p){
- if( p==0 ) return;
- sqlite3ExprListDelete(p->pEList);
- sqlite3SrcListDelete(p->pSrc);
- sqlite3ExprDelete(p->pWhere);
- sqlite3ExprListDelete(p->pGroupBy);
- sqlite3ExprDelete(p->pHaving);
- sqlite3ExprListDelete(p->pOrderBy);
- sqlite3SelectDelete(p->pPrior);
- sqliteFree(p->zSelect);
- sqliteFree(p);
-}
-
-/*
-** Delete the aggregate information from the parse structure.
-*/
-static void sqliteAggregateInfoReset(Parse *pParse){
- sqliteFree(pParse->aAgg);
- pParse->aAgg = 0;
- pParse->nAgg = 0;
- pParse->useAgg = 0;
-}
-
-/*
-** Insert code into "v" that will push the record on the top of the
-** stack into the sorter.
-*/
-static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
- int i;
- for(i=0; i<pOrderBy->nExpr; i++){
- sqlite3ExprCode(pParse, pOrderBy->a[i].pExpr);
- }
- sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr, 0);
- sqlite3VdbeAddOp(v, OP_SortPut, 0, 0);
-}
-
-/*
-** Add code to implement the OFFSET and LIMIT
-*/
-static void codeLimiter(
- Vdbe *v, /* Generate code into this VM */
- Select *p, /* The SELECT statement being coded */
- int iContinue, /* Jump here to skip the current record */
- int iBreak, /* Jump here to end the loop */
- int nPop /* Number of times to pop stack when jumping */
-){
- if( p->iOffset>=0 ){
- int addr = sqlite3VdbeCurrentAddr(v) + 2;
- if( nPop>0 ) addr++;
- sqlite3VdbeAddOp(v, OP_MemIncr, p->iOffset, addr);
- if( nPop>0 ){
- sqlite3VdbeAddOp(v, OP_Pop, nPop, 0);
- }
- sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue);
- VdbeComment((v, "# skip OFFSET records"));
- }
- if( p->iLimit>=0 ){
- sqlite3VdbeAddOp(v, OP_MemIncr, p->iLimit, iBreak);
- VdbeComment((v, "# exit when LIMIT reached"));
- }
-}
-
-/*
-** This routine generates the code for the inside of the inner loop
-** of a SELECT.
-**
-** If srcTab and nColumn are both zero, then the pEList expressions
-** are evaluated in order to get the data for this row. If nColumn>0
-** then data is pulled from srcTab and pEList is used only to get the
-** datatypes for each column.
-*/
-static int selectInnerLoop(
- Parse *pParse, /* The parser context */
- Select *p, /* The complete select statement being coded */
- ExprList *pEList, /* List of values being extracted */
- int srcTab, /* Pull data from this table */
- int nColumn, /* Number of columns in the source table */
- ExprList *pOrderBy, /* If not NULL, sort results using this key */
- int distinct, /* If >=0, make sure results are distinct */
- int eDest, /* How to dispose of the results */
- int iParm, /* An argument to the disposal method */
- int iContinue, /* Jump here to continue with next row */
- int iBreak, /* Jump here to break out of the inner loop */
- char *aff /* affinity string if eDest is SRT_Union */
-){
- Vdbe *v = pParse->pVdbe;
- int i;
- int hasDistinct; /* True if the DISTINCT keyword is present */
-
- if( v==0 ) return 0;
- assert( pEList!=0 );
-
- /* If there was a LIMIT clause on the SELECT statement, then do the check
- ** to see if this row should be output.
- */
- hasDistinct = distinct>=0 && pEList && pEList->nExpr>0;
- if( pOrderBy==0 && !hasDistinct ){
- codeLimiter(v, p, iContinue, iBreak, 0);
- }
-
- /* Pull the requested columns.
- */
- if( nColumn>0 ){
- for(i=0; i<nColumn; i++){
- sqlite3VdbeAddOp(v, OP_Column, srcTab, i);
- }
- }else{
- nColumn = pEList->nExpr;
- for(i=0; i<pEList->nExpr; i++){
- sqlite3ExprCode(pParse, pEList->a[i].pExpr);
- }
- }
-
- /* If the DISTINCT keyword was present on the SELECT statement
- ** and this row has been seen before, then do not make this row
- ** part of the result.
- */
- if( hasDistinct ){
-#if NULL_ALWAYS_DISTINCT
- sqlite3VdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqlite3VdbeCurrentAddr(v)+7);
-#endif
- /* Deliberately leave the affinity string off of the following
- ** OP_MakeRecord */
- sqlite3VdbeAddOp(v, OP_MakeRecord, pEList->nExpr * -1, 0);
- sqlite3VdbeAddOp(v, OP_Distinct, distinct, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue);
- VdbeComment((v, "# skip indistinct records"));
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- sqlite3VdbeAddOp(v, OP_PutStrKey, distinct, 0);
- if( pOrderBy==0 ){
- codeLimiter(v, p, iContinue, iBreak, nColumn);
- }
- }
-
- switch( eDest ){
- /* In this mode, write each query result to the key of the temporary
- ** table iParm.
- */
- case SRT_Union: {
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
- sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- sqlite3VdbeAddOp(v, OP_PutStrKey, iParm, 0);
- break;
- }
-
- /* Store the result as data using a unique key.
- */
- case SRT_Table:
- case SRT_TempTable: {
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
- if( pOrderBy ){
- pushOntoSorter(pParse, v, pOrderBy);
- }else{
- sqlite3VdbeAddOp(v, OP_NewRecno, iParm, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- sqlite3VdbeAddOp(v, OP_PutIntKey, iParm, 0);
- }
- break;
- }
-
- /* Construct a record from the query result, but instead of
- ** saving that record, use it as a key to delete elements from
- ** the temporary table iParm.
- */
- case SRT_Except: {
- int addr;
- addr = sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
- sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
- sqlite3VdbeAddOp(v, OP_NotFound, iParm, addr+3);
- sqlite3VdbeAddOp(v, OP_Delete, iParm, 0);
- break;
- }
-
- /* If we are creating a set for an "expr IN (SELECT ...)" construct,
- ** then there should be a single item on the stack. Write this
- ** item into the set table with bogus data.
- */
- case SRT_Set: {
- int addr1 = sqlite3VdbeCurrentAddr(v);
- int addr2;
-
- assert( nColumn==1 );
- sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
- if( pOrderBy ){
- pushOntoSorter(pParse, v, pOrderBy);
- }else{
- char aff = (iParm>>16)&0xFF;
- aff = sqlite3CompareAffinity(pEList->a[0].pExpr, aff);
- sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &aff, 1);
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- sqlite3VdbeAddOp(v, OP_PutStrKey, (iParm&0x0000FFFF), 0);
- }
- sqlite3VdbeChangeP2(v, addr2, sqlite3VdbeCurrentAddr(v));
- break;
- }
-
- /* If this is a scalar select that is part of an expression, then
- ** store the results in the appropriate memory cell and break out
- ** of the scan loop.
- */
- case SRT_Mem: {
- assert( nColumn==1 );
- if( pOrderBy ){
- pushOntoSorter(pParse, v, pOrderBy);
- }else{
- sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
- sqlite3VdbeAddOp(v, OP_Goto, 0, iBreak);
- }
- break;
- }
-
- /* Send the data to the callback function.
- */
- case SRT_Callback:
- case SRT_Sorter: {
- if( pOrderBy ){
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
- pushOntoSorter(pParse, v, pOrderBy);
- }else{
- assert( eDest==SRT_Callback );
- sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0);
- }
- break;
- }
-
- /* Invoke a subroutine to handle the results. The subroutine itself
- ** is responsible for popping the results off of the stack.
- */
- case SRT_Subroutine: {
- if( pOrderBy ){
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
- pushOntoSorter(pParse, v, pOrderBy);
- }else{
- sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
- }
- break;
- }
-
- /* Discard the results. This is used for SELECT statements inside
- ** the body of a TRIGGER. The purpose of such selects is to call
- ** user-defined functions that have side effects. We do not care
- ** about the actual results of the select.
- */
- default: {
- assert( eDest==SRT_Discard );
- sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
- break;
- }
- }
- return 0;
-}
-
-/*
-** If the inner loop was generated using a non-null pOrderBy argument,
-** then the results were placed in a sorter. After the loop is terminated
-** we need to run the sorter and output the results. The following
-** routine generates the code needed to do that.
-*/
-static void generateSortTail(
- Parse *pParse, /* The parsing context */
- Select *p, /* The SELECT statement */
- Vdbe *v, /* Generate code into this VDBE */
- int nColumn, /* Number of columns of data */
- int eDest, /* Write the sorted results here */
- int iParm /* Optional parameter associated with eDest */
-){
- int end1 = sqlite3VdbeMakeLabel(v);
- int end2 = sqlite3VdbeMakeLabel(v);
- int addr;
- KeyInfo *pInfo;
- ExprList *pOrderBy;
- int nCol, i;
- sqlite3 *db = pParse->db;
-
- if( eDest==SRT_Sorter ) return;
- pOrderBy = p->pOrderBy;
- nCol = pOrderBy->nExpr;
- pInfo = sqliteMalloc( sizeof(*pInfo) + nCol*(sizeof(CollSeq*)+1) );
- if( pInfo==0 ) return;
- pInfo->aSortOrder = (char*)&pInfo->aColl[nCol];
- pInfo->nField = nCol;
- for(i=0; i<nCol; i++){
- /* If a collation sequence was specified explicity, then it
- ** is stored in pOrderBy->a[i].zName. Otherwise, use the default
- ** collation type for the expression.
- */
- pInfo->aColl[i] = sqlite3ExprCollSeq(pParse, pOrderBy->a[i].pExpr);
- if( !pInfo->aColl[i] ){
- pInfo->aColl[i] = db->pDfltColl;
- }
- pInfo->aSortOrder[i] = pOrderBy->a[i].sortOrder;
- }
- sqlite3VdbeOp3(v, OP_Sort, 0, 0, (char*)pInfo, P3_KEYINFO_HANDOFF);
- addr = sqlite3VdbeAddOp(v, OP_SortNext, 0, end1);
- codeLimiter(v, p, addr, end2, 1);
- switch( eDest ){
- case SRT_Table:
- case SRT_TempTable: {
- sqlite3VdbeAddOp(v, OP_NewRecno, iParm, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- sqlite3VdbeAddOp(v, OP_PutIntKey, iParm, 0);
- break;
- }
- case SRT_Set: {
- assert( nColumn==1 );
- sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "n", P3_STATIC);
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- sqlite3VdbeAddOp(v, OP_PutStrKey, (iParm&0x0000FFFF), 0);
- break;
- }
- case SRT_Mem: {
- assert( nColumn==1 );
- sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
- sqlite3VdbeAddOp(v, OP_Goto, 0, end1);
- break;
- }
- case SRT_Callback:
- case SRT_Subroutine: {
- int i;
- sqlite3VdbeAddOp(v, OP_Integer, p->pEList->nExpr, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- for(i=0; i<nColumn; i++){
- sqlite3VdbeAddOp(v, OP_Column, -1-i, i);
- }
- if( eDest==SRT_Callback ){
- sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0);
- }else{
- sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
- }
- sqlite3VdbeAddOp(v, OP_Pop, 2, 0);
- break;
- }
- default: {
- /* Do nothing */
- break;
- }
- }
- sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
- sqlite3VdbeResolveLabel(v, end2);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeResolveLabel(v, end1);
- sqlite3VdbeAddOp(v, OP_SortReset, 0, 0);
-}
-
-/*
-** Return a pointer to a string containing the 'declaration type' of the
-** expression pExpr. The string may be treated as static by the caller.
-**
-** If the declaration type is the exact datatype definition extracted from
-** the original CREATE TABLE statement if the expression is a column.
-**
-** The declaration type for an expression is either TEXT, NUMERIC or ANY.
-** The declaration type for a ROWID field is INTEGER.
-*/
-static const char *columnType(Parse *pParse, SrcList *pTabList, Expr *pExpr){
- char const *zType;
- int j;
- if( pExpr==0 || pTabList==0 ) return 0;
-
- switch( pExpr->op ){
- case TK_COLUMN: {
- Table *pTab;
- int iCol = pExpr->iColumn;
- for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable; j++){}
- assert( j<pTabList->nSrc );
- pTab = pTabList->a[j].pTab;
- if( iCol<0 ) iCol = pTab->iPKey;
- assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
- if( iCol<0 ){
- zType = "INTEGER";
- }else{
- zType = pTab->aCol[iCol].zType;
- }
- break;
- }
- case TK_AS:
- zType = columnType(pParse, pTabList, pExpr->pLeft);
- break;
- case TK_SELECT: {
- Select *pS = pExpr->pSelect;
- zType = columnType(pParse, pS->pSrc, pS->pEList->a[0].pExpr);
- break;
- }
- default:
- zType = 0;
- }
-
- return zType;
-}
-
-/*
-** Generate code that will tell the VDBE the declaration types of columns
-** in the result set.
-*/
-static void generateColumnTypes(
- Parse *pParse, /* Parser context */
- SrcList *pTabList, /* List of tables */
- ExprList *pEList /* Expressions defining the result set */
-){
- Vdbe *v = pParse->pVdbe;
- int i;
- for(i=0; i<pEList->nExpr; i++){
- Expr *p = pEList->a[i].pExpr;
- const char *zType = columnType(pParse, pTabList, p);
- if( zType==0 ) continue;
- /* The vdbe must make it's own copy of the column-type, in case the
- ** schema is reset before this virtual machine is deleted.
- */
- sqlite3VdbeSetColName(v, i+pEList->nExpr, zType, strlen(zType));
- }
-}
-
-/*
-** Generate code that will tell the VDBE the names of columns
-** in the result set. This information is used to provide the
-** azCol[] values in the callback.
-*/
-static void generateColumnNames(
- Parse *pParse, /* Parser context */
- SrcList *pTabList, /* List of tables */
- ExprList *pEList /* Expressions defining the result set */
-){
- Vdbe *v = pParse->pVdbe;
- int i, j;
- sqlite3 *db = pParse->db;
- int fullNames, shortNames;
-
- /* If this is an EXPLAIN, skip this step */
- if( pParse->explain ){
- return;
- }
-
- assert( v!=0 );
- if( pParse->colNamesSet || v==0 || sqlite3_malloc_failed ) return;
- pParse->colNamesSet = 1;
- fullNames = (db->flags & SQLITE_FullColNames)!=0;
- shortNames = (db->flags & SQLITE_ShortColNames)!=0;
- sqlite3VdbeSetNumCols(v, pEList->nExpr);
- for(i=0; i<pEList->nExpr; i++){
- Expr *p;
- p = pEList->a[i].pExpr;
- if( p==0 ) continue;
- if( pEList->a[i].zName ){
- char *zName = pEList->a[i].zName;
- sqlite3VdbeSetColName(v, i, zName, strlen(zName));
- continue;
- }
- if( p->op==TK_COLUMN && pTabList ){
- Table *pTab;
- char *zCol;
- int iCol = p->iColumn;
- for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=p->iTable; j++){}
- assert( j<pTabList->nSrc );
- pTab = pTabList->a[j].pTab;
- if( iCol<0 ) iCol = pTab->iPKey;
- assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
- if( iCol<0 ){
- zCol = "_ROWID_";
- }else{
- zCol = pTab->aCol[iCol].zName;
- }
- if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){
- sqlite3VdbeSetColName(v, i, p->span.z, p->span.n);
- }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){
- char *zName = 0;
- char *zTab;
-
- zTab = pTabList->a[j].zAlias;
- if( fullNames || zTab==0 ) zTab = pTab->zName;
- sqlite3SetString(&zName, zTab, ".", zCol, 0);
- sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC);
- }else{
- sqlite3VdbeSetColName(v, i, zCol, 0);
- }
- }else if( p->span.z && p->span.z[0] ){
- sqlite3VdbeSetColName(v, i, p->span.z, p->span.n);
- /* sqlite3VdbeCompressSpace(v, addr); */
- }else{
- char zName[30];
- assert( p->op!=TK_COLUMN || pTabList==0 );
- sprintf(zName, "column%d", i+1);
- sqlite3VdbeSetColName(v, i, zName, 0);
- }
- }
- generateColumnTypes(pParse, pTabList, pEList);
-}
-
-/*
-** Name of the connection operator, used for error messages.
-*/
-static const char *selectOpName(int id){
- char *z;
- switch( id ){
- case TK_ALL: z = "UNION ALL"; break;
- case TK_INTERSECT: z = "INTERSECT"; break;
- case TK_EXCEPT: z = "EXCEPT"; break;
- default: z = "UNION"; break;
- }
- return z;
-}
-
-/*
-** Forward declaration
-*/
-static int fillInColumnList(Parse*, Select*);
-
-/*
-** Given a SELECT statement, generate a Table structure that describes
-** the result set of that SELECT.
-*/
-Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
- Table *pTab;
- int i, j;
- ExprList *pEList;
- Column *aCol, *pCol;
-
- if( fillInColumnList(pParse, pSelect) ){
- return 0;
- }
- pTab = sqliteMalloc( sizeof(Table) );
- if( pTab==0 ){
- return 0;
- }
- pTab->zName = zTabName ? sqliteStrDup(zTabName) : 0;
- pEList = pSelect->pEList;
- pTab->nCol = pEList->nExpr;
- assert( pTab->nCol>0 );
- pTab->aCol = aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol );
- for(i=0, pCol=aCol; i<pTab->nCol; i++, pCol++){
- Expr *pR;
- char *zType;
- char *zName;
- Expr *p = pEList->a[i].pExpr;
- assert( p->pRight==0 || p->pRight->token.z==0 || p->pRight->token.z[0]!=0 );
- if( (zName = pEList->a[i].zName)!=0 ){
- zName = sqliteStrDup(zName);
- }else if( p->op==TK_DOT
- && (pR=p->pRight)!=0 && pR->token.z && pR->token.z[0] ){
- int cnt;
- zName = sqlite3MPrintf("%T", &pR->token);
- for(j=cnt=0; j<i; j++){
- if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
- sqliteFree(zName);
- zName = sqlite3MPrintf("%T_%d", &pR->token, ++cnt);
- j = -1;
- }
- }
- }else if( p->span.z && p->span.z[0] ){
- zName = sqlite3MPrintf("%T", &p->span);
- }else{
- zName = sqlite3MPrintf("column%d", i+1);
- }
- sqlite3Dequote(zName);
- pCol->zName = zName;
-
- zType = sqliteStrDup(columnType(pParse, pSelect->pSrc ,p));
- pCol->zType = zType;
- pCol->affinity = SQLITE_AFF_NUMERIC;
- if( zType ){
- pCol->affinity = sqlite3AffinityType(zType, strlen(zType));
- }
- pCol->pColl = sqlite3ExprCollSeq(pParse, p);
- if( !pCol->pColl ){
- pCol->pColl = pParse->db->pDfltColl;
- }
- }
- pTab->iPKey = -1;
- return pTab;
-}
-
-/*
-** For the given SELECT statement, do three things.
-**
-** (1) Fill in the pTabList->a[].pTab fields in the SrcList that
-** defines the set of tables that should be scanned. For views,
-** fill pTabList->a[].pSelect with a copy of the SELECT statement
-** that implements the view. A copy is made of the view's SELECT
-** statement so that we can freely modify or delete that statement
-** without worrying about messing up the presistent representation
-** of the view.
-**
-** (2) Add terms to the WHERE clause to accomodate the NATURAL keyword
-** on joins and the ON and USING clause of joins.
-**
-** (3) Scan the list of columns in the result set (pEList) looking
-** for instances of the "*" operator or the TABLE.* operator.
-** If found, expand each "*" to be every column in every table
-** and TABLE.* to be every column in TABLE.
-**
-** Return 0 on success. If there are problems, leave an error message
-** in pParse and return non-zero.
-*/
-static int fillInColumnList(Parse *pParse, Select *p){
- int i, j, k, rc;
- SrcList *pTabList;
- ExprList *pEList;
- Table *pTab;
- struct SrcList_item *pFrom;
-
- if( p==0 || p->pSrc==0 ) return 1;
- pTabList = p->pSrc;
- pEList = p->pEList;
-
- /* Look up every table in the table list.
- */
- for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
- if( pFrom->pTab ){
- /* This routine has run before! No need to continue */
- return 0;
- }
- if( pFrom->zName==0 ){
- /* A sub-query in the FROM clause of a SELECT */
- assert( pFrom->pSelect!=0 );
- if( pFrom->zAlias==0 ){
- pFrom->zAlias =
- sqlite3MPrintf("sqlite_subquery_%p_", (void*)pFrom->pSelect);
- }
- pFrom->pTab = pTab =
- sqlite3ResultSetOfSelect(pParse, pFrom->zAlias, pFrom->pSelect);
- if( pTab==0 ){
- return 1;
- }
- /* The isTransient flag indicates that the Table structure has been
- ** dynamically allocated and may be freed at any time. In other words,
- ** pTab is not pointing to a persistent table structure that defines
- ** part of the schema. */
- pTab->isTransient = 1;
- }else{
- /* An ordinary table or view name in the FROM clause */
- pFrom->pTab = pTab =
- sqlite3LocateTable(pParse,pFrom->zName,pFrom->zDatabase);
- if( pTab==0 ){
- return 1;
- }
- if( pTab->pSelect ){
- /* We reach here if the named table is a really a view */
- if( sqlite3ViewGetColumnNames(pParse, pTab) ){
- return 1;
- }
- /* If pFrom->pSelect!=0 it means we are dealing with a
- ** view within a view. The SELECT structure has already been
- ** copied by the outer view so we can skip the copy step here
- ** in the inner view.
- */
- if( pFrom->pSelect==0 ){
- pFrom->pSelect = sqlite3SelectDup(pTab->pSelect);
- }
- }
- }
- }
-
- /* Process NATURAL keywords, and ON and USING clauses of joins.
- */
- if( sqliteProcessJoin(pParse, p) ) return 1;
-
- /* For every "*" that occurs in the column list, insert the names of
- ** all columns in all tables. And for every TABLE.* insert the names
- ** of all columns in TABLE. The parser inserted a special expression
- ** with the TK_ALL operator for each "*" that it found in the column list.
- ** The following code just has to locate the TK_ALL expressions and expand
- ** each one to the list of all columns in all tables.
- **
- ** The first loop just checks to see if there are any "*" operators
- ** that need expanding.
- */
- for(k=0; k<pEList->nExpr; k++){
- Expr *pE = pEList->a[k].pExpr;
- if( pE->op==TK_ALL ) break;
- if( pE->op==TK_DOT && pE->pRight && pE->pRight->op==TK_ALL
- && pE->pLeft && pE->pLeft->op==TK_ID ) break;
- }
- rc = 0;
- if( k<pEList->nExpr ){
- /*
- ** If we get here it means the result set contains one or more "*"
- ** operators that need to be expanded. Loop through each expression
- ** in the result set and expand them one by one.
- */
- struct ExprList_item *a = pEList->a;
- ExprList *pNew = 0;
- for(k=0; k<pEList->nExpr; k++){
- Expr *pE = a[k].pExpr;
- if( pE->op!=TK_ALL &&
- (pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){
- /* This particular expression does not need to be expanded.
- */
- pNew = sqlite3ExprListAppend(pNew, a[k].pExpr, 0);
- pNew->a[pNew->nExpr-1].zName = a[k].zName;
- a[k].pExpr = 0;
- a[k].zName = 0;
- }else{
- /* This expression is a "*" or a "TABLE.*" and needs to be
- ** expanded. */
- int tableSeen = 0; /* Set to 1 when TABLE matches */
- char *zTName; /* text of name of TABLE */
- if( pE->op==TK_DOT && pE->pLeft ){
- zTName = sqlite3NameFromToken(&pE->pLeft->token);
- }else{
- zTName = 0;
- }
- for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
- Table *pTab = pFrom->pTab;
- char *zTabName = pFrom->zAlias;
- if( zTabName==0 || zTabName[0]==0 ){
- zTabName = pTab->zName;
- }
- if( zTName && (zTabName==0 || zTabName[0]==0 ||
- sqlite3StrICmp(zTName, zTabName)!=0) ){
- continue;
- }
- tableSeen = 1;
- for(j=0; j<pTab->nCol; j++){
- Expr *pExpr, *pLeft, *pRight;
- char *zName = pTab->aCol[j].zName;
-
- if( i>0 ){
- struct SrcList_item *pLeft = &pTabList->a[i-1];
- if( (pLeft->jointype & JT_NATURAL)!=0 &&
- columnIndex(pLeft->pTab, zName)>=0 ){
- /* In a NATURAL join, omit the join columns from the
- ** table on the right */
- continue;
- }
- if( sqlite3IdListIndex(pLeft->pUsing, zName)>=0 ){
- /* In a join with a USING clause, omit columns in the
- ** using clause from the table on the right. */
- continue;
- }
- }
- pRight = sqlite3Expr(TK_ID, 0, 0, 0);
- if( pRight==0 ) break;
- setToken(&pRight->token, zName);
- if( zTabName && pTabList->nSrc>1 ){
- pLeft = sqlite3Expr(TK_ID, 0, 0, 0);
- pExpr = sqlite3Expr(TK_DOT, pLeft, pRight, 0);
- if( pExpr==0 ) break;
- setToken(&pLeft->token, zTabName);
- setToken(&pExpr->span, sqlite3MPrintf("%s.%s", zTabName, zName));
- pExpr->span.dyn = 1;
- pExpr->token.z = 0;
- pExpr->token.n = 0;
- pExpr->token.dyn = 0;
- }else{
- pExpr = pRight;
- pExpr->span = pExpr->token;
- }
- pNew = sqlite3ExprListAppend(pNew, pExpr, 0);
- }
- }
- if( !tableSeen ){
- if( zTName ){
- sqlite3ErrorMsg(pParse, "no such table: %s", zTName);
- }else{
- sqlite3ErrorMsg(pParse, "no tables specified");
- }
- rc = 1;
- }
- sqliteFree(zTName);
- }
- }
- sqlite3ExprListDelete(pEList);
- p->pEList = pNew;
- }
- return rc;
-}
-
-/*
-** This routine recursively unlinks the Select.pSrc.a[].pTab pointers
-** in a select structure. It just sets the pointers to NULL. This
-** routine is recursive in the sense that if the Select.pSrc.a[].pSelect
-** pointer is not NULL, this routine is called recursively on that pointer.
-**
-** This routine is called on the Select structure that defines a
-** VIEW in order to undo any bindings to tables. This is necessary
-** because those tables might be DROPed by a subsequent SQL command.
-** If the bindings are not removed, then the Select.pSrc->a[].pTab field
-** will be left pointing to a deallocated Table structure after the
-** DROP and a coredump will occur the next time the VIEW is used.
-*/
-void sqlite3SelectUnbind(Select *p){
- int i;
- SrcList *pSrc = p->pSrc;
- struct SrcList_item *pItem;
- Table *pTab;
- if( p==0 ) return;
- for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
- if( (pTab = pItem->pTab)!=0 ){
- if( pTab->isTransient ){
- sqlite3DeleteTable(0, pTab);
- }
- pItem->pTab = 0;
- if( pItem->pSelect ){
- sqlite3SelectUnbind(pItem->pSelect);
- }
- }
- }
-}
-
-/*
-** This routine associates entries in an ORDER BY expression list with
-** columns in a result. For each ORDER BY expression, the opcode of
-** the top-level node is changed to TK_COLUMN and the iColumn value of
-** the top-level node is filled in with column number and the iTable
-** value of the top-level node is filled with iTable parameter.
-**
-** If there are prior SELECT clauses, they are processed first. A match
-** in an earlier SELECT takes precedence over a later SELECT.
-**
-** Any entry that does not match is flagged as an error. The number
-** of errors is returned.
-*/
-static int matchOrderbyToColumn(
- Parse *pParse, /* A place to leave error messages */
- Select *pSelect, /* Match to result columns of this SELECT */
- ExprList *pOrderBy, /* The ORDER BY values to match against columns */
- int iTable, /* Insert this value in iTable */
- int mustComplete /* If TRUE all ORDER BYs must match */
-){
- int nErr = 0;
- int i, j;
- ExprList *pEList;
-
- if( pSelect==0 || pOrderBy==0 ) return 1;
- if( mustComplete ){
- for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].done = 0; }
- }
- if( fillInColumnList(pParse, pSelect) ){
- return 1;
- }
- if( pSelect->pPrior ){
- if( matchOrderbyToColumn(pParse, pSelect->pPrior, pOrderBy, iTable, 0) ){
- return 1;
- }
- }
- pEList = pSelect->pEList;
- for(i=0; i<pOrderBy->nExpr; i++){
- Expr *pE = pOrderBy->a[i].pExpr;
- int iCol = -1;
- if( pOrderBy->a[i].done ) continue;
- if( sqlite3ExprIsInteger(pE, &iCol) ){
- if( iCol<=0 || iCol>pEList->nExpr ){
- sqlite3ErrorMsg(pParse,
- "ORDER BY position %d should be between 1 and %d",
- iCol, pEList->nExpr);
- nErr++;
- break;
- }
- if( !mustComplete ) continue;
- iCol--;
- }
- for(j=0; iCol<0 && j<pEList->nExpr; j++){
- if( pEList->a[j].zName && (pE->op==TK_ID || pE->op==TK_STRING) ){
- char *zName, *zLabel;
- zName = pEList->a[j].zName;
- zLabel = sqlite3NameFromToken(&pE->token);
- assert( zLabel!=0 );
- if( sqlite3StrICmp(zName, zLabel)==0 ){
- iCol = j;
- }
- sqliteFree(zLabel);
- }
- if( iCol<0 && sqlite3ExprCompare(pE, pEList->a[j].pExpr) ){
- iCol = j;
- }
- }
- if( iCol>=0 ){
- pE->op = TK_COLUMN;
- pE->iColumn = iCol;
- pE->iTable = iTable;
- pOrderBy->a[i].done = 1;
- }
- if( iCol<0 && mustComplete ){
- sqlite3ErrorMsg(pParse,
- "ORDER BY term number %d does not match any result column", i+1);
- nErr++;
- break;
- }
- }
- return nErr;
-}
-
-/*
-** Get a VDBE for the given parser context. Create a new one if necessary.
-** If an error occurs, return NULL and leave a message in pParse.
-*/
-Vdbe *sqlite3GetVdbe(Parse *pParse){
- Vdbe *v = pParse->pVdbe;
- if( v==0 ){
- v = pParse->pVdbe = sqlite3VdbeCreate(pParse->db);
- }
- return v;
-}
-
-/*
-** Compute the iLimit and iOffset fields of the SELECT based on the
-** nLimit and nOffset fields. nLimit and nOffset hold the integers
-** that appear in the original SQL statement after the LIMIT and OFFSET
-** keywords. Or that hold -1 and 0 if those keywords are omitted.
-** iLimit and iOffset are the integer memory register numbers for
-** counters used to compute the limit and offset. If there is no
-** limit and/or offset, then iLimit and iOffset are negative.
-**
-** This routine changes the values if iLimit and iOffset only if
-** a limit or offset is defined by nLimit and nOffset. iLimit and
-** iOffset should have been preset to appropriate default values
-** (usually but not always -1) prior to calling this routine.
-** Only if nLimit>=0 or nOffset>0 do the limit registers get
-** redefined. The UNION ALL operator uses this property to force
-** the reuse of the same limit and offset registers across multiple
-** SELECT statements.
-*/
-static void computeLimitRegisters(Parse *pParse, Select *p){
- /*
- ** If the comparison is p->nLimit>0 then "LIMIT 0" shows
- ** all rows. It is the same as no limit. If the comparision is
- ** p->nLimit>=0 then "LIMIT 0" show no rows at all.
- ** "LIMIT -1" always shows all rows. There is some
- ** contraversy about what the correct behavior should be.
- ** The current implementation interprets "LIMIT 0" to mean
- ** no rows.
- */
- if( p->nLimit>=0 ){
- int iMem = pParse->nMem++;
- Vdbe *v = sqlite3GetVdbe(pParse);
- if( v==0 ) return;
- sqlite3VdbeAddOp(v, OP_Integer, -p->nLimit, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1);
- VdbeComment((v, "# LIMIT counter"));
- p->iLimit = iMem;
- }
- if( p->nOffset>0 ){
- int iMem = pParse->nMem++;
- Vdbe *v = sqlite3GetVdbe(pParse);
- if( v==0 ) return;
- sqlite3VdbeAddOp(v, OP_Integer, -p->nOffset, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1);
- VdbeComment((v, "# OFFSET counter"));
- p->iOffset = iMem;
- }
-}
-
-/*
-** Generate VDBE instructions that will open a transient table that
-** will be used for an index or to store keyed results for a compound
-** select. In other words, open a transient table that needs a
-** KeyInfo structure. The number of columns in the KeyInfo is determined
-** by the result set of the SELECT statement in the second argument.
-**
-** Specifically, this routine is called to open an index table for
-** DISTINCT, UNION, INTERSECT and EXCEPT select statements (but not
-** UNION ALL).
-**
-** Make the new table a KeyAsData table if keyAsData is true.
-**
-** The value returned is the address of the OP_OpenTemp instruction.
-*/
-static int openTempIndex(Parse *pParse, Select *p, int iTab, int keyAsData){
- KeyInfo *pKeyInfo;
- int nColumn;
- sqlite3 *db = pParse->db;
- int i;
- Vdbe *v = pParse->pVdbe;
- int addr;
-
- if( fillInColumnList(pParse, p) ){
- return 0;
- }
- nColumn = p->pEList->nExpr;
- pKeyInfo = sqliteMalloc( sizeof(*pKeyInfo)+nColumn*sizeof(CollSeq*) );
- if( pKeyInfo==0 ) return 0;
- pKeyInfo->enc = db->enc;
- pKeyInfo->nField = nColumn;
- for(i=0; i<nColumn; i++){
- pKeyInfo->aColl[i] = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr);
- if( !pKeyInfo->aColl[i] ){
- pKeyInfo->aColl[i] = db->pDfltColl;
- }
- }
- addr = sqlite3VdbeOp3(v, OP_OpenTemp, iTab, 0,
- (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
- if( keyAsData ){
- sqlite3VdbeAddOp(v, OP_KeyAsData, iTab, 1);
- }
- return addr;
-}
-
-/*
-** Add the address "addr" to the set of all OpenTemp opcode addresses
-** that are being accumulated in p->ppOpenTemp.
-*/
-static int multiSelectOpenTempAddr(Select *p, int addr){
- IdList *pList = *p->ppOpenTemp = sqlite3IdListAppend(*p->ppOpenTemp, 0);
- if( pList==0 ){
- return SQLITE_NOMEM;
- }
- pList->a[pList->nId-1].idx = addr;
- return SQLITE_OK;
-}
-
-/*
-** Return the appropriate collating sequence for the iCol-th column of
-** the result set for the compound-select statement "p". Return NULL if
-** the column has no default collating sequence.
-**
-** The collating sequence for the compound select is taken from the
-** left-most term of the select that has a collating sequence.
-*/
-static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){
- CollSeq *pRet;
- if( p->pPrior ){
- pRet = multiSelectCollSeq(pParse, p->pPrior, iCol);
- }else{
- pRet = 0;
- }
- if( pRet==0 ){
- pRet = sqlite3ExprCollSeq(pParse, p->pEList->a[iCol].pExpr);
- }
- return pRet;
-}
-
-/*
-** This routine is called to process a query that is really the union
-** or intersection of two or more separate queries.
-**
-** "p" points to the right-most of the two queries. the query on the
-** left is p->pPrior. The left query could also be a compound query
-** in which case this routine will be called recursively.
-**
-** The results of the total query are to be written into a destination
-** of type eDest with parameter iParm.
-**
-** Example 1: Consider a three-way compound SQL statement.
-**
-** SELECT a FROM t1 UNION SELECT b FROM t2 UNION SELECT c FROM t3
-**
-** This statement is parsed up as follows:
-**
-** SELECT c FROM t3
-** |
-** `-----> SELECT b FROM t2
-** |
-** `------> SELECT a FROM t1
-**
-** The arrows in the diagram above represent the Select.pPrior pointer.
-** So if this routine is called with p equal to the t3 query, then
-** pPrior will be the t2 query. p->op will be TK_UNION in this case.
-**
-** Notice that because of the way SQLite parses compound SELECTs, the
-** individual selects always group from left to right.
-*/
-static int multiSelect(
- Parse *pParse, /* Parsing context */
- Select *p, /* The right-most of SELECTs to be coded */
- int eDest, /* \___ Store query results as specified */
- int iParm, /* / by these two parameters. */
- char *aff /* If eDest is SRT_Union, the affinity string */
-){
- int rc = SQLITE_OK; /* Success code from a subroutine */
- Select *pPrior; /* Another SELECT immediately to our left */
- Vdbe *v; /* Generate code to this VDBE */
- IdList *pOpenTemp = 0;/* OP_OpenTemp opcodes that need a KeyInfo */
- int aAddr[5]; /* Addresses of SetNumColumns operators */
- int nAddr = 0; /* Number used */
- int nCol; /* Number of columns in the result set */
-
- /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only
- ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
- */
- if( p==0 || p->pPrior==0 ){
- rc = 1;
- goto multi_select_end;
- }
- pPrior = p->pPrior;
- if( pPrior->pOrderBy ){
- sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
- selectOpName(p->op));
- rc = 1;
- goto multi_select_end;
- }
- if( pPrior->nLimit>=0 || pPrior->nOffset>0 ){
- sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before",
- selectOpName(p->op));
- rc = 1;
- goto multi_select_end;
- }
-
- /* Make sure we have a valid query engine. If not, create a new one.
- */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ){
- rc = 1;
- goto multi_select_end;
- }
-
- /* If *p this is the right-most select statement, then initialize
- ** p->ppOpenTemp to point to pOpenTemp. If *p is not the right most
- ** statement then p->ppOpenTemp will have already been initialized
- ** by a prior call to this same procedure. Pass along the pOpenTemp
- ** pointer to pPrior, the next statement to our left.
- */
- if( p->ppOpenTemp==0 ){
- p->ppOpenTemp = &pOpenTemp;
- }
- pPrior->ppOpenTemp = p->ppOpenTemp;
-
- /* Create the destination temporary table if necessary
- */
- if( eDest==SRT_TempTable ){
- assert( p->pEList );
- sqlite3VdbeAddOp(v, OP_OpenTemp, iParm, 0);
- assert( nAddr==0 );
- aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, 0);
- eDest = SRT_Table;
- }
-
- /* Generate code for the left and right SELECT statements.
- */
- switch( p->op ){
- case TK_ALL: {
- if( p->pOrderBy==0 ){
- pPrior->nLimit = p->nLimit;
- pPrior->nOffset = p->nOffset;
- rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff);
- if( rc ){
- goto multi_select_end;
- }
- p->pPrior = 0;
- p->iLimit = pPrior->iLimit;
- p->iOffset = pPrior->iOffset;
- p->nLimit = -1;
- p->nOffset = 0;
- rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff);
- p->pPrior = pPrior;
- if( rc ){
- goto multi_select_end;
- }
- break;
- }
- /* For UNION ALL ... ORDER BY fall through to the next case */
- }
- case TK_EXCEPT:
- case TK_UNION: {
- int unionTab; /* Cursor number of the temporary table holding result */
- int op = 0; /* One of the SRT_ operations to apply to self */
- int priorOp; /* The SRT_ operation to apply to prior selects */
- int nLimit, nOffset; /* Saved values of p->nLimit and p->nOffset */
- ExprList *pOrderBy; /* The ORDER BY clause for the right SELECT */
- int addr;
-
- priorOp = p->op==TK_ALL ? SRT_Table : SRT_Union;
- if( eDest==priorOp && p->pOrderBy==0 && p->nLimit<0 && p->nOffset==0 ){
- /* We can reuse a temporary table generated by a SELECT to our
- ** right.
- */
- unionTab = iParm;
- }else{
- /* We will need to create our own temporary table to hold the
- ** intermediate results.
- */
- unionTab = pParse->nTab++;
- if( p->pOrderBy
- && matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){
- rc = 1;
- goto multi_select_end;
- }
- addr = sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 0);
- if( p->op!=TK_ALL ){
- rc = multiSelectOpenTempAddr(p, addr);
- if( rc!=SQLITE_OK ){
- goto multi_select_end;
- }
- sqlite3VdbeAddOp(v, OP_KeyAsData, unionTab, 1);
- }
- assert( nAddr<sizeof(aAddr)/sizeof(aAddr[0]) );
- aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, unionTab, 0);
- assert( p->pEList );
- }
-
- /* Code the SELECT statements to our left
- */
- rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff);
- if( rc ){
- goto multi_select_end;
- }
-
- /* Code the current SELECT statement
- */
- switch( p->op ){
- case TK_EXCEPT: op = SRT_Except; break;
- case TK_UNION: op = SRT_Union; break;
- case TK_ALL: op = SRT_Table; break;
- }
- p->pPrior = 0;
- pOrderBy = p->pOrderBy;
- p->pOrderBy = 0;
- nLimit = p->nLimit;
- p->nLimit = -1;
- nOffset = p->nOffset;
- p->nOffset = 0;
- rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff);
- p->pPrior = pPrior;
- p->pOrderBy = pOrderBy;
- p->nLimit = nLimit;
- p->nOffset = nOffset;
- if( rc ){
- goto multi_select_end;
- }
-
-
- /* Convert the data in the temporary table into whatever form
- ** it is that we currently need.
- */
- if( eDest!=priorOp || unionTab!=iParm ){
- int iCont, iBreak, iStart;
- assert( p->pEList );
- if( eDest==SRT_Callback ){
- generateColumnNames(pParse, 0, p->pEList);
- }
- iBreak = sqlite3VdbeMakeLabel(v);
- iCont = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak);
- computeLimitRegisters(pParse, p);
- iStart = sqlite3VdbeCurrentAddr(v);
- rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
- p->pOrderBy, -1, eDest, iParm,
- iCont, iBreak, 0);
- if( rc ){
- rc = 1;
- goto multi_select_end;
- }
- sqlite3VdbeResolveLabel(v, iCont);
- sqlite3VdbeAddOp(v, OP_Next, unionTab, iStart);
- sqlite3VdbeResolveLabel(v, iBreak);
- sqlite3VdbeAddOp(v, OP_Close, unionTab, 0);
- }
- break;
- }
- case TK_INTERSECT: {
- int tab1, tab2;
- int iCont, iBreak, iStart;
- int nLimit, nOffset;
- int addr;
-
- /* INTERSECT is different from the others since it requires
- ** two temporary tables. Hence it has its own case. Begin
- ** by allocating the tables we will need.
- */
- tab1 = pParse->nTab++;
- tab2 = pParse->nTab++;
- if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
- rc = 1;
- goto multi_select_end;
- }
-
- addr = sqlite3VdbeAddOp(v, OP_OpenTemp, tab1, 0);
- rc = multiSelectOpenTempAddr(p, addr);
- if( rc!=SQLITE_OK ){
- goto multi_select_end;
- }
- sqlite3VdbeAddOp(v, OP_KeyAsData, tab1, 1);
- assert( nAddr<sizeof(aAddr)/sizeof(aAddr[0]) );
- aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, tab1, 0);
- assert( p->pEList );
-
- /* Code the SELECTs to our left into temporary table "tab1".
- */
- rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff);
- if( rc ){
- goto multi_select_end;
- }
-
- /* Code the current SELECT into temporary table "tab2"
- */
- addr = sqlite3VdbeAddOp(v, OP_OpenTemp, tab2, 0);
- rc = multiSelectOpenTempAddr(p, addr);
- if( rc!=SQLITE_OK ){
- goto multi_select_end;
- }
- sqlite3VdbeAddOp(v, OP_KeyAsData, tab2, 1);
- assert( nAddr<sizeof(aAddr)/sizeof(aAddr[0]) );
- aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, tab2, 0);
- p->pPrior = 0;
- nLimit = p->nLimit;
- p->nLimit = -1;
- nOffset = p->nOffset;
- p->nOffset = 0;
- rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff);
- p->pPrior = pPrior;
- p->nLimit = nLimit;
- p->nOffset = nOffset;
- if( rc ){
- goto multi_select_end;
- }
-
- /* Generate code to take the intersection of the two temporary
- ** tables.
- */
- assert( p->pEList );
- if( eDest==SRT_Callback ){
- generateColumnNames(pParse, 0, p->pEList);
- }
- iBreak = sqlite3VdbeMakeLabel(v);
- iCont = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak);
- computeLimitRegisters(pParse, p);
- iStart = sqlite3VdbeAddOp(v, OP_FullKey, tab1, 0);
- sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont);
- rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
- p->pOrderBy, -1, eDest, iParm,
- iCont, iBreak, 0);
- if( rc ){
- rc = 1;
- goto multi_select_end;
- }
- sqlite3VdbeResolveLabel(v, iCont);
- sqlite3VdbeAddOp(v, OP_Next, tab1, iStart);
- sqlite3VdbeResolveLabel(v, iBreak);
- sqlite3VdbeAddOp(v, OP_Close, tab2, 0);
- sqlite3VdbeAddOp(v, OP_Close, tab1, 0);
- break;
- }
- }
-
- /* Make sure all SELECTs in the statement have the same number of elements
- ** in their result sets.
- */
- assert( p->pEList && pPrior->pEList );
- if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
- sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
- " do not have the same number of result columns", selectOpName(p->op));
- rc = 1;
- goto multi_select_end;
- }
-
- /* Set the number of columns in temporary tables
- */
- nCol = p->pEList->nExpr;
- while( nAddr>0 ){
- nAddr--;
- sqlite3VdbeChangeP2(v, aAddr[nAddr], nCol);
- }
-
- /* Compute collating sequences used by either the ORDER BY clause or
- ** by any temporary tables needed to implement the compound select.
- ** Attach the KeyInfo structure to all temporary tables. Invoke the
- ** ORDER BY processing if there is an ORDER BY clause.
- **
- ** This section is run by the right-most SELECT statement only.
- ** SELECT statements to the left always skip this part. The right-most
- ** SELECT might also skip this part if it has no ORDER BY clause and
- ** no temp tables are required.
- */
- if( p->pOrderBy || (pOpenTemp && pOpenTemp->nId>0) ){
- int i; /* Loop counter */
- KeyInfo *pKeyInfo; /* Collating sequence for the result set */
-
- assert( p->ppOpenTemp == &pOpenTemp );
- pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*sizeof(CollSeq*));
- if( !pKeyInfo ){
- rc = SQLITE_NOMEM;
- goto multi_select_end;
- }
-
- pKeyInfo->enc = pParse->db->enc;
- pKeyInfo->nField = nCol;
-
- for(i=0; i<nCol; i++){
- pKeyInfo->aColl[i] = multiSelectCollSeq(pParse, p, i);
- if( !pKeyInfo->aColl[i] ){
- pKeyInfo->aColl[i] = pParse->db->pDfltColl;
- }
- }
-
- for(i=0; pOpenTemp && i<pOpenTemp->nId; i++){
- int p3type = (i==0?P3_KEYINFO_HANDOFF:P3_KEYINFO);
- int addr = pOpenTemp->a[i].idx;
- sqlite3VdbeChangeP3(v, addr, (char *)pKeyInfo, p3type);
- }
-
- if( p->pOrderBy ){
- struct ExprList_item *pOrderByTerm = p->pOrderBy->a;
- for(i=0; i<p->pOrderBy->nExpr; i++, pOrderByTerm++){
- Expr *pExpr = pOrderByTerm->pExpr;
- char *zName = pOrderByTerm->zName;
- assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol );
- assert( !pExpr->pColl );
- if( zName ){
- pExpr->pColl = sqlite3LocateCollSeq(pParse, zName, -1);
- }else{
- pExpr->pColl = pKeyInfo->aColl[pExpr->iColumn];
- }
- }
- generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm);
- }
-
- if( !pOpenTemp ){
- /* This happens for UNION ALL ... ORDER BY */
- sqliteFree(pKeyInfo);
- }
- }
-
-multi_select_end:
- if( pOpenTemp ){
- sqlite3IdListDelete(pOpenTemp);
- }
- p->ppOpenTemp = 0;
- return rc;
-}
-
-/*
-** Scan through the expression pExpr. Replace every reference to
-** a column in table number iTable with a copy of the iColumn-th
-** entry in pEList. (But leave references to the ROWID column
-** unchanged.)
-**
-** This routine is part of the flattening procedure. A subquery
-** whose result set is defined by pEList appears as entry in the
-** FROM clause of a SELECT such that the VDBE cursor assigned to that
-** FORM clause entry is iTable. This routine make the necessary
-** changes to pExpr so that it refers directly to the source table
-** of the subquery rather the result set of the subquery.
-*/
-static void substExprList(ExprList*,int,ExprList*); /* Forward Decl */
-static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
- if( pExpr==0 ) return;
- if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
- if( pExpr->iColumn<0 ){
- pExpr->op = TK_NULL;
- }else{
- Expr *pNew;
- assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
- assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
- pNew = pEList->a[pExpr->iColumn].pExpr;
- assert( pNew!=0 );
- pExpr->op = pNew->op;
- assert( pExpr->pLeft==0 );
- pExpr->pLeft = sqlite3ExprDup(pNew->pLeft);
- assert( pExpr->pRight==0 );
- pExpr->pRight = sqlite3ExprDup(pNew->pRight);
- assert( pExpr->pList==0 );
- pExpr->pList = sqlite3ExprListDup(pNew->pList);
- pExpr->iTable = pNew->iTable;
- pExpr->iColumn = pNew->iColumn;
- pExpr->iAgg = pNew->iAgg;
- sqlite3TokenCopy(&pExpr->token, &pNew->token);
- sqlite3TokenCopy(&pExpr->span, &pNew->span);
- }
- }else{
- substExpr(pExpr->pLeft, iTable, pEList);
- substExpr(pExpr->pRight, iTable, pEList);
- substExprList(pExpr->pList, iTable, pEList);
- }
-}
-static void
-substExprList(ExprList *pList, int iTable, ExprList *pEList){
- int i;
- if( pList==0 ) return;
- for(i=0; i<pList->nExpr; i++){
- substExpr(pList->a[i].pExpr, iTable, pEList);
- }
-}
-
-/*
-** This routine attempts to flatten subqueries in order to speed
-** execution. It returns 1 if it makes changes and 0 if no flattening
-** occurs.
-**
-** To understand the concept of flattening, consider the following
-** query:
-**
-** SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5
-**
-** The default way of implementing this query is to execute the
-** subquery first and store the results in a temporary table, then
-** run the outer query on that temporary table. This requires two
-** passes over the data. Furthermore, because the temporary table
-** has no indices, the WHERE clause on the outer query cannot be
-** optimized.
-**
-** This routine attempts to rewrite queries such as the above into
-** a single flat select, like this:
-**
-** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
-**
-** The code generated for this simpification gives the same result
-** but only has to scan the data once. And because indices might
-** exist on the table t1, a complete scan of the data might be
-** avoided.
-**
-** Flattening is only attempted if all of the following are true:
-**
-** (1) The subquery and the outer query do not both use aggregates.
-**
-** (2) The subquery is not an aggregate or the outer query is not a join.
-**
-** (3) The subquery is not the right operand of a left outer join, or
-** the subquery is not itself a join. (Ticket #306)
-**
-** (4) The subquery is not DISTINCT or the outer query is not a join.
-**
-** (5) The subquery is not DISTINCT or the outer query does not use
-** aggregates.
-**
-** (6) The subquery does not use aggregates or the outer query is not
-** DISTINCT.
-**
-** (7) The subquery has a FROM clause.
-**
-** (8) The subquery does not use LIMIT or the outer query is not a join.
-**
-** (9) The subquery does not use LIMIT or the outer query does not use
-** aggregates.
-**
-** (10) The subquery does not use aggregates or the outer query does not
-** use LIMIT.
-**
-** (11) The subquery and the outer query do not both have ORDER BY clauses.
-**
-** (12) The subquery is not the right term of a LEFT OUTER JOIN or the
-** subquery has no WHERE clause. (added by ticket #350)
-**
-** In this routine, the "p" parameter is a pointer to the outer query.
-** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
-** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
-**
-** If flattening is not attempted, this routine is a no-op and returns 0.
-** If flattening is attempted this routine returns 1.
-**
-** All of the expression analysis must occur on both the outer query and
-** the subquery before this routine runs.
-*/
-static int flattenSubquery(
- Parse *pParse, /* The parsing context */
- Select *p, /* The parent or outer SELECT statement */
- int iFrom, /* Index in p->pSrc->a[] of the inner subquery */
- int isAgg, /* True if outer SELECT uses aggregate functions */
- int subqueryIsAgg /* True if the subquery uses aggregate functions */
-){
- Select *pSub; /* The inner query or "subquery" */
- SrcList *pSrc; /* The FROM clause of the outer query */
- SrcList *pSubSrc; /* The FROM clause of the subquery */
- ExprList *pList; /* The result set of the outer query */
- int iParent; /* VDBE cursor number of the pSub result set temp table */
- int i; /* Loop counter */
- Expr *pWhere; /* The WHERE clause */
- struct SrcList_item *pSubitem; /* The subquery */
-
- /* Check to see if flattening is permitted. Return 0 if not.
- */
- if( p==0 ) return 0;
- pSrc = p->pSrc;
- assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
- pSubitem = &pSrc->a[iFrom];
- pSub = pSubitem->pSelect;
- assert( pSub!=0 );
- if( isAgg && subqueryIsAgg ) return 0;
- if( subqueryIsAgg && pSrc->nSrc>1 ) return 0;
- pSubSrc = pSub->pSrc;
- assert( pSubSrc );
- if( pSubSrc->nSrc==0 ) return 0;
- if( (pSub->isDistinct || pSub->nLimit>=0) && (pSrc->nSrc>1 || isAgg) ){
- return 0;
- }
- if( (p->isDistinct || p->nLimit>=0) && subqueryIsAgg ) return 0;
- if( p->pOrderBy && pSub->pOrderBy ) return 0;
-
- /* Restriction 3: If the subquery is a join, make sure the subquery is
- ** not used as the right operand of an outer join. Examples of why this
- ** is not allowed:
- **
- ** t1 LEFT OUTER JOIN (t2 JOIN t3)
- **
- ** If we flatten the above, we would get
- **
- ** (t1 LEFT OUTER JOIN t2) JOIN t3
- **
- ** which is not at all the same thing.
- */
- if( pSubSrc->nSrc>1 && iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0 ){
- return 0;
- }
-
- /* Restriction 12: If the subquery is the right operand of a left outer
- ** join, make sure the subquery has no WHERE clause.
- ** An examples of why this is not allowed:
- **
- ** t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0)
- **
- ** If we flatten the above, we would get
- **
- ** (t1 LEFT OUTER JOIN t2) WHERE t2.x>0
- **
- ** But the t2.x>0 test will always fail on a NULL row of t2, which
- ** effectively converts the OUTER JOIN into an INNER JOIN.
- */
- if( iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0
- && pSub->pWhere!=0 ){
- return 0;
- }
-
- /* If we reach this point, it means flattening is permitted for the
- ** iFrom-th entry of the FROM clause in the outer query.
- */
-
- /* Move all of the FROM elements of the subquery into the
- ** the FROM clause of the outer query. Before doing this, remember
- ** the cursor number for the original outer query FROM element in
- ** iParent. The iParent cursor will never be used. Subsequent code
- ** will scan expressions looking for iParent references and replace
- ** those references with expressions that resolve to the subquery FROM
- ** elements we are now copying in.
- */
- iParent = pSubitem->iCursor;
- {
- int nSubSrc = pSubSrc->nSrc;
- int jointype = pSubitem->jointype;
- Table *pTab = pSubitem->pTab;
-
- if( pTab && pTab->isTransient ){
- sqlite3DeleteTable(0, pSubitem->pTab);
- }
- sqliteFree(pSubitem->zDatabase);
- sqliteFree(pSubitem->zName);
- sqliteFree(pSubitem->zAlias);
- if( nSubSrc>1 ){
- int extra = nSubSrc - 1;
- for(i=1; i<nSubSrc; i++){
- pSrc = sqlite3SrcListAppend(pSrc, 0, 0);
- }
- p->pSrc = pSrc;
- for(i=pSrc->nSrc-1; i-extra>=iFrom; i--){
- pSrc->a[i] = pSrc->a[i-extra];
- }
- }
- for(i=0; i<nSubSrc; i++){
- pSrc->a[i+iFrom] = pSubSrc->a[i];
- memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
- }
- pSrc->a[iFrom+nSubSrc-1].jointype = jointype;
- }
-
- /* Now begin substituting subquery result set expressions for
- ** references to the iParent in the outer query.
- **
- ** Example:
- **
- ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b;
- ** \ \_____________ subquery __________/ /
- ** \_____________________ outer query ______________________________/
- **
- ** We look at every expression in the outer query and every place we see
- ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
- */
- substExprList(p->pEList, iParent, pSub->pEList);
- pList = p->pEList;
- for(i=0; i<pList->nExpr; i++){
- Expr *pExpr;
- if( pList->a[i].zName==0 && (pExpr = pList->a[i].pExpr)->span.z!=0 ){
- pList->a[i].zName = sqliteStrNDup(pExpr->span.z, pExpr->span.n);
- }
- }
- if( isAgg ){
- substExprList(p->pGroupBy, iParent, pSub->pEList);
- substExpr(p->pHaving, iParent, pSub->pEList);
- }
- if( pSub->pOrderBy ){
- assert( p->pOrderBy==0 );
- p->pOrderBy = pSub->pOrderBy;
- pSub->pOrderBy = 0;
- }else if( p->pOrderBy ){
- substExprList(p->pOrderBy, iParent, pSub->pEList);
- }
- if( pSub->pWhere ){
- pWhere = sqlite3ExprDup(pSub->pWhere);
- }else{
- pWhere = 0;
- }
- if( subqueryIsAgg ){
- assert( p->pHaving==0 );
- p->pHaving = p->pWhere;
- p->pWhere = pWhere;
- substExpr(p->pHaving, iParent, pSub->pEList);
- p->pHaving = sqlite3ExprAnd(p->pHaving, sqlite3ExprDup(pSub->pHaving));
- assert( p->pGroupBy==0 );
- p->pGroupBy = sqlite3ExprListDup(pSub->pGroupBy);
- }else{
- substExpr(p->pWhere, iParent, pSub->pEList);
- p->pWhere = sqlite3ExprAnd(p->pWhere, pWhere);
- }
-
- /* The flattened query is distinct if either the inner or the
- ** outer query is distinct.
- */
- p->isDistinct = p->isDistinct || pSub->isDistinct;
-
- /* Transfer the limit expression from the subquery to the outer
- ** query.
- */
- if( pSub->nLimit>=0 ){
- if( p->nLimit<0 ){
- p->nLimit = pSub->nLimit;
- }else if( p->nLimit+p->nOffset > pSub->nLimit+pSub->nOffset ){
- p->nLimit = pSub->nLimit + pSub->nOffset - p->nOffset;
- }
- }
- p->nOffset += pSub->nOffset;
-
- /* Finially, delete what is left of the subquery and return
- ** success.
- */
- sqlite3SelectDelete(pSub);
- return 1;
-}
-
-/*
-** Analyze the SELECT statement passed in as an argument to see if it
-** is a simple min() or max() query. If it is and this query can be
-** satisfied using a single seek to the beginning or end of an index,
-** then generate the code for this SELECT and return 1. If this is not a
-** simple min() or max() query, then return 0;
-**
-** A simply min() or max() query looks like this:
-**
-** SELECT min(a) FROM table;
-** SELECT max(a) FROM table;
-**
-** The query may have only a single table in its FROM argument. There
-** can be no GROUP BY or HAVING or WHERE clauses. The result set must
-** be the min() or max() of a single column of the table. The column
-** in the min() or max() function must be indexed.
-**
-** The parameters to this routine are the same as for sqlite3Select().
-** See the header comment on that routine for additional information.
-*/
-static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
- Expr *pExpr;
- int iCol;
- Table *pTab;
- Index *pIdx;
- int base;
- Vdbe *v;
- int seekOp;
- int cont;
- ExprList *pEList, *pList, eList;
- struct ExprList_item eListItem;
- SrcList *pSrc;
-
-
- /* Check to see if this query is a simple min() or max() query. Return
- ** zero if it is not.
- */
- if( p->pGroupBy || p->pHaving || p->pWhere ) return 0;
- pSrc = p->pSrc;
- if( pSrc->nSrc!=1 ) return 0;
- pEList = p->pEList;
- if( pEList->nExpr!=1 ) return 0;
- pExpr = pEList->a[0].pExpr;
- if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
- pList = pExpr->pList;
- if( pList==0 || pList->nExpr!=1 ) return 0;
- if( pExpr->token.n!=3 ) return 0;
- if( sqlite3StrNICmp(pExpr->token.z,"min",3)==0 ){
- seekOp = OP_Rewind;
- }else if( sqlite3StrNICmp(pExpr->token.z,"max",3)==0 ){
- seekOp = OP_Last;
- }else{
- return 0;
- }
- pExpr = pList->a[0].pExpr;
- if( pExpr->op!=TK_COLUMN ) return 0;
- iCol = pExpr->iColumn;
- pTab = pSrc->a[0].pTab;
-
- /* If we get to here, it means the query is of the correct form.
- ** Check to make sure we have an index and make pIdx point to the
- ** appropriate index. If the min() or max() is on an INTEGER PRIMARY
- ** key column, no index is necessary so set pIdx to NULL. If no
- ** usable index is found, return 0.
- */
- if( iCol<0 ){
- pIdx = 0;
- }else{
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- assert( pIdx->nColumn>=1 );
- if( pIdx->aiColumn[0]==iCol && pIdx->keyInfo.aColl[0]==pColl ) break;
- }
- if( pIdx==0 ) return 0;
- }
-
- /* Identify column types if we will be using the callback. This
- ** step is skipped if the output is going to a table or a memory cell.
- ** The column names have already been generated in the calling function.
- */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) return 0;
-
- /* If the output is destined for a temporary table, open that table.
- */
- if( eDest==SRT_TempTable ){
- sqlite3VdbeAddOp(v, OP_OpenTemp, iParm, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, 1);
- }
-
- /* Generating code to find the min or the max. Basically all we have
- ** to do is find the first or the last entry in the chosen index. If
- ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
- ** or last entry in the main table.
- */
- sqlite3CodeVerifySchema(pParse, pTab->iDb);
- base = pSrc->a[0].iCursor;
- computeLimitRegisters(pParse, p);
- if( pSrc->a[0].pSelect==0 ){
- sqlite3OpenTableForReading(v, base, pTab);
- }
- cont = sqlite3VdbeMakeLabel(v);
- if( pIdx==0 ){
- sqlite3VdbeAddOp(v, seekOp, base, 0);
- }else{
- sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
- sqlite3VdbeOp3(v, OP_OpenRead, base+1, pIdx->tnum,
- (char*)&pIdx->keyInfo, P3_KEYINFO);
- if( seekOp==OP_Rewind ){
- sqlite3VdbeAddOp(v, OP_String, 0, 0);
- sqlite3VdbeAddOp(v, OP_MakeRecord, 1, 0);
- seekOp = OP_MoveGt;
- }
- sqlite3VdbeAddOp(v, seekOp, base+1, 0);
- sqlite3VdbeAddOp(v, OP_IdxRecno, base+1, 0);
- sqlite3VdbeAddOp(v, OP_Close, base+1, 0);
- sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
- }
- eList.nExpr = 1;
- memset(&eListItem, 0, sizeof(eListItem));
- eList.a = &eListItem;
- eList.a[0].pExpr = pExpr;
- selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont, 0);
- sqlite3VdbeResolveLabel(v, cont);
- sqlite3VdbeAddOp(v, OP_Close, base, 0);
-
- return 1;
-}
-
-/*
-** Analyze and ORDER BY or GROUP BY clause in a SELECT statement. Return
-** the number of errors seen.
-**
-** An ORDER BY or GROUP BY is a list of expressions. If any expression
-** is an integer constant, then that expression is replaced by the
-** corresponding entry in the result set.
-*/
-static int processOrderGroupBy(
- Parse *pParse, /* Parsing context */
- ExprList *pOrderBy, /* The ORDER BY or GROUP BY clause to be processed */
- SrcList *pTabList, /* The FROM clause */
- ExprList *pEList, /* The result set */
- int isAgg, /* True if aggregate functions are involved */
- const char *zType /* Either "ORDER" or "GROUP", as appropriate */
-){
- int i;
- if( pOrderBy==0 ) return 0;
- for(i=0; i<pOrderBy->nExpr; i++){
- int iCol;
- Expr *pE = pOrderBy->a[i].pExpr;
- if( sqlite3ExprIsInteger(pE, &iCol) && iCol>0 && iCol<=pEList->nExpr ){
- sqlite3ExprDelete(pE);
- pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr);
- }
- if( sqlite3ExprResolveAndCheck(pParse, pTabList, pEList, pE, isAgg, 0) ){
- return 1;
- }
- if( sqlite3ExprIsConstant(pE) ){
- if( sqlite3ExprIsInteger(pE, &iCol)==0 ){
- sqlite3ErrorMsg(pParse,
- "%s BY terms must not be non-integer constants", zType);
- return 1;
- }else if( iCol<=0 || iCol>pEList->nExpr ){
- sqlite3ErrorMsg(pParse,
- "%s BY column number %d out of range - should be "
- "between 1 and %d", zType, iCol, pEList->nExpr);
- return 1;
- }
- }
- }
- return 0;
-}
-
-/*
-** Generate code for the given SELECT statement.
-**
-** The results are distributed in various ways depending on the
-** value of eDest and iParm.
-**
-** eDest Value Result
-** ------------ -------------------------------------------
-** SRT_Callback Invoke the callback for each row of the result.
-**
-** SRT_Mem Store first result in memory cell iParm
-**
-** SRT_Set Store results as keys of table iParm.
-**
-** SRT_Union Store results as a key in a temporary table iParm
-**
-** SRT_Except Remove results from the temporary table iParm.
-**
-** SRT_Table Store results in temporary table iParm
-**
-** The table above is incomplete. Additional eDist value have be added
-** since this comment was written. See the selectInnerLoop() function for
-** a complete listing of the allowed values of eDest and their meanings.
-**
-** This routine returns the number of errors. If any errors are
-** encountered, then an appropriate error message is left in
-** pParse->zErrMsg.
-**
-** This routine does NOT free the Select structure passed in. The
-** calling function needs to do that.
-**
-** The pParent, parentTab, and *pParentAgg fields are filled in if this
-** SELECT is a subquery. This routine may try to combine this SELECT
-** with its parent to form a single flat query. In so doing, it might
-** change the parent query from a non-aggregate to an aggregate query.
-** For that reason, the pParentAgg flag is passed as a pointer, so it
-** can be changed.
-**
-** Example 1: The meaning of the pParent parameter.
-**
-** SELECT * FROM t1 JOIN (SELECT x, count(*) FROM t2) JOIN t3;
-** \ \_______ subquery _______/ /
-** \ /
-** \____________________ outer query ___________________/
-**
-** This routine is called for the outer query first. For that call,
-** pParent will be NULL. During the processing of the outer query, this
-** routine is called recursively to handle the subquery. For the recursive
-** call, pParent will point to the outer query. Because the subquery is
-** the second element in a three-way join, the parentTab parameter will
-** be 1 (the 2nd value of a 0-indexed array.)
-*/
-int sqlite3Select(
- Parse *pParse, /* The parser context */
- Select *p, /* The SELECT statement being coded. */
- int eDest, /* How to dispose of the results */
- int iParm, /* A parameter used by the eDest disposal method */
- Select *pParent, /* Another SELECT for which this is a sub-query */
- int parentTab, /* Index in pParent->pSrc of this query */
- int *pParentAgg, /* True if pParent uses aggregate functions */
- char *aff /* If eDest is SRT_Union, the affinity string */
-){
- int i;
- WhereInfo *pWInfo;
- Vdbe *v;
- int isAgg = 0; /* True for select lists like "count(*)" */
- ExprList *pEList; /* List of columns to extract. */
- SrcList *pTabList; /* List of tables to select from */
- Expr *pWhere; /* The WHERE clause. May be NULL */
- ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
- ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
- Expr *pHaving; /* The HAVING clause. May be NULL */
- int isDistinct; /* True if the DISTINCT keyword is present */
- int distinct; /* Table to use for the distinct set */
- int rc = 1; /* Value to return from this function */
-
- if( sqlite3_malloc_failed || pParse->nErr || p==0 ) return 1;
- if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
-
- /* If there is are a sequence of queries, do the earlier ones first.
- */
- if( p->pPrior ){
- return multiSelect(pParse, p, eDest, iParm, aff);
- }
-
- /* Make local copies of the parameters for this query.
- */
- pTabList = p->pSrc;
- pWhere = p->pWhere;
- pOrderBy = p->pOrderBy;
- pGroupBy = p->pGroupBy;
- pHaving = p->pHaving;
- isDistinct = p->isDistinct;
-
- /* Allocate VDBE cursors for each table in the FROM clause
- */
- sqlite3SrcListAssignCursors(pParse, pTabList);
-
- /*
- ** Do not even attempt to generate any code if we have already seen
- ** errors before this routine starts.
- */
- if( pParse->nErr>0 ) goto select_end;
-
- /* Expand any "*" terms in the result set. (For example the "*" in
- ** "SELECT * FROM t1") The fillInColumnlist() routine also does some
- ** other housekeeping - see the header comment for details.
- */
- if( fillInColumnList(pParse, p) ){
- goto select_end;
- }
- pWhere = p->pWhere;
- pEList = p->pEList;
- if( pEList==0 ) goto select_end;
-
- /* If writing to memory or generating a set
- ** only a single column may be output.
- */
- if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){
- sqlite3ErrorMsg(pParse, "only a single result allowed for "
- "a SELECT that is part of an expression");
- goto select_end;
- }
-
- /* ORDER BY is ignored for some destinations.
- */
- switch( eDest ){
- case SRT_Union:
- case SRT_Except:
- case SRT_Discard:
- pOrderBy = 0;
- break;
- default:
- break;
- }
-
- /* At this point, we should have allocated all the cursors that we
- ** need to handle subquerys and temporary tables.
- **
- ** Resolve the column names and do a semantics check on all the expressions.
- */
- for(i=0; i<pEList->nExpr; i++){
- if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pEList->a[i].pExpr,
- 1, &isAgg) ){
- goto select_end;
- }
- }
- if( sqlite3ExprResolveAndCheck(pParse, pTabList, pEList, pWhere, 0, 0) ){
- goto select_end;
- }
- if( pHaving ){
- if( pGroupBy==0 ){
- sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
- goto select_end;
- }
- if( sqlite3ExprResolveAndCheck(pParse, pTabList, pEList,pHaving,1,&isAgg) ){
- goto select_end;
- }
- }
- if( processOrderGroupBy(pParse, pOrderBy, pTabList, pEList, isAgg, "ORDER")
- || processOrderGroupBy(pParse, pGroupBy, pTabList, pEList, isAgg, "GROUP")
- ){
- goto select_end;
- }
-
- /* Begin generating code.
- */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto select_end;
-
- /* Identify column names if we will be using them in a callback. This
- ** step is skipped if the output is going to some other destination.
- */
- if( eDest==SRT_Callback ){
- generateColumnNames(pParse, pTabList, pEList);
- }
-
- /* Generate code for all sub-queries in the FROM clause
- */
- for(i=0; i<pTabList->nSrc; i++){
- const char *zSavedAuthContext = 0;
- int needRestoreContext;
-
- if( pTabList->a[i].pSelect==0 ) continue;
- if( pTabList->a[i].zName!=0 ){
- zSavedAuthContext = pParse->zAuthContext;
- pParse->zAuthContext = pTabList->a[i].zName;
- needRestoreContext = 1;
- }else{
- needRestoreContext = 0;
- }
- sqlite3Select(pParse, pTabList->a[i].pSelect, SRT_TempTable,
- pTabList->a[i].iCursor, p, i, &isAgg, 0);
- if( needRestoreContext ){
- pParse->zAuthContext = zSavedAuthContext;
- }
- pTabList = p->pSrc;
- pWhere = p->pWhere;
- if( eDest!=SRT_Union && eDest!=SRT_Except && eDest!=SRT_Discard ){
- pOrderBy = p->pOrderBy;
- }
- pGroupBy = p->pGroupBy;
- pHaving = p->pHaving;
- isDistinct = p->isDistinct;
- }
-
- /* Check for the special case of a min() or max() function by itself
- ** in the result set.
- */
- if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){
- rc = 0;
- goto select_end;
- }
-
- /* Check to see if this is a subquery that can be "flattened" into its parent.
- ** If flattening is a possiblity, do so and return immediately.
- */
- if( pParent && pParentAgg &&
- flattenSubquery(pParse, pParent, parentTab, *pParentAgg, isAgg) ){
- if( isAgg ) *pParentAgg = 1;
- return rc;
- }
-
- /* If there is an ORDER BY clause, resolve any collation sequences
- ** names that have been explicitly specified.
- */
- if( pOrderBy ){
- for(i=0; i<pOrderBy->nExpr; i++){
- if( pOrderBy->a[i].zName ){
- pOrderBy->a[i].pExpr->pColl =
- sqlite3LocateCollSeq(pParse, pOrderBy->a[i].zName, -1);
- }
- }
- if( pParse->nErr ){
- goto select_end;
- }
- }
-
- /* Set the limiter.
- */
- computeLimitRegisters(pParse, p);
-
- /* If the output is destined for a temporary table, open that table.
- */
- if( eDest==SRT_TempTable ){
- sqlite3VdbeAddOp(v, OP_OpenTemp, iParm, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, pEList->nExpr);
- }
-
- /* Do an analysis of aggregate expressions.
- */
- sqliteAggregateInfoReset(pParse);
- if( isAgg || pGroupBy ){
- assert( pParse->nAgg==0 );
- isAgg = 1;
- for(i=0; i<pEList->nExpr; i++){
- if( sqlite3ExprAnalyzeAggregates(pParse, pEList->a[i].pExpr) ){
- goto select_end;
- }
- }
- if( pGroupBy ){
- for(i=0; i<pGroupBy->nExpr; i++){
- if( sqlite3ExprAnalyzeAggregates(pParse, pGroupBy->a[i].pExpr) ){
- goto select_end;
- }
- }
- }
- if( pHaving && sqlite3ExprAnalyzeAggregates(pParse, pHaving) ){
- goto select_end;
- }
- if( pOrderBy ){
- for(i=0; i<pOrderBy->nExpr; i++){
- if( sqlite3ExprAnalyzeAggregates(pParse, pOrderBy->a[i].pExpr) ){
- goto select_end;
- }
- }
- }
- }
-
- /* Reset the aggregator
- */
- if( isAgg ){
- int addr = sqlite3VdbeAddOp(v, OP_AggReset, (pGroupBy?0:1), pParse->nAgg);
- for(i=0; i<pParse->nAgg; i++){
- FuncDef *pFunc;
- if( (pFunc = pParse->aAgg[i].pFunc)!=0 && pFunc->xFinalize!=0 ){
- sqlite3VdbeOp3(v, OP_AggInit, 0, i, (char*)pFunc, P3_FUNCDEF);
- }
- }
- if( pGroupBy ){
- int sz = sizeof(KeyInfo) + pGroupBy->nExpr*sizeof(CollSeq*);
- KeyInfo *pKey = (KeyInfo *)sqliteMalloc(sz);
- if( 0==pKey ){
- goto select_end;
- }
- pKey->enc = pParse->db->enc;
- pKey->nField = pGroupBy->nExpr;
- for(i=0; i<pGroupBy->nExpr; i++){
- pKey->aColl[i] = sqlite3ExprCollSeq(pParse, pGroupBy->a[i].pExpr);
- if( !pKey->aColl[i] ){
- pKey->aColl[i] = pParse->db->pDfltColl;
- }
- }
- sqlite3VdbeChangeP3(v, addr, (char *)pKey, P3_KEYINFO_HANDOFF);
- }
- }
-
- /* Initialize the memory cell to NULL
- */
- if( eDest==SRT_Mem ){
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
- }
-
- /* Open a temporary table to use for the distinct set.
- */
- if( isDistinct ){
- distinct = pParse->nTab++;
- openTempIndex(pParse, p, distinct, 0);
- }else{
- distinct = -1;
- }
-
- /* Begin the database scan
- */
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
- pGroupBy ? 0 : &pOrderBy);
- if( pWInfo==0 ) goto select_end;
-
- /* Use the standard inner loop if we are not dealing with
- ** aggregates
- */
- if( !isAgg ){
- if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
- iParm, pWInfo->iContinue, pWInfo->iBreak, aff) ){
- goto select_end;
- }
- }
-
- /* If we are dealing with aggregates, then do the special aggregate
- ** processing.
- */
- else{
- AggExpr *pAgg;
- if( pGroupBy ){
- int lbl1;
- for(i=0; i<pGroupBy->nExpr; i++){
- sqlite3ExprCode(pParse, pGroupBy->a[i].pExpr);
- }
- /* No affinity string is attached to the following OP_MakeRecord
- ** because we do not need to do any coercion of datatypes. */
- sqlite3VdbeAddOp(v, OP_MakeRecord, pGroupBy->nExpr, 0);
- lbl1 = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_AggFocus, 0, lbl1);
- for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
- if( pAgg->isAgg ) continue;
- sqlite3ExprCode(pParse, pAgg->pExpr);
- sqlite3VdbeAddOp(v, OP_AggSet, 0, i);
- }
- sqlite3VdbeResolveLabel(v, lbl1);
- }
- for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
- Expr *pE;
- int nExpr;
- FuncDef *pDef;
- if( !pAgg->isAgg ) continue;
- assert( pAgg->pFunc!=0 );
- assert( pAgg->pFunc->xStep!=0 );
- pDef = pAgg->pFunc;
- pE = pAgg->pExpr;
- assert( pE!=0 );
- assert( pE->op==TK_AGG_FUNCTION );
- nExpr = sqlite3ExprCodeExprList(pParse, pE->pList);
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- if( pDef->needCollSeq ){
- CollSeq *pColl = 0;
- int j;
- for(j=0; !pColl && j<nExpr; j++){
- pColl = sqlite3ExprCollSeq(pParse, pE->pList->a[j].pExpr);
- }
- if( !pColl ) pColl = pParse->db->pDfltColl;
- sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
- }
- sqlite3VdbeOp3(v, OP_AggFunc, 0, nExpr, (char*)pDef, P3_POINTER);
- }
- }
-
- /* End the database scan loop.
- */
- sqlite3WhereEnd(pWInfo);
-
- /* If we are processing aggregates, we need to set up a second loop
- ** over all of the aggregate values and process them.
- */
- if( isAgg ){
- int endagg = sqlite3VdbeMakeLabel(v);
- int startagg;
- startagg = sqlite3VdbeAddOp(v, OP_AggNext, 0, endagg);
- pParse->useAgg = 1;
- if( pHaving ){
- sqlite3ExprIfFalse(pParse, pHaving, startagg, 1);
- }
- if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
- iParm, startagg, endagg, aff) ){
- goto select_end;
- }
- sqlite3VdbeAddOp(v, OP_Goto, 0, startagg);
- sqlite3VdbeResolveLabel(v, endagg);
- sqlite3VdbeAddOp(v, OP_Noop, 0, 0);
- pParse->useAgg = 0;
- }
-
- /* If there is an ORDER BY clause, then we need to sort the results
- ** and send them to the callback one by one.
- */
- if( pOrderBy ){
- generateSortTail(pParse, p, v, pEList->nExpr, eDest, iParm);
- }
-
- /* If this was a subquery, we have now converted the subquery into a
- ** temporary table. So delete the subquery structure from the parent
- ** to prevent this subquery from being evaluated again and to force the
- ** the use of the temporary table.
- */
- if( pParent ){
- assert( pParent->pSrc->nSrc>parentTab );
- assert( pParent->pSrc->a[parentTab].pSelect==p );
- sqlite3SelectDelete(p);
- pParent->pSrc->a[parentTab].pSelect = 0;
- }
-
- /* The SELECT was successfully coded. Set the return code to 0
- ** to indicate no errors.
- */
- rc = 0;
-
- /* Control jumps to here if an error is encountered above, or upon
- ** successful coding of the SELECT.
- */
-select_end:
- sqliteAggregateInfoReset(pParse);
- return rc;
-}
diff --git a/kopete/plugins/statistics/sqlite/shell.c b/kopete/plugins/statistics/sqlite/shell.c
deleted file mode 100644
index bdd13cc9..00000000
--- a/kopete/plugins/statistics/sqlite/shell.c
+++ /dev/null
@@ -1,1786 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains code to implement the "sqlite" command line
-** utility for accessing SQLite databases.
-**
-** $Id$
-*/
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include "sqlite3.h"
-#include <ctype.h>
-
-#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__)
-# include <signal.h>
-# include <pwd.h>
-# include <unistd.h>
-# include <sys/types.h>
-#endif
-
-#ifdef __MACOS__
-# include <console.h>
-# include <signal.h>
-# include <unistd.h>
-# include <extras.h>
-# include <Files.h>
-# include <Folders.h>
-#endif
-
-#if defined(HAVE_READLINE) && HAVE_READLINE==1
-# include <readline/readline.h>
-# include <readline/history.h>
-#else
-# define readline(p) local_getline(p,stdin)
-# define add_history(X)
-# define read_history(X)
-# define write_history(X)
-# define stifle_history(X)
-#endif
-
-/* Make sure isatty() has a prototype.
-*/
-extern int isatty();
-
-/*
-** The following is the open SQLite database. We make a pointer
-** to this database a static variable so that it can be accessed
-** by the SIGINT handler to interrupt database processing.
-*/
-static sqlite3 *db = 0;
-
-/*
-** True if an interrupt (Control-C) has been received.
-*/
-static int seenInterrupt = 0;
-
-/*
-** This is the name of our program. It is set in main(), used
-** in a number of other places, mostly for error messages.
-*/
-static char *Argv0;
-
-/*
-** Prompt strings. Initialized in main. Settable with
-** .prompt main continue
-*/
-static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
-static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
-
-
-/*
-** Determines if a string is a number of not.
-*/
-static int isNumber(const unsigned char *z, int *realnum){
- if( *z=='-' || *z=='+' ) z++;
- if( !isdigit(*z) ){
- return 0;
- }
- z++;
- if( realnum ) *realnum = 0;
- while( isdigit(*z) ){ z++; }
- if( *z=='.' ){
- z++;
- if( !isdigit(*z) ) return 0;
- while( isdigit(*z) ){ z++; }
- if( realnum ) *realnum = 1;
- }
- if( *z=='e' || *z=='E' ){
- z++;
- if( *z=='+' || *z=='-' ) z++;
- if( !isdigit(*z) ) return 0;
- while( isdigit(*z) ){ z++; }
- if( realnum ) *realnum = 1;
- }
- return *z==0;
-}
-
-/*
-** A global char* and an SQL function to access its current value
-** from within an SQL statement. This program used to use the
-** sqlite_exec_printf() API to substitue a string into an SQL statement.
-** The correct way to do this with sqlite3 is to use the bind API, but
-** since the shell is built around the callback paradigm it would be a lot
-** of work. Instead just use this hack, which is quite harmless.
-*/
-static const char *zShellStatic = 0;
-static void shellstaticFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- assert( 0==argc );
- assert( zShellStatic );
- sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
-}
-
-
-/*
-** This routine reads a line of text from FILE in, stores
-** the text in memory obtained from malloc() and returns a pointer
-** to the text. NULL is returned at end of file, or if malloc()
-** fails.
-**
-** The interface is like "readline" but no command-line editing
-** is done.
-*/
-static char *local_getline(char *zPrompt, FILE *in){
- char *zLine;
- int nLine;
- int n;
- int eol;
-
- if( zPrompt && *zPrompt ){
- printf("%s",zPrompt);
- fflush(stdout);
- }
- nLine = 100;
- zLine = malloc( nLine );
- if( zLine==0 ) return 0;
- n = 0;
- eol = 0;
- while( !eol ){
- if( n+100>nLine ){
- nLine = nLine*2 + 100;
- zLine = realloc(zLine, nLine);
- if( zLine==0 ) return 0;
- }
- if( fgets(&zLine[n], nLine - n, in)==0 ){
- if( n==0 ){
- free(zLine);
- return 0;
- }
- zLine[n] = 0;
- eol = 1;
- break;
- }
- while( zLine[n] ){ n++; }
- if( n>0 && zLine[n-1]=='\n' ){
- n--;
- zLine[n] = 0;
- eol = 1;
- }
- }
- zLine = realloc( zLine, n+1 );
- return zLine;
-}
-
-/*
-** Retrieve a single line of input text. "isatty" is true if text
-** is coming from a terminal. In that case, we issue a prompt and
-** attempt to use "readline" for command-line editing. If "isatty"
-** is false, use "local_getline" instead of "readline" and issue no prompt.
-**
-** zPrior is a string of prior text retrieved. If not the empty
-** string, then issue a continuation prompt.
-*/
-static char *one_input_line(const char *zPrior, FILE *in){
- char *zPrompt;
- char *zResult;
- if( in!=0 ){
- return local_getline(0, in);
- }
- if( zPrior && zPrior[0] ){
- zPrompt = continuePrompt;
- }else{
- zPrompt = mainPrompt;
- }
- zResult = readline(zPrompt);
- if( zResult ) add_history(zResult);
- return zResult;
-}
-
-struct previous_mode_data {
- int valid; /* Is there legit data in here? */
- int mode;
- int showHeader;
- int colWidth[100];
-};
-/*
-** An pointer to an instance of this structure is passed from
-** the main program to the callback. This is used to communicate
-** state and mode information.
-*/
-struct callback_data {
- sqlite3 *db; /* The database */
- int echoOn; /* True to echo input commands */
- int cnt; /* Number of records displayed so far */
- FILE *out; /* Write results here */
- int mode; /* An output mode setting */
- int showHeader; /* True to show column names in List or Column mode */
- char *zDestTable; /* Name of destination table when MODE_Insert */
- char separator[20]; /* Separator character for MODE_List */
- int colWidth[100]; /* Requested width of each column when in column mode*/
- int actualWidth[100]; /* Actual width of each column */
- char nullvalue[20]; /* The text to print when a NULL comes back from
- ** the database */
- struct previous_mode_data explainPrev;
- /* Holds the mode information just before
- ** .explain ON */
- char outfile[FILENAME_MAX]; /* Filename for *out */
- const char *zDbFilename; /* name of the database file */
- char *zKey; /* Encryption key */
-};
-
-/*
-** These are the allowed modes.
-*/
-#define MODE_Line 0 /* One column per line. Blank line between records */
-#define MODE_Column 1 /* One record per line in neat columns */
-#define MODE_List 2 /* One record per line with a separator */
-#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
-#define MODE_Html 4 /* Generate an XHTML table */
-#define MODE_Insert 5 /* Generate SQL "insert" statements */
-#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
-#define MODE_Csv 7 /* Quote strings, numbers are plain */
-#define MODE_NUM_OF 8 /* The number of modes (not a mode itself) */
-
-char *modeDescr[MODE_NUM_OF] = {
- "line",
- "column",
- "list",
- "semi",
- "html",
- "insert",
- "tcl",
- "csv",
-};
-
-/*
-** Number of elements in an array
-*/
-#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
-
-/*
-** Output the given string as a quoted string using SQL quoting conventions.
-*/
-static void output_quoted_string(FILE *out, const char *z){
- int i;
- int nSingle = 0;
- for(i=0; z[i]; i++){
- if( z[i]=='\'' ) nSingle++;
- }
- if( nSingle==0 ){
- fprintf(out,"'%s'",z);
- }else{
- fprintf(out,"'");
- while( *z ){
- for(i=0; z[i] && z[i]!='\''; i++){}
- if( i==0 ){
- fprintf(out,"''");
- z++;
- }else if( z[i]=='\'' ){
- fprintf(out,"%.*s''",i,z);
- z += i+1;
- }else{
- fprintf(out,"%s",z);
- break;
- }
- }
- fprintf(out,"'");
- }
-}
-
-/*
-** Output the given string as a quoted according to C or TCL quoting rules.
-*/
-static void output_c_string(FILE *out, const char *z){
- unsigned int c;
- fputc('"', out);
- while( (c = *(z++))!=0 ){
- if( c=='\\' ){
- fputc(c, out);
- fputc(c, out);
- }else if( c=='\t' ){
- fputc('\\', out);
- fputc('t', out);
- }else if( c=='\n' ){
- fputc('\\', out);
- fputc('n', out);
- }else if( c=='\r' ){
- fputc('\\', out);
- fputc('r', out);
- }else if( !isprint(c) ){
- fprintf(out, "\\%03o", c);
- }else{
- fputc(c, out);
- }
- }
- fputc('"', out);
-}
-
-/*
-** Output the given string with characters that are special to
-** HTML escaped.
-*/
-static void output_html_string(FILE *out, const char *z){
- int i;
- while( *z ){
- for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
- if( i>0 ){
- fprintf(out,"%.*s",i,z);
- }
- if( z[i]=='<' ){
- fprintf(out,"&lt;");
- }else if( z[i]=='&' ){
- fprintf(out,"&amp;");
- }else{
- break;
- }
- z += i + 1;
- }
-}
-
-/*
-** Output a single term of CSV. Actually, p->separator is used for
-** the separator, which may or may not be a comma. p->nullvalue is
-** the null value. Strings are quoted using ANSI-C rules. Numbers
-** appear outside of quotes.
-*/
-static void output_csv(struct callback_data *p, const char *z, int bSep){
- if( z==0 ){
- fprintf(p->out,"%s",p->nullvalue);
- }else if( isNumber(z, 0) ){
- fprintf(p->out,"%s",z);
- }else{
- output_c_string(p->out, z);
- }
- if( bSep ){
- fprintf(p->out, p->separator);
- }
-}
-
-/*
-** This routine runs when the user presses Ctrl-C
-*/
-static void interrupt_handler(int NotUsed){
- seenInterrupt = 1;
- if( db ) sqlite3_interrupt(db);
-}
-
-/*
-** This is the callback routine that the SQLite library
-** invokes for each row of a query result.
-*/
-static int callback(void *pArg, int nArg, char **azArg, char **azCol){
- int i;
- struct callback_data *p = (struct callback_data*)pArg;
- switch( p->mode ){
- case MODE_Line: {
- int w = 5;
- if( azArg==0 ) break;
- for(i=0; i<nArg; i++){
- int len = strlen(azCol[i]);
- if( len>w ) w = len;
- }
- if( p->cnt++>0 ) fprintf(p->out,"\n");
- for(i=0; i<nArg; i++){
- fprintf(p->out,"%*s = %s\n", w, azCol[i],
- azArg[i] ? azArg[i] : p->nullvalue);
- }
- break;
- }
- case MODE_Column: {
- if( p->cnt++==0 ){
- for(i=0; i<nArg; i++){
- int w, n;
- if( i<ArraySize(p->colWidth) ){
- w = p->colWidth[i];
- }else{
- w = 0;
- }
- if( w<=0 ){
- w = strlen(azCol[i] ? azCol[i] : "");
- if( w<10 ) w = 10;
- n = strlen(azArg && azArg[i] ? azArg[i] : p->nullvalue);
- if( w<n ) w = n;
- }
- if( i<ArraySize(p->actualWidth) ){
- p->actualWidth[i] = w;
- }
- if( p->showHeader ){
- fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
- }
- }
- if( p->showHeader ){
- for(i=0; i<nArg; i++){
- int w;
- if( i<ArraySize(p->actualWidth) ){
- w = p->actualWidth[i];
- }else{
- w = 10;
- }
- fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
- "----------------------------------------------------------",
- i==nArg-1 ? "\n": " ");
- }
- }
- }
- if( azArg==0 ) break;
- for(i=0; i<nArg; i++){
- int w;
- if( i<ArraySize(p->actualWidth) ){
- w = p->actualWidth[i];
- }else{
- w = 10;
- }
- fprintf(p->out,"%-*.*s%s",w,w,
- azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
- }
- break;
- }
- case MODE_Semi:
- case MODE_List: {
- if( p->cnt++==0 && p->showHeader ){
- for(i=0; i<nArg; i++){
- fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
- }
- }
- if( azArg==0 ) break;
- for(i=0; i<nArg; i++){
- char *z = azArg[i];
- if( z==0 ) z = p->nullvalue;
- fprintf(p->out, "%s", z);
- if( i<nArg-1 ){
- fprintf(p->out, "%s", p->separator);
- }else if( p->mode==MODE_Semi ){
- fprintf(p->out, ";\n");
- }else{
- fprintf(p->out, "\n");
- }
- }
- break;
- }
- case MODE_Html: {
- if( p->cnt++==0 && p->showHeader ){
- fprintf(p->out,"<TR>");
- for(i=0; i<nArg; i++){
- fprintf(p->out,"<TH>%s</TH>",azCol[i]);
- }
- fprintf(p->out,"</TR>\n");
- }
- if( azArg==0 ) break;
- fprintf(p->out,"<TR>");
- for(i=0; i<nArg; i++){
- fprintf(p->out,"<TD>");
- output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
- fprintf(p->out,"</TD>\n");
- }
- fprintf(p->out,"</TR>\n");
- break;
- }
- case MODE_Tcl: {
- if( p->cnt++==0 && p->showHeader ){
- for(i=0; i<nArg; i++){
- output_c_string(p->out,azCol[i]);
- fprintf(p->out, "%s", p->separator);
- }
- fprintf(p->out,"\n");
- }
- if( azArg==0 ) break;
- for(i=0; i<nArg; i++){
- output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
- fprintf(p->out, "%s", p->separator);
- }
- fprintf(p->out,"\n");
- break;
- }
- case MODE_Csv: {
- if( p->cnt++==0 && p->showHeader ){
- for(i=0; i<nArg; i++){
- output_csv(p, azCol[i], i<nArg-1);
- }
- fprintf(p->out,"\n");
- }
- if( azArg==0 ) break;
- for(i=0; i<nArg; i++){
- output_csv(p, azArg[i], i<nArg-1);
- }
- fprintf(p->out,"\n");
- break;
- }
- case MODE_Insert: {
- if( azArg==0 ) break;
- fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
- for(i=0; i<nArg; i++){
- char *zSep = i>0 ? ",": "";
- if( azArg[i]==0 ){
- fprintf(p->out,"%sNULL",zSep);
- }else if( isNumber(azArg[i], 0) ){
- fprintf(p->out,"%s%s",zSep, azArg[i]);
- }else{
- if( zSep[0] ) fprintf(p->out,"%s",zSep);
- output_quoted_string(p->out, azArg[i]);
- }
- }
- fprintf(p->out,");\n");
- break;
- }
- }
- return 0;
-}
-
-/*
-** Set the destination table field of the callback_data structure to
-** the name of the table given. Escape any quote characters in the
-** table name.
-*/
-static void set_table_name(struct callback_data *p, const char *zName){
- int i, n;
- int needQuote;
- char *z;
-
- if( p->zDestTable ){
- free(p->zDestTable);
- p->zDestTable = 0;
- }
- if( zName==0 ) return;
- needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
- for(i=n=0; zName[i]; i++, n++){
- if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
- needQuote = 1;
- if( zName[i]=='\'' ) n++;
- }
- }
- if( needQuote ) n += 2;
- z = p->zDestTable = malloc( n+1 );
- if( z==0 ){
- fprintf(stderr,"Out of memory!\n");
- exit(1);
- }
- n = 0;
- if( needQuote ) z[n++] = '\'';
- for(i=0; zName[i]; i++){
- z[n++] = zName[i];
- if( zName[i]=='\'' ) z[n++] = '\'';
- }
- if( needQuote ) z[n++] = '\'';
- z[n] = 0;
-}
-
-/* zIn is either a pointer to a NULL-terminated string in memory obtained
-** from malloc(), or a NULL pointer. The string pointed to by zAppend is
-** added to zIn, and the result returned in memory obtained from malloc().
-** zIn, if it was not NULL, is freed.
-**
-** If the third argument, quote, is not '\0', then it is used as a
-** quote character for zAppend.
-*/
-static char * appendText(char *zIn, char const *zAppend, char quote){
- int len;
- int i;
- int nAppend = strlen(zAppend);
- int nIn = (zIn?strlen(zIn):0);
-
- len = nAppend+nIn+1;
- if( quote ){
- len += 2;
- for(i=0; i<nAppend; i++){
- if( zAppend[i]==quote ) len++;
- }
- }
-
- zIn = (char *)realloc(zIn, len);
- if( !zIn ){
- return 0;
- }
-
- if( quote ){
- char *zCsr = &zIn[nIn];
- *zCsr++ = quote;
- for(i=0; i<nAppend; i++){
- *zCsr++ = zAppend[i];
- if( zAppend[i]==quote ) *zCsr++ = quote;
- }
- *zCsr++ = quote;
- *zCsr++ = '\0';
- assert( (zCsr-zIn)==len );
- }else{
- memcpy(&zIn[nIn], zAppend, nAppend);
- zIn[len-1] = '\0';
- }
-
- return zIn;
-}
-
-
-/*
-** Execute a query statement that has a single result column. Print
-** that result column on a line by itself with a semicolon terminator.
-*/
-static int run_table_dump_query(FILE *out, sqlite3 *db, const char *zSelect){
- sqlite3_stmt *pSelect;
- int rc;
- rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0);
- if( rc!=SQLITE_OK || !pSelect ){
- return rc;
- }
- rc = sqlite3_step(pSelect);
- while( rc==SQLITE_ROW ){
- fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0));
- rc = sqlite3_step(pSelect);
- }
- return sqlite3_finalize(pSelect);
-}
-
-
-/*
-** This is a different callback routine used for dumping the database.
-** Each row received by this callback consists of a table name,
-** the table type ("index" or "table") and SQL to create the table.
-** This routine should print text sufficient to recreate the table.
-*/
-static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
- int rc;
- const char *zTable;
- const char *zType;
- const char *zSql;
- struct callback_data *p = (struct callback_data *)pArg;
-
- if( nArg!=3 ) return 1;
- zTable = azArg[0];
- zType = azArg[1];
- zSql = azArg[2];
-
- fprintf(p->out, "%s;\n", zSql);
-
- if( strcmp(zType, "table")==0 ){
- sqlite3_stmt *pTableInfo = 0;
- char *zSelect = 0;
- char *zTableInfo = 0;
- char *zTmp = 0;
-
- zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
- zTableInfo = appendText(zTableInfo, zTable, '"');
- zTableInfo = appendText(zTableInfo, ");", 0);
-
- rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
- if( zTableInfo ) free(zTableInfo);
- if( rc!=SQLITE_OK || !pTableInfo ){
- return 1;
- }
-
- zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
- zTmp = appendText(zTmp, zTable, '"');
- if( zTmp ){
- zSelect = appendText(zSelect, zTmp, '\'');
- }
- zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
- rc = sqlite3_step(pTableInfo);
- while( rc==SQLITE_ROW ){
- zSelect = appendText(zSelect, "quote(", 0);
- zSelect = appendText(zSelect, sqlite3_column_text(pTableInfo, 1), '"');
- rc = sqlite3_step(pTableInfo);
- if( rc==SQLITE_ROW ){
- zSelect = appendText(zSelect, ") || ', ' || ", 0);
- }else{
- zSelect = appendText(zSelect, ") ", 0);
- }
- }
- rc = sqlite3_finalize(pTableInfo);
- if( rc!=SQLITE_OK ){
- if( zSelect ) free(zSelect);
- return 1;
- }
- zSelect = appendText(zSelect, "|| ')' FROM ", 0);
- zSelect = appendText(zSelect, zTable, '"');
-
- rc = run_table_dump_query(p->out, p->db, zSelect);
- if( rc==SQLITE_CORRUPT ){
- zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
- rc = run_table_dump_query(p->out, p->db, zSelect);
- }
- if( zSelect ) free(zSelect);
- if( rc!=SQLITE_OK ){
- return 1;
- }
- }
- return 0;
-}
-
-/*
-** Run zQuery. Update dump_callback() as the callback routine.
-** If we get a SQLITE_CORRUPT error, rerun the query after appending
-** "ORDER BY rowid DESC" to the end.
-*/
-static int run_schema_dump_query(
- struct callback_data *p,
- const char *zQuery,
- char **pzErrMsg
-){
- int rc;
- rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg);
- if( rc==SQLITE_CORRUPT ){
- char *zQ2;
- int len = strlen(zQuery);
- if( pzErrMsg ) sqlite3_free(*pzErrMsg);
- zQ2 = malloc( len+100 );
- if( zQ2==0 ) return rc;
- sprintf(zQ2, "%s ORDER BY rowid DESC", zQuery);
- rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg);
- free(zQ2);
- }
- return rc;
-}
-
-/*
-** Text of a help message
-*/
-static char zHelp[] =
- ".databases List names and files of attached databases\n"
- ".dump ?TABLE? ... Dump the database in an SQL text format\n"
- ".echo ON|OFF Turn command echo on or off\n"
- ".exit Exit this program\n"
- ".explain ON|OFF Turn output mode suitable for EXPLAIN on or off.\n"
- ".header(s) ON|OFF Turn display of headers on or off\n"
- ".help Show this message\n"
- ".import FILE TABLE Import data from FILE into TABLE\n"
- ".indices TABLE Show names of all indices on TABLE\n"
- ".mode MODE ?TABLE? Set output mode where MODE is on of:\n"
- " csv Comma-separated values\n"
- " column Left-aligned columns. (See .width)\n"
- " html HTML <table> code\n"
- " insert SQL insert statements for TABLE\n"
- " line One value per line\n"
- " list Values delimited by .separator string\n"
- " tabs Tab-separated values\n"
- " tcl TCL list elements\n"
- ".nullvalue STRING Print STRING in place of NULL values\n"
- ".output FILENAME Send output to FILENAME\n"
- ".output stdout Send output to the screen\n"
- ".prompt MAIN CONTINUE Replace the standard prompts\n"
- ".quit Exit this program\n"
- ".read FILENAME Execute SQL in FILENAME\n"
-#ifdef SQLITE_HAS_CODEC
- ".rekey OLD NEW NEW Change the encryption key\n"
-#endif
- ".schema ?TABLE? Show the CREATE statements\n"
- ".separator STRING Change separator used by output mode and .import\n"
- ".show Show the current values for various settings\n"
- ".tables ?PATTERN? List names of tables matching a LIKE pattern\n"
- ".timeout MS Try opening locked tables for MS milliseconds\n"
- ".width NUM NUM ... Set column widths for \"column\" mode\n"
-;
-
-/* Forward reference */
-static void process_input(struct callback_data *p, FILE *in);
-
-/*
-** Make sure the database is open. If it is not, then open it. If
-** the database fails to open, print an error message and exit.
-*/
-static void open_db(struct callback_data *p){
- if( p->db==0 ){
- sqlite3_open(p->zDbFilename, &p->db);
- db = p->db;
-#ifdef SQLITE_HAS_CODEC
- sqlite3_key(p->db, p->zKey, p->zKey ? strlen(p->zKey) : 0);
-#endif
- sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
- shellstaticFunc, 0, 0);
- if( SQLITE_OK!=sqlite3_errcode(db) ){
- fprintf(stderr,"Unable to open database \"%s\": %s\n",
- p->zDbFilename, sqlite3_errmsg(db));
- exit(1);
- }
- }
-}
-
-/*
-** Do C-language style dequoting.
-**
-** \t -> tab
-** \n -> newline
-** \r -> carriage return
-** \NNN -> ascii character NNN in octal
-** \\ -> backslash
-*/
-static void resolve_backslashes(char *z){
- int i, j, c;
- for(i=j=0; (c = z[i])!=0; i++, j++){
- if( c=='\\' ){
- c = z[++i];
- if( c=='n' ){
- c = '\n';
- }else if( c=='t' ){
- c = '\t';
- }else if( c=='r' ){
- c = '\r';
- }else if( c>='0' && c<='7' ){
- c =- '0';
- if( z[i+1]>='0' && z[i+1]<='7' ){
- i++;
- c = (c<<3) + z[i] - '0';
- if( z[i+1]>='0' && z[i+1]<='7' ){
- i++;
- c = (c<<3) + z[i] - '0';
- }
- }
- }
- }
- z[j] = c;
- }
- z[j] = 0;
-}
-
-/*
-** If an input line begins with "." then invoke this routine to
-** process that line.
-**
-** Return 1 to exit and 0 to continue.
-*/
-static int do_meta_command(char *zLine, struct callback_data *p){
- int i = 1;
- int nArg = 0;
- int n, c;
- int rc = 0;
- char *azArg[50];
-
- /* Parse the input line into tokens.
- */
- while( zLine[i] && nArg<ArraySize(azArg) ){
- while( isspace((unsigned char)zLine[i]) ){ i++; }
- if( zLine[i]==0 ) break;
- if( zLine[i]=='\'' || zLine[i]=='"' ){
- int delim = zLine[i++];
- azArg[nArg++] = &zLine[i];
- while( zLine[i] && zLine[i]!=delim ){ i++; }
- if( zLine[i]==delim ){
- zLine[i++] = 0;
- }
- if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
- }else{
- azArg[nArg++] = &zLine[i];
- while( zLine[i] && !isspace((unsigned char)zLine[i]) ){ i++; }
- if( zLine[i] ) zLine[i++] = 0;
- resolve_backslashes(azArg[nArg-1]);
- }
- }
-
- /* Process the input line.
- */
- if( nArg==0 ) return rc;
- n = strlen(azArg[0]);
- c = azArg[0][0];
- if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
- struct callback_data data;
- char *zErrMsg = 0;
- open_db(p);
- memcpy(&data, p, sizeof(data));
- data.showHeader = 1;
- data.mode = MODE_Column;
- data.colWidth[0] = 3;
- data.colWidth[1] = 15;
- data.colWidth[2] = 58;
- sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
- if( zErrMsg ){
- fprintf(stderr,"Error: %s\n", zErrMsg);
- sqlite3_free(zErrMsg);
- }
- }else
-
- if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
- char *zErrMsg = 0;
- open_db(p);
- fprintf(p->out, "BEGIN TRANSACTION;\n");
- if( nArg==1 ){
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE sql NOT NULL AND type=='table'", 0
- );
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE sql NOT NULL AND type!='table' AND type!='meta'", 0
- );
- }else{
- int i;
- for(i=1; i<nArg; i++){
- zShellStatic = azArg[i];
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE tbl_name LIKE shellstatic() AND type=='table'"
- " AND sql NOT NULL", 0);
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE tbl_name LIKE shellstatic() AND type!='table'"
- " AND type!='meta' AND sql NOT NULL", 0);
- zShellStatic = 0;
- }
- }
- if( zErrMsg ){
- fprintf(stderr,"Error: %s\n", zErrMsg);
- sqlite3_free(zErrMsg);
- }else{
- fprintf(p->out, "COMMIT;\n");
- }
- }else
-
- if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
- int j;
- char *z = azArg[1];
- int val = atoi(azArg[1]);
- for(j=0; z[j]; j++){
- z[j] = tolower((unsigned char)z[j]);
- }
- if( strcmp(z,"on")==0 ){
- val = 1;
- }else if( strcmp(z,"yes")==0 ){
- val = 1;
- }
- p->echoOn = val;
- }else
-
- if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
- rc = 1;
- }else
-
- if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
- int j;
- static char zOne[] = "1";
- char *z = nArg>=2 ? azArg[1] : zOne;
- int val = atoi(z);
- for(j=0; z[j]; j++){
- z[j] = tolower((unsigned char)z[j]);
- }
- if( strcmp(z,"on")==0 ){
- val = 1;
- }else if( strcmp(z,"yes")==0 ){
- val = 1;
- }
- if(val == 1) {
- if(!p->explainPrev.valid) {
- p->explainPrev.valid = 1;
- p->explainPrev.mode = p->mode;
- p->explainPrev.showHeader = p->showHeader;
- memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
- }
- /* We could put this code under the !p->explainValid
- ** condition so that it does not execute if we are already in
- ** explain mode. However, always executing it allows us an easy
- ** was to reset to explain mode in case the user previously
- ** did an .explain followed by a .width, .mode or .header
- ** command.
- */
- p->mode = MODE_Column;
- p->showHeader = 1;
- memset(p->colWidth,0,ArraySize(p->colWidth));
- p->colWidth[0] = 4;
- p->colWidth[1] = 12;
- p->colWidth[2] = 10;
- p->colWidth[3] = 10;
- p->colWidth[4] = 35;
- }else if (p->explainPrev.valid) {
- p->explainPrev.valid = 0;
- p->mode = p->explainPrev.mode;
- p->showHeader = p->explainPrev.showHeader;
- memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
- }
- }else
-
- if( c=='h' && (strncmp(azArg[0], "header", n)==0
- ||
- strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
- int j;
- char *z = azArg[1];
- int val = atoi(azArg[1]);
- for(j=0; z[j]; j++){
- z[j] = tolower((unsigned char)z[j]);
- }
- if( strcmp(z,"on")==0 ){
- val = 1;
- }else if( strcmp(z,"yes")==0 ){
- val = 1;
- }
- p->showHeader = val;
- }else
-
- if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
- fprintf(stderr,zHelp);
- }else
-
- if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg>=3 ){
- char *zTable = azArg[2]; /* Insert data into this table */
- char *zFile = azArg[1]; /* The file from which to extract data */
- sqlite3_stmt *pStmt; /* A statement */
- int rc; /* Result code */
- int nCol; /* Number of columns in the table */
- int nByte; /* Number of bytes in an SQL string */
- int i, j; /* Loop counters */
- int nSep; /* Number of bytes in p->separator[] */
- char *zSql; /* An SQL statement */
- char *zLine; /* A single line of input from the file */
- char **azCol; /* zLine[] broken up into columns */
- char *zCommit; /* How to commit changes */
- FILE *in; /* The input file */
- int lineno = 0; /* Line number of input file */
-
- nSep = strlen(p->separator);
- if( nSep==0 ){
- fprintf(stderr, "non-null separator required for import\n");
- return 0;
- }
- zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
- if( zSql==0 ) return 0;
- nByte = strlen(zSql);
- rc = sqlite3_prepare(p->db, zSql, 0, &pStmt, 0);
- sqlite3_free(zSql);
- if( rc ){
- fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
- nCol = 0;
- }else{
- nCol = sqlite3_column_count(pStmt);
- }
- sqlite3_finalize(pStmt);
- if( nCol==0 ) return 0;
- zSql = malloc( nByte + 20 + nCol*2 );
- if( zSql==0 ) return 0;
- sqlite3_snprintf(nByte+20, zSql, "INSERT INTO '%q' VALUES(?", zTable);
- j = strlen(zSql);
- for(i=1; i<nCol; i++){
- zSql[j++] = ',';
- zSql[j++] = '?';
- }
- zSql[j++] = ')';
- zSql[j] = 0;
- rc = sqlite3_prepare(p->db, zSql, 0, &pStmt, 0);
- free(zSql);
- if( rc ){
- fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
- sqlite3_finalize(pStmt);
- return 0;
- }
- in = fopen(zFile, "rb");
- if( in==0 ){
- fprintf(stderr, "cannot open file: %s\n", zFile);
- sqlite3_finalize(pStmt);
- return 0;
- }
- azCol = malloc( sizeof(azCol[0])*(nCol+1) );
- if( azCol==0 ) return 0;
- sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
- zCommit = "COMMIT";
- while( (zLine = local_getline(0, in))!=0 ){
- char *z;
- i = 0;
- lineno++;
- azCol[0] = zLine;
- for(i=0, z=zLine; *z && *z!='\n' && *z!='\r'; z++){
- if( *z==p->separator[0] && strncmp(z, p->separator, nSep)==0 ){
- *z = 0;
- i++;
- if( i<nCol ){
- azCol[i] = &z[nSep];
- z += nSep-1;
- }
- }
- }
- if( i+1!=nCol ){
- fprintf(stderr,"%s line %d: expected %d columns of data but found %d\n",
- zFile, lineno, nCol, i+1);
- zCommit = "ROLLBACK";
- break;
- }
- for(i=0; i<nCol; i++){
- sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
- }
- sqlite3_step(pStmt);
- rc = sqlite3_reset(pStmt);
- free(zLine);
- if( rc!=SQLITE_OK ){
- fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
- zCommit = "ROLLBACK";
- break;
- }
- }
- free(azCol);
- fclose(in);
- sqlite3_finalize(pStmt);
- sqlite3_exec(p->db, zCommit, 0, 0, 0);
- }else
-
- if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
- struct callback_data data;
- char *zErrMsg = 0;
- open_db(p);
- memcpy(&data, p, sizeof(data));
- data.showHeader = 0;
- data.mode = MODE_List;
- zShellStatic = azArg[1];
- sqlite3_exec(p->db,
- "SELECT name FROM sqlite_master "
- "WHERE type='index' AND tbl_name LIKE shellstatic() "
- "UNION ALL "
- "SELECT name FROM sqlite_temp_master "
- "WHERE type='index' AND tbl_name LIKE shellstatic() "
- "ORDER BY 1",
- callback, &data, &zErrMsg
- );
- zShellStatic = 0;
- if( zErrMsg ){
- fprintf(stderr,"Error: %s\n", zErrMsg);
- sqlite3_free(zErrMsg);
- }
- }else
-
- if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
- int n2 = strlen(azArg[1]);
- if( strncmp(azArg[1],"line",n2)==0
- ||
- strncmp(azArg[1],"lines",n2)==0 ){
- p->mode = MODE_Line;
- }else if( strncmp(azArg[1],"column",n2)==0
- ||
- strncmp(azArg[1],"columns",n2)==0 ){
- p->mode = MODE_Column;
- }else if( strncmp(azArg[1],"list",n2)==0 ){
- p->mode = MODE_List;
- }else if( strncmp(azArg[1],"html",n2)==0 ){
- p->mode = MODE_Html;
- }else if( strncmp(azArg[1],"tcl",n2)==0 ){
- p->mode = MODE_Tcl;
- }else if( strncmp(azArg[1],"csv",n2)==0 ){
- p->mode = MODE_Csv;
- strcpy(p->separator, ",");
- }else if( strncmp(azArg[1],"tabs",n2)==0 ){
- p->mode = MODE_List;
- strcpy(p->separator, "\t");
- }else if( strncmp(azArg[1],"insert",n2)==0 ){
- p->mode = MODE_Insert;
- if( nArg>=3 ){
- set_table_name(p, azArg[2]);
- }else{
- set_table_name(p, "table");
- }
- }else {
- fprintf(stderr,"mode should be on of: "
- "column csv html insert line list tabs tcl\n");
- }
- }else
-
- if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
- sprintf(p->nullvalue, "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
- }else
-
- if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
- if( p->out!=stdout ){
- fclose(p->out);
- }
- if( strcmp(azArg[1],"stdout")==0 ){
- p->out = stdout;
- strcpy(p->outfile,"stdout");
- }else{
- p->out = fopen(azArg[1], "wb");
- if( p->out==0 ){
- fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
- p->out = stdout;
- } else {
- strcpy(p->outfile,azArg[1]);
- }
- }
- }else
-
- if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
- if( nArg >= 2) {
- strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
- }
- if( nArg >= 3) {
- strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
- }
- }else
-
- if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
- rc = 1;
- }else
-
- if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
- FILE *alt = fopen(azArg[1], "rb");
- if( alt==0 ){
- fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
- }else{
- process_input(p, alt);
- fclose(alt);
- }
- }else
-
-#ifdef SQLITE_HAS_CODEC
- if( c=='r' && strncmp(azArg[0],"rekey", n)==0 && nArg==4 ){
- char *zOld = p->zKey;
- if( zOld==0 ) zOld = "";
- if( strcmp(azArg[1],zOld) ){
- fprintf(stderr,"old key is incorrect\n");
- }else if( strcmp(azArg[2], azArg[3]) ){
- fprintf(stderr,"2nd copy of new key does not match the 1st\n");
- }else{
- sqlite3_free(p->zKey);
- p->zKey = sqlite3_mprintf("%s", azArg[2]);
- sqlite3_rekey(p->db, p->zKey, strlen(p->zKey));
- }
- }else
-#endif
-
- if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
- struct callback_data data;
- char *zErrMsg = 0;
- open_db(p);
- memcpy(&data, p, sizeof(data));
- data.showHeader = 0;
- data.mode = MODE_Semi;
- if( nArg>1 ){
- int i;
- for(i=0; azArg[1][i]; i++) azArg[1][i] = tolower(azArg[1][i]);
- if( strcmp(azArg[1],"sqlite_master")==0 ){
- char *new_argv[2], *new_colv[2];
- new_argv[0] = "CREATE TABLE sqlite_master (\n"
- " type text,\n"
- " name text,\n"
- " tbl_name text,\n"
- " rootpage integer,\n"
- " sql text\n"
- ")";
- new_argv[1] = 0;
- new_colv[0] = "sql";
- new_colv[1] = 0;
- callback(&data, 1, new_argv, new_colv);
- }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
- char *new_argv[2], *new_colv[2];
- new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
- " type text,\n"
- " name text,\n"
- " tbl_name text,\n"
- " rootpage integer,\n"
- " sql text\n"
- ")";
- new_argv[1] = 0;
- new_colv[0] = "sql";
- new_colv[1] = 0;
- callback(&data, 1, new_argv, new_colv);
- }else{
- zShellStatic = azArg[1];
- sqlite3_exec(p->db,
- "SELECT sql FROM "
- " (SELECT * FROM sqlite_master UNION ALL"
- " SELECT * FROM sqlite_temp_master) "
- "WHERE tbl_name LIKE shellstatic() AND type!='meta' AND sql NOTNULL "
- "ORDER BY substr(type,2,1), name",
- callback, &data, &zErrMsg);
- zShellStatic = 0;
- }
- }else{
- sqlite3_exec(p->db,
- "SELECT sql FROM "
- " (SELECT * FROM sqlite_master UNION ALL"
- " SELECT * FROM sqlite_temp_master) "
- "WHERE type!='meta' AND sql NOTNULL "
- "ORDER BY substr(type,2,1), name",
- callback, &data, &zErrMsg
- );
- }
- if( zErrMsg ){
- fprintf(stderr,"Error: %s\n", zErrMsg);
- sqlite3_free(zErrMsg);
- }
- }else
-
- if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
- sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
- }else
-
- if( c=='s' && strncmp(azArg[0], "show", n)==0){
- int i;
- fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
- fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
- fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
- fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
- fprintf(p->out,"%9.9s: ", "nullvalue");
- output_c_string(p->out, p->nullvalue);
- fprintf(p->out, "\n");
- fprintf(p->out,"%9.9s: %s\n","output",
- strlen(p->outfile) ? p->outfile : "stdout");
- fprintf(p->out,"%9.9s: ", "separator");
- output_c_string(p->out, p->separator);
- fprintf(p->out, "\n");
- fprintf(p->out,"%9.9s: ","width");
- for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
- fprintf(p->out,"%d ",p->colWidth[i]);
- }
- fprintf(p->out,"\n");
- }else
-
- if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
- char **azResult;
- int nRow, rc;
- char *zErrMsg;
- open_db(p);
- if( nArg==1 ){
- rc = sqlite3_get_table(p->db,
- "SELECT name FROM sqlite_master "
- "WHERE type IN ('table','view') "
- "UNION ALL "
- "SELECT name FROM sqlite_temp_master "
- "WHERE type IN ('table','view') "
- "ORDER BY 1",
- &azResult, &nRow, 0, &zErrMsg
- );
- }else{
- zShellStatic = azArg[1];
- rc = sqlite3_get_table(p->db,
- "SELECT name FROM sqlite_master "
- "WHERE type IN ('table','view') AND name LIKE '%'||shellstatic()||'%' "
- "UNION ALL "
- "SELECT name FROM sqlite_temp_master "
- "WHERE type IN ('table','view') AND name LIKE '%'||shellstatic()||'%' "
- "ORDER BY 1",
- &azResult, &nRow, 0, &zErrMsg
- );
- zShellStatic = 0;
- }
- if( zErrMsg ){
- fprintf(stderr,"Error: %s\n", zErrMsg);
- sqlite3_free(zErrMsg);
- }
- if( rc==SQLITE_OK ){
- int len, maxlen = 0;
- int i, j;
- int nPrintCol, nPrintRow;
- for(i=1; i<=nRow; i++){
- if( azResult[i]==0 ) continue;
- len = strlen(azResult[i]);
- if( len>maxlen ) maxlen = len;
- }
- nPrintCol = 80/(maxlen+2);
- if( nPrintCol<1 ) nPrintCol = 1;
- nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
- for(i=0; i<nPrintRow; i++){
- for(j=i+1; j<=nRow; j+=nPrintRow){
- char *zSp = j<=nPrintRow ? "" : " ";
- printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
- }
- printf("\n");
- }
- }
- sqlite3_free_table(azResult);
- }else
-
- if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
- open_db(p);
- sqlite3_busy_timeout(p->db, atoi(azArg[1]));
- }else
-
- if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
- int j;
- for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
- p->colWidth[j-1] = atoi(azArg[j]);
- }
- }else
-
- {
- fprintf(stderr, "unknown command or invalid arguments: "
- " \"%s\". Enter \".help\" for help\n", azArg[0]);
- }
-
- return rc;
-}
-
-/*
-** Return TRUE if the last non-whitespace character in z[] is a semicolon.
-** z[] is N characters long.
-*/
-static int _ends_with_semicolon(const char *z, int N){
- while( N>0 && isspace((unsigned char)z[N-1]) ){ N--; }
- return N>0 && z[N-1]==';';
-}
-
-/*
-** Test to see if a line consists entirely of whitespace.
-*/
-static int _all_whitespace(const char *z){
- for(; *z; z++){
- if( isspace(*(unsigned char*)z) ) continue;
- if( *z=='/' && z[1]=='*' ){
- z += 2;
- while( *z && (*z!='*' || z[1]!='/') ){ z++; }
- if( *z==0 ) return 0;
- z++;
- continue;
- }
- if( *z=='-' && z[1]=='-' ){
- z += 2;
- while( *z && *z!='\n' ){ z++; }
- if( *z==0 ) return 1;
- continue;
- }
- return 0;
- }
- return 1;
-}
-
-/*
-** Return TRUE if the line typed in is an SQL command terminator other
-** than a semi-colon. The SQL Server style "go" command is understood
-** as is the Oracle "/".
-*/
-static int _is_command_terminator(const char *zLine){
- while( isspace(*(unsigned char*)zLine) ){ zLine++; };
- if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ) return 1; /* Oracle */
- if( tolower(zLine[0])=='g' && tolower(zLine[1])=='o'
- && _all_whitespace(&zLine[2]) ){
- return 1; /* SQL Server */
- }
- return 0;
-}
-
-/*
-** Read input from *in and process it. If *in==0 then input
-** is interactive - the user is typing it it. Otherwise, input
-** is coming from a file or device. A prompt is issued and history
-** is saved only if input is interactive. An interrupt signal will
-** cause this routine to exit immediately, unless input is interactive.
-*/
-static void process_input(struct callback_data *p, FILE *in){
- char *zLine;
- char *zSql = 0;
- int nSql = 0;
- char *zErrMsg;
- int rc;
- while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){
- if( seenInterrupt ){
- if( in!=0 ) break;
- seenInterrupt = 0;
- }
- if( p->echoOn ) printf("%s\n", zLine);
- if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
- if( zLine && zLine[0]=='.' && nSql==0 ){
- int rc = do_meta_command(zLine, p);
- free(zLine);
- if( rc ) break;
- continue;
- }
- if( _is_command_terminator(zLine) ){
- strcpy(zLine,";");
- }
- if( zSql==0 ){
- int i;
- for(i=0; zLine[i] && isspace((unsigned char)zLine[i]); i++){}
- if( zLine[i]!=0 ){
- nSql = strlen(zLine);
- zSql = malloc( nSql+1 );
- strcpy(zSql, zLine);
- }
- }else{
- int len = strlen(zLine);
- zSql = realloc( zSql, nSql + len + 2 );
- if( zSql==0 ){
- fprintf(stderr,"%s: out of memory!\n", Argv0);
- exit(1);
- }
- strcpy(&zSql[nSql++], "\n");
- strcpy(&zSql[nSql], zLine);
- nSql += len;
- }
- free(zLine);
- if( zSql && _ends_with_semicolon(zSql, nSql) && sqlite3_complete(zSql) ){
- p->cnt = 0;
- open_db(p);
- rc = sqlite3_exec(p->db, zSql, callback, p, &zErrMsg);
- if( rc || zErrMsg ){
- if( in!=0 && !p->echoOn ) printf("%s\n",zSql);
- if( zErrMsg!=0 ){
- printf("SQL error: %s\n", zErrMsg);
- sqlite3_free(zErrMsg);
- zErrMsg = 0;
- }else{
- printf("SQL error: %s\n", sqlite3_errmsg(p->db));
- }
- }
- free(zSql);
- zSql = 0;
- nSql = 0;
- }
- }
- if( zSql ){
- if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql);
- free(zSql);
- }
-}
-
-/*
-** Return a pathname which is the user's home directory. A
-** 0 return indicates an error of some kind. Space to hold the
-** resulting string is obtained from malloc(). The calling
-** function should free the result.
-*/
-static char *find_home_dir(void){
- char *home_dir = NULL;
-
-#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__)
- struct passwd *pwent;
- uid_t uid = getuid();
- if( (pwent=getpwuid(uid)) != NULL) {
- home_dir = pwent->pw_dir;
- }
-#endif
-
-#ifdef __MACOS__
- char home_path[_MAX_PATH+1];
- home_dir = getcwd(home_path, _MAX_PATH);
-#endif
-
- if (!home_dir) {
- home_dir = getenv("HOME");
- if (!home_dir) {
- home_dir = getenv("HOMEPATH"); /* Windows? */
- }
- }
-
-#if defined(_WIN32) || defined(WIN32)
- if (!home_dir) {
- home_dir = "c:";
- }
-#endif
-
- if( home_dir ){
- char *z = malloc( strlen(home_dir)+1 );
- if( z ) strcpy(z, home_dir);
- home_dir = z;
- }
-
- return home_dir;
-}
-
-/*
-** Read input from the file given by sqliterc_override. Or if that
-** parameter is NULL, take input from ~/.sqliterc
-*/
-static void process_sqliterc(
- struct callback_data *p, /* Configuration data */
- const char *sqliterc_override /* Name of config file. NULL to use default */
-){
- char *home_dir = NULL;
- const char *sqliterc = sqliterc_override;
- char *zBuf;
- FILE *in = NULL;
-
- if (sqliterc == NULL) {
- home_dir = find_home_dir();
- if( home_dir==0 ){
- fprintf(stderr,"%s: cannot locate your home directory!\n", Argv0);
- return;
- }
- zBuf = malloc(strlen(home_dir) + 15);
- if( zBuf==0 ){
- fprintf(stderr,"%s: out of memory!\n", Argv0);
- exit(1);
- }
- sprintf(zBuf,"%s/.sqliterc",home_dir);
- free(home_dir);
- sqliterc = (const char*)zBuf;
- }
- in = fopen(sqliterc,"rb");
- if( in ){
- if( isatty(fileno(stdout)) ){
- printf("Loading resources from %s\n",sqliterc);
- }
- process_input(p,in);
- fclose(in);
- }
- return;
-}
-
-/*
-** Show available command line options
-*/
-static const char zOptions[] =
- " -init filename read/process named file\n"
- " -echo print commands before execution\n"
- " -[no]header turn headers on or off\n"
- " -column set output mode to 'column'\n"
- " -html set output mode to HTML\n"
-#ifdef SQLITE_HAS_CODEC
- " -key KEY encryption key\n"
-#endif
- " -line set output mode to 'line'\n"
- " -list set output mode to 'list'\n"
- " -separator 'x' set output field separator (|)\n"
- " -nullvalue 'text' set text string for NULL values\n"
- " -version show SQLite version\n"
- " -help show this text, also show dot-commands\n"
-;
-static void usage(int showDetail){
- fprintf(stderr, "Usage: %s [OPTIONS] FILENAME [SQL]\n", Argv0);
- if( showDetail ){
- fprintf(stderr, "Options are:\n%s", zOptions);
- }else{
- fprintf(stderr, "Use the -help option for additional information\n");
- }
- exit(1);
-}
-
-/*
-** Initialize the state information in data
-*/
-void main_init(struct callback_data *data) {
- memset(data, 0, sizeof(*data));
- data->mode = MODE_List;
- strcpy(data->separator,"|");
- data->showHeader = 0;
- strcpy(mainPrompt,"sqlite> ");
- strcpy(continuePrompt," ...> ");
-}
-
-int main(int argc, char **argv){
- char *zErrMsg = 0;
- struct callback_data data;
- const char *zInitFile = 0;
- char *zFirstCmd = 0;
- int i;
-
-#ifdef __MACOS__
- argc = ccommand(&argv);
-#endif
-
- Argv0 = argv[0];
- main_init(&data);
-
- /* Make sure we have a valid signal handler early, before anything
- ** else is done.
- */
-#ifdef SIGINT
- signal(SIGINT, interrupt_handler);
-#endif
-
- /* Do an initial pass through the command-line argument to locate
- ** the name of the database file, the name of the initialization file,
- ** and the first command to execute.
- */
- for(i=1; i<argc-1; i++){
- if( argv[i][0]!='-' ) break;
- if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
- i++;
- }else if( strcmp(argv[i],"-init")==0 ){
- i++;
- zInitFile = argv[i];
- }else if( strcmp(argv[i],"-key")==0 ){
- i++;
- data.zKey = sqlite3_mprintf("%s",argv[i]);
- }
- }
- if( i<argc ){
- data.zDbFilename = argv[i++];
- }else{
- data.zDbFilename = ":memory:";
- }
- if( i<argc ){
- zFirstCmd = argv[i++];
- }
- data.out = stdout;
-
- /* Go ahead and open the database file if it already exists. If the
- ** file does not exist, delay opening it. This prevents empty database
- ** files from being created if a user mistypes the database name argument
- ** to the sqlite command-line tool.
- */
- if( access(data.zDbFilename, 0)==0 ){
- open_db(&data);
- }
-
- /* Process the initialization file if there is one. If no -init option
- ** is given on the command line, look for a file named ~/.sqliterc and
- ** try to process it.
- */
- process_sqliterc(&data,zInitFile);
-
- /* Make a second pass through the command-line argument and set
- ** options. This second pass is delayed until after the initialization
- ** file is processed so that the command-line arguments will override
- ** settings in the initialization file.
- */
- for(i=1; i<argc && argv[i][0]=='-'; i++){
- char *z = argv[i];
- if( strcmp(z,"-init")==0 || strcmp(z,"-key")==0 ){
- i++;
- }else if( strcmp(z,"-html")==0 ){
- data.mode = MODE_Html;
- }else if( strcmp(z,"-list")==0 ){
- data.mode = MODE_List;
- }else if( strcmp(z,"-line")==0 ){
- data.mode = MODE_Line;
- }else if( strcmp(z,"-column")==0 ){
- data.mode = MODE_Column;
- }else if( strcmp(z,"-separator")==0 ){
- i++;
- sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[i]);
- }else if( strcmp(z,"-nullvalue")==0 ){
- i++;
- sprintf(data.nullvalue,"%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
- }else if( strcmp(z,"-header")==0 ){
- data.showHeader = 1;
- }else if( strcmp(z,"-noheader")==0 ){
- data.showHeader = 0;
- }else if( strcmp(z,"-echo")==0 ){
- data.echoOn = 1;
- }else if( strcmp(z,"-version")==0 ){
- printf("%s\n", sqlite3_libversion());
- return 1;
- }else if( strcmp(z,"-help")==0 ){
- usage(1);
- }else{
- fprintf(stderr,"%s: unknown option: %s\n", Argv0, z);
- fprintf(stderr,"Use -help for a list of options.\n");
- return 1;
- }
- }
-
- if( zFirstCmd ){
- /* Run just the command that follows the database name
- */
- if( zFirstCmd[0]=='.' ){
- do_meta_command(zFirstCmd, &data);
- exit(0);
- }else{
- int rc;
- open_db(&data);
- rc = sqlite3_exec(data.db, zFirstCmd, callback, &data, &zErrMsg);
- if( rc!=0 && zErrMsg!=0 ){
- fprintf(stderr,"SQL error: %s\n", zErrMsg);
- exit(1);
- }
- }
- }else{
- /* Run commands received from standard input
- */
- if( isatty(fileno(stdout)) && isatty(fileno(stdin)) ){
- char *zHome;
- char *zHistory = 0;
- printf(
- "SQLite version %s\n"
- "Enter \".help\" for instructions\n",
- sqlite3_libversion()
- );
- zHome = find_home_dir();
- if( zHome && (zHistory = malloc(strlen(zHome)+20))!=0 ){
- sprintf(zHistory,"%s/.sqlite_history", zHome);
- }
- if( zHistory ) read_history(zHistory);
- process_input(&data, 0);
- if( zHistory ){
- stifle_history(100);
- write_history(zHistory);
- }
- }else{
- process_input(&data, stdin);
- }
- }
- set_table_name(&data, 0);
- if( db ) sqlite3_close(db);
- return 0;
-}
diff --git a/kopete/plugins/statistics/sqlite/sqlite3.h b/kopete/plugins/statistics/sqlite/sqlite3.h
deleted file mode 100644
index d6b99049..00000000
--- a/kopete/plugins/statistics/sqlite/sqlite3.h
+++ /dev/null
@@ -1,1166 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This header file defines the interface that the SQLite library
-** presents to client programs.
-**
-** @(#) $Id$
-*/
-#ifndef _SQLITE3_H_
-#define _SQLITE3_H_
-#include <stdarg.h> /* Needed for the definition of va_list */
-
-/*
-** Make sure we can call this stuff from C++.
-*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
-** The version of the SQLite library.
-*/
-#ifdef SQLITE_VERSION
-# undef SQLITE_VERSION
-#else
-# define SQLITE_VERSION "3.0.8"
-#endif
-
-/*
-** The version string is also compiled into the library so that a program
-** can check to make sure that the lib*.a file and the *.h file are from
-** the same version. The sqlite3_libversion() function returns a pointer
-** to the sqlite3_version variable - useful in DLLs which cannot access
-** global variables.
-*/
-extern const char sqlite3_version[];
-const char *sqlite3_libversion(void);
-
-/*
-** Each open sqlite database is represented by an instance of the
-** following opaque structure.
-*/
-typedef struct sqlite3 sqlite3;
-
-
-/*
-** Some compilers do not support the "long long" datatype. So we have
-** to do a typedef that for 64-bit integers that depends on what compiler
-** is being used.
-*/
-#if defined(_MSC_VER) || defined(__BORLANDC__)
- typedef __int64 sqlite_int64;
- typedef unsigned __int64 sqlite_uint64;
-#else
- typedef long long int sqlite_int64;
- typedef unsigned long long int sqlite_uint64;
-#endif
-
-
-/*
-** A function to close the database.
-**
-** Call this function with a pointer to a structure that was previously
-** returned from sqlite3_open() and the corresponding database will by closed.
-**
-** All SQL statements prepared using sqlite3_prepare() or
-** sqlite3_prepare16() must be deallocated using sqlite3_finalize() before
-** this routine is called. Otherwise, SQLITE_BUSY is returned and the
-** database connection remains open.
-*/
-int sqlite3_close(sqlite3 *);
-
-/*
-** The type for a callback function.
-*/
-typedef int (*sqlite3_callback)(void*,int,char**, char**);
-
-/*
-** A function to executes one or more statements of SQL.
-**
-** If one or more of the SQL statements are queries, then
-** the callback function specified by the 3rd parameter is
-** invoked once for each row of the query result. This callback
-** should normally return 0. If the callback returns a non-zero
-** value then the query is aborted, all subsequent SQL statements
-** are skipped and the sqlite3_exec() function returns the SQLITE_ABORT.
-**
-** The 4th parameter is an arbitrary pointer that is passed
-** to the callback function as its first parameter.
-**
-** The 2nd parameter to the callback function is the number of
-** columns in the query result. The 3rd parameter to the callback
-** is an array of strings holding the values for each column.
-** The 4th parameter to the callback is an array of strings holding
-** the names of each column.
-**
-** The callback function may be NULL, even for queries. A NULL
-** callback is not an error. It just means that no callback
-** will be invoked.
-**
-** If an error occurs while parsing or evaluating the SQL (but
-** not while executing the callback) then an appropriate error
-** message is written into memory obtained from malloc() and
-** *errmsg is made to point to that message. The calling function
-** is responsible for freeing the memory that holds the error
-** message. Use sqlite3_free() for this. If errmsg==NULL,
-** then no error message is ever written.
-**
-** The return value is is SQLITE_OK if there are no errors and
-** some other return code if there is an error. The particular
-** return value depends on the type of error.
-**
-** If the query could not be executed because a database file is
-** locked or busy, then this function returns SQLITE_BUSY. (This
-** behavior can be modified somewhat using the sqlite3_busy_handler()
-** and sqlite3_busy_timeout() functions below.)
-*/
-int sqlite3_exec(
- sqlite3*, /* An open database */
- const char *sql, /* SQL to be executed */
- sqlite3_callback, /* Callback function */
- void *, /* 1st argument to callback function */
- char **errmsg /* Error msg written here */
-);
-
-/*
-** Return values for sqlite3_exec() and sqlite3_step()
-*/
-#define SQLITE_OK 0 /* Successful result */
-#define SQLITE_ERROR 1 /* SQL error or missing database */
-#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
-#define SQLITE_PERM 3 /* Access permission denied */
-#define SQLITE_ABORT 4 /* Callback routine requested an abort */
-#define SQLITE_BUSY 5 /* The database file is locked */
-#define SQLITE_LOCKED 6 /* A table in the database is locked */
-#define SQLITE_NOMEM 7 /* A malloc() failed */
-#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
-#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
-#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
-#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
-#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */
-#define SQLITE_FULL 13 /* Insertion failed because database is full */
-#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
-#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
-#define SQLITE_EMPTY 16 /* Database is empty */
-#define SQLITE_SCHEMA 17 /* The database schema changed */
-#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */
-#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */
-#define SQLITE_MISMATCH 20 /* Data type mismatch */
-#define SQLITE_MISUSE 21 /* Library used incorrectly */
-#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
-#define SQLITE_AUTH 23 /* Authorization denied */
-#define SQLITE_FORMAT 24 /* Auxiliary database format error */
-#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
-#define SQLITE_NOTADB 26 /* File opened that is not a database file */
-#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
-#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
-
-/*
-** Each entry in an SQLite table has a unique integer key. (The key is
-** the value of the INTEGER PRIMARY KEY column if there is such a column,
-** otherwise the key is generated at random. The unique key is always
-** available as the ROWID, OID, or _ROWID_ column.) The following routine
-** returns the integer key of the most recent insert in the database.
-**
-** This function is similar to the mysql_insert_id() function from MySQL.
-*/
-sqlite_int64 sqlite3_last_insert_rowid(sqlite3*);
-
-/*
-** This function returns the number of database rows that were changed
-** (or inserted or deleted) by the most recent called sqlite3_exec().
-**
-** All changes are counted, even if they were later undone by a
-** ROLLBACK or ABORT. Except, changes associated with creating and
-** dropping tables are not counted.
-**
-** If a callback invokes sqlite3_exec() recursively, then the changes
-** in the inner, recursive call are counted together with the changes
-** in the outer call.
-**
-** SQLite implements the command "DELETE FROM table" without a WHERE clause
-** by dropping and recreating the table. (This is much faster than going
-** through and deleting individual elements form the table.) Because of
-** this optimization, the change count for "DELETE FROM table" will be
-** zero regardless of the number of elements that were originally in the
-** table. To get an accurate count of the number of rows deleted, use
-** "DELETE FROM table WHERE 1" instead.
-*/
-int sqlite3_changes(sqlite3*);
-
-/*
-** This function returns the number of database rows that have been
-** modified by INSERT, UPDATE or DELETE statements since the database handle
-** was opened. This includes UPDATE, INSERT and DELETE statements executed
-** as part of trigger programs. All changes are counted as soon as the
-** statement that makes them is completed (when the statement handle is
-** passed to sqlite3_reset() or sqlite_finalise()).
-**
-** SQLite implements the command "DELETE FROM table" without a WHERE clause
-** by dropping and recreating the table. (This is much faster than going
-** through and deleting individual elements form the table.) Because of
-** this optimization, the change count for "DELETE FROM table" will be
-** zero regardless of the number of elements that were originally in the
-** table. To get an accurate count of the number of rows deleted, use
-** "DELETE FROM table WHERE 1" instead.
-*/
-int sqlite3_total_changes(sqlite3*);
-
-/* This function causes any pending database operation to abort and
-** return at its earliest opportunity. This routine is typically
-** called in response to a user action such as pressing "Cancel"
-** or Ctrl-C where the user wants a long query operation to halt
-** immediately.
-*/
-void sqlite3_interrupt(sqlite3*);
-
-
-/* These functions return true if the given input string comprises
-** one or more complete SQL statements. For the sqlite3_complete() call,
-** the parameter must be a nul-terminated UTF-8 string. For
-** sqlite3_complete16(), a nul-terminated machine byte order UTF-16 string
-** is required.
-**
-** The algorithm is simple. If the last token other than spaces
-** and comments is a semicolon, then return true. otherwise return
-** false.
-*/
-int sqlite3_complete(const char *sql);
-int sqlite3_complete16(const void *sql);
-
-/*
-** This routine identifies a callback function that is invoked
-** whenever an attempt is made to open a database table that is
-** currently locked by another process or thread. If the busy callback
-** is NULL, then sqlite3_exec() returns SQLITE_BUSY immediately if
-** it finds a locked table. If the busy callback is not NULL, then
-** sqlite3_exec() invokes the callback with three arguments. The
-** second argument is the name of the locked table and the third
-** argument is the number of times the table has been busy. If the
-** busy callback returns 0, then sqlite3_exec() immediately returns
-** SQLITE_BUSY. If the callback returns non-zero, then sqlite3_exec()
-** tries to open the table again and the cycle repeats.
-**
-** The default busy callback is NULL.
-**
-** Sqlite is re-entrant, so the busy handler may start a new query.
-** (It is not clear why anyone would every want to do this, but it
-** is allowed, in theory.) But the busy handler may not close the
-** database. Closing the database from a busy handler will delete
-** data structures out from under the executing query and will
-** probably result in a coredump.
-*/
-int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
-
-/*
-** This routine sets a busy handler that sleeps for a while when a
-** table is locked. The handler will sleep multiple times until
-** at least "ms" milleseconds of sleeping have been done. After
-** "ms" milleseconds of sleeping, the handler returns 0 which
-** causes sqlite3_exec() to return SQLITE_BUSY.
-**
-** Calling this routine with an argument less than or equal to zero
-** turns off all busy handlers.
-*/
-int sqlite3_busy_timeout(sqlite3*, int ms);
-
-/*
-** This next routine is really just a wrapper around sqlite3_exec().
-** Instead of invoking a user-supplied callback for each row of the
-** result, this routine remembers each row of the result in memory
-** obtained from malloc(), then returns all of the result after the
-** query has finished.
-**
-** As an example, suppose the query result where this table:
-**
-** Name | Age
-** -----------------------
-** Alice | 43
-** Bob | 28
-** Cindy | 21
-**
-** If the 3rd argument were &azResult then after the function returns
-** azResult will contain the following data:
-**
-** azResult[0] = "Name";
-** azResult[1] = "Age";
-** azResult[2] = "Alice";
-** azResult[3] = "43";
-** azResult[4] = "Bob";
-** azResult[5] = "28";
-** azResult[6] = "Cindy";
-** azResult[7] = "21";
-**
-** Notice that there is an extra row of data containing the column
-** headers. But the *nrow return value is still 3. *ncolumn is
-** set to 2. In general, the number of values inserted into azResult
-** will be ((*nrow) + 1)*(*ncolumn).
-**
-** After the calling function has finished using the result, it should
-** pass the result data pointer to sqlite3_free_table() in order to
-** release the memory that was malloc-ed. Because of the way the
-** malloc() happens, the calling function must not try to call
-** malloc() directly. Only sqlite3_free_table() is able to release
-** the memory properly and safely.
-**
-** The return value of this routine is the same as from sqlite3_exec().
-*/
-int sqlite3_get_table(
- sqlite3*, /* An open database */
- const char *sql, /* SQL to be executed */
- char ***resultp, /* Result written to a char *[] that this points to */
- int *nrow, /* Number of result rows written here */
- int *ncolumn, /* Number of result columns written here */
- char **errmsg /* Error msg written here */
-);
-
-/*
-** Call this routine to free the memory that sqlite3_get_table() allocated.
-*/
-void sqlite3_free_table(char **result);
-
-/*
-** The following routines are variants of the "sprintf()" from the
-** standard C library. The resulting string is written into memory
-** obtained from malloc() so that there is never a possiblity of buffer
-** overflow. These routines also implement some additional formatting
-** options that are useful for constructing SQL statements.
-**
-** The strings returned by these routines should be freed by calling
-** sqlite3_free().
-**
-** All of the usual printf formatting options apply. In addition, there
-** is a "%q" option. %q works like %s in that it substitutes a null-terminated
-** string from the argument list. But %q also doubles every '\'' character.
-** %q is designed for use inside a string literal. By doubling each '\''
-** character it escapes that character and allows it to be inserted into
-** the string.
-**
-** For example, so some string variable contains text as follows:
-**
-** char *zText = "It's a happy day!";
-**
-** We can use this text in an SQL statement as follows:
-**
-** sqlite3_exec_printf(db, "INSERT INTO table VALUES('%q')",
-** callback1, 0, 0, zText);
-**
-** Because the %q format string is used, the '\'' character in zText
-** is escaped and the SQL generated is as follows:
-**
-** INSERT INTO table1 VALUES('It''s a happy day!')
-**
-** This is correct. Had we used %s instead of %q, the generated SQL
-** would have looked like this:
-**
-** INSERT INTO table1 VALUES('It's a happy day!');
-**
-** This second example is an SQL syntax error. As a general rule you
-** should always use %q instead of %s when inserting text into a string
-** literal.
-*/
-char *sqlite3_mprintf(const char*,...);
-char *sqlite3_vmprintf(const char*, va_list);
-void sqlite3_free(char *z);
-char *sqlite3_snprintf(int,char*,const char*, ...);
-
-#ifndef SQLITE_OMIT_AUTHORIZATION
-/*
-** This routine registers a callback with the SQLite library. The
-** callback is invoked (at compile-time, not at run-time) for each
-** attempt to access a column of a table in the database. The callback
-** returns SQLITE_OK if access is allowed, SQLITE_DENY if the entire
-** SQL statement should be aborted with an error and SQLITE_IGNORE
-** if the column should be treated as a NULL value.
-*/
-int sqlite3_set_authorizer(
- sqlite3*,
- int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
- void *pUserData
-);
-#endif
-
-/*
-** The second parameter to the access authorization function above will
-** be one of the values below. These values signify what kind of operation
-** is to be authorized. The 3rd and 4th parameters to the authorization
-** function will be parameters or NULL depending on which of the following
-** codes is used as the second parameter. The 5th parameter is the name
-** of the database ("main", "temp", etc.) if applicable. The 6th parameter
-** is the name of the inner-most trigger or view that is responsible for
-** the access attempt or NULL if this access attempt is directly from
-** input SQL code.
-**
-** Arg-3 Arg-4
-*/
-#define SQLITE_COPY 0 /* Table Name File Name */
-#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */
-#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */
-#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */
-#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */
-#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */
-#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */
-#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */
-#define SQLITE_CREATE_VIEW 8 /* View Name NULL */
-#define SQLITE_DELETE 9 /* Table Name NULL */
-#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */
-#define SQLITE_DROP_TABLE 11 /* Table Name NULL */
-#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */
-#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */
-#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */
-#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */
-#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */
-#define SQLITE_DROP_VIEW 17 /* View Name NULL */
-#define SQLITE_INSERT 18 /* Table Name NULL */
-#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */
-#define SQLITE_READ 20 /* Table Name Column Name */
-#define SQLITE_SELECT 21 /* NULL NULL */
-#define SQLITE_TRANSACTION 22 /* NULL NULL */
-#define SQLITE_UPDATE 23 /* Table Name Column Name */
-#define SQLITE_ATTACH 24 /* Filename NULL */
-#define SQLITE_DETACH 25 /* Database Name NULL */
-
-
-/*
-** The return value of the authorization function should be one of the
-** following constants:
-*/
-/* #define SQLITE_OK 0 // Allow access (This is actually defined above) */
-#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
-#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
-
-/*
-** Register a function that is called at every invocation of sqlite3_exec()
-** or sqlite3_prepare(). This function can be used (for example) to generate
-** a log file of all SQL executed against a database.
-*/
-void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
-
-/*
-** This routine configures a callback function - the progress callback - that
-** is invoked periodically during long running calls to sqlite3_exec(),
-** sqlite3_step() and sqlite3_get_table(). An example use for this API is to keep
-** a GUI updated during a large query.
-**
-** The progress callback is invoked once for every N virtual machine opcodes,
-** where N is the second argument to this function. The progress callback
-** itself is identified by the third argument to this function. The fourth
-** argument to this function is a void pointer passed to the progress callback
-** function each time it is invoked.
-**
-** If a call to sqlite3_exec(), sqlite3_step() or sqlite3_get_table() results
-** in less than N opcodes being executed, then the progress callback is not
-** invoked.
-**
-** To remove the progress callback altogether, pass NULL as the third
-** argument to this function.
-**
-** If the progress callback returns a result other than 0, then the current
-** query is immediately terminated and any database changes rolled back. If the
-** query was part of a larger transaction, then the transaction is not rolled
-** back and remains active. The sqlite3_exec() call returns SQLITE_ABORT.
-**
-******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
-*/
-void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
-
-/*
-** Register a callback function to be invoked whenever a new transaction
-** is committed. The pArg argument is passed through to the callback.
-** callback. If the callback function returns non-zero, then the commit
-** is converted into a rollback.
-**
-** If another function was previously registered, its pArg value is returned.
-** Otherwise NULL is returned.
-**
-** Registering a NULL function disables the callback.
-**
-******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
-*/
-void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
-
-/*
-** Open the sqlite database file "filename". The "filename" is UTF-8
-** encoded for sqlite3_open() and UTF-16 encoded in the native byte order
-** for sqlite3_open16(). An sqlite3* handle is returned in *ppDb, even
-** if an error occurs. If the database is opened (or created) successfully,
-** then SQLITE_OK is returned. Otherwise an error code is returned. The
-** sqlite3_errmsg() or sqlite3_errmsg16() routines can be used to obtain
-** an English language description of the error.
-**
-** If the database file does not exist, then a new database is created.
-** The encoding for the database is UTF-8 if sqlite3_open() is called and
-** UTF-16 if sqlite3_open16 is used.
-**
-** Whether or not an error occurs when it is opened, resources associated
-** with the sqlite3* handle should be released by passing it to
-** sqlite3_close() when it is no longer required.
-*/
-int sqlite3_open(
- const char *filename, /* Database filename (UTF-8) */
- sqlite3 **ppDb /* OUT: SQLite db handle */
-);
-int sqlite3_open16(
- const void *filename, /* Database filename (UTF-16) */
- sqlite3 **ppDb /* OUT: SQLite db handle */
-);
-
-/*
-** Return the error code for the most recent sqlite3_* API call associated
-** with sqlite3 handle 'db'. SQLITE_OK is returned if the most recent
-** API call was successful.
-**
-** Calls to many sqlite3_* functions set the error code and string returned
-** by sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16()
-** (overwriting the previous values). Note that calls to sqlite3_errcode(),
-** sqlite3_errmsg() and sqlite3_errmsg16() themselves do not affect the
-** results of future invocations.
-**
-** Assuming no other intervening sqlite3_* API calls are made, the error
-** code returned by this function is associated with the same error as
-** the strings returned by sqlite3_errmsg() and sqlite3_errmsg16().
-*/
-int sqlite3_errcode(sqlite3 *db);
-
-/*
-** Return a pointer to a UTF-8 encoded string describing in english the
-** error condition for the most recent sqlite3_* API call. The returned
-** string is always terminated by an 0x00 byte.
-**
-** The string "not an error" is returned when the most recent API call was
-** successful.
-*/
-const char *sqlite3_errmsg(sqlite3*);
-
-/*
-** Return a pointer to a UTF-16 native byte order encoded string describing
-** in english the error condition for the most recent sqlite3_* API call.
-** The returned string is always terminated by a pair of 0x00 bytes.
-**
-** The string "not an error" is returned when the most recent API call was
-** successful.
-*/
-const void *sqlite3_errmsg16(sqlite3*);
-
-/*
-** An instance of the following opaque structure is used to represent
-** a compiled SQL statment.
-*/
-typedef struct sqlite3_stmt sqlite3_stmt;
-
-/*
-** To execute an SQL query, it must first be compiled into a byte-code
-** program using one of the following routines. The only difference between
-** them is that the second argument, specifying the SQL statement to
-** compile, is assumed to be encoded in UTF-8 for the sqlite3_prepare()
-** function and UTF-16 for sqlite3_prepare16().
-**
-** The first parameter "db" is an SQLite database handle. The second
-** parameter "zSql" is the statement to be compiled, encoded as either
-** UTF-8 or UTF-16 (see above). If the next parameter, "nBytes", is less
-** than zero, then zSql is read up to the first nul terminator. If
-** "nBytes" is not less than zero, then it is the length of the string zSql
-** in bytes (not characters).
-**
-** *pzTail is made to point to the first byte past the end of the first
-** SQL statement in zSql. This routine only compiles the first statement
-** in zSql, so *pzTail is left pointing to what remains uncompiled.
-**
-** *ppStmt is left pointing to a compiled SQL statement that can be
-** executed using sqlite3_step(). Or if there is an error, *ppStmt may be
-** set to NULL. If the input text contained no SQL (if the input is and
-** empty string or a comment) then *ppStmt is set to NULL.
-**
-** On success, SQLITE_OK is returned. Otherwise an error code is returned.
-*/
-int sqlite3_prepare(
- sqlite3 *db, /* Database handle */
- const char *zSql, /* SQL statement, UTF-8 encoded */
- int nBytes, /* Length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: Statement handle */
- const char **pzTail /* OUT: Pointer to unused portion of zSql */
-);
-int sqlite3_prepare16(
- sqlite3 *db, /* Database handle */
- const void *zSql, /* SQL statement, UTF-16 encoded */
- int nBytes, /* Length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: Statement handle */
- const void **pzTail /* OUT: Pointer to unused portion of zSql */
-);
-
-/*
-** Pointers to the following two opaque structures are used to communicate
-** with the implementations of user-defined functions.
-*/
-typedef struct sqlite3_context sqlite3_context;
-typedef struct Mem sqlite3_value;
-
-/*
-** In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
-** one or more literals can be replace by a wildcard "?" or ":N:" where
-** N is an integer. These value of these wildcard literals can be set
-** using the routines listed below.
-**
-** In every case, the first parameter is a pointer to the sqlite3_stmt
-** structure returned from sqlite3_prepare(). The second parameter is the
-** index of the wildcard. The first "?" has an index of 1. ":N:" wildcards
-** use the index N.
-**
-** The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
-** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
-** text after SQLite has finished with it. If the fifth argument is the
-** special value SQLITE_STATIC, then the library assumes that the information
-** is in static, unmanaged space and does not need to be freed. If the
-** fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
-** own private copy of the data.
-**
-** The sqlite3_bind_* routine must be called before sqlite3_step() after
-** an sqlite3_prepare() or sqlite3_reset(). Unbound wildcards are interpreted
-** as NULL.
-*/
-int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
-int sqlite3_bind_double(sqlite3_stmt*, int, double);
-int sqlite3_bind_int(sqlite3_stmt*, int, int);
-int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite_int64);
-int sqlite3_bind_null(sqlite3_stmt*, int);
-int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
-int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
-int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
-
-/*
-** Return the number of wildcards in a compiled SQL statement. This
-** routine was added to support DBD::SQLite.
-*/
-int sqlite3_bind_parameter_count(sqlite3_stmt*);
-
-/*
-** Return the name of the i-th parameter. Ordinary wildcards "?" are
-** nameless and a NULL is returned. For wildcards of the form :N or
-** $vvvv the complete text of the wildcard is returned.
-** NULL is returned if the index is out of range.
-*/
-const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
-
-/*
-** Return the index of a parameter with the given name. The name
-** must match exactly. If no parameter with the given name is found,
-** return 0.
-*/
-int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
-
-/*
-** Return the number of columns in the result set returned by the compiled
-** SQL statement. This routine returns 0 if pStmt is an SQL statement
-** that does not return data (for example an UPDATE).
-*/
-int sqlite3_column_count(sqlite3_stmt *pStmt);
-
-/*
-** The first parameter is a compiled SQL statement. This function returns
-** the column heading for the Nth column of that statement, where N is the
-** second function parameter. The string returned is UTF-8 for
-** sqlite3_column_name() and UTF-16 for sqlite3_column_name16().
-*/
-const char *sqlite3_column_name(sqlite3_stmt*,int);
-const void *sqlite3_column_name16(sqlite3_stmt*,int);
-
-/*
-** The first parameter is a compiled SQL statement. If this statement
-** is a SELECT statement, the Nth column of the returned result set
-** of the SELECT is a table column then the declared type of the table
-** column is returned. If the Nth column of the result set is not at table
-** column, then a NULL pointer is returned. The returned string is always
-** UTF-8 encoded. For example, in the database schema:
-**
-** CREATE TABLE t1(c1 VARIANT);
-**
-** And the following statement compiled:
-**
-** SELECT c1 + 1, 0 FROM t1;
-**
-** Then this routine would return the string "VARIANT" for the second
-** result column (i==1), and a NULL pointer for the first result column
-** (i==0).
-*/
-const char *sqlite3_column_decltype(sqlite3_stmt *, int i);
-
-/*
-** The first parameter is a compiled SQL statement. If this statement
-** is a SELECT statement, the Nth column of the returned result set
-** of the SELECT is a table column then the declared type of the table
-** column is returned. If the Nth column of the result set is not at table
-** column, then a NULL pointer is returned. The returned string is always
-** UTF-16 encoded. For example, in the database schema:
-**
-** CREATE TABLE t1(c1 INTEGER);
-**
-** And the following statement compiled:
-**
-** SELECT c1 + 1, 0 FROM t1;
-**
-** Then this routine would return the string "INTEGER" for the second
-** result column (i==1), and a NULL pointer for the first result column
-** (i==0).
-*/
-const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
-
-/*
-** After an SQL query has been compiled with a call to either
-** sqlite3_prepare() or sqlite3_prepare16(), then this function must be
-** called one or more times to execute the statement.
-**
-** The return value will be either SQLITE_BUSY, SQLITE_DONE,
-** SQLITE_ROW, SQLITE_ERROR, or SQLITE_MISUSE.
-**
-** SQLITE_BUSY means that the database engine attempted to open
-** a locked database and there is no busy callback registered.
-** Call sqlite3_step() again to retry the open.
-**
-** SQLITE_DONE means that the statement has finished executing
-** successfully. sqlite3_step() should not be called again on this virtual
-** machine.
-**
-** If the SQL statement being executed returns any data, then
-** SQLITE_ROW is returned each time a new row of data is ready
-** for processing by the caller. The values may be accessed using
-** the sqlite3_column_*() functions described below. sqlite3_step()
-** is called again to retrieve the next row of data.
-**
-** SQLITE_ERROR means that a run-time error (such as a constraint
-** violation) has occurred. sqlite3_step() should not be called again on
-** the VM. More information may be found by calling sqlite3_errmsg().
-**
-** SQLITE_MISUSE means that the this routine was called inappropriately.
-** Perhaps it was called on a virtual machine that had already been
-** finalized or on one that had previously returned SQLITE_ERROR or
-** SQLITE_DONE. Or it could be the case the the same database connection
-** is being used simulataneously by two or more threads.
-*/
-int sqlite3_step(sqlite3_stmt*);
-
-/*
-** Return the number of values in the current row of the result set.
-**
-** After a call to sqlite3_step() that returns SQLITE_ROW, this routine
-** will return the same value as the sqlite3_column_count() function.
-** After sqlite3_step() has returned an SQLITE_DONE, SQLITE_BUSY or
-** error code, or before sqlite3_step() has been called on a
-** compiled SQL statement, this routine returns zero.
-*/
-int sqlite3_data_count(sqlite3_stmt *pStmt);
-
-/*
-** Values are stored in the database in one of the following fundamental
-** types.
-*/
-#define SQLITE_INTEGER 1
-#define SQLITE_FLOAT 2
-/* #define SQLITE_TEXT 3 // See below */
-#define SQLITE_BLOB 4
-#define SQLITE_NULL 5
-
-/*
-** SQLite version 2 defines SQLITE_TEXT differently. To allow both
-** version 2 and version 3 to be included, undefine them both if a
-** conflict is seen. Define SQLITE3_TEXT to be the version 3 value.
-*/
-#ifdef SQLITE_TEXT
-# undef SQLITE_TEXT
-#else
-# define SQLITE_TEXT 3
-#endif
-#define SQLITE3_TEXT 3
-
-/*
-** The next group of routines returns information about the information
-** in a single column of the current result row of a query. In every
-** case the first parameter is a pointer to the SQL statement that is being
-** executed (the sqlite_stmt* that was returned from sqlite3_prepare()) and
-** the second argument is the index of the column for which information
-** should be returned. iCol is zero-indexed. The left-most column as an
-** index of 0.
-**
-** If the SQL statement is not currently point to a valid row, or if the
-** the colulmn index is out of range, the result is undefined.
-**
-** These routines attempt to convert the value where appropriate. For
-** example, if the internal representation is FLOAT and a text result
-** is requested, sprintf() is used internally to do the conversion
-** automatically. The following table details the conversions that
-** are applied:
-**
-** Internal Type Requested Type Conversion
-** ------------- -------------- --------------------------
-** NULL INTEGER Result is 0
-** NULL FLOAT Result is 0.0
-** NULL TEXT Result is an empty string
-** NULL BLOB Result is a zero-length BLOB
-** INTEGER FLOAT Convert from integer to float
-** INTEGER TEXT ASCII rendering of the integer
-** INTEGER BLOB Same as for INTEGER->TEXT
-** FLOAT INTEGER Convert from float to integer
-** FLOAT TEXT ASCII rendering of the float
-** FLOAT BLOB Same as FLOAT->TEXT
-** TEXT INTEGER Use atoi()
-** TEXT FLOAT Use atof()
-** TEXT BLOB No change
-** BLOB INTEGER Convert to TEXT then use atoi()
-** BLOB FLOAT Convert to TEXT then use atof()
-** BLOB TEXT Add a \000 terminator if needed
-**
-** The following access routines are provided:
-**
-** _type() Return the datatype of the result. This is one of
-** SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB,
-** or SQLITE_NULL.
-** _blob() Return the value of a BLOB.
-** _bytes() Return the number of bytes in a BLOB value or the number
-** of bytes in a TEXT value represented as UTF-8. The \000
-** terminator is included in the byte count for TEXT values.
-** _bytes16() Return the number of bytes in a BLOB value or the number
-** of bytes in a TEXT value represented as UTF-16. The \u0000
-** terminator is included in the byte count for TEXT values.
-** _double() Return a FLOAT value.
-** _int() Return an INTEGER value in the host computer's native
-** integer representation. This might be either a 32- or 64-bit
-** integer depending on the host.
-** _int64() Return an INTEGER value as a 64-bit signed integer.
-** _text() Return the value as UTF-8 text.
-** _text16() Return the value as UTF-16 text.
-*/
-const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
-int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
-double sqlite3_column_double(sqlite3_stmt*, int iCol);
-int sqlite3_column_int(sqlite3_stmt*, int iCol);
-sqlite_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
-const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
-const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
-int sqlite3_column_type(sqlite3_stmt*, int iCol);
-
-/*
-** The sqlite3_finalize() function is called to delete a compiled
-** SQL statement obtained by a previous call to sqlite3_prepare()
-** or sqlite3_prepare16(). If the statement was executed successfully, or
-** not executed at all, then SQLITE_OK is returned. If execution of the
-** statement failed then an error code is returned.
-**
-** This routine can be called at any point during the execution of the
-** virtual machine. If the virtual machine has not completed execution
-** when this routine is called, that is like encountering an error or
-** an interrupt. (See sqlite3_interrupt().) Incomplete updates may be
-** rolled back and transactions cancelled, depending on the circumstances,
-** and the result code returned will be SQLITE_ABORT.
-*/
-int sqlite3_finalize(sqlite3_stmt *pStmt);
-
-/*
-** The sqlite3_reset() function is called to reset a compiled SQL
-** statement obtained by a previous call to sqlite3_prepare() or
-** sqlite3_prepare16() back to it's initial state, ready to be re-executed.
-** Any SQL statement variables that had values bound to them using
-** the sqlite3_bind_*() API retain their values.
-*/
-int sqlite3_reset(sqlite3_stmt *pStmt);
-
-/*
-** The following two functions are used to add user functions or aggregates
-** implemented in C to the SQL langauge interpreted by SQLite. The
-** difference only between the two is that the second parameter, the
-** name of the (scalar) function or aggregate, is encoded in UTF-8 for
-** sqlite3_create_function() and UTF-16 for sqlite3_create_function16().
-**
-** The first argument is the database handle that the new function or
-** aggregate is to be added to. If a single program uses more than one
-** database handle internally, then user functions or aggregates must
-** be added individually to each database handle with which they will be
-** used.
-**
-** The third parameter is the number of arguments that the function or
-** aggregate takes. If this parameter is negative, then the function or
-** aggregate may take any number of arguments.
-**
-** The fourth parameter is one of SQLITE_UTF* values defined below,
-** indicating the encoding that the function is most likely to handle
-** values in. This does not change the behaviour of the programming
-** interface. However, if two versions of the same function are registered
-** with different encoding values, SQLite invokes the version likely to
-** minimize conversions between text encodings.
-**
-** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are
-** pointers to user implemented C functions that implement the user
-** function or aggregate. A scalar function requires an implementation of
-** the xFunc callback only, NULL pointers should be passed as the xStep
-** and xFinal parameters. An aggregate function requires an implementation
-** of xStep and xFinal, but NULL should be passed for xFunc. To delete an
-** existing user function or aggregate, pass NULL for all three function
-** callback. Specifying an inconstent set of callback values, such as an
-** xFunc and an xFinal, or an xStep but no xFinal, SQLITE_ERROR is
-** returned.
-*/
-int sqlite3_create_function(
- sqlite3 *,
- const char *zFunctionName,
- int nArg,
- int eTextRep,
- void*,
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
- void (*xStep)(sqlite3_context*,int,sqlite3_value**),
- void (*xFinal)(sqlite3_context*)
-);
-int sqlite3_create_function16(
- sqlite3*,
- const void *zFunctionName,
- int nArg,
- int eTextRep,
- void*,
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
- void (*xStep)(sqlite3_context*,int,sqlite3_value**),
- void (*xFinal)(sqlite3_context*)
-);
-
-/*
-** The next routine returns the number of calls to xStep for a particular
-** aggregate function instance. The current call to xStep counts so this
-** routine always returns at least 1.
-*/
-int sqlite3_aggregate_count(sqlite3_context*);
-
-/*
-** The next group of routines returns information about parameters to
-** a user-defined function. Function implementations use these routines
-** to access their parameters. These routines are the same as the
-** sqlite3_column_* routines except that these routines take a single
-** sqlite3_value* pointer instead of an sqlite3_stmt* and an integer
-** column number.
-*/
-const void *sqlite3_value_blob(sqlite3_value*);
-int sqlite3_value_bytes(sqlite3_value*);
-int sqlite3_value_bytes16(sqlite3_value*);
-double sqlite3_value_double(sqlite3_value*);
-int sqlite3_value_int(sqlite3_value*);
-sqlite_int64 sqlite3_value_int64(sqlite3_value*);
-const unsigned char *sqlite3_value_text(sqlite3_value*);
-const void *sqlite3_value_text16(sqlite3_value*);
-const void *sqlite3_value_text16le(sqlite3_value*);
-const void *sqlite3_value_text16be(sqlite3_value*);
-int sqlite3_value_type(sqlite3_value*);
-
-/*
-** Aggregate functions use the following routine to allocate
-** a structure for storing their state. The first time this routine
-** is called for a particular aggregate, a new structure of size nBytes
-** is allocated, zeroed, and returned. On subsequent calls (for the
-** same aggregate instance) the same buffer is returned. The implementation
-** of the aggregate can use the returned buffer to accumulate data.
-**
-** The buffer allocated is freed automatically by SQLite.
-*/
-void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
-
-/*
-** The pUserData parameter to the sqlite3_create_function() and
-** sqlite3_create_aggregate() routines used to register user functions
-** is available to the implementation of the function using this
-** call.
-*/
-void *sqlite3_user_data(sqlite3_context*);
-
-/*
-** The following two functions may be used by scalar user functions to
-** associate meta-data with argument values. If the same value is passed to
-** multiple invocations of the user-function during query execution, under
-** some circumstances the associated meta-data may be preserved. This may
-** be used, for example, to add a regular-expression matching scalar
-** function. The compiled version of the regular expression is stored as
-** meta-data associated with the SQL value passed as the regular expression
-** pattern.
-**
-** Calling sqlite3_get_auxdata() returns a pointer to the meta data
-** associated with the Nth argument value to the current user function
-** call, where N is the second parameter. If no meta-data has been set for
-** that value, then a NULL pointer is returned.
-**
-** The sqlite3_set_auxdata() is used to associate meta data with a user
-** function argument. The third parameter is a pointer to the meta data
-** to be associated with the Nth user function argument value. The fourth
-** parameter specifies a 'delete function' that will be called on the meta
-** data pointer to release it when it is no longer required. If the delete
-** function pointer is NULL, it is not invoked.
-**
-** In practice, meta-data is preserved between function calls for
-** expressions that are constant at compile time. This includes literal
-** values and SQL variables.
-*/
-void *sqlite3_get_auxdata(sqlite3_context*, int);
-void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
-
-
-/*
-** These are special value for the destructor that is passed in as the
-** final argument to routines like sqlite3_result_blob(). If the destructor
-** argument is SQLITE_STATIC, it means that the content pointer is constant
-** and will never change. It does not need to be destroyed. The
-** SQLITE_TRANSIENT value means that the content will likely change in
-** the near future and that SQLite should make its own private copy of
-** the content before returning.
-*/
-#define SQLITE_STATIC ((void(*)(void *))0)
-#define SQLITE_TRANSIENT ((void(*)(void *))-1)
-
-/*
-** User-defined functions invoke the following routines in order to
-** set their return value.
-*/
-void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
-void sqlite3_result_double(sqlite3_context*, double);
-void sqlite3_result_error(sqlite3_context*, const char*, int);
-void sqlite3_result_error16(sqlite3_context*, const void*, int);
-void sqlite3_result_int(sqlite3_context*, int);
-void sqlite3_result_int64(sqlite3_context*, sqlite_int64);
-void sqlite3_result_null(sqlite3_context*);
-void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
-void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
-void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
-void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
-void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
-
-/*
-** These are the allowed values for the eTextRep argument to
-** sqlite3_create_collation and sqlite3_create_function.
-*/
-#define SQLITE_UTF8 1
-#define SQLITE_UTF16LE 2
-#define SQLITE_UTF16BE 3
-#define SQLITE_UTF16 4 /* Use native byte order */
-#define SQLITE_ANY 5 /* sqlite3_create_function only */
-
-/*
-** These two functions are used to add new collation sequences to the
-** sqlite3 handle specified as the first argument.
-**
-** The name of the new collation sequence is specified as a UTF-8 string
-** for sqlite3_create_collation() and a UTF-16 string for
-** sqlite3_create_collation16(). In both cases the name is passed as the
-** second function argument.
-**
-** The third argument must be one of the constants SQLITE_UTF8,
-** SQLITE_UTF16LE or SQLITE_UTF16BE, indicating that the user-supplied
-** routine expects to be passed pointers to strings encoded using UTF-8,
-** UTF-16 little-endian or UTF-16 big-endian respectively.
-**
-** A pointer to the user supplied routine must be passed as the fifth
-** argument. If it is NULL, this is the same as deleting the collation
-** sequence (so that SQLite cannot call it anymore). Each time the user
-** supplied function is invoked, it is passed a copy of the void* passed as
-** the fourth argument to sqlite3_create_collation() or
-** sqlite3_create_collation16() as its first parameter.
-**
-** The remaining arguments to the user-supplied routine are two strings,
-** each represented by a [length, data] pair and encoded in the encoding
-** that was passed as the third argument when the collation sequence was
-** registered. The user routine should return negative, zero or positive if
-** the first string is less than, equal to, or greater than the second
-** string. i.e. (STRING1 - STRING2).
-*/
-int sqlite3_create_collation(
- sqlite3*,
- const char *zName,
- int eTextRep,
- void*,
- int(*xCompare)(void*,int,const void*,int,const void*)
-);
-int sqlite3_create_collation16(
- sqlite3*,
- const char *zName,
- int eTextRep,
- void*,
- int(*xCompare)(void*,int,const void*,int,const void*)
-);
-
-/*
-** To avoid having to register all collation sequences before a database
-** can be used, a single callback function may be registered with the
-** database handle to be called whenever an undefined collation sequence is
-** required.
-**
-** If the function is registered using the sqlite3_collation_needed() API,
-** then it is passed the names of undefined collation sequences as strings
-** encoded in UTF-8. If sqlite3_collation_needed16() is used, the names
-** are passed as UTF-16 in machine native byte order. A call to either
-** function replaces any existing callback.
-**
-** When the user-function is invoked, the first argument passed is a copy
-** of the second argument to sqlite3_collation_needed() or
-** sqlite3_collation_needed16(). The second argument is the database
-** handle. The third argument is one of SQLITE_UTF8, SQLITE_UTF16BE or
-** SQLITE_UTF16LE, indicating the most desirable form of the collation
-** sequence function required. The fourth parameter is the name of the
-** required collation sequence.
-**
-** The collation sequence is returned to SQLite by a collation-needed
-** callback using the sqlite3_create_collation() or
-** sqlite3_create_collation16() APIs, described above.
-*/
-int sqlite3_collation_needed(
- sqlite3*,
- void*,
- void(*)(void*,sqlite3*,int eTextRep,const char*)
-);
-int sqlite3_collation_needed16(
- sqlite3*,
- void*,
- void(*)(void*,sqlite3*,int eTextRep,const void*)
-);
-
-/*
-** Specify the key for an encrypted database. This routine should be
-** called right after sqlite3_open().
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-int sqlite3_key(
- sqlite3 *db, /* Database to be rekeyed */
- const void *pKey, int nKey /* The key */
-);
-
-/*
-** Change the key on an open database. If the current database is not
-** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
-** database is decrypted.
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-int sqlite3_rekey(
- sqlite3 *db, /* Database to be rekeyed */
- const void *pKey, int nKey /* The new key */
-);
-
-/*
-** If the following global variable is made to point to a constant
-** string which is the name of a directory, then all temporary files
-** created by SQLite will be placed in that directory. If this variable
-** is NULL pointer, then SQLite does a search for an appropriate temporary
-** file directory.
-**
-** This variable should only be changed when there are no open databases.
-** Once sqlite3_open() has been called, this variable should not be changed
-** until all database connections are closed.
-*/
-extern const char *sqlite3_temp_directory;
-
-#ifdef __cplusplus
-} /* End of the 'extern "C"' block */
-#endif
-#endif
diff --git a/kopete/plugins/statistics/sqlite/sqliteInt.h b/kopete/plugins/statistics/sqlite/sqliteInt.h
deleted file mode 100644
index b4fa474b..00000000
--- a/kopete/plugins/statistics/sqlite/sqliteInt.h
+++ /dev/null
@@ -1,1419 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** Internal interface definitions for SQLite.
-**
-** @(#) $Id$
-*/
-#ifndef _SQLITEINT_H_
-#define _SQLITEINT_H_
-
-/*
-** These #defines should enable >2GB file support on Posix if the
-** underlying operating system supports it. If the OS lacks
-** large file support, or if the OS is windows, these should be no-ops.
-**
-** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
-** on the compiler command line. This is necessary if you are compiling
-** on a recent machine (ex: RedHat 7.2) but you want your code to work
-** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2
-** without this option, LFS is enable. But LFS does not exist in the kernel
-** in RedHat 6.0, so the code won't work. Hence, for maximum binary
-** portability you should omit LFS.
-**
-** Similar is true for MacOS. LFS is only supported on MacOS 9 and later.
-*/
-#ifndef SQLITE_DISABLE_LFS
-# define _LARGE_FILE 1
-# ifndef _FILE_OFFSET_BITS
-# define _FILE_OFFSET_BITS 64
-# endif
-# define _LARGEFILE_SOURCE 1
-#endif
-
-#include "config.h"
-#include "sqlite3.h"
-#include "hash.h"
-#include "parse.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-/*
-** The maximum number of in-memory pages to use for the main database
-** table and for temporary tables.
-*/
-#define MAX_PAGES 2000
-#define TEMP_PAGES 500
-
-/*
-** If the following macro is set to 1, then NULL values are considered
-** distinct for the SELECT DISTINCT statement and for UNION or EXCEPT
-** compound queries. No other SQL database engine (among those tested)
-** works this way except for OCELOT. But the SQL92 spec implies that
-** this is how things should work.
-**
-** If the following macro is set to 0, then NULLs are indistinct for
-** SELECT DISTINCT and for UNION.
-*/
-#define NULL_ALWAYS_DISTINCT 0
-
-/*
-** If the following macro is set to 1, then NULL values are considered
-** distinct when determining whether or not two entries are the same
-** in a UNIQUE index. This is the way PostgreSQL, Oracle, DB2, MySQL,
-** OCELOT, and Firebird all work. The SQL92 spec explicitly says this
-** is the way things are suppose to work.
-**
-** If the following macro is set to 0, the NULLs are indistinct for
-** a UNIQUE index. In this mode, you can only have a single NULL entry
-** for a column declared UNIQUE. This is the way Informix and SQL Server
-** work.
-*/
-#define NULL_DISTINCT_FOR_UNIQUE 1
-
-/*
-** The maximum number of attached databases. This must be at least 2
-** in order to support the main database file (0) and the file used to
-** hold temporary tables (1). And it must be less than 32 because
-** we use a bitmask of databases with a u32 in places (for example
-** the Parse.cookieMask field).
-*/
-#define MAX_ATTACHED 10
-
-/*
-** The maximum value of a ?nnn wildcard that the parser will accept.
-*/
-#define SQLITE_MAX_VARIABLE_NUMBER 999
-
-/*
-** When building SQLite for embedded systems where memory is scarce,
-** you can define one or more of the following macros to omit extra
-** features of the library and thus keep the size of the library to
-** a minimum.
-*/
-/* #define SQLITE_OMIT_AUTHORIZATION 1 */
-/* #define SQLITE_OMIT_INMEMORYDB 1 */
-/* #define SQLITE_OMIT_VACUUM 1 */
-/* #define SQLITE_OMIT_DATETIME_FUNCS 1 */
-/* #define SQLITE_OMIT_PROGRESS_CALLBACK 1 */
-
-/*
-** Integers of known sizes. These typedefs might change for architectures
-** where the sizes very. Preprocessor macros are available so that the
-** types can be conveniently redefined at compile-type. Like this:
-**
-** cc '-DUINTPTR_TYPE=long long int' ...
-*/
-#ifndef UINT64_TYPE
-# if defined(_MSC_VER) || defined(__BORLANDC__)
-# define UINT64_TYPE unsigned __int64
-# else
-# define UINT64_TYPE unsigned long long int
-# endif
-#endif
-#ifndef UINT32_TYPE
-# define UINT32_TYPE unsigned int
-#endif
-#ifndef UINT16_TYPE
-# define UINT16_TYPE unsigned short int
-#endif
-#ifndef INT16_TYPE
-# define INT16_TYPE short int
-#endif
-#ifndef UINT8_TYPE
-# define UINT8_TYPE unsigned char
-#endif
-#ifndef INT8_TYPE
-# define INT8_TYPE signed char
-#endif
-#ifndef LONGDOUBLE_TYPE
-# define LONGDOUBLE_TYPE long double
-#endif
-#ifndef INTPTR_TYPE
-# if SQLITE_PTR_SZ==4
-# define INTPTR_TYPE int
-# else
-# define INTPTR_TYPE sqlite_int64
-# endif
-#endif
-#ifndef UINTPTR_TYPE
-# if SQLITE_PTR_SZ==4
-# define UINTPTR_TYPE unsigned int
-# else
-# define UINTPTR_TYPE sqlite_uint64
-# endif
-#endif
-typedef sqlite_int64 i64; /* 8-byte signed integer */
-typedef UINT64_TYPE u64; /* 8-byte unsigned integer */
-typedef UINT32_TYPE u32; /* 4-byte unsigned integer */
-typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
-typedef INT16_TYPE i16; /* 2-byte signed integer */
-typedef UINT8_TYPE u8; /* 1-byte unsigned integer */
-typedef UINT8_TYPE i8; /* 1-byte signed integer */
-typedef INTPTR_TYPE ptr; /* Big enough to hold a pointer */
-typedef UINTPTR_TYPE uptr; /* Big enough to hold a pointer */
-
-/*
-** Macros to determine whether the machine is big or little endian,
-** evaluated at runtime.
-*/
-extern const int sqlite3one;
-#define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
-#define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
-
-/*
-** An instance of the following structure is used to store the busy-handler
-** callback for a given sqlite handle.
-**
-** The sqlite.busyHandler member of the sqlite struct contains the busy
-** callback for the database handle. Each pager opened via the sqlite
-** handle is passed a pointer to sqlite.busyHandler. The busy-handler
-** callback is currently invoked only from within pager.c.
-*/
-typedef struct BusyHandler BusyHandler;
-struct BusyHandler {
- int (*xFunc)(void *,int); /* The busy callback */
- void *pArg; /* First arg to busy callback */
-};
-
-/*
-** Defer sourcing vdbe.h and btree.h until after the "u8" and
-** "BusyHandler typedefs.
-*/
-#include "vdbe.h"
-#include "btree.h"
-
-/*
-** This macro casts a pointer to an integer. Useful for doing
-** pointer arithmetic.
-*/
-#define Addr(X) ((uptr)X)
-
-/*
-** If memory allocation problems are found, recompile with
-**
-** -DSQLITE_DEBUG=1
-**
-** to enable some sanity checking on malloc() and free(). To
-** check for memory leaks, recompile with
-**
-** -DSQLITE_DEBUG=2
-**
-** and a line of text will be written to standard error for
-** each malloc() and free(). This output can be analyzed
-** by an AWK script to determine if there are any leaks.
-*/
-#ifdef SQLITE_DEBUG
-# define sqliteMalloc(X) sqlite3Malloc_(X,1,__FILE__,__LINE__)
-# define sqliteMallocRaw(X) sqlite3Malloc_(X,0,__FILE__,__LINE__)
-# define sqliteFree(X) sqlite3Free_(X,__FILE__,__LINE__)
-# define sqliteRealloc(X,Y) sqlite3Realloc_(X,Y,__FILE__,__LINE__)
-# define sqliteStrDup(X) sqlite3StrDup_(X,__FILE__,__LINE__)
-# define sqliteStrNDup(X,Y) sqlite3StrNDup_(X,Y,__FILE__,__LINE__)
-#else
-# define sqliteFree sqlite3FreeX
-# define sqliteMalloc sqlite3Malloc
-# define sqliteMallocRaw sqlite3MallocRaw
-# define sqliteRealloc sqlite3Realloc
-# define sqliteStrDup sqlite3StrDup
-# define sqliteStrNDup sqlite3StrNDup
-#endif
-
-/*
-** This variable gets set if malloc() ever fails. After it gets set,
-** the SQLite library shuts down permanently.
-*/
-extern int sqlite3_malloc_failed;
-
-/*
-** The following global variables are used for testing and debugging
-** only. They only work if SQLITE_DEBUG is defined.
-*/
-#ifdef SQLITE_DEBUG
-extern int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
-extern int sqlite3_nFree; /* Number of sqliteFree() calls */
-extern int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
-#endif
-
-/*
-** Name of the master database table. The master database table
-** is a special table that holds the names and attributes of all
-** user tables and indices.
-*/
-#define MASTER_NAME "sqlite_master"
-#define TEMP_MASTER_NAME "sqlite_temp_master"
-
-/*
-** The root-page of the master database table.
-*/
-#define MASTER_ROOT 1
-
-/*
-** The name of the schema table.
-*/
-#define SCHEMA_TABLE(x) (x==1?TEMP_MASTER_NAME:MASTER_NAME)
-
-/*
-** A convenience macro that returns the number of elements in
-** an array.
-*/
-#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
-
-/*
-** Forward references to structures
-*/
-typedef struct Column Column;
-typedef struct Table Table;
-typedef struct Index Index;
-typedef struct Instruction Instruction;
-typedef struct Expr Expr;
-typedef struct ExprList ExprList;
-typedef struct Parse Parse;
-typedef struct Token Token;
-typedef struct IdList IdList;
-typedef struct SrcList SrcList;
-typedef struct WhereInfo WhereInfo;
-typedef struct WhereLevel WhereLevel;
-typedef struct Select Select;
-typedef struct AggExpr AggExpr;
-typedef struct FuncDef FuncDef;
-typedef struct Trigger Trigger;
-typedef struct TriggerStep TriggerStep;
-typedef struct TriggerStack TriggerStack;
-typedef struct FKey FKey;
-typedef struct Db Db;
-typedef struct AuthContext AuthContext;
-typedef struct KeyClass KeyClass;
-typedef struct CollSeq CollSeq;
-typedef struct KeyInfo KeyInfo;
-
-/*
-** Each database file to be accessed by the system is an instance
-** of the following structure. There are normally two of these structures
-** in the sqlite.aDb[] array. aDb[0] is the main database file and
-** aDb[1] is the database file used to hold temporary tables. Additional
-** databases may be attached.
-*/
-struct Db {
- char *zName; /* Name of this database */
- Btree *pBt; /* The B*Tree structure for this database file */
- int schema_cookie; /* Database schema version number for this file */
- Hash tblHash; /* All tables indexed by name */
- Hash idxHash; /* All (named) indices indexed by name */
- Hash trigHash; /* All triggers indexed by name */
- Hash aFKey; /* Foreign keys indexed by to-table */
- u16 flags; /* Flags associated with this database */
- u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */
- u8 safety_level; /* How aggressive at synching data to disk */
- int cache_size; /* Number of pages to use in the cache */
- void *pAux; /* Auxiliary data. Usually NULL */
- void (*xFreeAux)(void*); /* Routine to free pAux */
-};
-
-/*
-** These macros can be used to test, set, or clear bits in the
-** Db.flags field.
-*/
-#define DbHasProperty(D,I,P) (((D)->aDb[I].flags&(P))==(P))
-#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].flags&(P))!=0)
-#define DbSetProperty(D,I,P) (D)->aDb[I].flags|=(P)
-#define DbClearProperty(D,I,P) (D)->aDb[I].flags&=~(P)
-
-/*
-** Allowed values for the DB.flags field.
-**
-** The DB_SchemaLoaded flag is set after the database schema has been
-** read into internal hash tables.
-**
-** DB_UnresetViews means that one or more views have column names that
-** have been filled out. If the schema changes, these column names might
-** changes and so the view will need to be reset.
-*/
-#define DB_SchemaLoaded 0x0001 /* The schema has been loaded */
-#define DB_UnresetViews 0x0002 /* Some views have defined column names */
-
-#define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
-
-/*
-** Each database is an instance of the following structure.
-**
-** The sqlite.lastRowid records the last insert rowid generated by an
-** insert statement. Inserts on views do not affect its value. Each
-** trigger has its own context, so that lastRowid can be updated inside
-** triggers as usual. The previous value will be restored once the trigger
-** exits. Upon entering a before or instead of trigger, lastRowid is no
-** longer (since after version 2.8.12) reset to -1.
-**
-** The sqlite.nChange does not count changes within triggers and keeps no
-** context. It is reset at start of sqlite3_exec.
-** The sqlite.lsChange represents the number of changes made by the last
-** insert, update, or delete statement. It remains constant throughout the
-** length of a statement and is then updated by OP_SetCounts. It keeps a
-** context stack just like lastRowid so that the count of changes
-** within a trigger is not seen outside the trigger. Changes to views do not
-** affect the value of lsChange.
-** The sqlite.csChange keeps track of the number of current changes (since
-** the last statement) and is used to update sqlite_lsChange.
-**
-** The member variables sqlite.errCode, sqlite.zErrMsg and sqlite.zErrMsg16
-** store the most recent error code and, if applicable, string. The
-** internal function sqlite3Error() is used to set these variables
-** consistently.
-*/
-struct sqlite3 {
- int nDb; /* Number of backends currently in use */
- Db *aDb; /* All backends */
- Db aDbStatic[2]; /* Static space for the 2 default backends */
- int flags; /* Miscellanous flags. See below */
- u8 file_format; /* What file format version is this database? */
- u8 temp_store; /* 1: file 2: memory 0: default */
- int nTable; /* Number of tables in the database */
- BusyHandler busyHandler; /* Busy callback */
- void *pCommitArg; /* Argument to xCommitCallback() */
- int (*xCommitCallback)(void*);/* Invoked at every commit. */
- Hash aFunc; /* All functions that can be in SQL exprs */
- Hash aCollSeq; /* All collating sequences */
- CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
- i64 lastRowid; /* ROWID of most recent insert (see above) */
- i64 priorNewRowid; /* Last randomly generated ROWID */
- int magic; /* Magic number for detect library misuse */
- int nChange; /* Value returned by sqlite3_changes() */
- int nTotalChange; /* Value returned by sqlite3_total_changes() */
- struct sqlite3InitInfo { /* Information used during initialization */
- int iDb; /* When back is being initialized */
- int newTnum; /* Rootpage of table being initialized */
- u8 busy; /* TRUE if currently initializing */
- } init;
- struct Vdbe *pVdbe; /* List of active virtual machines */
- int activeVdbeCnt; /* Number of vdbes currently executing */
- void (*xTrace)(void*,const char*); /* Trace function */
- void *pTraceArg; /* Argument to the trace function */
-#ifndef SQLITE_OMIT_AUTHORIZATION
- int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
- /* Access authorization function */
- void *pAuthArg; /* 1st argument to the access auth function */
-#endif
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- int (*xProgress)(void *); /* The progress callback */
- void *pProgressArg; /* Argument to the progress callback */
- int nProgressOps; /* Number of opcodes for progress callback */
-#endif
-
- int errCode; /* Most recent error code (SQLITE_*) */
- u8 enc; /* Text encoding for this database. */
- u8 autoCommit; /* The auto-commit flag. */
- void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
- void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
- void *pCollNeededArg;
- sqlite3_value *pValue; /* Value used for transient conversions */
- sqlite3_value *pErr; /* Most recent error message */
-
- char *zErrMsg; /* Most recent error message (UTF-8 encoded) */
- char *zErrMsg16; /* Most recent error message (UTF-8 encoded) */
-};
-
-/*
-** Possible values for the sqlite.flags and or Db.flags fields.
-**
-** On sqlite.flags, the SQLITE_InTrans value means that we have
-** executed a BEGIN. On Db.flags, SQLITE_InTrans means a statement
-** transaction is active on that particular database file.
-*/
-#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
-#define SQLITE_Initialized 0x00000002 /* True after initialization */
-#define SQLITE_Interrupt 0x00000004 /* Cancel current operation */
-#define SQLITE_InTrans 0x00000008 /* True if in a transaction */
-#define SQLITE_InternChanges 0x00000010 /* Uncommitted Hash table changes */
-#define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */
-#define SQLITE_ShortColNames 0x00000040 /* Show short columns names */
-#define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */
- /* DELETE, or UPDATE and return */
- /* the count using a callback. */
-#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
- /* result set is empty */
-#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */
-#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */
-
-/*
-** Possible values for the sqlite.magic field.
-** The numbers are obtained at random and have no special meaning, other
-** than being distinct from one another.
-*/
-#define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */
-#define SQLITE_MAGIC_CLOSED 0x9f3c2d33 /* Database is closed */
-#define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */
-#define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */
-
-/*
-** Each SQL function is defined by an instance of the following
-** structure. A pointer to this structure is stored in the sqlite.aFunc
-** hash table. When multiple functions have the same name, the hash table
-** points to a linked list of these structures.
-*/
-struct FuncDef {
- char *zName; /* SQL name of the function */
- int nArg; /* Number of arguments. -1 means unlimited */
- u8 iPrefEnc; /* Preferred text encoding (SQLITE_UTF8, 16LE, 16BE) */
- void *pUserData; /* User data parameter */
- FuncDef *pNext; /* Next function with same name */
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
- void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */
- void (*xFinalize)(sqlite3_context*); /* Aggregate finializer */
- u8 needCollSeq; /* True if sqlite3GetFuncCollSeq() might be called */
-};
-
-/*
-** information about each column of an SQL table is held in an instance
-** of this structure.
-*/
-struct Column {
- char *zName; /* Name of this column */
- char *zDflt; /* Default value of this column */
- char *zType; /* Data type for this column */
- CollSeq *pColl; /* Collating sequence. If NULL, use the default */
- u8 notNull; /* True if there is a NOT NULL constraint */
- u8 isPrimKey; /* True if this column is part of the PRIMARY KEY */
- char affinity; /* One of the SQLITE_AFF_... values */
-};
-
-/*
-** A "Collating Sequence" is defined by an instance of the following
-** structure. Conceptually, a collating sequence consists of a name and
-** a comparison routine that defines the order of that sequence.
-**
-** There may two seperate implementations of the collation function, one
-** that processes text in UTF-8 encoding (CollSeq.xCmp) and another that
-** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine
-** native byte order. When a collation sequence is invoked, SQLite selects
-** the version that will require the least expensive encoding
-** transalations, if any.
-**
-** The CollSeq.pUser member variable is an extra parameter that passed in
-** as the first argument to the UTF-8 comparison function, xCmp.
-** CollSeq.pUser16 is the equivalent for the UTF-16 comparison function,
-** xCmp16.
-**
-** If both CollSeq.xCmp and CollSeq.xCmp16 are NULL, it means that the
-** collating sequence is undefined. Indices built on an undefined
-** collating sequence may not be read or written.
-*/
-struct CollSeq {
- char *zName; /* Name of the collating sequence, UTF-8 encoded */
- u8 enc; /* Text encoding handled by xCmp() */
- void *pUser; /* First argument to xCmp() */
- int (*xCmp)(void*,int, const void*, int, const void*);
-};
-
-/*
-** A sort order can be either ASC or DESC.
-*/
-#define SQLITE_SO_ASC 0 /* Sort in ascending order */
-#define SQLITE_SO_DESC 1 /* Sort in ascending order */
-
-/*
-** Column affinity types.
-*/
-#define SQLITE_AFF_INTEGER 'i'
-#define SQLITE_AFF_NUMERIC 'n'
-#define SQLITE_AFF_TEXT 't'
-#define SQLITE_AFF_NONE 'o'
-
-
-/*
-** Each SQL table is represented in memory by an instance of the
-** following structure.
-**
-** Table.zName is the name of the table. The case of the original
-** CREATE TABLE statement is stored, but case is not significant for
-** comparisons.
-**
-** Table.nCol is the number of columns in this table. Table.aCol is a
-** pointer to an array of Column structures, one for each column.
-**
-** If the table has an INTEGER PRIMARY KEY, then Table.iPKey is the index of
-** the column that is that key. Otherwise Table.iPKey is negative. Note
-** that the datatype of the PRIMARY KEY must be INTEGER for this field to
-** be set. An INTEGER PRIMARY KEY is used as the rowid for each row of
-** the table. If a table has no INTEGER PRIMARY KEY, then a random rowid
-** is generated for each row of the table. Table.hasPrimKey is true if
-** the table has any PRIMARY KEY, INTEGER or otherwise.
-**
-** Table.tnum is the page number for the root BTree page of the table in the
-** database file. If Table.iDb is the index of the database table backend
-** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that
-** holds temporary tables and indices. If Table.isTransient
-** is true, then the table is stored in a file that is automatically deleted
-** when the VDBE cursor to the table is closed. In this case Table.tnum
-** refers VDBE cursor number that holds the table open, not to the root
-** page number. Transient tables are used to hold the results of a
-** sub-query that appears instead of a real table name in the FROM clause
-** of a SELECT statement.
-*/
-struct Table {
- char *zName; /* Name of the table */
- int nCol; /* Number of columns in this table */
- Column *aCol; /* Information about each column */
- int iPKey; /* If not less then 0, use aCol[iPKey] as the primary key */
- Index *pIndex; /* List of SQL indexes on this table. */
- int tnum; /* Root BTree node for this table (see note above) */
- Select *pSelect; /* NULL for tables. Points to definition if a view. */
- u8 readOnly; /* True if this table should not be written by the user */
- u8 iDb; /* Index into sqlite.aDb[] of the backend for this table */
- u8 isTransient; /* True if automatically deleted when VDBE finishes */
- u8 hasPrimKey; /* True if there exists a primary key */
- u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
- Trigger *pTrigger; /* List of SQL triggers on this table */
- FKey *pFKey; /* Linked list of all foreign keys in this table */
- char *zColAff; /* String defining the affinity of each column */
-};
-
-/*
-** Each foreign key constraint is an instance of the following structure.
-**
-** A foreign key is associated with two tables. The "from" table is
-** the table that contains the REFERENCES clause that creates the foreign
-** key. The "to" table is the table that is named in the REFERENCES clause.
-** Consider this example:
-**
-** CREATE TABLE ex1(
-** a INTEGER PRIMARY KEY,
-** b INTEGER CONSTRAINT fk1 REFERENCES ex2(x)
-** );
-**
-** For foreign key "fk1", the from-table is "ex1" and the to-table is "ex2".
-**
-** Each REFERENCES clause generates an instance of the following structure
-** which is attached to the from-table. The to-table need not exist when
-** the from-table is created. The existance of the to-table is not checked
-** until an attempt is made to insert data into the from-table.
-**
-** The sqlite.aFKey hash table stores pointers to this structure
-** given the name of a to-table. For each to-table, all foreign keys
-** associated with that table are on a linked list using the FKey.pNextTo
-** field.
-*/
-struct FKey {
- Table *pFrom; /* The table that constains the REFERENCES clause */
- FKey *pNextFrom; /* Next foreign key in pFrom */
- char *zTo; /* Name of table that the key points to */
- FKey *pNextTo; /* Next foreign key that points to zTo */
- int nCol; /* Number of columns in this key */
- struct sColMap { /* Mapping of columns in pFrom to columns in zTo */
- int iFrom; /* Index of column in pFrom */
- char *zCol; /* Name of column in zTo. If 0 use PRIMARY KEY */
- } *aCol; /* One entry for each of nCol column s */
- u8 isDeferred; /* True if constraint checking is deferred till COMMIT */
- u8 updateConf; /* How to resolve conflicts that occur on UPDATE */
- u8 deleteConf; /* How to resolve conflicts that occur on DELETE */
- u8 insertConf; /* How to resolve conflicts that occur on INSERT */
-};
-
-/*
-** SQLite supports many different ways to resolve a contraint
-** error. ROLLBACK processing means that a constraint violation
-** causes the operation in process to fail and for the current transaction
-** to be rolled back. ABORT processing means the operation in process
-** fails and any prior changes from that one operation are backed out,
-** but the transaction is not rolled back. FAIL processing means that
-** the operation in progress stops and returns an error code. But prior
-** changes due to the same operation are not backed out and no rollback
-** occurs. IGNORE means that the particular row that caused the constraint
-** error is not inserted or updated. Processing continues and no error
-** is returned. REPLACE means that preexisting database rows that caused
-** a UNIQUE constraint violation are removed so that the new insert or
-** update can proceed. Processing continues and no error is reported.
-**
-** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys.
-** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the
-** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign
-** key is set to NULL. CASCADE means that a DELETE or UPDATE of the
-** referenced table row is propagated into the row that holds the
-** foreign key.
-**
-** The following symbolic values are used to record which type
-** of action to take.
-*/
-#define OE_None 0 /* There is no constraint to check */
-#define OE_Rollback 1 /* Fail the operation and rollback the transaction */
-#define OE_Abort 2 /* Back out changes but do no rollback transaction */
-#define OE_Fail 3 /* Stop the operation but leave all prior changes */
-#define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */
-#define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */
-
-#define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */
-#define OE_SetNull 7 /* Set the foreign key value to NULL */
-#define OE_SetDflt 8 /* Set the foreign key value to its default */
-#define OE_Cascade 9 /* Cascade the changes */
-
-#define OE_Default 99 /* Do whatever the default action is */
-
-
-/*
-** An instance of the following structure is passed as the first
-** argument to sqlite3VdbeKeyCompare and is used to control the
-** comparison of the two index keys.
-**
-** If the KeyInfo.incrKey value is true and the comparison would
-** otherwise be equal, then return a result as if the second key larger.
-*/
-struct KeyInfo {
- u8 enc; /* Text encoding - one of the TEXT_Utf* values */
- u8 incrKey; /* Increase 2nd key by epsilon before comparison */
- int nField; /* Number of entries in aColl[] */
- u8 *aSortOrder; /* If defined an aSortOrder[i] is true, sort DESC */
- CollSeq *aColl[1]; /* Collating sequence for each term of the key */
-};
-
-/*
-** Each SQL index is represented in memory by an
-** instance of the following structure.
-**
-** The columns of the table that are to be indexed are described
-** by the aiColumn[] field of this structure. For example, suppose
-** we have the following table and index:
-**
-** CREATE TABLE Ex1(c1 int, c2 int, c3 text);
-** CREATE INDEX Ex2 ON Ex1(c3,c1);
-**
-** In the Table structure describing Ex1, nCol==3 because there are
-** three columns in the table. In the Index structure describing
-** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed.
-** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the
-** first column to be indexed (c3) has an index of 2 in Ex1.aCol[].
-** The second column to be indexed (c1) has an index of 0 in
-** Ex1.aCol[], hence Ex2.aiColumn[1]==0.
-**
-** The Index.onError field determines whether or not the indexed columns
-** must be unique and what to do if they are not. When Index.onError=OE_None,
-** it means this is not a unique index. Otherwise it is a unique index
-** and the value of Index.onError indicate the which conflict resolution
-** algorithm to employ whenever an attempt is made to insert a non-unique
-** element.
-*/
-struct Index {
- char *zName; /* Name of this index */
- int nColumn; /* Number of columns in the table used by this index */
- int *aiColumn; /* Which columns are used by this index. 1st is 0 */
- Table *pTable; /* The SQL table being indexed */
- int tnum; /* Page containing root of this index in database file */
- u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
- u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
- u8 iDb; /* Index in sqlite.aDb[] of where this index is stored */
- char *zColAff; /* String defining the affinity of each column */
- Index *pNext; /* The next index associated with the same table */
- KeyInfo keyInfo; /* Info on how to order keys. MUST BE LAST */
-};
-
-/*
-** Each token coming out of the lexer is an instance of
-** this structure. Tokens are also used as part of an expression.
-**
-** Note if Token.z==0 then Token.dyn and Token.n are undefined and
-** may contain random values. Do not make any assuptions about Token.dyn
-** and Token.n when Token.z==0.
-*/
-struct Token {
- const unsigned char *z; /* Text of the token. Not NULL-terminated! */
- unsigned dyn : 1; /* True for malloced memory, false for static */
- unsigned n : 31; /* Number of characters in this token */
-};
-
-/*
-** Each node of an expression in the parse tree is an instance
-** of this structure.
-**
-** Expr.op is the opcode. The integer parser token codes are reused
-** as opcodes here. For example, the parser defines TK_GE to be an integer
-** code representing the ">=" operator. This same integer code is reused
-** to represent the greater-than-or-equal-to operator in the expression
-** tree.
-**
-** Expr.pRight and Expr.pLeft are subexpressions. Expr.pList is a list
-** of argument if the expression is a function.
-**
-** Expr.token is the operator token for this node. For some expressions
-** that have subexpressions, Expr.token can be the complete text that gave
-** rise to the Expr. In the latter case, the token is marked as being
-** a compound token.
-**
-** An expression of the form ID or ID.ID refers to a column in a table.
-** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is
-** the integer cursor number of a VDBE cursor pointing to that table and
-** Expr.iColumn is the column number for the specific column. If the
-** expression is used as a result in an aggregate SELECT, then the
-** value is also stored in the Expr.iAgg column in the aggregate so that
-** it can be accessed after all aggregates are computed.
-**
-** If the expression is a function, the Expr.iTable is an integer code
-** representing which function. If the expression is an unbound variable
-** marker (a question mark character '?' in the original SQL) then the
-** Expr.iTable holds the index number for that variable.
-**
-** The Expr.pSelect field points to a SELECT statement. The SELECT might
-** be the right operand of an IN operator. Or, if a scalar SELECT appears
-** in an expression the opcode is TK_SELECT and Expr.pSelect is the only
-** operand.
-*/
-struct Expr {
- u8 op; /* Operation performed by this node */
- char affinity; /* The affinity of the column or 0 if not a column */
- u8 iDb; /* Database referenced by this expression */
- u8 flags; /* Various flags. See below */
- CollSeq *pColl; /* The collation type of the column or 0 */
- Expr *pLeft, *pRight; /* Left and right subnodes */
- ExprList *pList; /* A list of expressions used as function arguments
- ** or in "<expr> IN (<expr-list)" */
- Token token; /* An operand token */
- Token span; /* Complete text of the expression */
- int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
- ** iColumn-th field of the iTable-th table. */
- int iAgg; /* When op==TK_COLUMN and pParse->useAgg==TRUE, pull
- ** result from the iAgg-th element of the aggregator */
- Select *pSelect; /* When the expression is a sub-select. Also the
- ** right side of "<expr> IN (<select>)" */
-};
-
-/*
-** The following are the meanings of bits in the Expr.flags field.
-*/
-#define EP_FromJoin 0x0001 /* Originated in ON or USING clause of a join */
-
-/*
-** These macros can be used to test, set, or clear bits in the
-** Expr.flags field.
-*/
-#define ExprHasProperty(E,P) (((E)->flags&(P))==(P))
-#define ExprHasAnyProperty(E,P) (((E)->flags&(P))!=0)
-#define ExprSetProperty(E,P) (E)->flags|=(P)
-#define ExprClearProperty(E,P) (E)->flags&=~(P)
-
-/*
-** A list of expressions. Each expression may optionally have a
-** name. An expr/name combination can be used in several ways, such
-** as the list of "expr AS ID" fields following a "SELECT" or in the
-** list of "ID = expr" items in an UPDATE. A list of expressions can
-** also be used as the argument to a function, in which case the a.zName
-** field is not used.
-*/
-struct ExprList {
- int nExpr; /* Number of expressions on the list */
- int nAlloc; /* Number of entries allocated below */
- struct ExprList_item {
- Expr *pExpr; /* The list of expressions */
- char *zName; /* Token associated with this expression */
- u8 sortOrder; /* 1 for DESC or 0 for ASC */
- u8 isAgg; /* True if this is an aggregate like count(*) */
- u8 done; /* A flag to indicate when processing is finished */
- } *a; /* One entry for each expression */
-};
-
-/*
-** An instance of this structure can hold a simple list of identifiers,
-** such as the list "a,b,c" in the following statements:
-**
-** INSERT INTO t(a,b,c) VALUES ...;
-** CREATE INDEX idx ON t(a,b,c);
-** CREATE TRIGGER trig BEFORE UPDATE ON t(a,b,c) ...;
-**
-** The IdList.a.idx field is used when the IdList represents the list of
-** column names after a table name in an INSERT statement. In the statement
-**
-** INSERT INTO t(a,b,c) ...
-**
-** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
-*/
-struct IdList {
- int nId; /* Number of identifiers on the list */
- int nAlloc; /* Number of entries allocated for a[] below */
- struct IdList_item {
- char *zName; /* Name of the identifier */
- int idx; /* Index in some Table.aCol[] of a column named zName */
- } *a;
-};
-
-/*
-** The following structure describes the FROM clause of a SELECT statement.
-** Each table or subquery in the FROM clause is a separate element of
-** the SrcList.a[] array.
-**
-** With the addition of multiple database support, the following structure
-** can also be used to describe a particular table such as the table that
-** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL,
-** such a table must be a simple name: ID. But in SQLite, the table can
-** now be identified by a database name, a dot, then the table name: ID.ID.
-*/
-struct SrcList {
- i16 nSrc; /* Number of tables or subqueries in the FROM clause */
- i16 nAlloc; /* Number of entries allocated in a[] below */
- struct SrcList_item {
- char *zDatabase; /* Name of database holding this table */
- char *zName; /* Name of the table */
- char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
- Table *pTab; /* An SQL table corresponding to zName */
- Select *pSelect; /* A SELECT statement used in place of a table name */
- int jointype; /* Type of join between this table and the next */
- int iCursor; /* The VDBE cursor number used to access this table */
- Expr *pOn; /* The ON clause of a join */
- IdList *pUsing; /* The USING clause of a join */
- } a[1]; /* One entry for each identifier on the list */
-};
-
-/*
-** Permitted values of the SrcList.a.jointype field
-*/
-#define JT_INNER 0x0001 /* Any kind of inner or cross join */
-#define JT_NATURAL 0x0002 /* True for a "natural" join */
-#define JT_LEFT 0x0004 /* Left outer join */
-#define JT_RIGHT 0x0008 /* Right outer join */
-#define JT_OUTER 0x0010 /* The "OUTER" keyword is present */
-#define JT_ERROR 0x0020 /* unknown or unsupported join type */
-
-/*
-** For each nested loop in a WHERE clause implementation, the WhereInfo
-** structure contains a single instance of this structure. This structure
-** is intended to be private the the where.c module and should not be
-** access or modified by other modules.
-*/
-struct WhereLevel {
- int iMem; /* Memory cell used by this level */
- Index *pIdx; /* Index used */
- int iCur; /* Cursor number used for this index */
- int score; /* How well this indexed scored */
- int brk; /* Jump here to break out of the loop */
- int cont; /* Jump here to continue with the next loop cycle */
- int op, p1, p2; /* Opcode used to terminate the loop */
- int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */
- int top; /* First instruction of interior of the loop */
- int inOp, inP1, inP2;/* Opcode used to implement an IN operator */
- int bRev; /* Do the scan in the reverse direction */
-};
-
-/*
-** The WHERE clause processing routine has two halves. The
-** first part does the start of the WHERE loop and the second
-** half does the tail of the WHERE loop. An instance of
-** this structure is returned by the first half and passed
-** into the second half to give some continuity.
-*/
-struct WhereInfo {
- Parse *pParse;
- SrcList *pTabList; /* List of tables in the join */
- int iContinue; /* Jump here to continue with next record */
- int iBreak; /* Jump here to break out of the loop */
- int nLevel; /* Number of nested loop */
- WhereLevel a[1]; /* Information about each nest loop in the WHERE */
-};
-
-/*
-** An instance of the following structure contains all information
-** needed to generate code for a single SELECT statement.
-**
-** The zSelect field is used when the Select structure must be persistent.
-** Normally, the expression tree points to tokens in the original input
-** string that encodes the select. But if the Select structure must live
-** longer than its input string (for example when it is used to describe
-** a VIEW) we have to make a copy of the input string so that the nodes
-** of the expression tree will have something to point to. zSelect is used
-** to hold that copy.
-**
-** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0.
-** If there is a LIMIT clause, the parser sets nLimit to the value of the
-** limit and nOffset to the value of the offset (or 0 if there is not
-** offset). But later on, nLimit and nOffset become the memory locations
-** in the VDBE that record the limit and offset counters.
-*/
-struct Select {
- ExprList *pEList; /* The fields of the result */
- u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
- u8 isDistinct; /* True if the DISTINCT keyword is present */
- SrcList *pSrc; /* The FROM clause */
- Expr *pWhere; /* The WHERE clause */
- ExprList *pGroupBy; /* The GROUP BY clause */
- Expr *pHaving; /* The HAVING clause */
- ExprList *pOrderBy; /* The ORDER BY clause */
- Select *pPrior; /* Prior select in a compound select statement */
- int nLimit, nOffset; /* LIMIT and OFFSET values. -1 means not used */
- int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
- char *zSelect; /* Complete text of the SELECT command */
- IdList **ppOpenTemp; /* OP_OpenTemp addresses used by multi-selects */
-};
-
-/*
-** The results of a select can be distributed in several ways.
-*/
-#define SRT_Callback 1 /* Invoke a callback with each row of result */
-#define SRT_Mem 2 /* Store result in a memory cell */
-#define SRT_Set 3 /* Store result as unique keys in a table */
-#define SRT_Union 5 /* Store result as keys in a table */
-#define SRT_Except 6 /* Remove result from a UNION table */
-#define SRT_Table 7 /* Store result as data with a unique key */
-#define SRT_TempTable 8 /* Store result in a trasient table */
-#define SRT_Discard 9 /* Do not save the results anywhere */
-#define SRT_Sorter 10 /* Store results in the sorter */
-#define SRT_Subroutine 11 /* Call a subroutine to handle results */
-
-/*
-** When a SELECT uses aggregate functions (like "count(*)" or "avg(f1)")
-** we have to do some additional analysis of expressions. An instance
-** of the following structure holds information about a single subexpression
-** somewhere in the SELECT statement. An array of these structures holds
-** all the information we need to generate code for aggregate
-** expressions.
-**
-** Note that when analyzing a SELECT containing aggregates, both
-** non-aggregate field variables and aggregate functions are stored
-** in the AggExpr array of the Parser structure.
-**
-** The pExpr field points to an expression that is part of either the
-** field list, the GROUP BY clause, the HAVING clause or the ORDER BY
-** clause. The expression will be freed when those clauses are cleaned
-** up. Do not try to delete the expression attached to AggExpr.pExpr.
-**
-** If AggExpr.pExpr==0, that means the expression is "count(*)".
-*/
-struct AggExpr {
- int isAgg; /* if TRUE contains an aggregate function */
- Expr *pExpr; /* The expression */
- FuncDef *pFunc; /* Information about the aggregate function */
-};
-
-/*
-** An SQL parser context. A copy of this structure is passed through
-** the parser and down into all the parser action routine in order to
-** carry around information that is global to the entire parse.
-*/
-struct Parse {
- sqlite3 *db; /* The main database structure */
- int rc; /* Return code from execution */
- char *zErrMsg; /* An error message */
- Token sErrToken; /* The token at which the error occurred */
- Token sNameToken; /* Token with unqualified schema object name */
- Token sLastToken; /* The last token parsed */
- const char *zSql; /* All SQL text */
- const char *zTail; /* All SQL text past the last semicolon parsed */
- Table *pNewTable; /* A table being constructed by CREATE TABLE */
- Vdbe *pVdbe; /* An engine for executing database bytecode */
- u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
- u8 explain; /* True if the EXPLAIN flag is found on the query */
- u8 nameClash; /* A permanent table name clashes with temp table name */
- u8 useAgg; /* If true, extract field values from the aggregator
- ** while generating expressions. Normally false */
- u8 checkSchema; /* Causes schema cookie check after an error */
- int nErr; /* Number of errors seen */
- int nTab; /* Number of previously allocated VDBE cursors */
- int nMem; /* Number of memory cells used so far */
- int nSet; /* Number of sets used so far */
- int nAgg; /* Number of aggregate expressions */
- int nVar; /* Number of '?' variables seen in the SQL so far */
- int nVarExpr; /* Number of used slots in apVarExpr[] */
- int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
- Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
- AggExpr *aAgg; /* An array of aggregate expressions */
- const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
- Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
- TriggerStack *trigStack; /* Trigger actions being coded */
- u32 cookieMask; /* Bitmask of schema verified databases */
- int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */
- int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
- u32 writeMask; /* Start a write transaction on these databases */
-};
-
-/*
-** An instance of the following structure can be declared on a stack and used
-** to save the Parse.zAuthContext value so that it can be restored later.
-*/
-struct AuthContext {
- const char *zAuthContext; /* Put saved Parse.zAuthContext here */
- Parse *pParse; /* The Parse structure */
-};
-
-/*
-** Bitfield flags for P2 value in OP_PutIntKey and OP_Delete
-*/
-#define OPFLAG_NCHANGE 1 /* Set to update db->nChange */
-#define OPFLAG_LASTROWID 2 /* Set to update db->lastRowid */
-
-/*
- * Each trigger present in the database schema is stored as an instance of
- * struct Trigger.
- *
- * Pointers to instances of struct Trigger are stored in two ways.
- * 1. In the "trigHash" hash table (part of the sqlite3* that represents the
- * database). This allows Trigger structures to be retrieved by name.
- * 2. All triggers associated with a single table form a linked list, using the
- * pNext member of struct Trigger. A pointer to the first element of the
- * linked list is stored as the "pTrigger" member of the associated
- * struct Table.
- *
- * The "step_list" member points to the first element of a linked list
- * containing the SQL statements specified as the trigger program.
- */
-struct Trigger {
- char *name; /* The name of the trigger */
- char *table; /* The table or view to which the trigger applies */
- u8 iDb; /* Database containing this trigger */
- u8 iTabDb; /* Database containing Trigger.table */
- u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */
- u8 tr_tm; /* One of TK_BEFORE, TK_AFTER */
- Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */
- IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger,
- the <column-list> is stored here */
- int foreach; /* One of TK_ROW or TK_STATEMENT */
- Token nameToken; /* Token containing zName. Use during parsing only */
-
- TriggerStep *step_list; /* Link list of trigger program steps */
- Trigger *pNext; /* Next trigger associated with the table */
-};
-
-/*
- * An instance of struct TriggerStep is used to store a single SQL statement
- * that is a part of a trigger-program.
- *
- * Instances of struct TriggerStep are stored in a singly linked list (linked
- * using the "pNext" member) referenced by the "step_list" member of the
- * associated struct Trigger instance. The first element of the linked list is
- * the first step of the trigger-program.
- *
- * The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
- * "SELECT" statement. The meanings of the other members is determined by the
- * value of "op" as follows:
- *
- * (op == TK_INSERT)
- * orconf -> stores the ON CONFLICT algorithm
- * pSelect -> If this is an INSERT INTO ... SELECT ... statement, then
- * this stores a pointer to the SELECT statement. Otherwise NULL.
- * target -> A token holding the name of the table to insert into.
- * pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
- * this stores values to be inserted. Otherwise NULL.
- * pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
- * statement, then this stores the column-names to be
- * inserted into.
- *
- * (op == TK_DELETE)
- * target -> A token holding the name of the table to delete from.
- * pWhere -> The WHERE clause of the DELETE statement if one is specified.
- * Otherwise NULL.
- *
- * (op == TK_UPDATE)
- * target -> A token holding the name of the table to update rows of.
- * pWhere -> The WHERE clause of the UPDATE statement if one is specified.
- * Otherwise NULL.
- * pExprList -> A list of the columns to update and the expressions to update
- * them to. See sqlite3Update() documentation of "pChanges"
- * argument.
- *
- */
-struct TriggerStep {
- int op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
- int orconf; /* OE_Rollback etc. */
- Trigger *pTrig; /* The trigger that this step is a part of */
-
- Select *pSelect; /* Valid for SELECT and sometimes
- INSERT steps (when pExprList == 0) */
- Token target; /* Valid for DELETE, UPDATE, INSERT steps */
- Expr *pWhere; /* Valid for DELETE, UPDATE steps */
- ExprList *pExprList; /* Valid for UPDATE statements and sometimes
- INSERT steps (when pSelect == 0) */
- IdList *pIdList; /* Valid for INSERT statements only */
-
- TriggerStep * pNext; /* Next in the link-list */
-};
-
-/*
- * An instance of struct TriggerStack stores information required during code
- * generation of a single trigger program. While the trigger program is being
- * coded, its associated TriggerStack instance is pointed to by the
- * "pTriggerStack" member of the Parse structure.
- *
- * The pTab member points to the table that triggers are being coded on. The
- * newIdx member contains the index of the vdbe cursor that points at the temp
- * table that stores the new.* references. If new.* references are not valid
- * for the trigger being coded (for example an ON DELETE trigger), then newIdx
- * is set to -1. The oldIdx member is analogous to newIdx, for old.* references.
- *
- * The ON CONFLICT policy to be used for the trigger program steps is stored
- * as the orconf member. If this is OE_Default, then the ON CONFLICT clause
- * specified for individual triggers steps is used.
- *
- * struct TriggerStack has a "pNext" member, to allow linked lists to be
- * constructed. When coding nested triggers (triggers fired by other triggers)
- * each nested trigger stores its parent trigger's TriggerStack as the "pNext"
- * pointer. Once the nested trigger has been coded, the pNext value is restored
- * to the pTriggerStack member of the Parse stucture and coding of the parent
- * trigger continues.
- *
- * Before a nested trigger is coded, the linked list pointed to by the
- * pTriggerStack is scanned to ensure that the trigger is not about to be coded
- * recursively. If this condition is detected, the nested trigger is not coded.
- */
-struct TriggerStack {
- Table *pTab; /* Table that triggers are currently being coded on */
- int newIdx; /* Index of vdbe cursor to "new" temp table */
- int oldIdx; /* Index of vdbe cursor to "old" temp table */
- int orconf; /* Current orconf policy */
- int ignoreJump; /* where to jump to for a RAISE(IGNORE) */
- Trigger *pTrigger; /* The trigger currently being coded */
- TriggerStack *pNext; /* Next trigger down on the trigger stack */
-};
-
-/*
-** The following structure contains information used by the sqliteFix...
-** routines as they walk the parse tree to make database references
-** explicit.
-*/
-typedef struct DbFixer DbFixer;
-struct DbFixer {
- Parse *pParse; /* The parsing context. Error messages written here */
- const char *zDb; /* Make sure all objects are contained in this database */
- const char *zType; /* Type of the container - used for error messages */
- const Token *pName; /* Name of the container - used for error messages */
-};
-
-/*
-** A pointer to this structure is used to communicate information
-** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback.
-*/
-typedef struct {
- sqlite3 *db; /* The database being initialized */
- char **pzErrMsg; /* Error message stored here */
-} InitData;
-
-
-/*
- * This global flag is set for performance testing of triggers. When it is set
- * SQLite will perform the overhead of building new and old trigger references
- * even when no triggers exist
- */
-extern int sqlite3_always_code_trigger_setup;
-
-/*
-** Internal function prototypes
-*/
-int sqlite3StrICmp(const char *, const char *);
-int sqlite3StrNICmp(const char *, const char *, int);
-int sqlite3HashNoCase(const char *, int);
-int sqlite3IsNumber(const char*, int*, u8);
-int sqlite3Compare(const char *, const char *);
-int sqlite3SortCompare(const char *, const char *);
-void sqlite3RealToSortable(double r, char *);
-#ifdef SQLITE_DEBUG
- void *sqlite3Malloc_(int,int,char*,int);
- void sqlite3Free_(void*,char*,int);
- void *sqlite3Realloc_(void*,int,char*,int);
- char *sqlite3StrDup_(const char*,char*,int);
- char *sqlite3StrNDup_(const char*, int,char*,int);
- void sqlite3CheckMemory(void*,int);
-#else
- void *sqlite3Malloc(int);
- void *sqlite3MallocRaw(int);
- void sqlite3Free(void*);
- void *sqlite3Realloc(void*,int);
- char *sqlite3StrDup(const char*);
- char *sqlite3StrNDup(const char*, int);
-# define sqlite3CheckMemory(a,b)
-#endif
-void sqlite3FreeX(void*);
-char *sqlite3MPrintf(const char*, ...);
-char *sqlite3VMPrintf(const char*, va_list);
-void sqlite3DebugPrintf(const char*, ...);
-void *sqlite3TextToPtr(const char*);
-void sqlite3SetString(char **, const char *, ...);
-void sqlite3ErrorMsg(Parse*, const char*, ...);
-void sqlite3Dequote(char*);
-int sqlite3KeywordCode(const char*, int);
-int sqlite3RunParser(Parse*, const char*, char **);
-void sqlite3FinishCoding(Parse*);
-Expr *sqlite3Expr(int, Expr*, Expr*, Token*);
-Expr *sqlite3ExprAnd(Expr*, Expr*);
-void sqlite3ExprSpan(Expr*,Token*,Token*);
-Expr *sqlite3ExprFunction(ExprList*, Token*);
-void sqlite3ExprAssignVarNumber(Parse*, Expr*);
-void sqlite3ExprDelete(Expr*);
-ExprList *sqlite3ExprListAppend(ExprList*,Expr*,Token*);
-void sqlite3ExprListDelete(ExprList*);
-int sqlite3Init(sqlite3*, char**);
-int sqlite3InitCallback(void*, int, char**, char**);
-void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
-void sqlite3ResetInternalSchema(sqlite3*, int);
-void sqlite3BeginParse(Parse*,int);
-void sqlite3RollbackInternalChanges(sqlite3*);
-void sqlite3CommitInternalChanges(sqlite3*);
-Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*);
-void sqlite3OpenMasterTable(Vdbe *v, int);
-void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
-void sqlite3AddColumn(Parse*,Token*);
-void sqlite3AddNotNull(Parse*, int);
-void sqlite3AddPrimaryKey(Parse*, ExprList*, int);
-void sqlite3AddColumnType(Parse*,Token*,Token*);
-void sqlite3AddDefaultValue(Parse*,Token*,int);
-void sqlite3AddCollateType(Parse*, const char*, int);
-void sqlite3EndTable(Parse*,Token*,Select*);
-void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
-int sqlite3ViewGetColumnNames(Parse*,Table*);
-void sqlite3DropTable(Parse*, SrcList*, int);
-void sqlite3DeleteTable(sqlite3*, Table*);
-void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
-IdList *sqlite3IdListAppend(IdList*, Token*);
-int sqlite3IdListIndex(IdList*,const char*);
-SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*);
-void sqlite3SrcListAddAlias(SrcList*, Token*);
-void sqlite3SrcListAssignCursors(Parse*, SrcList*);
-void sqlite3IdListDelete(IdList*);
-void sqlite3SrcListDelete(SrcList*);
-void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
- Token*);
-void sqlite3DropIndex(Parse*, SrcList*);
-void sqlite3AddKeyType(Vdbe*, ExprList*);
-void sqlite3AddIdxKeyType(Vdbe*, Index*);
-int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff);
-Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
- int,int,int);
-void sqlite3SelectDelete(Select*);
-void sqlite3SelectUnbind(Select*);
-Table *sqlite3SrcListLookup(Parse*, SrcList*);
-int sqlite3IsReadOnly(Parse*, Table*, int);
-void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*);
-void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
-void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
-WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**);
-void sqlite3WhereEnd(WhereInfo*);
-void sqlite3ExprCode(Parse*, Expr*);
-int sqlite3ExprCodeExprList(Parse*, ExprList*);
-void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
-void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
-Table *sqlite3FindTable(sqlite3*,const char*, const char*);
-Table *sqlite3LocateTable(Parse*,const char*, const char*);
-Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
-void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
-void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
-void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
-void sqlite3Vacuum(Parse*, Token*);
-int sqlite3RunVacuum(char**, sqlite3*);
-char *sqlite3NameFromToken(Token*);
-int sqlite3ExprCheck(Parse*, Expr*, int, int*);
-int sqlite3ExprCompare(Expr*, Expr*);
-int sqliteFuncId(Token*);
-int sqlite3ExprResolveIds(Parse*, SrcList*, ExprList*, Expr*);
-int sqlite3ExprResolveAndCheck(Parse*,SrcList*,ExprList*,Expr*,int,int*);
-int sqlite3ExprAnalyzeAggregates(Parse*, Expr*);
-Vdbe *sqlite3GetVdbe(Parse*);
-void sqlite3Randomness(int, void*);
-void sqlite3RollbackAll(sqlite3*);
-void sqlite3CodeVerifySchema(Parse*, int);
-void sqlite3BeginTransaction(Parse*, int);
-void sqlite3CommitTransaction(Parse*);
-void sqlite3RollbackTransaction(Parse*);
-int sqlite3ExprIsConstant(Expr*);
-int sqlite3ExprIsInteger(Expr*, int*);
-int sqlite3IsRowid(const char*);
-void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int);
-void sqlite3GenerateRowIndexDelete(sqlite3*, Vdbe*, Table*, int, char*);
-void sqlite3GenerateIndexKey(Vdbe*, Index*, int);
-void sqlite3GenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
-void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int);
-void sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
-void sqlite3BeginWriteOperation(Parse*, int, int);
-Expr *sqlite3ExprDup(Expr*);
-void sqlite3TokenCopy(Token*, Token*);
-ExprList *sqlite3ExprListDup(ExprList*);
-SrcList *sqlite3SrcListDup(SrcList*);
-IdList *sqlite3IdListDup(IdList*);
-Select *sqlite3SelectDup(Select*);
-FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int);
-void sqlite3RegisterBuiltinFunctions(sqlite3*);
-void sqlite3RegisterDateTimeFunctions(sqlite3*);
-int sqlite3SafetyOn(sqlite3*);
-int sqlite3SafetyOff(sqlite3*);
-int sqlite3SafetyCheck(sqlite3*);
-void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
-void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
- int,Expr*,int);
-void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
-void sqlite3DropTrigger(Parse*, SrcList*);
-void sqlite3DropTriggerPtr(Parse*, Trigger*, int);
-int sqlite3TriggersExist(Parse* , Trigger* , int , int , int, ExprList*);
-int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
- int, int);
-void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
-void sqlite3DeleteTriggerStep(TriggerStep*);
-TriggerStep *sqlite3TriggerSelectStep(Select*);
-TriggerStep *sqlite3TriggerInsertStep(Token*, IdList*, ExprList*, Select*, int);
-TriggerStep *sqlite3TriggerUpdateStep(Token*, ExprList*, Expr*, int);
-TriggerStep *sqlite3TriggerDeleteStep(Token*, Expr*);
-void sqlite3DeleteTrigger(Trigger*);
-int sqlite3JoinType(Parse*, Token*, Token*, Token*);
-void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
-void sqlite3DeferForeignKey(Parse*, int);
-#ifndef SQLITE_OMIT_AUTHORIZATION
- void sqlite3AuthRead(Parse*,Expr*,SrcList*);
- int sqlite3AuthCheck(Parse*,int, const char*, const char*, const char*);
- void sqlite3AuthContextPush(Parse*, AuthContext*, const char*);
- void sqlite3AuthContextPop(AuthContext*);
-#else
-# define sqlite3AuthRead(a,b,c)
-# define sqlite3AuthCheck(a,b,c,d,e) SQLITE_OK
-# define sqlite3AuthContextPush(a,b,c)
-# define sqlite3AuthContextPop(a) ((void)(a))
-#endif
-void sqlite3Attach(Parse*, Token*, Token*, int, Token*);
-void sqlite3Detach(Parse*, Token*);
-int sqlite3BtreeFactory(const sqlite3 *db, const char *zFilename,
- int omitJournal, int nCache, Btree **ppBtree);
-int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
-int sqlite3FixSrcList(DbFixer*, SrcList*);
-int sqlite3FixSelect(DbFixer*, Select*);
-int sqlite3FixExpr(DbFixer*, Expr*);
-int sqlite3FixExprList(DbFixer*, ExprList*);
-int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
-double sqlite3AtoF(const char *z, const char **);
-char *sqlite3_snprintf(int,char*,const char*,...);
-int sqlite3GetInt32(const char *, int*);
-int sqlite3FitsIn64Bits(const char *);
-int sqlite3utf16ByteLen(const void *pData, int nChar);
-int sqlite3utf8CharLen(const char *pData, int nByte);
-int sqlite3ReadUtf8(const unsigned char *);
-int sqlite3PutVarint(unsigned char *, u64);
-int sqlite3GetVarint(const unsigned char *, u64 *);
-int sqlite3GetVarint32(const unsigned char *, u32 *);
-int sqlite3VarintLen(u64 v);
-char sqlite3AffinityType(const char *, int);
-void sqlite3IndexAffinityStr(Vdbe *, Index *);
-void sqlite3TableAffinityStr(Vdbe *, Table *);
-char sqlite3CompareAffinity(Expr *pExpr, char aff2);
-int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
-char sqlite3ExprAffinity(Expr *pExpr);
-int sqlite3atoi64(const char*, i64*);
-void sqlite3Error(sqlite3*, int, const char*,...);
-void *sqlite3HexToBlob(const char *z);
-int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
-const char *sqlite3ErrStr(int);
-int sqlite3ReadUniChar(const char *zStr, int *pOffset, u8 *pEnc, int fold);
-int sqlite3ReadSchema(Parse *pParse);
-CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char *,int,int);
-CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName);
-CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
-int sqlite3CheckCollSeq(Parse *, CollSeq *);
-int sqlite3CheckIndexCollSeq(Parse *, Index *);
-int sqlite3CheckObjectName(Parse *, const char *);
-void sqlite3VdbeSetChanges(sqlite3 *, int);
-void sqlite3utf16Substr(sqlite3_context *,int,sqlite3_value **);
-
-const void *sqlite3ValueText(sqlite3_value*, u8);
-int sqlite3ValueBytes(sqlite3_value*, u8);
-void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
-void sqlite3ValueFree(sqlite3_value*);
-sqlite3_value *sqlite3ValueNew();
-sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
-extern const unsigned char sqlite3UpperToLower[];
-
-#endif
diff --git a/kopete/plugins/statistics/sqlite/table.c b/kopete/plugins/statistics/sqlite/table.c
deleted file mode 100644
index d4ef2c8a..00000000
--- a/kopete/plugins/statistics/sqlite/table.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains the sqlite3_get_table() and sqlite3_free_table()
-** interface routines. These are just wrappers around the main
-** interface routine of sqlite3_exec().
-**
-** These routines are in a separate files so that they will not be linked
-** if they are not used.
-*/
-#include <stdlib.h>
-#include <string.h>
-#include "sqliteInt.h"
-
-/*
-** This structure is used to pass data from sqlite3_get_table() through
-** to the callback function is uses to build the result.
-*/
-typedef struct TabResult {
- char **azResult;
- char *zErrMsg;
- int nResult;
- int nAlloc;
- int nRow;
- int nColumn;
- int nData;
- int rc;
-} TabResult;
-
-/*
-** This routine is called once for each row in the result table. Its job
-** is to fill in the TabResult structure appropriately, allocating new
-** memory as necessary.
-*/
-static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
- TabResult *p = (TabResult*)pArg;
- int need;
- int i;
- char *z;
-
- /* Make sure there is enough space in p->azResult to hold everything
- ** we need to remember from this invocation of the callback.
- */
- if( p->nRow==0 && argv!=0 ){
- need = nCol*2;
- }else{
- need = nCol;
- }
- if( p->nData + need >= p->nAlloc ){
- char **azNew;
- p->nAlloc = p->nAlloc*2 + need + 1;
- azNew = realloc( p->azResult, sizeof(char*)*p->nAlloc );
- if( azNew==0 ) goto malloc_failed;
- p->azResult = azNew;
- }
-
- /* If this is the first row, then generate an extra row containing
- ** the names of all columns.
- */
- if( p->nRow==0 ){
- p->nColumn = nCol;
- for(i=0; i<nCol; i++){
- if( colv[i]==0 ){
- z = 0;
- }else{
- z = malloc( strlen(colv[i])+1 );
- if( z==0 ) goto malloc_failed;
- strcpy(z, colv[i]);
- }
- p->azResult[p->nData++] = z;
- }
- }else if( p->nColumn!=nCol ){
- sqlite3SetString(&p->zErrMsg,
- "sqlite3_get_table() called with two or more incompatible queries",
- (char*)0);
- p->rc = SQLITE_ERROR;
- return 1;
- }
-
- /* Copy over the row data
- */
- if( argv!=0 ){
- for(i=0; i<nCol; i++){
- if( argv[i]==0 ){
- z = 0;
- }else{
- z = malloc( strlen(argv[i])+1 );
- if( z==0 ) goto malloc_failed;
- strcpy(z, argv[i]);
- }
- p->azResult[p->nData++] = z;
- }
- p->nRow++;
- }
- return 0;
-
-malloc_failed:
- p->rc = SQLITE_NOMEM;
- return 1;
-}
-
-/*
-** Query the database. But instead of invoking a callback for each row,
-** malloc() for space to hold the result and return the entire results
-** at the conclusion of the call.
-**
-** The result that is written to ***pazResult is held in memory obtained
-** from malloc(). But the caller cannot free this memory directly.
-** Instead, the entire table should be passed to sqlite3_free_table() when
-** the calling procedure is finished using it.
-*/
-int sqlite3_get_table(
- sqlite3 *db, /* The database on which the SQL executes */
- const char *zSql, /* The SQL to be executed */
- char ***pazResult, /* Write the result table here */
- int *pnRow, /* Write the number of rows in the result here */
- int *pnColumn, /* Write the number of columns of result here */
- char **pzErrMsg /* Write error messages here */
-){
- int rc;
- TabResult res;
- if( pazResult==0 ){ return SQLITE_ERROR; }
- *pazResult = 0;
- if( pnColumn ) *pnColumn = 0;
- if( pnRow ) *pnRow = 0;
- res.zErrMsg = 0;
- res.nResult = 0;
- res.nRow = 0;
- res.nColumn = 0;
- res.nData = 1;
- res.nAlloc = 20;
- res.rc = SQLITE_OK;
- res.azResult = malloc( sizeof(char*)*res.nAlloc );
- if( res.azResult==0 ) return SQLITE_NOMEM;
- res.azResult[0] = 0;
- rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
- if( res.azResult ){
- res.azResult[0] = (char*)res.nData;
- }
- if( rc==SQLITE_ABORT ){
- sqlite3_free_table(&res.azResult[1]);
- if( res.zErrMsg ){
- if( pzErrMsg ){
- free(*pzErrMsg);
- *pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
- }
- sqliteFree(res.zErrMsg);
- }
- db->errCode = res.rc;
- return res.rc;
- }
- sqliteFree(res.zErrMsg);
- if( rc!=SQLITE_OK ){
- sqlite3_free_table(&res.azResult[1]);
- return rc;
- }
- if( res.nAlloc>res.nData ){
- char **azNew;
- azNew = realloc( res.azResult, sizeof(char*)*(res.nData+1) );
- if( azNew==0 ){
- sqlite3_free_table(&res.azResult[1]);
- return SQLITE_NOMEM;
- }
- res.nAlloc = res.nData+1;
- res.azResult = azNew;
- }
- *pazResult = &res.azResult[1];
- if( pnColumn ) *pnColumn = res.nColumn;
- if( pnRow ) *pnRow = res.nRow;
- return rc;
-}
-
-/*
-** This routine frees the space the sqlite3_get_table() malloced.
-*/
-void sqlite3_free_table(
- char **azResult /* Result returned from from sqlite3_get_table() */
-){
- if( azResult ){
- int i, n;
- azResult--;
- if( azResult==0 ) return;
- n = (int)azResult[0];
- for(i=1; i<n; i++){ if( azResult[i] ) free(azResult[i]); }
- free(azResult);
- }
-}
diff --git a/kopete/plugins/statistics/sqlite/tokenize.c b/kopete/plugins/statistics/sqlite/tokenize.c
deleted file mode 100644
index 061e5b9a..00000000
--- a/kopete/plugins/statistics/sqlite/tokenize.c
+++ /dev/null
@@ -1,707 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** An tokenizer for SQL
-**
-** This file contains C code that splits an SQL input string up into
-** individual tokens and sends those tokens one-by-one over to the
-** parser for analysis.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-#include "os.h"
-#include <ctype.h>
-#include <stdlib.h>
-
-/*
-** This function looks up an identifier to determine if it is a
-** keyword. If it is a keyword, the token code of that keyword is
-** returned. If the input is not a keyword, TK_ID is returned.
-**
-** The implementation of this routine was generated by a program,
-** mkkeywordhash.c, located in the tool subdirectory of the distribution.
-** The output of the mkkeywordhash.c program was manually cut and pasted
-** into this file. When the set of keywords for SQLite changes, you
-** must modify the mkkeywordhash.c program (to add or remove keywords from
-** the data tables) then rerun that program to regenerate this function.
-*/
-int sqlite3KeywordCode(const char *z, int n){
- static const char zText[519] =
- "ABORTAFTERALLANDASCATTACHBEFOREBEGINBETWEENBYCASCADECASECHECK"
- "COLLATECOMMITCONFLICTCONSTRAINTCREATECROSSDATABASEDEFAULTDEFERRABLE"
- "DEFERREDDELETEDESCDETACHDISTINCTDROPEACHELSEENDEXCEPTEXCLUSIVE"
- "EXPLAINFAILFOREIGNFROMFULLGLOBGROUPHAVINGIGNOREIMMEDIATEINDEX"
- "INITIALLYINNERINSERTINSTEADINTERSECTINTOISNULLJOINKEYLEFTLIKE"
- "LIMITMATCHNATURALNOTNULLNULLOFFSETONORDEROUTERPRAGMAPRIMARYRAISE"
- "REFERENCESREPLACERESTRICTRIGHTROLLBACKROWSELECTSETSTATEMENTTABLE"
- "TEMPORARYTHENTRANSACTIONTRIGGERUNIONUNIQUEUPDATEUSINGVACUUMVALUES"
- "VIEWWHENWHERE";
- static const unsigned char aHash[154] = {
- 0, 75, 82, 0, 0, 97, 80, 0, 83, 0, 0, 0, 0,
- 0, 0, 6, 0, 95, 4, 0, 0, 0, 0, 0, 0, 0,
- 0, 96, 86, 8, 0, 26, 13, 7, 19, 15, 0, 0, 32,
- 25, 0, 21, 31, 41, 0, 0, 0, 34, 27, 0, 0, 30,
- 0, 0, 0, 9, 0, 10, 0, 0, 0, 0, 51, 0, 44,
- 43, 0, 45, 40, 0, 29, 39, 35, 0, 0, 20, 0, 59,
- 0, 16, 0, 17, 0, 18, 0, 55, 42, 72, 0, 33, 0,
- 0, 61, 66, 56, 0, 0, 0, 0, 0, 0, 0, 54, 0,
- 0, 0, 0, 0, 74, 50, 76, 64, 52, 0, 0, 0, 0,
- 68, 84, 0, 47, 0, 58, 60, 92, 0, 0, 48, 0, 93,
- 0, 63, 71, 98, 0, 0, 0, 0, 0, 67, 0, 0, 0,
- 0, 87, 0, 0, 0, 0, 0, 90, 88, 0, 94,
- };
- static const unsigned char aNext[98] = {
- 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 12, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0,
- 0, 0, 0, 14, 3, 24, 0, 0, 0, 1, 22, 0, 0,
- 36, 23, 28, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0,
- 0, 49, 37, 0, 0, 0, 38, 0, 53, 0, 57, 62, 0,
- 0, 0, 0, 0, 0, 70, 46, 0, 65, 0, 0, 0, 0,
- 69, 73, 0, 77, 0, 0, 0, 0, 0, 0, 81, 85, 0,
- 91, 79, 78, 0, 0, 89, 0,
- };
- static const unsigned char aLen[98] = {
- 5, 5, 3, 3, 2, 3, 6, 6, 5, 7, 2, 7, 4,
- 5, 7, 6, 8, 10, 6, 5, 8, 7, 10, 8, 6, 4,
- 6, 8, 4, 4, 4, 3, 6, 9, 7, 4, 3, 7, 4,
- 4, 4, 5, 6, 6, 9, 2, 5, 9, 5, 6, 7, 9,
- 4, 2, 6, 4, 3, 4, 4, 5, 5, 7, 3, 7, 4,
- 2, 6, 2, 2, 5, 5, 6, 7, 5, 10, 7, 8, 5,
- 8, 3, 6, 3, 9, 5, 4, 9, 4, 11, 7, 5, 6,
- 6, 5, 6, 6, 4, 4, 5,
- };
- static const unsigned short int aOffset[98] = {
- 0, 5, 10, 13, 16, 16, 19, 25, 31, 36, 43, 45, 52,
- 56, 61, 68, 74, 82, 92, 98, 103, 111, 118, 128, 136, 142,
- 146, 152, 160, 164, 168, 172, 175, 181, 190, 197, 201, 201, 208,
- 212, 216, 220, 225, 231, 237, 246, 246, 251, 260, 265, 271, 278,
- 287, 291, 291, 297, 301, 304, 308, 312, 317, 322, 329, 329, 336,
- 340, 340, 346, 348, 348, 353, 358, 364, 371, 376, 386, 393, 401,
- 406, 414, 417, 423, 426, 435, 440, 440, 449, 453, 464, 471, 476,
- 482, 488, 493, 499, 505, 509, 513,
- };
- static const unsigned char aCode[98] = {
- TK_ABORT, TK_AFTER, TK_ALL, TK_AND, TK_AS,
- TK_ASC, TK_ATTACH, TK_BEFORE, TK_BEGIN, TK_BETWEEN,
- TK_BY, TK_CASCADE, TK_CASE, TK_CHECK, TK_COLLATE,
- TK_COMMIT, TK_CONFLICT, TK_CONSTRAINT, TK_CREATE, TK_JOIN_KW,
- TK_DATABASE, TK_DEFAULT, TK_DEFERRABLE, TK_DEFERRED, TK_DELETE,
- TK_DESC, TK_DETACH, TK_DISTINCT, TK_DROP, TK_EACH,
- TK_ELSE, TK_END, TK_EXCEPT, TK_EXCLUSIVE, TK_EXPLAIN,
- TK_FAIL, TK_FOR, TK_FOREIGN, TK_FROM, TK_JOIN_KW,
- TK_GLOB, TK_GROUP, TK_HAVING, TK_IGNORE, TK_IMMEDIATE,
- TK_IN, TK_INDEX, TK_INITIALLY, TK_JOIN_KW, TK_INSERT,
- TK_INSTEAD, TK_INTERSECT, TK_INTO, TK_IS, TK_ISNULL,
- TK_JOIN, TK_KEY, TK_JOIN_KW, TK_LIKE, TK_LIMIT,
- TK_MATCH, TK_JOIN_KW, TK_NOT, TK_NOTNULL, TK_NULL,
- TK_OF, TK_OFFSET, TK_ON, TK_OR, TK_ORDER,
- TK_JOIN_KW, TK_PRAGMA, TK_PRIMARY, TK_RAISE, TK_REFERENCES,
- TK_REPLACE, TK_RESTRICT, TK_JOIN_KW, TK_ROLLBACK, TK_ROW,
- TK_SELECT, TK_SET, TK_STATEMENT, TK_TABLE, TK_TEMP,
- TK_TEMP, TK_THEN, TK_TRANSACTION,TK_TRIGGER, TK_UNION,
- TK_UNIQUE, TK_UPDATE, TK_USING, TK_VACUUM, TK_VALUES,
- TK_VIEW, TK_WHEN, TK_WHERE,
- };
- int h, i;
- if( n<2 ) return TK_ID;
- h = (sqlite3UpperToLower[((unsigned char*)z)[0]]*5 +
- sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3 +
- n) % 154;
- for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
- if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){
- return aCode[i];
- }
- }
- return TK_ID;
-}
-
-/*
-** If X is a character that can be used in an identifier and
-** X&0x80==0 then isIdChar[X] will be 1. If X&0x80==0x80 then
-** X is always an identifier character. (Hence all UTF-8
-** characters can be part of an identifier). isIdChar[X] will
-** be 0 for every character in the lower 128 ASCII characters
-** that cannot be used as part of an identifier.
-**
-** In this implementation, an identifier can be a string of
-** alphabetic characters, digits, and "_" plus any character
-** with the high-order bit set. The latter rule means that
-** any sequence of UTF-8 characters or characters taken from
-** an extended ISO8859 character set can form an identifier.
-*/
-static const char isIdChar[] = {
-/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
-};
-
-#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x2f && isIdChar[c-0x30]))
-
-/*
-** Return the length of the token that begins at z[0].
-** Store the token type in *tokenType before returning.
-*/
-static int sqliteGetToken(const unsigned char *z, int *tokenType){
- int i, c;
- switch( *z ){
- case ' ': case '\t': case '\n': case '\f': case '\r': {
- for(i=1; isspace(z[i]); i++){}
- *tokenType = TK_SPACE;
- return i;
- }
- case '-': {
- if( z[1]=='-' ){
- for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
- *tokenType = TK_COMMENT;
- return i;
- }
- *tokenType = TK_MINUS;
- return 1;
- }
- case '(': {
- *tokenType = TK_LP;
- return 1;
- }
- case ')': {
- *tokenType = TK_RP;
- return 1;
- }
- case ';': {
- *tokenType = TK_SEMI;
- return 1;
- }
- case '+': {
- *tokenType = TK_PLUS;
- return 1;
- }
- case '*': {
- *tokenType = TK_STAR;
- return 1;
- }
- case '/': {
- if( z[1]!='*' || z[2]==0 ){
- *tokenType = TK_SLASH;
- return 1;
- }
- for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
- if( c ) i++;
- *tokenType = TK_COMMENT;
- return i;
- }
- case '%': {
- *tokenType = TK_REM;
- return 1;
- }
- case '=': {
- *tokenType = TK_EQ;
- return 1 + (z[1]=='=');
- }
- case '<': {
- if( (c=z[1])=='=' ){
- *tokenType = TK_LE;
- return 2;
- }else if( c=='>' ){
- *tokenType = TK_NE;
- return 2;
- }else if( c=='<' ){
- *tokenType = TK_LSHIFT;
- return 2;
- }else{
- *tokenType = TK_LT;
- return 1;
- }
- }
- case '>': {
- if( (c=z[1])=='=' ){
- *tokenType = TK_GE;
- return 2;
- }else if( c=='>' ){
- *tokenType = TK_RSHIFT;
- return 2;
- }else{
- *tokenType = TK_GT;
- return 1;
- }
- }
- case '!': {
- if( z[1]!='=' ){
- *tokenType = TK_ILLEGAL;
- return 2;
- }else{
- *tokenType = TK_NE;
- return 2;
- }
- }
- case '|': {
- if( z[1]!='|' ){
- *tokenType = TK_BITOR;
- return 1;
- }else{
- *tokenType = TK_CONCAT;
- return 2;
- }
- }
- case ',': {
- *tokenType = TK_COMMA;
- return 1;
- }
- case '&': {
- *tokenType = TK_BITAND;
- return 1;
- }
- case '~': {
- *tokenType = TK_BITNOT;
- return 1;
- }
- case '\'': case '"': {
- int delim = z[0];
- for(i=1; (c=z[i])!=0; i++){
- if( c==delim ){
- if( z[i+1]==delim ){
- i++;
- }else{
- break;
- }
- }
- }
- if( c ) i++;
- *tokenType = TK_STRING;
- return i;
- }
- case '.': {
- *tokenType = TK_DOT;
- return 1;
- }
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9': {
- *tokenType = TK_INTEGER;
- for(i=1; isdigit(z[i]); i++){}
- if( z[i]=='.' && isdigit(z[i+1]) ){
- i += 2;
- while( isdigit(z[i]) ){ i++; }
- *tokenType = TK_FLOAT;
- }
- if( (z[i]=='e' || z[i]=='E') &&
- ( isdigit(z[i+1])
- || ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2]))
- )
- ){
- i += 2;
- while( isdigit(z[i]) ){ i++; }
- *tokenType = TK_FLOAT;
- }
- return i;
- }
- case '[': {
- for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
- *tokenType = TK_ID;
- return i;
- }
- case '?': {
- *tokenType = TK_VARIABLE;
- for(i=1; isdigit(z[i]); i++){}
- return i;
- }
- case ':': {
- for(i=1; IdChar(z[i]); i++){}
- *tokenType = i>1 ? TK_VARIABLE : TK_ILLEGAL;
- return i;
- }
- case '$': {
- *tokenType = TK_VARIABLE;
- if( z[1]=='{' ){
- int nBrace = 1;
- for(i=2; (c=z[i])!=0 && nBrace; i++){
- if( c=='{' ){
- nBrace++;
- }else if( c=='}' ){
- nBrace--;
- }
- }
- if( c==0 ) *tokenType = TK_ILLEGAL;
- }else{
- int n = 0;
- for(i=1; (c=z[i])!=0; i++){
- if( isalnum(c) || c=='_' ){
- n++;
- }else if( c=='(' && n>0 ){
- do{
- i++;
- }while( (c=z[i])!=0 && !isspace(c) && c!=')' );
- if( c==')' ){
- i++;
- }else{
- *tokenType = TK_ILLEGAL;
- }
- break;
- }else if( c==':' && z[i+1]==':' ){
- i++;
- }else{
- break;
- }
- }
- if( n==0 ) *tokenType = TK_ILLEGAL;
- }
- return i;
- }
- case 'x': case 'X': {
- if( (c=z[1])=='\'' || c=='"' ){
- int delim = c;
- *tokenType = TK_BLOB;
- for(i=2; (c=z[i])!=0; i++){
- if( c==delim ){
- if( i%2 ) *tokenType = TK_ILLEGAL;
- break;
- }
- if( !isxdigit(c) ){
- *tokenType = TK_ILLEGAL;
- return i;
- }
- }
- if( c ) i++;
- return i;
- }
- /* Otherwise fall through to the next case */
- }
- default: {
- if( !IdChar(*z) ){
- break;
- }
- for(i=1; IdChar(z[i]); i++){}
- *tokenType = sqlite3KeywordCode((char*)z, i);
- return i;
- }
- }
- *tokenType = TK_ILLEGAL;
- return 1;
-}
-
-/*
-** Run the parser on the given SQL string. The parser structure is
-** passed in. An SQLITE_ status code is returned. If an error occurs
-** and pzErrMsg!=NULL then an error message might be written into
-** memory obtained from malloc() and *pzErrMsg made to point to that
-** error message. Or maybe not.
-*/
-int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
- int nErr = 0;
- int i;
- void *pEngine;
- int tokenType;
- int lastTokenParsed = -1;
- sqlite3 *db = pParse->db;
- extern void *sqlite3ParserAlloc(void*(*)(int));
- extern void sqlite3ParserFree(void*, void(*)(void*));
- extern int sqlite3Parser(void*, int, Token, Parse*);
-
- db->flags &= ~SQLITE_Interrupt;
- pParse->rc = SQLITE_OK;
- i = 0;
- pEngine = sqlite3ParserAlloc((void*(*)(int))malloc);
- if( pEngine==0 ){
- sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
- return 1;
- }
- assert( pParse->sLastToken.dyn==0 );
- assert( pParse->pNewTable==0 );
- assert( pParse->pNewTrigger==0 );
- assert( pParse->nVar==0 );
- assert( pParse->nVarExpr==0 );
- assert( pParse->nVarExprAlloc==0 );
- assert( pParse->apVarExpr==0 );
- pParse->zTail = pParse->zSql = zSql;
- while( sqlite3_malloc_failed==0 && zSql[i]!=0 ){
- assert( i>=0 );
- pParse->sLastToken.z = &zSql[i];
- assert( pParse->sLastToken.dyn==0 );
- pParse->sLastToken.n = sqliteGetToken((unsigned char*)&zSql[i], &tokenType);
- i += pParse->sLastToken.n;
- switch( tokenType ){
- case TK_SPACE:
- case TK_COMMENT: {
- if( (db->flags & SQLITE_Interrupt)!=0 ){
- pParse->rc = SQLITE_INTERRUPT;
- sqlite3SetString(pzErrMsg, "interrupt", (char*)0);
- goto abort_parse;
- }
- break;
- }
- case TK_ILLEGAL: {
- if( pzErrMsg ){
- sqliteFree(*pzErrMsg);
- *pzErrMsg = sqlite3MPrintf("unrecognized token: \"%T\"",
- &pParse->sLastToken);
- }
- nErr++;
- goto abort_parse;
- }
- case TK_SEMI: {
- pParse->zTail = &zSql[i];
- /* Fall thru into the default case */
- }
- default: {
- sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
- lastTokenParsed = tokenType;
- if( pParse->rc!=SQLITE_OK ){
- goto abort_parse;
- }
- break;
- }
- }
- }
-abort_parse:
- if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
- if( lastTokenParsed!=TK_SEMI ){
- sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
- pParse->zTail = &zSql[i];
- }
- sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
- }
- sqlite3ParserFree(pEngine, free);
- if( sqlite3_malloc_failed ){
- pParse->rc = SQLITE_NOMEM;
- }
- if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
- sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc),
- (char*)0);
- }
- if( pParse->zErrMsg ){
- if( pzErrMsg && *pzErrMsg==0 ){
- *pzErrMsg = pParse->zErrMsg;
- }else{
- sqliteFree(pParse->zErrMsg);
- }
- pParse->zErrMsg = 0;
- if( !nErr ) nErr++;
- }
- if( pParse->pVdbe && pParse->nErr>0 ){
- sqlite3VdbeDelete(pParse->pVdbe);
- pParse->pVdbe = 0;
- }
- sqlite3DeleteTable(pParse->db, pParse->pNewTable);
- sqlite3DeleteTrigger(pParse->pNewTrigger);
- sqliteFree(pParse->apVarExpr);
- if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
- pParse->rc = SQLITE_ERROR;
- }
- return nErr;
-}
-
-/*
-** Token types used by the sqlite3_complete() routine. See the header
-** comments on that procedure for additional information.
-*/
-#define tkEXPLAIN 0
-#define tkCREATE 1
-#define tkTEMP 2
-#define tkTRIGGER 3
-#define tkEND 4
-#define tkSEMI 5
-#define tkWS 6
-#define tkOTHER 7
-
-/*
-** Return TRUE if the given SQL string ends in a semicolon.
-**
-** Special handling is require for CREATE TRIGGER statements.
-** Whenever the CREATE TRIGGER keywords are seen, the statement
-** must end with ";END;".
-**
-** This implementation uses a state machine with 7 states:
-**
-** (0) START At the beginning or end of an SQL statement. This routine
-** returns 1 if it ends in the START state and 0 if it ends
-** in any other state.
-**
-** (1) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
-** a statement.
-**
-** (2) CREATE The keyword CREATE has been seen at the beginning of a
-** statement, possibly preceeded by EXPLAIN and/or followed by
-** TEMP or TEMPORARY
-**
-** (3) NORMAL We are in the middle of statement which ends with a single
-** semicolon.
-**
-** (4) TRIGGER We are in the middle of a trigger definition that must be
-** ended by a semicolon, the keyword END, and another semicolon.
-**
-** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at
-** the end of a trigger definition.
-**
-** (6) END We've seen the ";END" of the ";END;" that occurs at the end
-** of a trigger difinition.
-**
-** Transitions between states above are determined by tokens extracted
-** from the input. The following tokens are significant:
-**
-** (0) tkEXPLAIN The "explain" keyword.
-** (1) tkCREATE The "create" keyword.
-** (2) tkTEMP The "temp" or "temporary" keyword.
-** (3) tkTRIGGER The "trigger" keyword.
-** (4) tkEND The "end" keyword.
-** (5) tkSEMI A semicolon.
-** (6) tkWS Whitespace
-** (7) tkOTHER Any other SQL token.
-**
-** Whitespace never causes a state transition and is always ignored.
-*/
-int sqlite3_complete(const char *zSql){
- u8 state = 0; /* Current state, using numbers defined in header comment */
- u8 token; /* Value of the next token */
-
- /* The following matrix defines the transition from one state to another
- ** according to what token is seen. trans[state][token] returns the
- ** next state.
- */
- static const u8 trans[7][8] = {
- /* Token: */
- /* State: ** EXPLAIN CREATE TEMP TRIGGER END SEMI WS OTHER */
- /* 0 START: */ { 1, 2, 3, 3, 3, 0, 0, 3, },
- /* 1 EXPLAIN: */ { 3, 2, 3, 3, 3, 0, 1, 3, },
- /* 2 CREATE: */ { 3, 3, 2, 4, 3, 0, 2, 3, },
- /* 3 NORMAL: */ { 3, 3, 3, 3, 3, 0, 3, 3, },
- /* 4 TRIGGER: */ { 4, 4, 4, 4, 4, 5, 4, 4, },
- /* 5 SEMI: */ { 4, 4, 4, 4, 6, 5, 5, 4, },
- /* 6 END: */ { 4, 4, 4, 4, 4, 0, 6, 4, },
- };
-
- while( *zSql ){
- switch( *zSql ){
- case ';': { /* A semicolon */
- token = tkSEMI;
- break;
- }
- case ' ':
- case '\r':
- case '\t':
- case '\n':
- case '\f': { /* White space is ignored */
- token = tkWS;
- break;
- }
- case '/': { /* C-style comments */
- if( zSql[1]!='*' ){
- token = tkOTHER;
- break;
- }
- zSql += 2;
- while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
- if( zSql[0]==0 ) return 0;
- zSql++;
- token = tkWS;
- break;
- }
- case '-': { /* SQL-style comments from "--" to end of line */
- if( zSql[1]!='-' ){
- token = tkOTHER;
- break;
- }
- while( *zSql && *zSql!='\n' ){ zSql++; }
- if( *zSql==0 ) return state==0;
- token = tkWS;
- break;
- }
- case '[': { /* Microsoft-style identifiers in [...] */
- zSql++;
- while( *zSql && *zSql!=']' ){ zSql++; }
- if( *zSql==0 ) return 0;
- token = tkOTHER;
- break;
- }
- case '"': /* single- and double-quoted strings */
- case '\'': {
- int c = *zSql;
- zSql++;
- while( *zSql && *zSql!=c ){ zSql++; }
- if( *zSql==0 ) return 0;
- token = tkOTHER;
- break;
- }
- default: {
- int c;
- if( IdChar((u8)*zSql) ){
- /* Keywords and unquoted identifiers */
- int nId;
- for(nId=1; IdChar(zSql[nId]); nId++){}
- switch( *zSql ){
- case 'c': case 'C': {
- if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){
- token = tkCREATE;
- }else{
- token = tkOTHER;
- }
- break;
- }
- case 't': case 'T': {
- if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){
- token = tkTRIGGER;
- }else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){
- token = tkTEMP;
- }else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){
- token = tkTEMP;
- }else{
- token = tkOTHER;
- }
- break;
- }
- case 'e': case 'E': {
- if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){
- token = tkEND;
- }else if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){
- token = tkEXPLAIN;
- }else{
- token = tkOTHER;
- }
- break;
- }
- default: {
- token = tkOTHER;
- break;
- }
- }
- zSql += nId-1;
- }else{
- /* Operators and special symbols */
- token = tkOTHER;
- }
- break;
- }
- }
- state = trans[state][token];
- zSql++;
- }
- return state==0;
-}
-
-/*
-** This routine is the same as the sqlite3_complete() routine described
-** above, except that the parameter is required to be UTF-16 encoded, not
-** UTF-8.
-*/
-int sqlite3_complete16(const void *zSql){
- sqlite3_value *pVal;
- char const *zSql8;
- int rc = 0;
-
- pVal = sqlite3ValueNew();
- sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
- zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
- if( zSql8 ){
- rc = sqlite3_complete(zSql8);
- }
- sqlite3ValueFree(pVal);
- return rc;
-}
diff --git a/kopete/plugins/statistics/sqlite/trigger.c b/kopete/plugins/statistics/sqlite/trigger.c
deleted file mode 100644
index bbb526f8..00000000
--- a/kopete/plugins/statistics/sqlite/trigger.c
+++ /dev/null
@@ -1,804 +0,0 @@
-/*
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-*
-*/
-#include "sqliteInt.h"
-
-/*
-** Delete a linked list of TriggerStep structures.
-*/
-void sqlite3DeleteTriggerStep(TriggerStep *pTriggerStep){
- while( pTriggerStep ){
- TriggerStep * pTmp = pTriggerStep;
- pTriggerStep = pTriggerStep->pNext;
-
- if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
- sqlite3ExprDelete(pTmp->pWhere);
- sqlite3ExprListDelete(pTmp->pExprList);
- sqlite3SelectDelete(pTmp->pSelect);
- sqlite3IdListDelete(pTmp->pIdList);
-
- sqliteFree(pTmp);
- }
-}
-
-/*
-** This is called by the parser when it sees a CREATE TRIGGER statement
-** up to the point of the BEGIN before the trigger actions. A Trigger
-** structure is generated based on the information available and stored
-** in pParse->pNewTrigger. After the trigger actions have been parsed, the
-** sqlite3FinishTrigger() function is called to complete the trigger
-** construction process.
-*/
-void sqlite3BeginTrigger(
- Parse *pParse, /* The parse context of the CREATE TRIGGER statement */
- Token *pName1, /* The name of the trigger */
- Token *pName2, /* The name of the trigger */
- int tr_tm, /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
- int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
- IdList *pColumns, /* column list if this is an UPDATE OF trigger */
- SrcList *pTableName,/* The name of the table/view the trigger applies to */
- int foreach, /* One of TK_ROW or TK_STATEMENT */
- Expr *pWhen, /* WHEN clause */
- int isTemp /* True if the TEMPORARY keyword is present */
-){
- Trigger *pTrigger;
- Table *pTab;
- char *zName = 0; /* Name of the trigger */
- sqlite3 *db = pParse->db;
- int iDb; /* The database to store the trigger in */
- Token *pName; /* The unqualified db name */
- DbFixer sFix;
-
- if( isTemp ){
- /* If TEMP was specified, then the trigger name may not be qualified. */
- if( pName2 && pName2->n>0 ){
- sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name");
- goto trigger_cleanup;
- }
- iDb = 1;
- pName = pName1;
- }else{
- /* Figure out the db that the the trigger will be created in */
- iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
- if( iDb<0 ){
- goto trigger_cleanup;
- }
- }
-
- /* If the trigger name was unqualified, and the table is a temp table,
- ** then set iDb to 1 to create the trigger in the temporary database.
- ** If sqlite3SrcListLookup() returns 0, indicating the table does not
- ** exist, the error is caught by the block below.
- */
- if( !pTableName || sqlite3_malloc_failed ) goto trigger_cleanup;
- pTab = sqlite3SrcListLookup(pParse, pTableName);
- if( pName2->n==0 && pTab && pTab->iDb==1 ){
- iDb = 1;
- }
-
- /* Ensure the table name matches database name and that the table exists */
- if( sqlite3_malloc_failed ) goto trigger_cleanup;
- assert( pTableName->nSrc==1 );
- if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
- sqlite3FixSrcList(&sFix, pTableName) ){
- goto trigger_cleanup;
- }
- pTab = sqlite3SrcListLookup(pParse, pTableName);
- if( !pTab ){
- /* The table does not exist. */
- goto trigger_cleanup;
- }
-
- /* Check that the trigger name is not reserved and that no trigger of the
- ** specified name exists */
- zName = sqlite3NameFromToken(pName);
- if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
- goto trigger_cleanup;
- }
- if( sqlite3HashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
- sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
- goto trigger_cleanup;
- }
-
- /* Do not create a trigger on a system table */
- if( (iDb!=1 && sqlite3StrICmp(pTab->zName, MASTER_NAME)==0) ||
- (iDb==1 && sqlite3StrICmp(pTab->zName, TEMP_MASTER_NAME)==0)
- ){
- sqlite3ErrorMsg(pParse, "cannot create trigger on system table");
- pParse->nErr++;
- goto trigger_cleanup;
- }
-
- /* INSTEAD of triggers are only for views and views only support INSTEAD
- ** of triggers.
- */
- if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
- sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
- (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
- goto trigger_cleanup;
- }
- if( !pTab->pSelect && tr_tm==TK_INSTEAD ){
- sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF"
- " trigger on table: %S", pTableName, 0);
- goto trigger_cleanup;
- }
-
-#ifndef SQLITE_OMIT_AUTHORIZATION
- {
- int code = SQLITE_CREATE_TRIGGER;
- const char *zDb = db->aDb[pTab->iDb].zName;
- const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
- if( pTab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
- if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){
- goto trigger_cleanup;
- }
- if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(pTab->iDb),0,zDb)){
- goto trigger_cleanup;
- }
- }
-#endif
-
- /* INSTEAD OF triggers can only appear on views and BEFORE triggers
- ** cannot appear on views. So we might as well translate every
- ** INSTEAD OF trigger into a BEFORE trigger. It simplifies code
- ** elsewhere.
- */
- if (tr_tm == TK_INSTEAD){
- tr_tm = TK_BEFORE;
- }
-
- /* Build the Trigger object */
- pTrigger = (Trigger*)sqliteMalloc(sizeof(Trigger));
- if( pTrigger==0 ) goto trigger_cleanup;
- pTrigger->name = zName;
- zName = 0;
- pTrigger->table = sqliteStrDup(pTableName->a[0].zName);
- if( sqlite3_malloc_failed ) goto trigger_cleanup;
- pTrigger->iDb = iDb;
- pTrigger->iTabDb = pTab->iDb;
- pTrigger->op = op;
- pTrigger->tr_tm = tr_tm;
- pTrigger->pWhen = sqlite3ExprDup(pWhen);
- pTrigger->pColumns = sqlite3IdListDup(pColumns);
- pTrigger->foreach = foreach;
- sqlite3TokenCopy(&pTrigger->nameToken,pName);
- assert( pParse->pNewTrigger==0 );
- pParse->pNewTrigger = pTrigger;
-
-trigger_cleanup:
- sqliteFree(zName);
- sqlite3SrcListDelete(pTableName);
- sqlite3IdListDelete(pColumns);
- sqlite3ExprDelete(pWhen);
-}
-
-/*
-** This routine is called after all of the trigger actions have been parsed
-** in order to complete the process of building the trigger.
-*/
-void sqlite3FinishTrigger(
- Parse *pParse, /* Parser context */
- TriggerStep *pStepList, /* The triggered program */
- Token *pAll /* Token that describes the complete CREATE TRIGGER */
-){
- Trigger *nt = 0; /* The trigger whose construction is finishing up */
- sqlite3 *db = pParse->db; /* The database */
- DbFixer sFix;
-
- if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
- nt = pParse->pNewTrigger;
- pParse->pNewTrigger = 0;
- nt->step_list = pStepList;
- while( pStepList ){
- pStepList->pTrig = nt;
- pStepList = pStepList->pNext;
- }
- if( sqlite3FixInit(&sFix, pParse, nt->iDb, "trigger", &nt->nameToken)
- && sqlite3FixTriggerStep(&sFix, nt->step_list) ){
- goto triggerfinish_cleanup;
- }
-
- /* if we are not initializing, and this trigger is not on a TEMP table,
- ** build the sqlite_master entry
- */
- if( !db->init.busy ){
- static const VdbeOpList insertTrig[] = {
- { OP_NewRecno, 0, 0, 0 },
- { OP_String8, 0, 0, "trigger" },
- { OP_String8, 0, 0, 0 }, /* 2: trigger name */
- { OP_String8, 0, 0, 0 }, /* 3: table name */
- { OP_Integer, 0, 0, 0 },
- { OP_String8, 0, 0, "CREATE TRIGGER "},
- { OP_String8, 0, 0, 0 }, /* 6: SQL */
- { OP_Concat, 0, 0, 0 },
- { OP_MakeRecord, 5, 0, "tttit" },
- { OP_PutIntKey, 0, 0, 0 },
- };
- int addr;
- Vdbe *v;
-
- /* Make an entry in the sqlite_master table */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto triggerfinish_cleanup;
- sqlite3BeginWriteOperation(pParse, 0, nt->iDb);
- sqlite3OpenMasterTable(v, nt->iDb);
- addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
- sqlite3VdbeChangeP3(v, addr+2, nt->name, 0);
- sqlite3VdbeChangeP3(v, addr+3, nt->table, 0);
- sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
- if( nt->iDb!=0 ){
- sqlite3ChangeCookie(db, v, nt->iDb);
- }
- sqlite3VdbeAddOp(v, OP_Close, 0, 0);
- sqlite3VdbeOp3(v, OP_ParseSchema, nt->iDb, 0,
- sqlite3MPrintf("type='trigger' AND name='%q'", nt->name), P3_DYNAMIC);
- }
-
- if( db->init.busy ){
- Table *pTab;
- sqlite3HashInsert(&db->aDb[nt->iDb].trigHash,
- nt->name, strlen(nt->name)+1, nt);
- pTab = sqlite3LocateTable(pParse, nt->table, db->aDb[nt->iTabDb].zName);
- assert( pTab!=0 );
- nt->pNext = pTab->pTrigger;
- pTab->pTrigger = nt;
- nt = 0;
- }
-
-triggerfinish_cleanup:
- sqlite3DeleteTrigger(nt);
- sqlite3DeleteTrigger(pParse->pNewTrigger);
- pParse->pNewTrigger = 0;
- sqlite3DeleteTriggerStep(pStepList);
-}
-
-/*
-** Make a copy of all components of the given trigger step. This has
-** the effect of copying all Expr.token.z values into memory obtained
-** from sqliteMalloc(). As initially created, the Expr.token.z values
-** all point to the input string that was fed to the parser. But that
-** string is ephemeral - it will go away as soon as the sqlite3_exec()
-** call that started the parser exits. This routine makes a persistent
-** copy of all the Expr.token.z strings so that the TriggerStep structure
-** will be valid even after the sqlite3_exec() call returns.
-*/
-static void sqlitePersistTriggerStep(TriggerStep *p){
- if( p->target.z ){
- p->target.z = sqliteStrNDup(p->target.z, p->target.n);
- p->target.dyn = 1;
- }
- if( p->pSelect ){
- Select *pNew = sqlite3SelectDup(p->pSelect);
- sqlite3SelectDelete(p->pSelect);
- p->pSelect = pNew;
- }
- if( p->pWhere ){
- Expr *pNew = sqlite3ExprDup(p->pWhere);
- sqlite3ExprDelete(p->pWhere);
- p->pWhere = pNew;
- }
- if( p->pExprList ){
- ExprList *pNew = sqlite3ExprListDup(p->pExprList);
- sqlite3ExprListDelete(p->pExprList);
- p->pExprList = pNew;
- }
- if( p->pIdList ){
- IdList *pNew = sqlite3IdListDup(p->pIdList);
- sqlite3IdListDelete(p->pIdList);
- p->pIdList = pNew;
- }
-}
-
-/*
-** Turn a SELECT statement (that the pSelect parameter points to) into
-** a trigger step. Return a pointer to a TriggerStep structure.
-**
-** The parser calls this routine when it finds a SELECT statement in
-** body of a TRIGGER.
-*/
-TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
- TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
- if( pTriggerStep==0 ) return 0;
-
- pTriggerStep->op = TK_SELECT;
- pTriggerStep->pSelect = pSelect;
- pTriggerStep->orconf = OE_Default;
- sqlitePersistTriggerStep(pTriggerStep);
-
- return pTriggerStep;
-}
-
-/*
-** Build a trigger step out of an INSERT statement. Return a pointer
-** to the new trigger step.
-**
-** The parser calls this routine when it sees an INSERT inside the
-** body of a trigger.
-*/
-TriggerStep *sqlite3TriggerInsertStep(
- Token *pTableName, /* Name of the table into which we insert */
- IdList *pColumn, /* List of columns in pTableName to insert into */
- ExprList *pEList, /* The VALUE clause: a list of values to be inserted */
- Select *pSelect, /* A SELECT statement that supplies values */
- int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
-){
- TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
- if( pTriggerStep==0 ) return 0;
-
- assert(pEList == 0 || pSelect == 0);
- assert(pEList != 0 || pSelect != 0);
-
- pTriggerStep->op = TK_INSERT;
- pTriggerStep->pSelect = pSelect;
- pTriggerStep->target = *pTableName;
- pTriggerStep->pIdList = pColumn;
- pTriggerStep->pExprList = pEList;
- pTriggerStep->orconf = orconf;
- sqlitePersistTriggerStep(pTriggerStep);
-
- return pTriggerStep;
-}
-
-/*
-** Construct a trigger step that implements an UPDATE statement and return
-** a pointer to that trigger step. The parser calls this routine when it
-** sees an UPDATE statement inside the body of a CREATE TRIGGER.
-*/
-TriggerStep *sqlite3TriggerUpdateStep(
- Token *pTableName, /* Name of the table to be updated */
- ExprList *pEList, /* The SET clause: list of column and new values */
- Expr *pWhere, /* The WHERE clause */
- int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
-){
- TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
- if( pTriggerStep==0 ) return 0;
-
- pTriggerStep->op = TK_UPDATE;
- pTriggerStep->target = *pTableName;
- pTriggerStep->pExprList = pEList;
- pTriggerStep->pWhere = pWhere;
- pTriggerStep->orconf = orconf;
- sqlitePersistTriggerStep(pTriggerStep);
-
- return pTriggerStep;
-}
-
-/*
-** Construct a trigger step that implements a DELETE statement and return
-** a pointer to that trigger step. The parser calls this routine when it
-** sees a DELETE statement inside the body of a CREATE TRIGGER.
-*/
-TriggerStep *sqlite3TriggerDeleteStep(Token *pTableName, Expr *pWhere){
- TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
- if( pTriggerStep==0 ) return 0;
-
- pTriggerStep->op = TK_DELETE;
- pTriggerStep->target = *pTableName;
- pTriggerStep->pWhere = pWhere;
- pTriggerStep->orconf = OE_Default;
- sqlitePersistTriggerStep(pTriggerStep);
-
- return pTriggerStep;
-}
-
-/*
-** Recursively delete a Trigger structure
-*/
-void sqlite3DeleteTrigger(Trigger *pTrigger){
- if( pTrigger==0 ) return;
- sqlite3DeleteTriggerStep(pTrigger->step_list);
- sqliteFree(pTrigger->name);
- sqliteFree(pTrigger->table);
- sqlite3ExprDelete(pTrigger->pWhen);
- sqlite3IdListDelete(pTrigger->pColumns);
- if( pTrigger->nameToken.dyn ) sqliteFree((char*)pTrigger->nameToken.z);
- sqliteFree(pTrigger);
-}
-
-/*
-** This function is called to drop a trigger from the database schema.
-**
-** This may be called directly from the parser and therefore identifies
-** the trigger by name. The sqlite3DropTriggerPtr() routine does the
-** same job as this routine except it takes a pointer to the trigger
-** instead of the trigger name.
-**/
-void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
- Trigger *pTrigger = 0;
- int i;
- const char *zDb;
- const char *zName;
- int nName;
- sqlite3 *db = pParse->db;
-
- if( sqlite3_malloc_failed ) goto drop_trigger_cleanup;
- if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
- goto drop_trigger_cleanup;
- }
-
- assert( pName->nSrc==1 );
- zDb = pName->a[0].zDatabase;
- zName = pName->a[0].zName;
- nName = strlen(zName);
- for(i=0; i<db->nDb; i++){
- int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
- if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
- pTrigger = sqlite3HashFind(&(db->aDb[j].trigHash), zName, nName+1);
- if( pTrigger ) break;
- }
- if( !pTrigger ){
- sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
- goto drop_trigger_cleanup;
- }
- sqlite3DropTriggerPtr(pParse, pTrigger, 0);
-
-drop_trigger_cleanup:
- sqlite3SrcListDelete(pName);
-}
-
-/*
-** Return a pointer to the Table structure for the table that a trigger
-** is set on.
-*/
-static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){
- return sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
-}
-
-
-/*
-** Drop a trigger given a pointer to that trigger. If nested is false,
-** then also generate code to remove the trigger from the SQLITE_MASTER
-** table.
-*/
-void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
- Table *pTable;
- Vdbe *v;
- sqlite3 *db = pParse->db;
- int iDb;
-
- iDb = pTrigger->iDb;
- assert( iDb>=0 && iDb<db->nDb );
- pTable = tableOfTrigger(db, pTrigger);
- assert(pTable);
- assert( pTable->iDb==iDb || iDb==1 );
-#ifndef SQLITE_OMIT_AUTHORIZATION
- {
- int code = SQLITE_DROP_TRIGGER;
- const char *zDb = db->aDb[iDb].zName;
- const char *zTab = SCHEMA_TABLE(iDb);
- if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER;
- if( sqlite3AuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||
- sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
- return;
- }
- }
-#endif
-
- /* Generate code to destroy the database record of the trigger.
- */
- if( pTable!=0 && (v = sqlite3GetVdbe(pParse))!=0 ){
- int base;
- static const VdbeOpList dropTrigger[] = {
- { OP_Rewind, 0, ADDR(9), 0},
- { OP_String8, 0, 0, 0}, /* 1 */
- { OP_Column, 0, 1, 0},
- { OP_Ne, 0, ADDR(8), 0},
- { OP_String8, 0, 0, "trigger"},
- { OP_Column, 0, 0, 0},
- { OP_Ne, 0, ADDR(8), 0},
- { OP_Delete, 0, 0, 0},
- { OP_Next, 0, ADDR(1), 0}, /* 8 */
- };
-
- sqlite3BeginWriteOperation(pParse, 0, iDb);
- sqlite3OpenMasterTable(v, iDb);
- base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
- sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
- sqlite3ChangeCookie(db, v, iDb);
- sqlite3VdbeAddOp(v, OP_Close, 0, 0);
- sqlite3VdbeOp3(v, OP_DropTrigger, iDb, 0, pTrigger->name, 0);
- }
-}
-
-/*
-** Remove a trigger from the hash tables of the sqlite* pointer.
-*/
-void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
- Trigger *pTrigger;
- int nName = strlen(zName);
- pTrigger = sqlite3HashInsert(&(db->aDb[iDb].trigHash), zName, nName+1, 0);
- if( pTrigger ){
- Table *pTable = tableOfTrigger(db, pTrigger);
- assert( pTable!=0 );
- if( pTable->pTrigger == pTrigger ){
- pTable->pTrigger = pTrigger->pNext;
- }else{
- Trigger *cc = pTable->pTrigger;
- while( cc ){
- if( cc->pNext == pTrigger ){
- cc->pNext = cc->pNext->pNext;
- break;
- }
- cc = cc->pNext;
- }
- assert(cc);
- }
- sqlite3DeleteTrigger(pTrigger);
- db->flags |= SQLITE_InternChanges;
- }
-}
-
-/*
-** pEList is the SET clause of an UPDATE statement. Each entry
-** in pEList is of the format <id>=<expr>. If any of the entries
-** in pEList have an <id> which matches an identifier in pIdList,
-** then return TRUE. If pIdList==NULL, then it is considered a
-** wildcard that matches anything. Likewise if pEList==NULL then
-** it matches anything so always return true. Return false only
-** if there is no match.
-*/
-static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
- int e;
- if( !pIdList || !pEList ) return 1;
- for(e=0; e<pEList->nExpr; e++){
- if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
- }
- return 0;
-}
-
-/* A global variable that is TRUE if we should always set up temp tables for
- * for triggers, even if there are no triggers to code. This is used to test
- * how much overhead the triggers algorithm is causing.
- *
- * This flag can be set or cleared using the "trigger_overhead_test" pragma.
- * The pragma is not documented since it is not really part of the interface
- * to SQLite, just the test procedure.
-*/
-int sqlite3_always_code_trigger_setup = 0;
-
-/*
- * Returns true if a trigger matching op, tr_tm and foreach that is NOT already
- * on the Parse objects trigger-stack (to prevent recursive trigger firing) is
- * found in the list specified as pTrigger.
- */
-int sqlite3TriggersExist(
- Parse *pParse, /* Used to check for recursive triggers */
- Trigger *pTrigger, /* A list of triggers associated with a table */
- int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
- int tr_tm, /* one of TK_BEFORE, TK_AFTER */
- int foreach, /* one of TK_ROW or TK_STATEMENT */
- ExprList *pChanges /* Columns that change in an UPDATE statement */
-){
- Trigger * pTriggerCursor;
-
- if( sqlite3_always_code_trigger_setup ){
- return 1;
- }
-
- pTriggerCursor = pTrigger;
- while( pTriggerCursor ){
- if( pTriggerCursor->op == op &&
- pTriggerCursor->tr_tm == tr_tm &&
- pTriggerCursor->foreach == foreach &&
- checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
- TriggerStack * ss;
- ss = pParse->trigStack;
- while( ss && ss->pTrigger != pTrigger ){
- ss = ss->pNext;
- }
- if( !ss )return 1;
- }
- pTriggerCursor = pTriggerCursor->pNext;
- }
-
- return 0;
-}
-
-/*
-** Convert the pStep->target token into a SrcList and return a pointer
-** to that SrcList.
-**
-** This routine adds a specific database name, if needed, to the target when
-** forming the SrcList. This prevents a trigger in one database from
-** referring to a target in another database. An exception is when the
-** trigger is in TEMP in which case it can refer to any other database it
-** wants.
-*/
-static SrcList *targetSrcList(
- Parse *pParse, /* The parsing context */
- TriggerStep *pStep /* The trigger containing the target token */
-){
- Token sDb; /* Dummy database name token */
- int iDb; /* Index of the database to use */
- SrcList *pSrc; /* SrcList to be returned */
-
- iDb = pStep->pTrig->iDb;
- if( iDb==0 || iDb>=2 ){
- assert( iDb<pParse->db->nDb );
- sDb.z = pParse->db->aDb[iDb].zName;
- sDb.n = strlen(sDb.z);
- pSrc = sqlite3SrcListAppend(0, &sDb, &pStep->target);
- } else {
- pSrc = sqlite3SrcListAppend(0, &pStep->target, 0);
- }
- return pSrc;
-}
-
-/*
-** Generate VDBE code for zero or more statements inside the body of a
-** trigger.
-*/
-static int codeTriggerProgram(
- Parse *pParse, /* The parser context */
- TriggerStep *pStepList, /* List of statements inside the trigger body */
- int orconfin /* Conflict algorithm. (OE_Abort, etc) */
-){
- TriggerStep * pTriggerStep = pStepList;
- int orconf;
- Vdbe *v = pParse->pVdbe;
-
- assert( pTriggerStep!=0 );
- assert( v!=0 );
- sqlite3VdbeAddOp(v, OP_ContextPush, 0, 0);
- VdbeComment((v, "# begin trigger %s", pStepList->pTrig->name));
- while( pTriggerStep ){
- orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
- pParse->trigStack->orconf = orconf;
- switch( pTriggerStep->op ){
- case TK_SELECT: {
- Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);
- assert(ss);
- assert(ss->pSrc);
- sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
- sqlite3SelectDelete(ss);
- break;
- }
- case TK_UPDATE: {
- SrcList *pSrc;
- pSrc = targetSrcList(pParse, pTriggerStep);
- sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
- sqlite3Update(pParse, pSrc,
- sqlite3ExprListDup(pTriggerStep->pExprList),
- sqlite3ExprDup(pTriggerStep->pWhere), orconf);
- sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
- break;
- }
- case TK_INSERT: {
- SrcList *pSrc;
- pSrc = targetSrcList(pParse, pTriggerStep);
- sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
- sqlite3Insert(pParse, pSrc,
- sqlite3ExprListDup(pTriggerStep->pExprList),
- sqlite3SelectDup(pTriggerStep->pSelect),
- sqlite3IdListDup(pTriggerStep->pIdList), orconf);
- sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
- break;
- }
- case TK_DELETE: {
- SrcList *pSrc;
- sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
- pSrc = targetSrcList(pParse, pTriggerStep);
- sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(pTriggerStep->pWhere));
- sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
- break;
- }
- default:
- assert(0);
- }
- pTriggerStep = pTriggerStep->pNext;
- }
- sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
- VdbeComment((v, "# end trigger %s", pStepList->pTrig->name));
-
- return 0;
-}
-
-/*
-** This is called to code FOR EACH ROW triggers.
-**
-** When the code that this function generates is executed, the following
-** must be true:
-**
-** 1. No cursors may be open in the main database. (But newIdx and oldIdx
-** can be indices of cursors in temporary tables. See below.)
-**
-** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
-** a temporary vdbe cursor (index newIdx) must be open and pointing at
-** a row containing values to be substituted for new.* expressions in the
-** trigger program(s).
-**
-** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
-** a temporary vdbe cursor (index oldIdx) must be open and pointing at
-** a row containing values to be substituted for old.* expressions in the
-** trigger program(s).
-**
-*/
-int sqlite3CodeRowTrigger(
- Parse *pParse, /* Parse context */
- int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
- ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
- int tr_tm, /* One of TK_BEFORE, TK_AFTER */
- Table *pTab, /* The table to code triggers from */
- int newIdx, /* The indice of the "new" row to access */
- int oldIdx, /* The indice of the "old" row to access */
- int orconf, /* ON CONFLICT policy */
- int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
-){
- Trigger *pTrigger;
- TriggerStack *pStack;
- TriggerStack trigStackEntry;
-
- assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
- assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER );
-
- assert(newIdx != -1 || oldIdx != -1);
-
- pTrigger = pTab->pTrigger;
- while( pTrigger ){
- int fire_this = 0;
-
- /* determine whether we should code this trigger */
- if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
- pTrigger->foreach == TK_ROW ){
- fire_this = 1;
- for(pStack=pParse->trigStack; pStack; pStack=pStack->pNext){
- if( pStack->pTrigger==pTrigger ){
- fire_this = 0;
- }
- }
- if( op == TK_UPDATE && pTrigger->pColumns &&
- !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
- fire_this = 0;
- }
- }
-
- if( fire_this ){
- int endTrigger;
- SrcList dummyTablist;
- Expr * whenExpr;
- AuthContext sContext;
-
- dummyTablist.nSrc = 0;
-
- /* Push an entry on to the trigger stack */
- trigStackEntry.pTrigger = pTrigger;
- trigStackEntry.newIdx = newIdx;
- trigStackEntry.oldIdx = oldIdx;
- trigStackEntry.pTab = pTab;
- trigStackEntry.pNext = pParse->trigStack;
- trigStackEntry.ignoreJump = ignoreJump;
- pParse->trigStack = &trigStackEntry;
- sqlite3AuthContextPush(pParse, &sContext, pTrigger->name);
-
- /* code the WHEN clause */
- endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
- whenExpr = sqlite3ExprDup(pTrigger->pWhen);
- if( sqlite3ExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
- pParse->trigStack = trigStackEntry.pNext;
- sqlite3ExprDelete(whenExpr);
- return 1;
- }
- sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1);
- sqlite3ExprDelete(whenExpr);
-
- codeTriggerProgram(pParse, pTrigger->step_list, orconf);
-
- /* Pop the entry off the trigger stack */
- pParse->trigStack = trigStackEntry.pNext;
- sqlite3AuthContextPop(&sContext);
-
- sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
- }
- pTrigger = pTrigger->pNext;
- }
- return 0;
-}
diff --git a/kopete/plugins/statistics/sqlite/update.c b/kopete/plugins/statistics/sqlite/update.c
deleted file mode 100644
index 08c7987c..00000000
--- a/kopete/plugins/statistics/sqlite/update.c
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains C code routines that are called by the parser
-** to handle UPDATE statements.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-
-/*
-** Process an UPDATE statement.
-**
-** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
-** \_______/ \________/ \______/ \________________/
-* onError pTabList pChanges pWhere
-*/
-void sqlite3Update(
- Parse *pParse, /* The parser context */
- SrcList *pTabList, /* The table in which we should change things */
- ExprList *pChanges, /* Things to be changed */
- Expr *pWhere, /* The WHERE clause. May be null */
- int onError /* How to handle constraint errors */
-){
- int i, j; /* Loop counters */
- Table *pTab; /* The table to be updated */
- int addr = 0; /* VDBE instruction address of the start of the loop */
- WhereInfo *pWInfo; /* Information about the WHERE clause */
- Vdbe *v; /* The virtual database engine */
- Index *pIdx; /* For looping over indices */
- int nIdx; /* Number of indices that need updating */
- int nIdxTotal; /* Total number of indices */
- int iCur; /* VDBE Cursor number of pTab */
- sqlite3 *db; /* The database structure */
- Index **apIdx = 0; /* An array of indices that need updating too */
- char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */
- int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
- ** an expression for the i-th column of the table.
- ** aXRef[i]==-1 if the i-th column is not changed. */
- int chngRecno; /* True if the record number is being changed */
- Expr *pRecnoExpr = 0; /* Expression defining the new record number */
- int openAll = 0; /* True if all indices need to be opened */
- int isView; /* Trying to update a view */
- AuthContext sContext; /* The authorization context */
-
- int before_triggers; /* True if there are any BEFORE triggers */
- int after_triggers; /* True if there are any AFTER triggers */
- int row_triggers_exist = 0; /* True if any row triggers exist */
-
- int newIdx = -1; /* index of trigger "new" temp table */
- int oldIdx = -1; /* index of trigger "old" temp table */
-
- sContext.pParse = 0;
- if( pParse->nErr || sqlite3_malloc_failed ) goto update_cleanup;
- db = pParse->db;
- assert( pTabList->nSrc==1 );
-
- /* Locate the table which we want to update.
- */
- pTab = sqlite3SrcListLookup(pParse, pTabList);
- if( pTab==0 ) goto update_cleanup;
- before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
- TK_UPDATE, TK_BEFORE, TK_ROW, pChanges);
- after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
- TK_UPDATE, TK_AFTER, TK_ROW, pChanges);
- row_triggers_exist = before_triggers || after_triggers;
- isView = pTab->pSelect!=0;
- if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
- goto update_cleanup;
- }
- if( isView ){
- if( sqlite3ViewGetColumnNames(pParse, pTab) ){
- goto update_cleanup;
- }
- }
- aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol );
- if( aXRef==0 ) goto update_cleanup;
- for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
-
- /* If there are FOR EACH ROW triggers, allocate cursors for the
- ** special OLD and NEW tables
- */
- if( row_triggers_exist ){
- newIdx = pParse->nTab++;
- oldIdx = pParse->nTab++;
- }
-
- /* Allocate a cursors for the main database table and for all indices.
- ** The index cursors might not be used, but if they are used they
- ** need to occur right after the database cursor. So go ahead and
- ** allocate enough space, just in case.
- */
- pTabList->a[0].iCursor = iCur = pParse->nTab++;
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- pParse->nTab++;
- }
-
- /* Resolve the column names in all the expressions of the
- ** of the UPDATE statement. Also find the column index
- ** for each column to be updated in the pChanges array. For each
- ** column to be updated, make sure we have authorization to change
- ** that column.
- */
- chngRecno = 0;
- for(i=0; i<pChanges->nExpr; i++){
- if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0,
- pChanges->a[i].pExpr, 0, 0) ){
- goto update_cleanup;
- }
- for(j=0; j<pTab->nCol; j++){
- if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
- if( j==pTab->iPKey ){
- chngRecno = 1;
- pRecnoExpr = pChanges->a[i].pExpr;
- }
- aXRef[j] = i;
- break;
- }
- }
- if( j>=pTab->nCol ){
- if( sqlite3IsRowid(pChanges->a[i].zName) ){
- chngRecno = 1;
- pRecnoExpr = pChanges->a[i].pExpr;
- }else{
- sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
- goto update_cleanup;
- }
- }
-#ifndef SQLITE_OMIT_AUTHORIZATION
- {
- int rc;
- rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
- pTab->aCol[j].zName, db->aDb[pTab->iDb].zName);
- if( rc==SQLITE_DENY ){
- goto update_cleanup;
- }else if( rc==SQLITE_IGNORE ){
- aXRef[j] = -1;
- }
- }
-#endif
- }
-
- /* Allocate memory for the array apIdx[] and fill it with pointers to every
- ** index that needs to be updated. Indices only need updating if their
- ** key includes one of the columns named in pChanges or if the record
- ** number of the original table entry is changing.
- */
- for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){
- if( chngRecno ){
- i = 0;
- }else {
- for(i=0; i<pIdx->nColumn; i++){
- if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
- }
- }
- if( i<pIdx->nColumn ) nIdx++;
- }
- if( nIdxTotal>0 ){
- apIdx = sqliteMallocRaw( sizeof(Index*) * nIdx + nIdxTotal );
- if( apIdx==0 ) goto update_cleanup;
- aIdxUsed = (char*)&apIdx[nIdx];
- }
- for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
- if( chngRecno ){
- i = 0;
- }else{
- for(i=0; i<pIdx->nColumn; i++){
- if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
- }
- }
- if( i<pIdx->nColumn ){
- if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto update_cleanup;
- apIdx[nIdx++] = pIdx;
- aIdxUsed[j] = 1;
- }else{
- aIdxUsed[j] = 0;
- }
- }
-
- /* Resolve the column names in all the expressions in the
- ** WHERE clause.
- */
- if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
- goto update_cleanup;
- }
-
- /* Start the view context
- */
- if( isView ){
- sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
- }
-
- /* Begin generating code.
- */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto update_cleanup;
- sqlite3VdbeCountChanges(v);
- sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
-
- /* If we are trying to update a view, construct that view into
- ** a temporary table.
- */
- if( isView ){
- Select *pView;
- pView = sqlite3SelectDup(pTab->pSelect);
- sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
- sqlite3SelectDelete(pView);
- }
-
- /* Begin the database scan
- */
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
- if( pWInfo==0 ) goto update_cleanup;
-
- /* Remember the index of every item to be updated.
- */
- sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
-
- /* End the database scan loop.
- */
- sqlite3WhereEnd(pWInfo);
-
- /* Initialize the count of updated rows
- */
- if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
- }
-
- if( row_triggers_exist ){
- /* Create pseudo-tables for NEW and OLD
- */
- sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
- sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
-
- /* The top of the update loop for when there are triggers.
- */
- sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
- addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
-
- /* Open a cursor and make it point to the record that is
- ** being updated.
- */
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- if( !isView ){
- sqlite3OpenTableForReading(v, iCur, pTab);
- }
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
-
- /* Generate the OLD table
- */
- sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
- sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
- sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
-
- /* Generate the NEW table
- */
- if( chngRecno ){
- sqlite3ExprCode(pParse, pRecnoExpr);
- }else{
- sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
- }
- for(i=0; i<pTab->nCol; i++){ /* TODO: Factor out this loop as common code */
- if( i==pTab->iPKey ){
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- continue;
- }
- j = aXRef[i];
- if( j<0 ){
- sqlite3VdbeAddOp(v, OP_Column, iCur, i);
- }else{
- sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
- }
- }
- sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
- if( !isView ){
- sqlite3TableAffinityStr(v, pTab);
- }
- if( pParse->nErr ) goto update_cleanup;
- sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
-
- /* Fire the BEFORE and INSTEAD OF triggers
- */
- if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab,
- newIdx, oldIdx, onError, addr) ){
- goto update_cleanup;
- }
- }
-
- if( !isView ){
- /*
- ** Open every index that needs updating. Note that if any
- ** index could potentially invoke a REPLACE conflict resolution
- ** action, then we need to open all indices because we might need
- ** to be deleting some records.
- */
- sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
- sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
- if( onError==OE_Replace ){
- openAll = 1;
- }else{
- openAll = 0;
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->onError==OE_Replace ){
- openAll = 1;
- break;
- }
- }
- }
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- if( openAll || aIdxUsed[i] ){
- sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
- sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
- (char*)&pIdx->keyInfo, P3_KEYINFO);
- assert( pParse->nTab>iCur+i+1 );
- }
- }
-
- /* Loop over every record that needs updating. We have to load
- ** the old data for each record to be updated because some columns
- ** might not change and we will need to copy the old value.
- ** Also, the old data is needed to delete the old index entires.
- ** So make the cursor point at the old record.
- */
- if( !row_triggers_exist ){
- sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
- addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- }
- sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
-
- /* If the record number will change, push the record number as it
- ** will be after the update. (The old record number is currently
- ** on top of the stack.)
- */
- if( chngRecno ){
- sqlite3ExprCode(pParse, pRecnoExpr);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
- }
-
- /* Compute new data for this record.
- */
- for(i=0; i<pTab->nCol; i++){
- if( i==pTab->iPKey ){
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- continue;
- }
- j = aXRef[i];
- if( j<0 ){
- sqlite3VdbeAddOp(v, OP_Column, iCur, i);
- }else{
- sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
- }
- }
-
- /* Do constraint checks
- */
- sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1,
- onError, addr);
-
- /* Delete the old indices for the current record.
- */
- sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed);
-
- /* If changing the record number, delete the old record.
- */
- if( chngRecno ){
- sqlite3VdbeAddOp(v, OP_Delete, iCur, 0);
- }
-
- /* Create the new index entries and the new record.
- */
- sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, -1);
- }
-
- /* Increment the row counter
- */
- if( db->flags & SQLITE_CountRows && !pParse->trigStack){
- sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
- }
-
- /* If there are triggers, close all the cursors after each iteration
- ** through the loop. The fire the after triggers.
- */
- if( row_triggers_exist ){
- if( !isView ){
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- if( openAll || aIdxUsed[i] )
- sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
- }
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
- if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab,
- newIdx, oldIdx, onError, addr) ){
- goto update_cleanup;
- }
- }
-
- /* Repeat the above with the next record to be updated, until
- ** all record selected by the WHERE clause have been updated.
- */
- sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
- sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
- sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
-
- /* Close all tables if there were no FOR EACH ROW triggers */
- if( !row_triggers_exist ){
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- if( openAll || aIdxUsed[i] ){
- sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
- }
- }
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }else{
- sqlite3VdbeAddOp(v, OP_Close, newIdx, 0);
- sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
- }
-
- /*
- ** Return the number of rows that were changed.
- */
- if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
- sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, "rows updated", P3_STATIC);
- }
-
-update_cleanup:
- sqlite3AuthContextPop(&sContext);
- sqliteFree(apIdx);
- sqliteFree(aXRef);
- sqlite3SrcListDelete(pTabList);
- sqlite3ExprListDelete(pChanges);
- sqlite3ExprDelete(pWhere);
- return;
-}
diff --git a/kopete/plugins/statistics/sqlite/utf.c b/kopete/plugins/statistics/sqlite/utf.c
deleted file mode 100644
index 58b1a972..00000000
--- a/kopete/plugins/statistics/sqlite/utf.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
-** 2004 April 13
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains routines used to translate between UTF-8,
-** UTF-16, UTF-16BE, and UTF-16LE.
-**
-** $Id$
-**
-** Notes on UTF-8:
-**
-** Byte-0 Byte-1 Byte-2 Byte-3 Value
-** 0xxxxxxx 00000000 00000000 0xxxxxxx
-** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx
-** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx
-** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx
-**
-**
-** Notes on UTF-16: (with wwww+1==uuuuu)
-**
-** Word-0 Word-1 Value
-** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx
-** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx
-**
-**
-** BOM or Byte Order Mark:
-** 0xff 0xfe little-endian utf-16 follows
-** 0xfe 0xff big-endian utf-16 follows
-**
-**
-** Handling of malformed strings:
-**
-** SQLite accepts and processes malformed strings without an error wherever
-** possible. However this is not possible when converting between UTF-8 and
-** UTF-16.
-**
-** When converting malformed UTF-8 strings to UTF-16, one instance of the
-** replacement character U+FFFD for each byte that cannot be interpeted as
-** part of a valid unicode character.
-**
-** When converting malformed UTF-16 strings to UTF-8, one instance of the
-** replacement character U+FFFD for each pair of bytes that cannot be
-** interpeted as part of a valid unicode character.
-**
-** This file contains the following public routines:
-**
-** sqlite3VdbeMemTranslate() - Translate the encoding used by a Mem* string.
-** sqlite3VdbeMemHandleBom() - Handle byte-order-marks in UTF16 Mem* strings.
-** sqlite3utf16ByteLen() - Calculate byte-length of a void* UTF16 string.
-** sqlite3utf8CharLen() - Calculate char-length of a char* UTF8 string.
-** sqlite3utf8LikeCompare() - Do a LIKE match given two UTF8 char* strings.
-**
-*/
-#include <assert.h>
-#include "sqliteInt.h"
-#include "vdbeInt.h"
-
-/*
-** This table maps from the first byte of a UTF-8 character to the number
-** of trailing bytes expected. A value '255' indicates that the table key
-** is not a legal first byte for a UTF-8 character.
-*/
-static const u8 xtra_utf8_bytes[256] = {
-/* 0xxxxxxx */
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
-/* 10wwwwww */
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-
-/* 110yyyyy */
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
-/* 1110zzzz */
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-
-/* 11110yyy */
-3, 3, 3, 3, 3, 3, 3, 3, 255, 255, 255, 255, 255, 255, 255, 255,
-};
-
-/*
-** This table maps from the number of trailing bytes in a UTF-8 character
-** to an integer constant that is effectively calculated for each character
-** read by a naive implementation of a UTF-8 character reader. The code
-** in the READ_UTF8 macro explains things best.
-*/
-static const int xtra_utf8_bits[4] = {
-0,
-12416, /* (0xC0 << 6) + (0x80) */
-925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */
-63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
-};
-
-#define READ_UTF8(zIn, c) { \
- int xtra; \
- c = *(zIn)++; \
- xtra = xtra_utf8_bytes[c]; \
- switch( xtra ){ \
- case 255: c = (int)0xFFFD; break; \
- case 3: c = (c<<6) + *(zIn)++; \
- case 2: c = (c<<6) + *(zIn)++; \
- case 1: c = (c<<6) + *(zIn)++; \
- c -= xtra_utf8_bits[xtra]; \
- } \
-}
-int sqlite3ReadUtf8(const unsigned char *z){
- int c;
- READ_UTF8(z, c);
- return c;
-}
-
-#define SKIP_UTF8(zIn) { \
- zIn += (xtra_utf8_bytes[*(u8 *)zIn] + 1); \
-}
-
-#define WRITE_UTF8(zOut, c) { \
- if( c<0x00080 ){ \
- *zOut++ = (c&0xFF); \
- } \
- else if( c<0x00800 ){ \
- *zOut++ = 0xC0 + ((c>>6)&0x1F); \
- *zOut++ = 0x80 + (c & 0x3F); \
- } \
- else if( c<0x10000 ){ \
- *zOut++ = 0xE0 + ((c>>12)&0x0F); \
- *zOut++ = 0x80 + ((c>>6) & 0x3F); \
- *zOut++ = 0x80 + (c & 0x3F); \
- }else{ \
- *zOut++ = 0xF0 + ((c>>18) & 0x07); \
- *zOut++ = 0x80 + ((c>>12) & 0x3F); \
- *zOut++ = 0x80 + ((c>>6) & 0x3F); \
- *zOut++ = 0x80 + (c & 0x3F); \
- } \
-}
-
-#define WRITE_UTF16LE(zOut, c) { \
- if( c<=0xFFFF ){ \
- *zOut++ = (c&0x00FF); \
- *zOut++ = ((c>>8)&0x00FF); \
- }else{ \
- *zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
- *zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \
- *zOut++ = (c&0x00FF); \
- *zOut++ = (0x00DC + ((c>>8)&0x03)); \
- } \
-}
-
-#define WRITE_UTF16BE(zOut, c) { \
- if( c<=0xFFFF ){ \
- *zOut++ = ((c>>8)&0x00FF); \
- *zOut++ = (c&0x00FF); \
- }else{ \
- *zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \
- *zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
- *zOut++ = (0x00DC + ((c>>8)&0x03)); \
- *zOut++ = (c&0x00FF); \
- } \
-}
-
-#define READ_UTF16LE(zIn, c){ \
- c = (*zIn++); \
- c += ((*zIn++)<<8); \
- if( c>=0xD800 && c<=0xE000 ){ \
- int c2 = (*zIn++); \
- c2 += ((*zIn++)<<8); \
- c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
- } \
-}
-
-#define READ_UTF16BE(zIn, c){ \
- c = ((*zIn++)<<8); \
- c += (*zIn++); \
- if( c>=0xD800 && c<=0xE000 ){ \
- int c2 = ((*zIn++)<<8); \
- c2 += (*zIn++); \
- c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
- } \
-}
-
-#define SKIP_UTF16BE(zIn){ \
- if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn+1)==0x00)) ){ \
- zIn += 4; \
- }else{ \
- zIn += 2; \
- } \
-}
-#define SKIP_UTF16LE(zIn){ \
- zIn++; \
- if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn-1)==0x00)) ){ \
- zIn += 3; \
- }else{ \
- zIn += 1; \
- } \
-}
-
-#define RSKIP_UTF16LE(zIn){ \
- if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn-1)==0x00)) ){ \
- zIn -= 4; \
- }else{ \
- zIn -= 2; \
- } \
-}
-#define RSKIP_UTF16BE(zIn){ \
- zIn--; \
- if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn+1)==0x00)) ){ \
- zIn -= 3; \
- }else{ \
- zIn -= 1; \
- } \
-}
-
-/*
-** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
-** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
-*/
-/* #define TRANSLATE_TRACE 1 */
-
-/*
-** This routine transforms the internal text encoding used by pMem to
-** desiredEnc. It is an error if the string is already of the desired
-** encoding, or if *pMem does not contain a string value.
-*/
-int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
- unsigned char zShort[NBFS]; /* Temporary short output buffer */
- int len; /* Maximum length of output string in bytes */
- unsigned char *zOut; /* Output buffer */
- unsigned char *zIn; /* Input iterator */
- unsigned char *zTerm; /* End of input */
- unsigned char *z; /* Output iterator */
- int c;
-
- assert( pMem->flags&MEM_Str );
- assert( pMem->enc!=desiredEnc );
- assert( pMem->enc!=0 );
- assert( pMem->n>=0 );
-
-#ifdef TRANSLATE_TRACE
- {
- char zBuf[100];
- sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
- fprintf(stderr, "INPUT: %s\n", zBuf);
- }
-#endif
-
- /* If the translation is between UTF-16 little and big endian, then
- ** all that is required is to swap the byte order. This case is handled
- ** differently from the others.
- */
- if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){
- u8 temp;
- int rc;
- rc = sqlite3VdbeMemMakeWriteable(pMem);
- if( rc!=SQLITE_OK ){
- assert( rc==SQLITE_NOMEM );
- return SQLITE_NOMEM;
- }
- zIn = pMem->z;
- zTerm = &zIn[pMem->n];
- while( zIn<zTerm ){
- temp = *zIn;
- *zIn = *(zIn+1);
- zIn++;
- *zIn++ = temp;
- }
- pMem->enc = desiredEnc;
- goto translate_out;
- }
-
- /* Set len to the maximum number of bytes required in the output buffer. */
- if( desiredEnc==SQLITE_UTF8 ){
- /* When converting from UTF-16, the maximum growth results from
- ** translating a 2-byte character to a 3-byte UTF-8 character (i.e.
- ** code-point 0xFFFC). A single byte is required for the output string
- ** nul-terminator.
- */
- len = (pMem->n/2) * 3 + 1;
- }else{
- /* When converting from UTF-8 to UTF-16 the maximum growth is caused
- ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
- ** character. Two bytes are required in the output buffer for the
- ** nul-terminator.
- */
- len = pMem->n * 2 + 2;
- }
-
- /* Set zIn to point at the start of the input buffer and zTerm to point 1
- ** byte past the end.
- **
- ** Variable zOut is set to point at the output buffer. This may be space
- ** obtained from malloc(), or Mem.zShort, if it large enough and not in
- ** use, or the zShort array on the stack (see above).
- */
- zIn = pMem->z;
- zTerm = &zIn[pMem->n];
- if( len>NBFS ){
- zOut = sqliteMallocRaw(len);
- if( !zOut ) return SQLITE_NOMEM;
- }else{
- zOut = zShort;
- }
- z = zOut;
-
- if( pMem->enc==SQLITE_UTF8 ){
- if( desiredEnc==SQLITE_UTF16LE ){
- /* UTF-8 -> UTF-16 Little-endian */
- while( zIn<zTerm ){
- READ_UTF8(zIn, c);
- WRITE_UTF16LE(z, c);
- }
- }else{
- assert( desiredEnc==SQLITE_UTF16BE );
- /* UTF-8 -> UTF-16 Big-endian */
- while( zIn<zTerm ){
- READ_UTF8(zIn, c);
- WRITE_UTF16BE(z, c);
- }
- }
- pMem->n = z - zOut;
- *z++ = 0;
- }else{
- assert( desiredEnc==SQLITE_UTF8 );
- if( pMem->enc==SQLITE_UTF16LE ){
- /* UTF-16 Little-endian -> UTF-8 */
- while( zIn<zTerm ){
- READ_UTF16LE(zIn, c);
- WRITE_UTF8(z, c);
- }
- }else{
- /* UTF-16 Little-endian -> UTF-8 */
- while( zIn<zTerm ){
- READ_UTF16BE(zIn, c);
- WRITE_UTF8(z, c);
- }
- }
- pMem->n = z - zOut;
- }
- *z = 0;
- assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
-
- sqlite3VdbeMemRelease(pMem);
- pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
- pMem->enc = desiredEnc;
- if( zOut==zShort ){
- memcpy(pMem->zShort, zOut, len);
- zOut = pMem->zShort;
- pMem->flags |= (MEM_Term|MEM_Short);
- }else{
- pMem->flags |= (MEM_Term|MEM_Dyn);
- }
- pMem->z = zOut;
-
-translate_out:
-#ifdef TRANSLATE_TRACE
- {
- char zBuf[100];
- sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
- fprintf(stderr, "OUTPUT: %s\n", zBuf);
- }
-#endif
- return SQLITE_OK;
-}
-
-/*
-** This routine checks for a byte-order mark at the beginning of the
-** UTF-16 string stored in *pMem. If one is present, it is removed and
-** the encoding of the Mem adjusted. This routine does not do any
-** byte-swapping, it just sets Mem.enc appropriately.
-**
-** The allocation (static, dynamic etc.) and encoding of the Mem may be
-** changed by this function.
-*/
-int sqlite3VdbeMemHandleBom(Mem *pMem){
- int rc = SQLITE_OK;
- u8 bom = 0;
-
- if( pMem->n<0 || pMem->n>1 ){
- u8 b1 = *(u8 *)pMem->z;
- u8 b2 = *(((u8 *)pMem->z) + 1);
- if( b1==0xFE && b2==0xFF ){
- bom = SQLITE_UTF16BE;
- }
- if( b1==0xFF && b2==0xFE ){
- bom = SQLITE_UTF16LE;
- }
- }
-
- if( bom ){
- /* This function is called as soon as a string is stored in a Mem*,
- ** from within sqlite3VdbeMemSetStr(). At that point it is not possible
- ** for the string to be stored in Mem.zShort, or for it to be stored
- ** in dynamic memory with no destructor.
- */
- assert( !(pMem->flags&MEM_Short) );
- assert( !(pMem->flags&MEM_Dyn) || pMem->xDel );
- if( pMem->flags & MEM_Dyn ){
- void (*xDel)(void*) = pMem->xDel;
- char *z = pMem->z;
- pMem->z = 0;
- pMem->xDel = 0;
- rc = sqlite3VdbeMemSetStr(pMem, &z[2], pMem->n-2, bom, SQLITE_TRANSIENT);
- xDel(z);
- }else{
- rc = sqlite3VdbeMemSetStr(pMem, &pMem->z[2], pMem->n-2, bom,
- SQLITE_TRANSIENT);
- }
- }
- return rc;
-}
-
-/*
-** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
-** return the number of unicode characters in pZ up to (but not including)
-** the first 0x00 byte. If nByte is not less than zero, return the
-** number of unicode characters in the first nByte of pZ (or up to
-** the first 0x00, whichever comes first).
-*/
-int sqlite3utf8CharLen(const char *z, int nByte){
- int r = 0;
- const char *zTerm;
- if( nByte>=0 ){
- zTerm = &z[nByte];
- }else{
- zTerm = (const char *)(-1);
- }
- assert( z<=zTerm );
- while( *z!=0 && z<zTerm ){
- SKIP_UTF8(z);
- r++;
- }
- return r;
-}
-
-/*
-** pZ is a UTF-16 encoded unicode string. If nChar is less than zero,
-** return the number of bytes up to (but not including), the first pair
-** of consecutive 0x00 bytes in pZ. If nChar is not less than zero,
-** then return the number of bytes in the first nChar unicode characters
-** in pZ (or up until the first pair of 0x00 bytes, whichever comes first).
-*/
-int sqlite3utf16ByteLen(const void *zIn, int nChar){
- int c = 1;
- char const *z = zIn;
- int n = 0;
- if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
- while( c && ((nChar<0) || n<nChar) ){
- READ_UTF16BE(z, c);
- n++;
- }
- }else{
- while( c && ((nChar<0) || n<nChar) ){
- READ_UTF16LE(z, c);
- n++;
- }
- }
- return (z-(char const *)zIn)-((c==0)?2:0);
-}
-
-/*
-** UTF-16 implementation of the substr()
-*/
-void sqlite3utf16Substr(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- int y, z;
- unsigned char const *zStr;
- unsigned char const *zStrEnd;
- unsigned char const *zStart;
- unsigned char const *zEnd;
- int i;
-
- zStr = (unsigned char const *)sqlite3_value_text16(argv[0]);
- zStrEnd = &zStr[sqlite3_value_bytes16(argv[0])];
- y = sqlite3_value_int(argv[1]);
- z = sqlite3_value_int(argv[2]);
-
- if( y>0 ){
- y = y-1;
- zStart = zStr;
- if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
- for(i=0; i<y && zStart<zStrEnd; i++) SKIP_UTF16BE(zStart);
- }else{
- for(i=0; i<y && zStart<zStrEnd; i++) SKIP_UTF16LE(zStart);
- }
- }else{
- zStart = zStrEnd;
- if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
- for(i=y; i<0 && zStart>zStr; i++) RSKIP_UTF16BE(zStart);
- }else{
- for(i=y; i<0 && zStart>zStr; i++) RSKIP_UTF16LE(zStart);
- }
- for(; i<0; i++) z -= 1;
- }
-
- zEnd = zStart;
- if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
- for(i=0; i<z && zEnd<zStrEnd; i++) SKIP_UTF16BE(zEnd);
- }else{
- for(i=0; i<z && zEnd<zStrEnd; i++) SKIP_UTF16LE(zEnd);
- }
-
- sqlite3_result_text16(context, zStart, zEnd-zStart, SQLITE_TRANSIENT);
-}
-
-#if defined(SQLITE_TEST)
-/*
-** This routine is called from the TCL test function "translate_selftest".
-** It checks that the primitives for serializing and deserializing
-** characters in each encoding are inverses of each other.
-*/
-void sqlite3utfSelfTest(){
- int i;
- unsigned char zBuf[20];
- unsigned char *z;
- int n;
- int c;
-
- for(i=0; i<0x00110000; i++){
- z = zBuf;
- WRITE_UTF8(z, i);
- n = z-zBuf;
- z = zBuf;
- READ_UTF8(z, c);
- assert( c==i );
- assert( (z-zBuf)==n );
- }
- for(i=0; i<0x00110000; i++){
- if( i>=0xD800 && i<=0xE000 ) continue;
- z = zBuf;
- WRITE_UTF16LE(z, i);
- n = z-zBuf;
- z = zBuf;
- READ_UTF16LE(z, c);
- assert( c==i );
- assert( (z-zBuf)==n );
- }
- for(i=0; i<0x00110000; i++){
- if( i>=0xD800 && i<=0xE000 ) continue;
- z = zBuf;
- WRITE_UTF16BE(z, i);
- n = z-zBuf;
- z = zBuf;
- READ_UTF16BE(z, c);
- assert( c==i );
- assert( (z-zBuf)==n );
- }
-}
-#endif
diff --git a/kopete/plugins/statistics/sqlite/util.c b/kopete/plugins/statistics/sqlite/util.c
deleted file mode 100644
index 74ec8979..00000000
--- a/kopete/plugins/statistics/sqlite/util.c
+++ /dev/null
@@ -1,962 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** Utility functions used throughout sqlite.
-**
-** This file contains functions for allocating memory, comparing
-** strings, and stuff like that.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-#include <stdarg.h>
-#include <ctype.h>
-
-#if SQLITE_DEBUG>2 && defined(__GLIBC__)
-#include <execinfo.h>
-void print_stack_trace(){
- void *bt[30];
- int i;
- int n = backtrace(bt, 30);
-
- sqlite3DebugPrintf("STACK: ");
- for(i=0; i<n;i++){
- sqlite3DebugPrintf("%p ", bt[i]);
- }
- sqlite3DebugPrintf("\n");
-}
-#else
-#define print_stack_trace()
-#endif
-
-/*
-** If malloc() ever fails, this global variable gets set to 1.
-** This causes the library to abort and never again function.
-*/
-int sqlite3_malloc_failed = 0;
-
-/*
-** If SQLITE_DEBUG is defined, then use versions of malloc() and
-** free() that track memory usage and check for buffer overruns.
-*/
-#ifdef SQLITE_DEBUG
-
-/*
-** For keeping track of the number of mallocs and frees. This
-** is used to check for memory leaks.
-*/
-int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
-int sqlite3_nFree; /* Number of sqliteFree() calls */
-int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
-#if SQLITE_DEBUG>1
-static int memcnt = 0;
-#endif
-
-/*
-** Number of 32-bit guard words
-*/
-#define N_GUARD 1
-
-/*
-** Allocate new memory and set it to zero. Return NULL if
-** no memory is available.
-*/
-void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
- void *p;
- int *pi;
- int i, k;
- if( sqlite3_iMallocFail>=0 ){
- sqlite3_iMallocFail--;
- if( sqlite3_iMallocFail==0 ){
- sqlite3_malloc_failed++;
-#if SQLITE_DEBUG>1
- fprintf(stderr,"**** failed to allocate %d bytes at %s:%d\n",
- n, zFile,line);
-#endif
- sqlite3_iMallocFail--;
- return 0;
- }
- }
- if( n==0 ) return 0;
- k = (n+sizeof(int)-1)/sizeof(int);
- pi = malloc( (N_GUARD*2+1+k)*sizeof(int));
- if( pi==0 ){
- sqlite3_malloc_failed++;
- return 0;
- }
- sqlite3_nMalloc++;
- for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
- pi[N_GUARD] = n;
- for(i=0; i<N_GUARD; i++) pi[k+1+N_GUARD+i] = 0xdead3344;
- p = &pi[N_GUARD+1];
- memset(p, bZero==0, n);
-#if SQLITE_DEBUG>1
- print_stack_trace();
- fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n",
- ++memcnt, n, (int)p, zFile,line);
-#endif
- return p;
-}
-
-/*
-** Check to see if the given pointer was obtained from sqliteMalloc()
-** and is able to hold at least N bytes. Raise an exception if this
-** is not the case.
-**
-** This routine is used for testing purposes only.
-*/
-void sqlite3CheckMemory(void *p, int N){
- int *pi = p;
- int n, i, k;
- pi -= N_GUARD+1;
- for(i=0; i<N_GUARD; i++){
- assert( pi[i]==0xdead1122 );
- }
- n = pi[N_GUARD];
- assert( N>=0 && N<n );
- k = (n+sizeof(int)-1)/sizeof(int);
- for(i=0; i<N_GUARD; i++){
- assert( pi[k+N_GUARD+1+i]==0xdead3344 );
- }
-}
-
-/*
-** Free memory previously obtained from sqliteMalloc()
-*/
-void sqlite3Free_(void *p, char *zFile, int line){
- if( p ){
- int *pi, i, k, n;
- pi = p;
- pi -= N_GUARD+1;
- sqlite3_nFree++;
- for(i=0; i<N_GUARD; i++){
- if( pi[i]!=0xdead1122 ){
- fprintf(stderr,"Low-end memory corruption at 0x%x\n", (int)p);
- return;
- }
- }
- n = pi[N_GUARD];
- k = (n+sizeof(int)-1)/sizeof(int);
- for(i=0; i<N_GUARD; i++){
- if( pi[k+N_GUARD+1+i]!=0xdead3344 ){
- fprintf(stderr,"High-end memory corruption at 0x%x\n", (int)p);
- return;
- }
- }
- memset(pi, 0xff, (k+N_GUARD*2+1)*sizeof(int));
-#if SQLITE_DEBUG>1
- fprintf(stderr,"%06d free %d bytes at 0x%x from %s:%d\n",
- ++memcnt, n, (int)p, zFile,line);
-#endif
- free(pi);
- }
-}
-
-/*
-** Resize a prior allocation. If p==0, then this routine
-** works just like sqliteMalloc(). If n==0, then this routine
-** works just like sqliteFree().
-*/
-void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
- int *oldPi, *pi, i, k, oldN, oldK;
- void *p;
- if( oldP==0 ){
- return sqlite3Malloc_(n,1,zFile,line);
- }
- if( n==0 ){
- sqlite3Free_(oldP,zFile,line);
- return 0;
- }
- oldPi = oldP;
- oldPi -= N_GUARD+1;
- if( oldPi[0]!=0xdead1122 ){
- fprintf(stderr,"Low-end memory corruption in realloc at 0x%x\n", (int)oldP);
- return 0;
- }
- oldN = oldPi[N_GUARD];
- oldK = (oldN+sizeof(int)-1)/sizeof(int);
- for(i=0; i<N_GUARD; i++){
- if( oldPi[oldK+N_GUARD+1+i]!=0xdead3344 ){
- fprintf(stderr,"High-end memory corruption in realloc at 0x%x\n",
- (int)oldP);
- return 0;
- }
- }
- k = (n + sizeof(int) - 1)/sizeof(int);
- pi = malloc( (k+N_GUARD*2+1)*sizeof(int) );
- if( pi==0 ){
- sqlite3_malloc_failed++;
- return 0;
- }
- for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
- pi[N_GUARD] = n;
- for(i=0; i<N_GUARD; i++) pi[k+N_GUARD+1+i] = 0xdead3344;
- p = &pi[N_GUARD+1];
- memcpy(p, oldP, n>oldN ? oldN : n);
- if( n>oldN ){
- memset(&((char*)p)[oldN], 0x55, n-oldN);
- }
- memset(oldPi, 0xab, (oldK+N_GUARD+2)*sizeof(int));
- free(oldPi);
-#if SQLITE_DEBUG>1
- print_stack_trace();
- fprintf(stderr,"%06d realloc %d to %d bytes at 0x%x to 0x%x at %s:%d\n",
- ++memcnt, oldN, n, (int)oldP, (int)p, zFile, line);
-#endif
- return p;
-}
-
-/*
-** Make a copy of a string in memory obtained from sqliteMalloc()
-*/
-char *sqlite3StrDup_(const char *z, char *zFile, int line){
- char *zNew;
- if( z==0 ) return 0;
- zNew = sqlite3Malloc_(strlen(z)+1, 0, zFile, line);
- if( zNew ) strcpy(zNew, z);
- return zNew;
-}
-char *sqlite3StrNDup_(const char *z, int n, char *zFile, int line){
- char *zNew;
- if( z==0 ) return 0;
- zNew = sqlite3Malloc_(n+1, 0, zFile, line);
- if( zNew ){
- memcpy(zNew, z, n);
- zNew[n] = 0;
- }
- return zNew;
-}
-
-/*
-** A version of sqliteFree that is always a function, not a macro.
-*/
-void sqlite3FreeX(void *p){
- sqliteFree(p);
-}
-#endif /* SQLITE_DEBUG */
-
-/*
-** The following versions of malloc() and free() are for use in a
-** normal build.
-*/
-#if !defined(SQLITE_DEBUG)
-
-/*
-** Allocate new memory and set it to zero. Return NULL if
-** no memory is available. See also sqliteMallocRaw().
-*/
-void *sqlite3Malloc(int n){
- void *p;
- if( (p = malloc(n))==0 ){
- if( n>0 ) sqlite3_malloc_failed++;
- }else{
- memset(p, 0, n);
- }
- return p;
-}
-
-/*
-** Allocate new memory but do not set it to zero. Return NULL if
-** no memory is available. See also sqliteMalloc().
-*/
-void *sqlite3MallocRaw(int n){
- void *p;
- if( (p = malloc(n))==0 ){
- if( n>0 ) sqlite3_malloc_failed++;
- }
- return p;
-}
-
-/*
-** Free memory previously obtained from sqliteMalloc()
-*/
-void sqlite3FreeX(void *p){
- if( p ){
- free(p);
- }
-}
-
-/*
-** Resize a prior allocation. If p==0, then this routine
-** works just like sqliteMalloc(). If n==0, then this routine
-** works just like sqliteFree().
-*/
-void *sqlite3Realloc(void *p, int n){
- void *p2;
- if( p==0 ){
- return sqliteMalloc(n);
- }
- if( n==0 ){
- sqliteFree(p);
- return 0;
- }
- p2 = realloc(p, n);
- if( p2==0 ){
- sqlite3_malloc_failed++;
- }
- return p2;
-}
-
-/*
-** Make a copy of a string in memory obtained from sqliteMalloc()
-*/
-char *sqlite3StrDup(const char *z){
- char *zNew;
- if( z==0 ) return 0;
- zNew = sqliteMallocRaw(strlen(z)+1);
- if( zNew ) strcpy(zNew, z);
- return zNew;
-}
-char *sqlite3StrNDup(const char *z, int n){
- char *zNew;
- if( z==0 ) return 0;
- zNew = sqliteMallocRaw(n+1);
- if( zNew ){
- memcpy(zNew, z, n);
- zNew[n] = 0;
- }
- return zNew;
-}
-#endif /* !defined(SQLITE_DEBUG) */
-
-/*
-** Create a string from the 2nd and subsequent arguments (up to the
-** first NULL argument), store the string in memory obtained from
-** sqliteMalloc() and make the pointer indicated by the 1st argument
-** point to that string. The 1st argument must either be NULL or
-** point to memory obtained from sqliteMalloc().
-*/
-void sqlite3SetString(char **pz, const char *zFirst, ...){
- va_list ap;
- int nByte;
- const char *z;
- char *zResult;
-
- if( pz==0 ) return;
- nByte = strlen(zFirst) + 1;
- va_start(ap, zFirst);
- while( (z = va_arg(ap, const char*))!=0 ){
- nByte += strlen(z);
- }
- va_end(ap);
- sqliteFree(*pz);
- *pz = zResult = sqliteMallocRaw( nByte );
- if( zResult==0 ){
- return;
- }
- strcpy(zResult, zFirst);
- zResult += strlen(zResult);
- va_start(ap, zFirst);
- while( (z = va_arg(ap, const char*))!=0 ){
- strcpy(zResult, z);
- zResult += strlen(zResult);
- }
- va_end(ap);
-#ifdef SQLITE_DEBUG
-#if SQLITE_DEBUG>1
- fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz);
-#endif
-#endif
-}
-
-/*
-** Set the most recent error code and error string for the sqlite
-** handle "db". The error code is set to "err_code".
-**
-** If it is not NULL, string zFormat specifies the format of the
-** error string in the style of the printf functions: The following
-** format characters are allowed:
-**
-** %s Insert a string
-** %z A string that should be freed after use
-** %d Insert an integer
-** %T Insert a token
-** %S Insert the first element of a SrcList
-**
-** zFormat and any string tokens that follow it are assumed to be
-** encoded in UTF-8.
-**
-** To clear the most recent error for slqite handle "db", sqlite3Error
-** should be called with err_code set to SQLITE_OK and zFormat set
-** to NULL.
-*/
-void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
- if( db && (db->pErr || (db->pErr = sqlite3ValueNew())) ){
- db->errCode = err_code;
- if( zFormat ){
- char *z;
- va_list ap;
- va_start(ap, zFormat);
- z = sqlite3VMPrintf(zFormat, ap);
- va_end(ap);
- sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, sqlite3FreeX);
- }else{
- sqlite3ValueSetStr(db->pErr, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
- }
- }
-}
-
-/*
-** Add an error message to pParse->zErrMsg and increment pParse->nErr.
-** The following formatting characters are allowed:
-**
-** %s Insert a string
-** %z A string that should be freed after use
-** %d Insert an integer
-** %T Insert a token
-** %S Insert the first element of a SrcList
-**
-** This function should be used to report any error that occurs whilst
-** compiling an SQL statement (i.e. within sqlite3_prepare()). The
-** last thing the sqlite3_prepare() function does is copy the error
-** stored by this function into the database handle using sqlite3Error().
-** Function sqlite3Error() should be used during statement execution
-** (sqlite3_step() etc.).
-*/
-void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
- va_list ap;
- pParse->nErr++;
- sqliteFree(pParse->zErrMsg);
- va_start(ap, zFormat);
- pParse->zErrMsg = sqlite3VMPrintf(zFormat, ap);
- va_end(ap);
-}
-
-/*
-** Convert an SQL-style quoted string into a normal string by removing
-** the quote characters. The conversion is done in-place. If the
-** input does not begin with a quote character, then this routine
-** is a no-op.
-**
-** 2002-Feb-14: This routine is extended to remove MS-Access style
-** brackets from around identifers. For example: "[a-b-c]" becomes
-** "a-b-c".
-*/
-void sqlite3Dequote(char *z){
- int quote;
- int i, j;
- if( z==0 ) return;
- quote = z[0];
- switch( quote ){
- case '\'': break;
- case '"': break;
- case '[': quote = ']'; break;
- default: return;
- }
- for(i=1, j=0; z[i]; i++){
- if( z[i]==quote ){
- if( z[i+1]==quote ){
- z[j++] = quote;
- i++;
- }else{
- z[j++] = 0;
- break;
- }
- }else{
- z[j++] = z[i];
- }
- }
-}
-
-/* An array to map all upper-case characters into their corresponding
-** lower-case character.
-*/
-const unsigned char sqlite3UpperToLower[] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
- 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
- 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
- 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
- 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
- 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
- 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
- 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
- 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
- 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
- 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
- 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
- 252,253,254,255
-};
-#define UpperToLower sqlite3UpperToLower
-
-/*
-** This function computes a hash on the name of a keyword.
-** Case is not significant.
-*/
-int sqlite3HashNoCase(const char *z, int n){
- int h = 0;
- if( n<=0 ) n = strlen(z);
- while( n > 0 ){
- h = (h<<3) ^ h ^ UpperToLower[(unsigned char)*z++];
- n--;
- }
- return h & 0x7fffffff;
-}
-
-/*
-** Some systems have stricmp(). Others have strcasecmp(). Because
-** there is no consistency, we will define our own.
-*/
-int sqlite3StrICmp(const char *zLeft, const char *zRight){
- register unsigned char *a, *b;
- a = (unsigned char *)zLeft;
- b = (unsigned char *)zRight;
- while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
- return UpperToLower[*a] - UpperToLower[*b];
-}
-int sqlite3StrNICmp(const char *zLeft, const char *zRight, int N){
- register unsigned char *a, *b;
- a = (unsigned char *)zLeft;
- b = (unsigned char *)zRight;
- while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
- return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
-}
-
-/*
-** Return TRUE if z is a pure numeric string. Return FALSE if the
-** string contains any character which is not part of a number. If
-** the string is numeric and contains the '.' character, set *realnum
-** to TRUE (otherwise FALSE).
-**
-** An empty string is considered non-numeric.
-*/
-int sqlite3IsNumber(const char *z, int *realnum, u8 enc){
- int incr = (enc==SQLITE_UTF8?1:2);
- if( enc==SQLITE_UTF16BE ) z++;
- if( *z=='-' || *z=='+' ) z += incr;
- if( !isdigit(*(u8*)z) ){
- return 0;
- }
- z += incr;
- if( realnum ) *realnum = 0;
- while( isdigit(*(u8*)z) ){ z += incr; }
- if( *z=='.' ){
- z += incr;
- if( !isdigit(*(u8*)z) ) return 0;
- while( isdigit(*(u8*)z) ){ z += incr; }
- if( realnum ) *realnum = 1;
- }
- if( *z=='e' || *z=='E' ){
- z += incr;
- if( *z=='+' || *z=='-' ) z += incr;
- if( !isdigit(*(u8*)z) ) return 0;
- while( isdigit(*(u8*)z) ){ z += incr; }
- if( realnum ) *realnum = 1;
- }
- return *z==0;
-}
-
-/*
-** The string z[] is an ascii representation of a real number.
-** Convert this string to a double.
-**
-** This routine assumes that z[] really is a valid number. If it
-** is not, the result is undefined.
-**
-** This routine is used instead of the library atof() function because
-** the library atof() might want to use "," as the decimal point instead
-** of "." depending on how locale is set. But that would cause problems
-** for SQL. So this routine always uses "." regardless of locale.
-*/
-double sqlite3AtoF(const char *z, const char **pzEnd){
- int sign = 1;
- LONGDOUBLE_TYPE v1 = 0.0;
- if( *z=='-' ){
- sign = -1;
- z++;
- }else if( *z=='+' ){
- z++;
- }
- while( isdigit(*(u8*)z) ){
- v1 = v1*10.0 + (*z - '0');
- z++;
- }
- if( *z=='.' ){
- LONGDOUBLE_TYPE divisor = 1.0;
- z++;
- while( isdigit(*(u8*)z) ){
- v1 = v1*10.0 + (*z - '0');
- divisor *= 10.0;
- z++;
- }
- v1 /= divisor;
- }
- if( *z=='e' || *z=='E' ){
- int esign = 1;
- int eval = 0;
- LONGDOUBLE_TYPE scale = 1.0;
- z++;
- if( *z=='-' ){
- esign = -1;
- z++;
- }else if( *z=='+' ){
- z++;
- }
- while( isdigit(*(u8*)z) ){
- eval = eval*10 + *z - '0';
- z++;
- }
- while( eval>=64 ){ scale *= 1.0e+64; eval -= 64; }
- while( eval>=16 ){ scale *= 1.0e+16; eval -= 16; }
- while( eval>=4 ){ scale *= 1.0e+4; eval -= 4; }
- while( eval>=1 ){ scale *= 1.0e+1; eval -= 1; }
- if( esign<0 ){
- v1 /= scale;
- }else{
- v1 *= scale;
- }
- }
- if( pzEnd ) *pzEnd = z;
- return sign<0 ? -v1 : v1;
-}
-
-/*
-** Return TRUE if zNum is a 64-bit signed integer and write
-** the value of the integer into *pNum. If zNum is not an integer
-** or is an integer that is too large to be expressed with 64 bits,
-** then return false. If n>0 and the integer is string is not
-** exactly n bytes long, return false.
-**
-** When this routine was originally written it dealt with only
-** 32-bit numbers. At that time, it was much faster than the
-** atoi() library routine in RedHat 7.2.
-*/
-int sqlite3atoi64(const char *zNum, i64 *pNum){
- i64 v = 0;
- int neg;
- int i, c;
- if( *zNum=='-' ){
- neg = 1;
- zNum++;
- }else if( *zNum=='+' ){
- neg = 0;
- zNum++;
- }else{
- neg = 0;
- }
- for(i=0; (c=zNum[i])>='0' && c<='9'; i++){
- v = v*10 + c - '0';
- }
- *pNum = neg ? -v : v;
- return c==0 && i>0 &&
- (i<19 || (i==19 && memcmp(zNum,"9223372036854775807",19)<=0));
-}
-
-/*
-** The string zNum represents an integer. There might be some other
-** information following the integer too, but that part is ignored.
-** If the integer that the prefix of zNum represents will fit in a
-** 32-bit signed integer, return TRUE. Otherwise return FALSE.
-**
-** This routine returns FALSE for the string -2147483648 even that
-** that number will in fact fit in a 32-bit integer. But positive
-** 2147483648 will not fit in 32 bits. So it seems safer to return
-** false.
-*/
-static int sqlite3FitsIn32Bits(const char *zNum){
- int i, c;
- if( *zNum=='-' || *zNum=='+' ) zNum++;
- for(i=0; (c=zNum[i])>='0' && c<='9'; i++){}
- return i<10 || (i==10 && memcmp(zNum,"2147483647",10)<=0);
-}
-
-/*
-** If zNum represents an integer that will fit in 32-bits, then set
-** *pValue to that integer and return true. Otherwise return false.
-*/
-int sqlite3GetInt32(const char *zNum, int *pValue){
- if( sqlite3FitsIn32Bits(zNum) ){
- *pValue = atoi(zNum);
- return 1;
- }
- return 0;
-}
-
-/*
-** The string zNum represents an integer. There might be some other
-** information following the integer too, but that part is ignored.
-** If the integer that the prefix of zNum represents will fit in a
-** 64-bit signed integer, return TRUE. Otherwise return FALSE.
-**
-** This routine returns FALSE for the string -9223372036854775808 even that
-** that number will, in theory fit in a 64-bit integer. Positive
-** 9223373036854775808 will not fit in 64 bits. So it seems safer to return
-** false.
-*/
-int sqlite3FitsIn64Bits(const char *zNum){
- int i, c;
- if( *zNum=='-' || *zNum=='+' ) zNum++;
- for(i=0; (c=zNum[i])>='0' && c<='9'; i++){}
- return i<19 || (i==19 && memcmp(zNum,"9223372036854775807",19)<=0);
-}
-
-
-/*
-** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY.
-** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN
-** when this routine is called.
-**
-** This routine is a attempt to detect if two threads use the
-** same sqlite* pointer at the same time. There is a race
-** condition so it is possible that the error is not detected.
-** But usually the problem will be seen. The result will be an
-** error which can be used to debug the application that is
-** using SQLite incorrectly.
-**
-** Ticket #202: If db->magic is not a valid open value, take care not
-** to modify the db structure at all. It could be that db is a stale
-** pointer. In other words, it could be that there has been a prior
-** call to sqlite3_close(db) and db has been deallocated. And we do
-** not want to write into deallocated memory.
-*/
-int sqlite3SafetyOn(sqlite3 *db){
- if( db->magic==SQLITE_MAGIC_OPEN ){
- db->magic = SQLITE_MAGIC_BUSY;
- return 0;
- }else if( db->magic==SQLITE_MAGIC_BUSY || db->magic==SQLITE_MAGIC_ERROR ){
- db->magic = SQLITE_MAGIC_ERROR;
- db->flags |= SQLITE_Interrupt;
- }
- return 1;
-}
-
-/*
-** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN.
-** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY
-** when this routine is called.
-*/
-int sqlite3SafetyOff(sqlite3 *db){
- if( db->magic==SQLITE_MAGIC_BUSY ){
- db->magic = SQLITE_MAGIC_OPEN;
- return 0;
- }else if( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ERROR ){
- db->magic = SQLITE_MAGIC_ERROR;
- db->flags |= SQLITE_Interrupt;
- }
- return 1;
-}
-
-/*
-** Check to make sure we have a valid db pointer. This test is not
-** foolproof but it does provide some measure of protection against
-** misuse of the interface such as passing in db pointers that are
-** NULL or which have been previously closed. If this routine returns
-** TRUE it means that the db pointer is invalid and should not be
-** dereferenced for any reason. The calling function should invoke
-** SQLITE_MISUSE immediately.
-*/
-int sqlite3SafetyCheck(sqlite3 *db){
- int magic;
- if( db==0 ) return 1;
- magic = db->magic;
- if( magic!=SQLITE_MAGIC_CLOSED &&
- magic!=SQLITE_MAGIC_OPEN &&
- magic!=SQLITE_MAGIC_BUSY ) return 1;
- return 0;
-}
-
-/*
-** The variable-length integer encoding is as follows:
-**
-** KEY:
-** A = 0xxxxxxx 7 bits of data and one flag bit
-** B = 1xxxxxxx 7 bits of data and one flag bit
-** C = xxxxxxxx 8 bits of data
-**
-** 7 bits - A
-** 14 bits - BA
-** 21 bits - BBA
-** 28 bits - BBBA
-** 35 bits - BBBBA
-** 42 bits - BBBBBA
-** 49 bits - BBBBBBA
-** 56 bits - BBBBBBBA
-** 64 bits - BBBBBBBBC
-*/
-
-/*
-** Write a 64-bit variable-length integer to memory starting at p[0].
-** The length of data write will be between 1 and 9 bytes. The number
-** of bytes written is returned.
-**
-** A variable-length integer consists of the lower 7 bits of each byte
-** for all bytes that have the 8th bit set and one byte with the 8th
-** bit clear. Except, if we get to the 9th byte, it stores the full
-** 8 bits and is the last byte.
-*/
-int sqlite3PutVarint(unsigned char *p, u64 v){
- int i, j, n;
- u8 buf[10];
- if( v & 0xff00000000000000 ){
- p[8] = v;
- v >>= 8;
- for(i=7; i>=0; i--){
- p[i] = (v & 0x7f) | 0x80;
- v >>= 7;
- }
- return 9;
- }
- n = 0;
- do{
- buf[n++] = (v & 0x7f) | 0x80;
- v >>= 7;
- }while( v!=0 );
- buf[0] &= 0x7f;
- assert( n<=9 );
- for(i=0, j=n-1; j>=0; j--, i++){
- p[i] = buf[j];
- }
- return n;
-}
-
-/*
-** Read a 64-bit variable-length integer from memory starting at p[0].
-** Return the number of bytes read. The value is stored in *v.
-*/
-int sqlite3GetVarint(const unsigned char *p, u64 *v){
- u32 x;
- u64 x64;
- int n;
- unsigned char c;
- if( ((c = p[0]) & 0x80)==0 ){
- *v = c;
- return 1;
- }
- x = c & 0x7f;
- if( ((c = p[1]) & 0x80)==0 ){
- *v = (x<<7) | c;
- return 2;
- }
- x = (x<<7) | (c&0x7f);
- if( ((c = p[2]) & 0x80)==0 ){
- *v = (x<<7) | c;
- return 3;
- }
- x = (x<<7) | (c&0x7f);
- if( ((c = p[3]) & 0x80)==0 ){
- *v = (x<<7) | c;
- return 4;
- }
- x64 = (x<<7) | (c&0x7f);
- n = 4;
- do{
- c = p[n++];
- if( n==9 ){
- x64 = (x64<<8) | c;
- break;
- }
- x64 = (x64<<7) | (c&0x7f);
- }while( (c & 0x80)!=0 );
- *v = x64;
- return n;
-}
-
-/*
-** Read a 32-bit variable-length integer from memory starting at p[0].
-** Return the number of bytes read. The value is stored in *v.
-*/
-int sqlite3GetVarint32(const unsigned char *p, u32 *v){
- u32 x;
- int n;
- unsigned char c;
- if( ((c = p[0]) & 0x80)==0 ){
- *v = c;
- return 1;
- }
- x = c & 0x7f;
- if( ((c = p[1]) & 0x80)==0 ){
- *v = (x<<7) | c;
- return 2;
- }
- x = (x<<7) | (c & 0x7f);
- n = 2;
- do{
- x = (x<<7) | ((c = p[n++])&0x7f);
- }while( (c & 0x80)!=0 && n<9 );
- *v = x;
- return n;
-}
-
-/*
-** Return the number of bytes that will be needed to store the given
-** 64-bit integer.
-*/
-int sqlite3VarintLen(u64 v){
- int i = 0;
- do{
- i++;
- v >>= 7;
- }while( v!=0 && i<9 );
- return i;
-}
-
-/*
-** Translate a single byte of Hex into an integer.
-*/
-static int hexToInt(int h){
- if( h>='0' && h<='9' ){
- return h - '0';
- }else if( h>='a' && h<='f' ){
- return h - 'a' + 10;
- }else if( h>='A' && h<='F' ){
- return h - 'A' + 10;
- }else{
- return 0;
- }
-}
-
-/*
-** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
-** value. Return a pointer to its binary value. Space to hold the
-** binary value has been obtained from malloc and must be freed by
-** the calling routine.
-*/
-void *sqlite3HexToBlob(const char *z){
- char *zBlob;
- int i;
- int n = strlen(z);
- if( n%2 ) return 0;
-
- zBlob = (char *)sqliteMalloc(n/2);
- for(i=0; i<n; i+=2){
- zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]);
- }
- return zBlob;
-}
-
-#if defined(SQLITE_TEST)
-/*
-** Convert text generated by the "%p" conversion format back into
-** a pointer.
-*/
-void *sqlite3TextToPtr(const char *z){
- void *p;
- u64 v;
- u32 v2;
- if( z[0]=='0' && z[1]=='x' ){
- z += 2;
- }
- v = 0;
- while( *z ){
- v = (v<<4) + hexToInt(*z);
- z++;
- }
- if( sizeof(p)==sizeof(v) ){
- p = *(void**)&v;
- }else{
- assert( sizeof(p)==sizeof(v2) );
- v2 = (u32)v;
- p = *(void**)&v2;
- }
- return p;
-}
-#endif
diff --git a/kopete/plugins/statistics/sqlite/vacuum.c b/kopete/plugins/statistics/sqlite/vacuum.c
deleted file mode 100644
index 371a8557..00000000
--- a/kopete/plugins/statistics/sqlite/vacuum.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
-** 2003 April 6
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains code used to implement the VACUUM command.
-**
-** Most of the code in this file may be omitted by defining the
-** SQLITE_OMIT_VACUUM macro.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-#include "os.h"
-
-#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
-/*
-** Generate a random name of 20 character in length.
-*/
-static void randomName(unsigned char *zBuf){
- static const unsigned char zChars[] =
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789";
- int i;
- sqlite3Randomness(20, zBuf);
- for(i=0; i<20; i++){
- zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
- }
-}
-
-/*
-** Execute zSql on database db. Return an error code.
-*/
-static int execSql(sqlite3 *db, const char *zSql){
- sqlite3_stmt *pStmt;
- if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
- return sqlite3_errcode(db);
- }
- while( SQLITE_ROW==sqlite3_step(pStmt) );
- return sqlite3_finalize(pStmt);
-}
-
-/*
-** Execute zSql on database db. The statement returns exactly
-** one column. Execute this as SQL on the same database.
-*/
-static int execExecSql(sqlite3 *db, const char *zSql){
- sqlite3_stmt *pStmt;
- int rc;
-
- rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
- if( rc!=SQLITE_OK ) return rc;
-
- while( SQLITE_ROW==sqlite3_step(pStmt) ){
- rc = execSql(db, sqlite3_column_text(pStmt, 0));
- if( rc!=SQLITE_OK ){
- sqlite3_finalize(pStmt);
- return rc;
- }
- }
-
- return sqlite3_finalize(pStmt);
-}
-
-#endif
-
-/*
-** The non-standard VACUUM command is used to clean up the database,
-** collapse free space, etc. It is modelled after the VACUUM command
-** in PostgreSQL.
-**
-** In version 1.0.x of SQLite, the VACUUM command would call
-** gdbm_reorganize() on all the database tables. But beginning
-** with 2.0.0, SQLite no longer uses GDBM so this command has
-** become a no-op.
-*/
-void sqlite3Vacuum(Parse *pParse, Token *pTableName){
- Vdbe *v = sqlite3GetVdbe(pParse);
- if( v ){
- sqlite3VdbeAddOp(v, OP_Vacuum, 0, 0);
- }
- return;
-}
-
-/*
-** This routine implements the OP_Vacuum opcode of the VDBE.
-*/
-int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
- int rc = SQLITE_OK; /* Return code from service routines */
-#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
- const char *zFilename; /* full pathname of the database file */
- int nFilename; /* number of characters in zFilename[] */
- char *zTemp = 0; /* a temporary file in same directory as zFilename */
- int i; /* Loop counter */
- Btree *pMain; /* The database being vacuumed */
- Btree *pTemp;
- char *zSql = 0;
-
- if( !db->autoCommit ){
- sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
- (char*)0);
- rc = SQLITE_ERROR;
- goto end_of_vacuum;
- }
-
- /* Get the full pathname of the database file and create a
- ** temporary filename in the same directory as the original file.
- */
- pMain = db->aDb[0].pBt;
- zFilename = sqlite3BtreeGetFilename(pMain);
- assert( zFilename );
- if( zFilename[0]=='\0' ){
- /* The in-memory database. Do nothing. Return directly to avoid causing
- ** an error trying to DETACH the vacuum_db (which never got attached)
- ** in the exit-handler.
- */
- return SQLITE_OK;
- }
- nFilename = strlen(zFilename);
- zTemp = sqliteMalloc( nFilename+100 );
- if( zTemp==0 ){
- rc = SQLITE_NOMEM;
- goto end_of_vacuum;
- }
- strcpy(zTemp, zFilename);
- i = 0;
- do {
- zTemp[nFilename] = '-';
- randomName((unsigned char*)&zTemp[nFilename+1]);
- } while( i<10 && sqlite3OsFileExists(zTemp) );
-
- /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
- ** can be set to 'off' for this file, as it is not recovered if a crash
- ** occurs anyway. The integrity of the database is maintained by a
- ** (possibly synchronous) transaction opened on the main database before
- ** sqlite3BtreeCopyFile() is called.
- **
- ** An optimisation would be to use a non-journaled pager.
- */
- zSql = sqlite3MPrintf("ATTACH '%q' AS vacuum_db;", zTemp);
- if( !zSql ){
- rc = SQLITE_NOMEM;
- goto end_of_vacuum;
- }
- rc = execSql(db, zSql);
- sqliteFree(zSql);
- zSql = 0;
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
- assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
- pTemp = db->aDb[db->nDb-1].pBt;
- sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
- sqlite3BtreeGetReserve(pMain));
- assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
- execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
-
- /* Begin a transaction */
- rc = execSql(db, "BEGIN;");
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
-
- /* Query the schema of the main database. Create a mirror schema
- ** in the temporary database.
- */
- rc = execExecSql(db,
- "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) "
- " FROM sqlite_master WHERE type='table' "
- "UNION ALL "
- "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000) "
- " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' "
- "UNION ALL "
- "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) "
- " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"
- "UNION ALL "
- "SELECT 'CREATE VIEW vacuum_db.' || substr(sql,13,100000000) "
- " FROM sqlite_master WHERE type='view'"
- );
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
-
- /* Loop through the tables in the main database. For each, do
- ** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy
- ** the contents to the temporary database.
- */
- rc = execExecSql(db,
- "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
- "|| ' SELECT * FROM ' || quote(name) || ';'"
- "FROM sqlite_master "
- "WHERE type = 'table';"
- );
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
-
- /* Copy the triggers from the main database to the temporary database.
- ** This was deferred before in case the triggers interfered with copying
- ** the data. It's possible the indices should be deferred until this
- ** point also.
- */
- rc = execExecSql(db,
- "SELECT 'CREATE TRIGGER vacuum_db.' || substr(sql, 16, 1000000) "
- "FROM sqlite_master WHERE type='trigger'"
- );
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
-
-
- /* At this point, unless the main db was completely empty, there is now a
- ** transaction open on the vacuum database, but not on the main database.
- ** Open a btree level transaction on the main database. This allows a
- ** call to sqlite3BtreeCopyFile(). The main database btree level
- ** transaction is then committed, so the SQL level never knows it was
- ** opened for writing. This way, the SQL transaction used to create the
- ** temporary database never needs to be committed.
- */
- if( sqlite3BtreeIsInTrans(pTemp) ){
- u32 meta;
-
- assert( 0==sqlite3BtreeIsInTrans(pMain) );
- rc = sqlite3BtreeBeginTrans(pMain, 1);
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
-
- /* Copy Btree meta values 3 and 4. These correspond to SQL layer meta
- ** values 2 and 3, the default values of a couple of pragmas.
- */
- rc = sqlite3BtreeGetMeta(pMain, 3, &meta);
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
- rc = sqlite3BtreeUpdateMeta(pTemp, 3, meta);
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
- rc = sqlite3BtreeGetMeta(pMain, 4, &meta);
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
- rc = sqlite3BtreeUpdateMeta(pTemp, 4, meta);
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
-
- rc = sqlite3BtreeCopyFile(pMain, pTemp);
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
- rc = sqlite3BtreeCommit(pMain);
- }
-
-end_of_vacuum:
- /* Currently there is an SQL level transaction open on the vacuum
- ** database. No locks are held on any other files (since the main file
- ** was committed at the btree level). So it safe to end the transaction
- ** by manually setting the autoCommit flag to true and detaching the
- ** vacuum database. The vacuum_db journal file is deleted when the pager
- ** is closed by the DETACH.
- */
- db->autoCommit = 1;
- if( rc==SQLITE_OK ){
- rc = execSql(db, "DETACH vacuum_db;");
- }else{
- execSql(db, "DETACH vacuum_db;");
- }
- if( zTemp ){
- sqlite3OsDelete(zTemp);
- sqliteFree(zTemp);
- }
- if( zSql ) sqliteFree( zSql );
- sqlite3ResetInternalSchema(db, 0);
-#endif
- return rc;
-}
diff --git a/kopete/plugins/statistics/sqlite/vdbe.c b/kopete/plugins/statistics/sqlite/vdbe.c
deleted file mode 100644
index 58f8c731..00000000
--- a/kopete/plugins/statistics/sqlite/vdbe.c
+++ /dev/null
@@ -1,4450 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** The code in this file implements execution method of the
-** Virtual Database Engine (VDBE). A separate file ("vdbeaux.c")
-** handles housekeeping details such as creating and deleting
-** VDBE instances. This file is solely interested in executing
-** the VDBE program.
-**
-** In the external interface, an "sqlite3_stmt*" is an opaque pointer
-** to a VDBE.
-**
-** The SQL parser generates a program which is then executed by
-** the VDBE to do the work of the SQL statement. VDBE programs are
-** similar in form to assembly language. The program consists of
-** a linear sequence of operations. Each operation has an opcode
-** and 3 operands. Operands P1 and P2 are integers. Operand P3
-** is a null-terminated string. The P2 operand must be non-negative.
-** Opcodes will typically ignore one or more operands. Many opcodes
-** ignore all three operands.
-**
-** Computation results are stored on a stack. Each entry on the
-** stack is either an integer, a null-terminated string, a floating point
-** number, or the SQL "NULL" value. An inplicit conversion from one
-** type to the other occurs as necessary.
-**
-** Most of the code in this file is taken up by the sqlite3VdbeExec()
-** function which does the work of interpreting a VDBE program.
-** But other routines are also provided to help in building up
-** a program instruction by instruction.
-**
-** Various scripts scan this source file in order to generate HTML
-** documentation, headers files, or other derived files. The formatting
-** of the code in this file is, therefore, important. See other comments
-** in this file for details. If in doubt, do not deviate from existing
-** commenting and indentation practices when changing or adding code.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-#include "os.h"
-#include <ctype.h>
-#include "vdbeInt.h"
-
-/*
-** The following global variable is incremented every time a cursor
-** moves, either by the OP_MoveXX, OP_Next, or OP_Prev opcodes. The test
-** procedures use this information to make sure that indices are
-** working correctly. This variable has no function other than to
-** help verify the correct operation of the library.
-*/
-int sqlite3_search_count = 0;
-
-/*
-** When this global variable is positive, it gets decremented once before
-** each instruction in the VDBE. When reaches zero, the SQLITE_Interrupt
-** of the db.flags field is set in order to simulate and interrupt.
-**
-** This facility is used for testing purposes only. It does not function
-** in an ordinary build.
-*/
-int sqlite3_interrupt_count = 0;
-
-/*
-** Release the memory associated with the given stack level. This
-** leaves the Mem.flags field in an inconsistent state.
-*/
-#define Release(P) if((P)->flags&MEM_Dyn){ sqlite3VdbeMemRelease(P); }
-
-/*
-** Convert the given stack entity into a string if it isn't one
-** already. Return non-zero if a malloc() fails.
-*/
-#define Stringify(P, enc) \
- if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc)) \
- { goto no_mem; }
-
-/*
-** Convert the given stack entity into a string that has been obtained
-** from sqliteMalloc(). This is different from Stringify() above in that
-** Stringify() will use the NBFS bytes of static string space if the string
-** will fit but this routine always mallocs for space.
-** Return non-zero if we run out of memory.
-*/
-#define Dynamicify(P,enc) sqlite3VdbeMemDynamicify(P)
-
-
-/*
-** An ephemeral string value (signified by the MEM_Ephem flag) contains
-** a pointer to a dynamically allocated string where some other entity
-** is responsible for deallocating that string. Because the stack entry
-** does not control the string, it might be deleted without the stack
-** entry knowing it.
-**
-** This routine converts an ephemeral string into a dynamically allocated
-** string that the stack entry itself controls. In other words, it
-** converts an MEM_Ephem string into an MEM_Dyn string.
-*/
-#define Deephemeralize(P) \
- if( ((P)->flags&MEM_Ephem)!=0 \
- && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
-
-/*
-** Convert the given stack entity into a integer if it isn't one
-** already.
-**
-** Any prior string or real representation is invalidated.
-** NULLs are converted into 0.
-*/
-#define Integerify(P) sqlite3VdbeMemIntegerify(P)
-
-/*
-** Convert P so that it has type MEM_Real.
-**
-** Any prior string or integer representation is invalidated.
-** NULLs are converted into 0.0.
-*/
-#define Realify(P) sqlite3VdbeMemRealify(P)
-
-/*
-** Argument pMem points at a memory cell that will be passed to a
-** user-defined function or returned to the user as the result of a query.
-** The second argument, 'db_enc' is the text encoding used by the vdbe for
-** stack variables. This routine sets the pMem->enc and pMem->type
-** variables used by the sqlite3_value_*() routines.
-*/
-#define storeTypeInfo(A,B) _storeTypeInfo(A)
-static void _storeTypeInfo(Mem *pMem){
- int flags = pMem->flags;
- if( flags & MEM_Null ){
- pMem->type = SQLITE_NULL;
- }
- else if( flags & MEM_Int ){
- pMem->type = SQLITE_INTEGER;
- }
- else if( flags & MEM_Real ){
- pMem->type = SQLITE_FLOAT;
- }
- else if( flags & MEM_Str ){
- pMem->type = SQLITE_TEXT;
- }else{
- pMem->type = SQLITE_BLOB;
- }
-}
-
-/*
-** Insert a new aggregate element and make it the element that
-** has focus.
-**
-** Return 0 on success and 1 if memory is exhausted.
-*/
-static int AggInsert(Agg *p, char *zKey, int nKey){
- AggElem *pElem;
- int i;
- int rc;
- pElem = sqliteMalloc( sizeof(AggElem) + nKey +
- (p->nMem-1)*sizeof(pElem->aMem[0]) );
- if( pElem==0 ) return SQLITE_NOMEM;
- pElem->zKey = (char*)&pElem->aMem[p->nMem];
- memcpy(pElem->zKey, zKey, nKey);
- pElem->nKey = nKey;
-
- if( p->pCsr ){
- rc = sqlite3BtreeInsert(p->pCsr, zKey, nKey, &pElem, sizeof(AggElem*));
- if( rc!=SQLITE_OK ){
- sqliteFree(pElem);
- return rc;
- }
- }
-
- for(i=0; i<p->nMem; i++){
- pElem->aMem[i].flags = MEM_Null;
- }
- p->pCurrent = pElem;
- return 0;
-}
-
-/*
-** Pop the stack N times.
-*/
-static void popStack(Mem **ppTos, int N){
- Mem *pTos = *ppTos;
- while( N>0 ){
- N--;
- Release(pTos);
- pTos--;
- }
- *ppTos = pTos;
-}
-
-/*
-** The parameters are pointers to the head of two sorted lists
-** of Sorter structures. Merge these two lists together and return
-** a single sorted list. This routine forms the core of the merge-sort
-** algorithm.
-**
-** In the case of a tie, left sorts in front of right.
-*/
-static Sorter *Merge(Sorter *pLeft, Sorter *pRight, KeyInfo *pKeyInfo){
- Sorter sHead;
- Sorter *pTail;
- pTail = &sHead;
- pTail->pNext = 0;
- while( pLeft && pRight ){
- int c = sqlite3VdbeRecordCompare(pKeyInfo, pLeft->nKey, pLeft->zKey,
- pRight->nKey, pRight->zKey);
- if( c<=0 ){
- pTail->pNext = pLeft;
- pLeft = pLeft->pNext;
- }else{
- pTail->pNext = pRight;
- pRight = pRight->pNext;
- }
- pTail = pTail->pNext;
- }
- if( pLeft ){
- pTail->pNext = pLeft;
- }else if( pRight ){
- pTail->pNext = pRight;
- }
- return sHead.pNext;
-}
-
-/*
-** Allocate cursor number iCur. Return a pointer to it. Return NULL
-** if we run out of memory.
-*/
-static Cursor *allocateCursor(Vdbe *p, int iCur){
- Cursor *pCx;
- assert( iCur<p->nCursor );
- if( p->apCsr[iCur] ){
- sqlite3VdbeFreeCursor(p->apCsr[iCur]);
- }
- p->apCsr[iCur] = pCx = sqliteMalloc( sizeof(Cursor) );
- return pCx;
-}
-
-/*
-** Apply any conversion required by the supplied column affinity to
-** memory cell pRec. affinity may be one of:
-**
-** SQLITE_AFF_NUMERIC
-** SQLITE_AFF_TEXT
-** SQLITE_AFF_NONE
-** SQLITE_AFF_INTEGER
-**
-*/
-static void applyAffinity(Mem *pRec, char affinity, u8 enc){
- if( affinity==SQLITE_AFF_NONE ){
- /* do nothing */
- }else if( affinity==SQLITE_AFF_TEXT ){
- /* Only attempt the conversion to TEXT if there is an integer or real
- ** representation (blob and NULL do not get converted) but no string
- ** representation.
- */
- if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
- sqlite3VdbeMemStringify(pRec, enc);
- }
- pRec->flags &= ~(MEM_Real|MEM_Int);
- }else{
- if( 0==(pRec->flags&(MEM_Real|MEM_Int)) ){
- /* pRec does not have a valid integer or real representation.
- ** Attempt a conversion if pRec has a string representation and
- ** it looks like a number.
- */
- int realnum;
- sqlite3VdbeMemNulTerminate(pRec);
- if( pRec->flags&MEM_Str && sqlite3IsNumber(pRec->z, &realnum, enc) ){
- if( realnum ){
- Realify(pRec);
- }else{
- Integerify(pRec);
- }
- }
- }
-
- if( affinity==SQLITE_AFF_INTEGER ){
- /* For INTEGER affinity, try to convert a real value to an int */
- if( (pRec->flags&MEM_Real) && !(pRec->flags&MEM_Int) ){
- pRec->i = pRec->r;
- if( ((double)pRec->i)==pRec->r ){
- pRec->flags |= MEM_Int;
- }
- }
- }
- }
-}
-
-#ifndef NDEBUG
-/*
-** Write a nice string representation of the contents of cell pMem
-** into buffer zBuf, length nBuf.
-*/
-void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf){
- char *zCsr = zBuf;
- int f = pMem->flags;
-
- static const char *const encnames[] = {"(X)", "(8)", "(16LE)", "(16BE)"};
-
- if( f&MEM_Blob ){
- int i;
- char c;
- if( f & MEM_Dyn ){
- c = 'z';
- assert( (f & (MEM_Static|MEM_Ephem))==0 );
- }else if( f & MEM_Static ){
- c = 't';
- assert( (f & (MEM_Dyn|MEM_Ephem))==0 );
- }else if( f & MEM_Ephem ){
- c = 'e';
- assert( (f & (MEM_Static|MEM_Dyn))==0 );
- }else{
- c = 's';
- }
-
- zCsr += sprintf(zCsr, "%c", c);
- zCsr += sprintf(zCsr, "%d[", pMem->n);
- for(i=0; i<16 && i<pMem->n; i++){
- zCsr += sprintf(zCsr, "%02X ", ((int)pMem->z[i] & 0xFF));
- }
- for(i=0; i<16 && i<pMem->n; i++){
- char z = pMem->z[i];
- if( z<32 || z>126 ) *zCsr++ = '.';
- else *zCsr++ = z;
- }
-
- zCsr += sprintf(zCsr, "]");
- *zCsr = '\0';
- }else if( f & MEM_Str ){
- int j, k;
- zBuf[0] = ' ';
- if( f & MEM_Dyn ){
- zBuf[1] = 'z';
- assert( (f & (MEM_Static|MEM_Ephem))==0 );
- }else if( f & MEM_Static ){
- zBuf[1] = 't';
- assert( (f & (MEM_Dyn|MEM_Ephem))==0 );
- }else if( f & MEM_Ephem ){
- zBuf[1] = 'e';
- assert( (f & (MEM_Static|MEM_Dyn))==0 );
- }else{
- zBuf[1] = 's';
- }
- k = 2;
- k += sprintf(&zBuf[k], "%d", pMem->n);
- zBuf[k++] = '[';
- for(j=0; j<15 && j<pMem->n; j++){
- u8 c = pMem->z[j];
- if( c>=0x20 && c<0x7f ){
- zBuf[k++] = c;
- }else{
- zBuf[k++] = '.';
- }
- }
- zBuf[k++] = ']';
- k += sprintf(&zBuf[k], encnames[pMem->enc]);
- zBuf[k++] = 0;
- }
-}
-#endif
-
-
-#ifdef VDBE_PROFILE
-/*
-** The following routine only works on pentium-class processors.
-** It uses the RDTSC opcode to read cycle count value out of the
-** processor and returns that value. This can be used for high-res
-** profiling.
-*/
-__inline__ unsigned long long int hwtime(void){
- unsigned long long int x;
- __asm__("rdtsc\n\t"
- "mov %%edx, %%ecx\n\t"
- :"=A" (x));
- return x;
-}
-#endif
-
-/*
-** The CHECK_FOR_INTERRUPT macro defined here looks to see if the
-** sqlite3_interrupt() routine has been called. If it has been, then
-** processing of the VDBE program is interrupted.
-**
-** This macro added to every instruction that does a jump in order to
-** implement a loop. This test used to be on every single instruction,
-** but that meant we more testing that we needed. By only testing the
-** flag on jump instructions, we get a (small) speed improvement.
-*/
-#define CHECK_FOR_INTERRUPT \
- if( db->flags & SQLITE_Interrupt ) goto abort_due_to_interrupt;
-
-
-/*
-** Execute as much of a VDBE program as we can then return.
-**
-** sqlite3VdbeMakeReady() must be called before this routine in order to
-** close the program with a final OP_Halt and to set up the callbacks
-** and the error message pointer.
-**
-** Whenever a row or result data is available, this routine will either
-** invoke the result callback (if there is one) or return with
-** SQLITE_ROW.
-**
-** If an attempt is made to open a locked database, then this routine
-** will either invoke the busy callback (if there is one) or it will
-** return SQLITE_BUSY.
-**
-** If an error occurs, an error message is written to memory obtained
-** from sqliteMalloc() and p->zErrMsg is made to point to that memory.
-** The error code is stored in p->rc and this routine returns SQLITE_ERROR.
-**
-** If the callback ever returns non-zero, then the program exits
-** immediately. There will be no error message but the p->rc field is
-** set to SQLITE_ABORT and this routine will return SQLITE_ERROR.
-**
-** A memory allocation error causes p->rc to be set to SQLITE_NOMEM and this
-** routine to return SQLITE_ERROR.
-**
-** Other fatal errors return SQLITE_ERROR.
-**
-** After this routine has finished, sqlite3VdbeFinalize() should be
-** used to clean up the mess that was left behind.
-*/
-int sqlite3VdbeExec(
- Vdbe *p /* The VDBE */
-){
- int pc; /* The program counter */
- Op *pOp; /* Current operation */
- int rc = SQLITE_OK; /* Value to return */
- sqlite3 *db = p->db; /* The database */
- Mem *pTos; /* Top entry in the operand stack */
- char zBuf[100]; /* Space to sprintf() an integer */
-#ifdef VDBE_PROFILE
- unsigned long long start; /* CPU clock count at start of opcode */
- int origPc; /* Program counter at start of opcode */
-#endif
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- int nProgressOps = 0; /* Opcodes executed since progress callback. */
-#endif
-
- if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
- assert( db->magic==SQLITE_MAGIC_BUSY );
- assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
- p->rc = SQLITE_OK;
- assert( p->explain==0 );
- pTos = p->pTos;
- if( sqlite3_malloc_failed ) goto no_mem;
- if( p->popStack ){
- popStack(&pTos, p->popStack);
- p->popStack = 0;
- }
- p->resOnStack = 0;
- CHECK_FOR_INTERRUPT;
- for(pc=p->pc; rc==SQLITE_OK; pc++){
- assert( pc>=0 && pc<p->nOp );
- assert( pTos<=&p->aStack[pc] );
-#ifdef VDBE_PROFILE
- origPc = pc;
- start = hwtime();
-#endif
- pOp = &p->aOp[pc];
-
- /* Only allow tracing if NDEBUG is not defined.
- */
-#ifndef NDEBUG
- if( p->trace ){
- if( pc==0 ){
- printf("VDBE Execution Trace:\n");
- sqlite3VdbePrintSql(p);
- }
- sqlite3VdbePrintOp(p->trace, pc, pOp);
- }
-#endif
-#ifdef SQLITE_TEST
- if( p->trace==0 && pc==0 && sqlite3OsFileExists("vdbe_sqltrace") ){
- sqlite3VdbePrintSql(p);
- }
-#endif
-
-
- /* Check to see if we need to simulate an interrupt. This only happens
- ** if we have a special test build.
- */
-#ifdef SQLITE_TEST
- if( sqlite3_interrupt_count>0 ){
- sqlite3_interrupt_count--;
- if( sqlite3_interrupt_count==0 ){
- sqlite3_interrupt(db);
- }
- }
-#endif
-
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- /* Call the progress callback if it is configured and the required number
- ** of VDBE ops have been executed (either since this invocation of
- ** sqlite3VdbeExec() or since last time the progress callback was called).
- ** If the progress callback returns non-zero, exit the virtual machine with
- ** a return code SQLITE_ABORT.
- */
- if( db->xProgress ){
- if( db->nProgressOps==nProgressOps ){
- if( db->xProgress(db->pProgressArg)!=0 ){
- rc = SQLITE_ABORT;
- continue; /* skip to the next iteration of the for loop */
- }
- nProgressOps = 0;
- }
- nProgressOps++;
- }
-#endif
-
- switch( pOp->opcode ){
-
-/*****************************************************************************
-** What follows is a massive switch statement where each case implements a
-** separate instruction in the virtual machine. If we follow the usual
-** indentation conventions, each case should be indented by 6 spaces. But
-** that is a lot of wasted space on the left margin. So the code within
-** the switch statement will break with convention and be flush-left. Another
-** big comment (similar to this one) will mark the point in the code where
-** we transition back to normal indentation.
-**
-** The formatting of each case is important. The makefile for SQLite
-** generates two C files "opcodes.h" and "opcodes.c" by scanning this
-** file looking for lines that begin with "case OP_". The opcodes.h files
-** will be filled with #defines that give unique integer values to each
-** opcode and the opcodes.c file is filled with an array of strings where
-** each string is the symbolic name for the corresponding opcode. If the
-** case statement is followed by a comment of the form "/# same as ... #/"
-** that comment is used to determine the particular value of the opcode.
-**
-** Documentation about VDBE opcodes is generated by scanning this file
-** for lines of that contain "Opcode:". That line and all subsequent
-** comment lines are used in the generation of the opcode.html documentation
-** file.
-**
-** SUMMARY:
-**
-** Formatting is important to scripts that scan this file.
-** Do not deviate from the formatting style currently in use.
-**
-*****************************************************************************/
-
-/* Opcode: Goto * P2 *
-**
-** An unconditional jump to address P2.
-** The next instruction executed will be
-** the one at index P2 from the beginning of
-** the program.
-*/
-case OP_Goto: {
- CHECK_FOR_INTERRUPT;
- pc = pOp->p2 - 1;
- break;
-}
-
-/* Opcode: Gosub * P2 *
-**
-** Push the current address plus 1 onto the return address stack
-** and then jump to address P2.
-**
-** The return address stack is of limited depth. If too many
-** OP_Gosub operations occur without intervening OP_Returns, then
-** the return address stack will fill up and processing will abort
-** with a fatal error.
-*/
-case OP_Gosub: {
- assert( p->returnDepth<sizeof(p->returnStack)/sizeof(p->returnStack[0]) );
- p->returnStack[p->returnDepth++] = pc+1;
- pc = pOp->p2 - 1;
- break;
-}
-
-/* Opcode: Return * * *
-**
-** Jump immediately to the next instruction after the last unreturned
-** OP_Gosub. If an OP_Return has occurred for all OP_Gosubs, then
-** processing aborts with a fatal error.
-*/
-case OP_Return: {
- assert( p->returnDepth>0 );
- p->returnDepth--;
- pc = p->returnStack[p->returnDepth] - 1;
- break;
-}
-
-/* Opcode: Halt P1 P2 *
-**
-** Exit immediately. All open cursors, Lists, Sorts, etc are closed
-** automatically.
-**
-** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(),
-** or sqlite3_finalize(). For a normal halt, this should be SQLITE_OK (0).
-** For errors, it can be some other value. If P1!=0 then P2 will determine
-** whether or not to rollback the current transaction. Do not rollback
-** if P2==OE_Fail. Do the rollback if P2==OE_Rollback. If P2==OE_Abort,
-** then back out all changes that have occurred during this execution of the
-** VDBE, but do not rollback the transaction.
-**
-** There is an implied "Halt 0 0 0" instruction inserted at the very end of
-** every program. So a jump past the last instruction of the program
-** is the same as executing Halt.
-*/
-case OP_Halt: {
- p->pTos = pTos;
- p->rc = pOp->p1;
- p->pc = pc;
- p->errorAction = pOp->p2;
- if( pOp->p3 ){
- sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0);
- }
- rc = sqlite3VdbeHalt(p);
- if( rc==SQLITE_BUSY ){
- p->rc = SQLITE_BUSY;
- return SQLITE_BUSY;
- }else if( rc!=SQLITE_OK ){
- p->rc = rc;
- }
- return p->rc ? SQLITE_ERROR : SQLITE_DONE;
-}
-
-/* Opcode: Integer P1 * P3
-**
-** The integer value P1 is pushed onto the stack. If P3 is not zero
-** then it is assumed to be a string representation of the same integer.
-** If P1 is zero and P3 is not zero, then the value is derived from P3.
-*/
-case OP_Integer: {
- pTos++;
- if( pOp->p3==0 ){
- pTos->flags = MEM_Int;
- pTos->i = pOp->p1;
- }else{
- pTos->flags = MEM_Str|MEM_Static|MEM_Term;
- pTos->z = pOp->p3;
- pTos->n = strlen(pTos->z);
- pTos->enc = SQLITE_UTF8;
- pTos->i = sqlite3VdbeIntValue(pTos);
- pTos->flags |= MEM_Int;
- }
- break;
-}
-
-/* Opcode: Real * * P3
-**
-** The string value P3 is converted to a real and pushed on to the stack.
-*/
-case OP_Real: { /* same as TK_FLOAT */
- pTos++;
- pTos->flags = MEM_Str|MEM_Static|MEM_Term;
- pTos->z = pOp->p3;
- pTos->n = strlen(pTos->z);
- pTos->enc = SQLITE_UTF8;
- pTos->r = sqlite3VdbeRealValue(pTos);
- pTos->flags |= MEM_Real;
- sqlite3VdbeChangeEncoding(pTos, db->enc);
- break;
-}
-
-/* Opcode: String8 * * P3
-**
-** P3 points to a nul terminated UTF-8 string. This opcode is transformed
-** into an OP_String before it is executed for the first time.
-*/
-case OP_String8: { /* same as TK_STRING */
- pOp->opcode = OP_String;
-
- if( db->enc!=SQLITE_UTF8 && pOp->p3 ){
- pTos++;
- sqlite3VdbeMemSetStr(pTos, pOp->p3, -1, SQLITE_UTF8, SQLITE_STATIC);
- if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pTos, db->enc) ) goto no_mem;
- if( SQLITE_OK!=sqlite3VdbeMemDynamicify(pTos) ) goto no_mem;
- pTos->flags &= ~(MEM_Dyn);
- pTos->flags |= MEM_Static;
- if( pOp->p3type==P3_DYNAMIC ){
- sqliteFree(pOp->p3);
- }
- pOp->p3type = P3_DYNAMIC;
- pOp->p3 = pTos->z;
- break;
- }
- /* Otherwise fall through to the next case, OP_String */
-}
-
-/* Opcode: String * * P3
-**
-** The string value P3 is pushed onto the stack. If P3==0 then a
-** NULL is pushed onto the stack. P3 is assumed to be a nul terminated
-** string encoded with the database native encoding.
-*/
-case OP_String: {
- pTos++;
- if( pOp->p3 ){
- pTos->flags = MEM_Str|MEM_Static|MEM_Term;
- pTos->z = pOp->p3;
- if( db->enc==SQLITE_UTF8 ){
- pTos->n = strlen(pTos->z);
- }else{
- pTos->n = sqlite3utf16ByteLen(pTos->z, -1);
- }
- pTos->enc = db->enc;
- }else{
- pTos->flags = MEM_Null;
- }
- break;
-}
-
-/* Opcode: HexBlob * * P3
-**
-** P3 is an UTF-8 SQL hex encoding of a blob. The blob is pushed onto the
-** vdbe stack.
-**
-** The first time this instruction executes, in transforms itself into a
-** 'Blob' opcode with a binary blob as P3.
-*/
-case OP_HexBlob: { /* same as TK_BLOB */
- pOp->opcode = OP_Blob;
- pOp->p1 = strlen(pOp->p3)/2;
- if( pOp->p1 ){
- char *zBlob = sqlite3HexToBlob(pOp->p3);
- if( !zBlob ) goto no_mem;
- if( pOp->p3type==P3_DYNAMIC ){
- sqliteFree(pOp->p3);
- }
- pOp->p3 = zBlob;
- pOp->p3type = P3_DYNAMIC;
- }else{
- if( pOp->p3type==P3_DYNAMIC ){
- sqliteFree(pOp->p3);
- }
- pOp->p3type = P3_STATIC;
- pOp->p3 = "";
- }
-
- /* Fall through to the next case, OP_Blob. */
-}
-
-/* Opcode: Blob P1 * P3
-**
-** P3 points to a blob of data P1 bytes long. Push this
-** value onto the stack. This instruction is not coded directly
-** by the compiler. Instead, the compiler layer specifies
-** an OP_HexBlob opcode, with the hex string representation of
-** the blob as P3. This opcode is transformed to an OP_Blob
-** before execution (within the sqlite3_prepare() function).
-*/
-case OP_Blob: {
- pTos++;
- sqlite3VdbeMemSetStr(pTos, pOp->p3, pOp->p1, 0, 0);
- break;
-}
-
-/* Opcode: Variable P1 * *
-**
-** Push the value of variable P1 onto the stack. A variable is
-** an unknown in the original SQL string as handed to sqlite3_compile().
-** Any occurance of the '?' character in the original SQL is considered
-** a variable. Variables in the SQL string are number from left to
-** right beginning with 1. The values of variables are set using the
-** sqlite3_bind() API.
-*/
-case OP_Variable: {
- int j = pOp->p1 - 1;
- assert( j>=0 && j<p->nVar );
-
- pTos++;
- sqlite3VdbeMemShallowCopy(pTos, &p->aVar[j], MEM_Static);
- break;
-}
-
-/* Opcode: Pop P1 * *
-**
-** P1 elements are popped off of the top of stack and discarded.
-*/
-case OP_Pop: {
- assert( pOp->p1>=0 );
- popStack(&pTos, pOp->p1);
- assert( pTos>=&p->aStack[-1] );
- break;
-}
-
-/* Opcode: Dup P1 P2 *
-**
-** A copy of the P1-th element of the stack
-** is made and pushed onto the top of the stack.
-** The top of the stack is element 0. So the
-** instruction "Dup 0 0 0" will make a copy of the
-** top of the stack.
-**
-** If the content of the P1-th element is a dynamically
-** allocated string, then a new copy of that string
-** is made if P2==0. If P2!=0, then just a pointer
-** to the string is copied.
-**
-** Also see the Pull instruction.
-*/
-case OP_Dup: {
- Mem *pFrom = &pTos[-pOp->p1];
- assert( pFrom<=pTos && pFrom>=p->aStack );
- pTos++;
- sqlite3VdbeMemShallowCopy(pTos, pFrom, MEM_Ephem);
- if( pOp->p2 ){
- Deephemeralize(pTos);
- }
- break;
-}
-
-/* Opcode: Pull P1 * *
-**
-** The P1-th element is removed from its current location on
-** the stack and pushed back on top of the stack. The
-** top of the stack is element 0, so "Pull 0 0 0" is
-** a no-op. "Pull 1 0 0" swaps the top two elements of
-** the stack.
-**
-** See also the Dup instruction.
-*/
-case OP_Pull: {
- Mem *pFrom = &pTos[-pOp->p1];
- int i;
- Mem ts;
-
- ts = *pFrom;
- Deephemeralize(pTos);
- for(i=0; i<pOp->p1; i++, pFrom++){
- Deephemeralize(&pFrom[1]);
- assert( (pFrom->flags & MEM_Ephem)==0 );
- *pFrom = pFrom[1];
- if( pFrom->flags & MEM_Short ){
- assert( pFrom->flags & (MEM_Str|MEM_Blob) );
- assert( pFrom->z==pFrom[1].zShort );
- pFrom->z = pFrom->zShort;
- }
- }
- *pTos = ts;
- if( pTos->flags & MEM_Short ){
- assert( pTos->flags & (MEM_Str|MEM_Blob) );
- assert( pTos->z==pTos[-pOp->p1].zShort );
- pTos->z = pTos->zShort;
- }
- break;
-}
-
-/* Opcode: Push P1 * *
-**
-** Overwrite the value of the P1-th element down on the
-** stack (P1==0 is the top of the stack) with the value
-** of the top of the stack. Then pop the top of the stack.
-*/
-case OP_Push: {
- Mem *pTo = &pTos[-pOp->p1];
-
- assert( pTo>=p->aStack );
- sqlite3VdbeMemMove(pTo, pTos);
- pTos--;
- break;
-}
-
-/* Opcode: Callback P1 * *
-**
-** Pop P1 values off the stack and form them into an array. Then
-** invoke the callback function using the newly formed array as the
-** 3rd parameter.
-*/
-case OP_Callback: {
- int i;
- assert( p->nResColumn==pOp->p1 );
-
- for(i=0; i<pOp->p1; i++){
- Mem *pVal = &pTos[0-i];
- sqlite3VdbeMemNulTerminate(pVal);
- storeTypeInfo(pVal, db->enc);
- }
-
- p->resOnStack = 1;
- p->nCallback++;
- p->popStack = pOp->p1;
- p->pc = pc + 1;
- p->pTos = pTos;
- return SQLITE_ROW;
-}
-
-/* Opcode: Concat P1 P2 *
-**
-** Look at the first P1+2 elements of the stack. Append them all
-** together with the lowest element first. The original P1+2 elements
-** are popped from the stack if P2==0 and retained if P2==1. If
-** any element of the stack is NULL, then the result is NULL.
-**
-** When P1==1, this routine makes a copy of the top stack element
-** into memory obtained from sqliteMalloc().
-*/
-case OP_Concat: { /* same as TK_CONCAT */
- char *zNew;
- int nByte;
- int nField;
- int i, j;
- Mem *pTerm;
-
- /* Loop through the stack elements to see how long the result will be. */
- nField = pOp->p1 + 2;
- pTerm = &pTos[1-nField];
- nByte = 0;
- for(i=0; i<nField; i++, pTerm++){
- assert( pOp->p2==0 || (pTerm->flags&MEM_Str) );
- if( pTerm->flags&MEM_Null ){
- nByte = -1;
- break;
- }
- Stringify(pTerm, db->enc);
- nByte += pTerm->n;
- }
-
- if( nByte<0 ){
- /* If nByte is less than zero, then there is a NULL value on the stack.
- ** In this case just pop the values off the stack (if required) and
- ** push on a NULL.
- */
- if( pOp->p2==0 ){
- popStack(&pTos, nField);
- }
- pTos++;
- pTos->flags = MEM_Null;
- }else{
- /* Otherwise malloc() space for the result and concatenate all the
- ** stack values.
- */
- zNew = sqliteMallocRaw( nByte+2 );
- if( zNew==0 ) goto no_mem;
- j = 0;
- pTerm = &pTos[1-nField];
- for(i=j=0; i<nField; i++, pTerm++){
- int n = pTerm->n;
- assert( pTerm->flags & MEM_Str );
- memcpy(&zNew[j], pTerm->z, n);
- j += n;
- }
- zNew[j] = 0;
- zNew[j+1] = 0;
- assert( j==nByte );
-
- if( pOp->p2==0 ){
- popStack(&pTos, nField);
- }
- pTos++;
- pTos->n = j;
- pTos->flags = MEM_Str|MEM_Dyn|MEM_Term;
- pTos->xDel = 0;
- pTos->enc = db->enc;
- pTos->z = zNew;
- }
- break;
-}
-
-/* Opcode: Add * * *
-**
-** Pop the top two elements from the stack, add them together,
-** and push the result back onto the stack. If either element
-** is a string then it is converted to a double using the atof()
-** function before the addition.
-** If either operand is NULL, the result is NULL.
-*/
-/* Opcode: Multiply * * *
-**
-** Pop the top two elements from the stack, multiply them together,
-** and push the result back onto the stack. If either element
-** is a string then it is converted to a double using the atof()
-** function before the multiplication.
-** If either operand is NULL, the result is NULL.
-*/
-/* Opcode: Subtract * * *
-**
-** Pop the top two elements from the stack, subtract the
-** first (what was on top of the stack) from the second (the
-** next on stack)
-** and push the result back onto the stack. If either element
-** is a string then it is converted to a double using the atof()
-** function before the subtraction.
-** If either operand is NULL, the result is NULL.
-*/
-/* Opcode: Divide * * *
-**
-** Pop the top two elements from the stack, divide the
-** first (what was on top of the stack) from the second (the
-** next on stack)
-** and push the result back onto the stack. If either element
-** is a string then it is converted to a double using the atof()
-** function before the division. Division by zero returns NULL.
-** If either operand is NULL, the result is NULL.
-*/
-/* Opcode: Remainder * * *
-**
-** Pop the top two elements from the stack, divide the
-** first (what was on top of the stack) from the second (the
-** next on stack)
-** and push the remainder after division onto the stack. If either element
-** is a string then it is converted to a double using the atof()
-** function before the division. Division by zero returns NULL.
-** If either operand is NULL, the result is NULL.
-*/
-case OP_Add: /* same as TK_PLUS */
-case OP_Subtract: /* same as TK_MINUS */
-case OP_Multiply: /* same as TK_STAR */
-case OP_Divide: /* same as TK_SLASH */
-case OP_Remainder: { /* same as TK_REM */
- Mem *pNos = &pTos[-1];
- assert( pNos>=p->aStack );
- if( ((pTos->flags | pNos->flags) & MEM_Null)!=0 ){
- Release(pTos);
- pTos--;
- Release(pTos);
- pTos->flags = MEM_Null;
- }else if( (pTos->flags & pNos->flags & MEM_Int)==MEM_Int ){
- i64 a, b;
- a = pTos->i;
- b = pNos->i;
- switch( pOp->opcode ){
- case OP_Add: b += a; break;
- case OP_Subtract: b -= a; break;
- case OP_Multiply: b *= a; break;
- case OP_Divide: {
- if( a==0 ) goto divide_by_zero;
- b /= a;
- break;
- }
- default: {
- if( a==0 ) goto divide_by_zero;
- b %= a;
- break;
- }
- }
- Release(pTos);
- pTos--;
- Release(pTos);
- pTos->i = b;
- pTos->flags = MEM_Int;
- }else{
- double a, b;
- a = sqlite3VdbeRealValue(pTos);
- b = sqlite3VdbeRealValue(pNos);
- switch( pOp->opcode ){
- case OP_Add: b += a; break;
- case OP_Subtract: b -= a; break;
- case OP_Multiply: b *= a; break;
- case OP_Divide: {
- if( a==0.0 ) goto divide_by_zero;
- b /= a;
- break;
- }
- default: {
- int ia = (int)a;
- int ib = (int)b;
- if( ia==0.0 ) goto divide_by_zero;
- b = ib % ia;
- break;
- }
- }
- Release(pTos);
- pTos--;
- Release(pTos);
- pTos->r = b;
- pTos->flags = MEM_Real;
- }
- break;
-
-divide_by_zero:
- Release(pTos);
- pTos--;
- Release(pTos);
- pTos->flags = MEM_Null;
- break;
-}
-
-/* Opcode: CollSeq * * P3
-**
-** P3 is a pointer to a CollSeq struct. If the next call to a user function
-** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
-** be returned. This is used by the built-in min(), max() and nullif()
-** built-in functions.
-**
-** The interface used by the implementation of the aforementioned functions
-** to retrieve the collation sequence set by this opcode is not available
-** publicly, only to user functions defined in func.c.
-*/
-case OP_CollSeq: {
- assert( pOp->p3type==P3_COLLSEQ );
- break;
-}
-
-/* Opcode: Function P1 P2 P3
-**
-** Invoke a user function (P3 is a pointer to a Function structure that
-** defines the function) with P1 arguments taken from the stack. Pop all
-** arguments from the stack and push back the result.
-**
-** P2 is a 32-bit bitmask indicating whether or not each argument to the
-** function was determined to be constant at compile time. If the first
-** argument was constant then bit 0 of P2 is set. This is used to determine
-** whether meta data associated with a user function argument using the
-** sqlite3_set_auxdata() API may be safely retained until the next
-** invocation of this opcode.
-**
-** See also: AggFunc
-*/
-case OP_Function: {
- int i;
- Mem *pArg;
- sqlite3_context ctx;
- sqlite3_value **apVal;
- int n = pOp->p1;
-
- n = pOp->p1;
- apVal = p->apArg;
- assert( apVal || n==0 );
-
- pArg = &pTos[1-n];
- for(i=0; i<n; i++, pArg++){
- apVal[i] = pArg;
- storeTypeInfo(pArg, db->enc);
- }
-
- assert( pOp->p3type==P3_FUNCDEF || pOp->p3type==P3_VDBEFUNC );
- if( pOp->p3type==P3_FUNCDEF ){
- ctx.pFunc = (FuncDef*)pOp->p3;
- ctx.pVdbeFunc = 0;
- }else{
- ctx.pVdbeFunc = (VdbeFunc*)pOp->p3;
- ctx.pFunc = ctx.pVdbeFunc->pFunc;
- }
-
- ctx.s.flags = MEM_Null;
- ctx.s.z = 0;
- ctx.s.xDel = 0;
- ctx.isError = 0;
- ctx.isStep = 0;
- if( ctx.pFunc->needCollSeq ){
- assert( pOp>p->aOp );
- assert( pOp[-1].p3type==P3_COLLSEQ );
- assert( pOp[-1].opcode==OP_CollSeq );
- ctx.pColl = (CollSeq *)pOp[-1].p3;
- }
- if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
- (*ctx.pFunc->xFunc)(&ctx, n, apVal);
- if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
- if( sqlite3_malloc_failed ) goto no_mem;
- popStack(&pTos, n);
-
- /* If any auxilary data functions have been called by this user function,
- ** immediately call the destructor for any non-static values.
- */
- if( ctx.pVdbeFunc ){
- sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p2);
- pOp->p3 = (char *)ctx.pVdbeFunc;
- pOp->p3type = P3_VDBEFUNC;
- }
-
- /* Copy the result of the function to the top of the stack */
- sqlite3VdbeChangeEncoding(&ctx.s, db->enc);
- pTos++;
- pTos->flags = 0;
- sqlite3VdbeMemMove(pTos, &ctx.s);
-
- /* If the function returned an error, throw an exception */
- if( ctx.isError ){
- if( !(pTos->flags&MEM_Str) ){
- sqlite3SetString(&p->zErrMsg, "user function error", (char*)0);
- }else{
- sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pTos), (char*)0);
- sqlite3VdbeChangeEncoding(pTos, db->enc);
- }
- rc = SQLITE_ERROR;
- }
- break;
-}
-
-/* Opcode: BitAnd * * *
-**
-** Pop the top two elements from the stack. Convert both elements
-** to integers. Push back onto the stack the bit-wise AND of the
-** two elements.
-** If either operand is NULL, the result is NULL.
-*/
-/* Opcode: BitOr * * *
-**
-** Pop the top two elements from the stack. Convert both elements
-** to integers. Push back onto the stack the bit-wise OR of the
-** two elements.
-** If either operand is NULL, the result is NULL.
-*/
-/* Opcode: ShiftLeft * * *
-**
-** Pop the top two elements from the stack. Convert both elements
-** to integers. Push back onto the stack the second element shifted
-** left by N bits where N is the top element on the stack.
-** If either operand is NULL, the result is NULL.
-*/
-/* Opcode: ShiftRight * * *
-**
-** Pop the top two elements from the stack. Convert both elements
-** to integers. Push back onto the stack the second element shifted
-** right by N bits where N is the top element on the stack.
-** If either operand is NULL, the result is NULL.
-*/
-case OP_BitAnd: /* same as TK_BITAND */
-case OP_BitOr: /* same as TK_BITOR */
-case OP_ShiftLeft: /* same as TK_LSHIFT */
-case OP_ShiftRight: { /* same as TK_RSHIFT */
- Mem *pNos = &pTos[-1];
- int a, b;
-
- assert( pNos>=p->aStack );
- if( (pTos->flags | pNos->flags) & MEM_Null ){
- popStack(&pTos, 2);
- pTos++;
- pTos->flags = MEM_Null;
- break;
- }
- a = sqlite3VdbeIntValue(pNos);
- b = sqlite3VdbeIntValue(pTos);
- switch( pOp->opcode ){
- case OP_BitAnd: a &= b; break;
- case OP_BitOr: a |= b; break;
- case OP_ShiftLeft: a <<= b; break;
- case OP_ShiftRight: a >>= b; break;
- default: /* CANT HAPPEN */ break;
- }
- Release(pTos);
- pTos--;
- Release(pTos);
- pTos->i = a;
- pTos->flags = MEM_Int;
- break;
-}
-
-/* Opcode: AddImm P1 * *
-**
-** Add the value P1 to whatever is on top of the stack. The result
-** is always an integer.
-**
-** To force the top of the stack to be an integer, just add 0.
-*/
-case OP_AddImm: {
- assert( pTos>=p->aStack );
- Integerify(pTos);
- pTos->i += pOp->p1;
- break;
-}
-
-/* Opcode: ForceInt P1 P2 *
-**
-** Convert the top of the stack into an integer. If the current top of
-** the stack is not numeric (meaning that is is a NULL or a string that
-** does not look like an integer or floating point number) then pop the
-** stack and jump to P2. If the top of the stack is numeric then
-** convert it into the least integer that is greater than or equal to its
-** current value if P1==0, or to the least integer that is strictly
-** greater than its current value if P1==1.
-*/
-case OP_ForceInt: {
- int v;
- assert( pTos>=p->aStack );
- applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
- if( (pTos->flags & (MEM_Int|MEM_Real))==0 ){
- Release(pTos);
- pTos--;
- pc = pOp->p2 - 1;
- break;
- }
- if( pTos->flags & MEM_Int ){
- v = pTos->i + (pOp->p1!=0);
- }else{
- Realify(pTos);
- v = (int)pTos->r;
- if( pTos->r>(double)v ) v++;
- if( pOp->p1 && pTos->r==(double)v ) v++;
- }
- Release(pTos);
- pTos->i = v;
- pTos->flags = MEM_Int;
- break;
-}
-
-/* Opcode: MustBeInt P1 P2 *
-**
-** Force the top of the stack to be an integer. If the top of the
-** stack is not an integer and cannot be converted into an integer
-** with out data loss, then jump immediately to P2, or if P2==0
-** raise an SQLITE_MISMATCH exception.
-**
-** If the top of the stack is not an integer and P2 is not zero and
-** P1 is 1, then the stack is popped. In all other cases, the depth
-** of the stack is unchanged.
-*/
-case OP_MustBeInt: {
- assert( pTos>=p->aStack );
- applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
- if( (pTos->flags & MEM_Int)==0 ){
- if( pOp->p2==0 ){
- rc = SQLITE_MISMATCH;
- goto abort_due_to_error;
- }else{
- if( pOp->p1 ) popStack(&pTos, 1);
- pc = pOp->p2 - 1;
- }
- }else{
- Release(pTos);
- pTos->flags = MEM_Int;
- }
- break;
-}
-
-/* Opcode: Eq P1 P2 P3
-**
-** Pop the top two elements from the stack. If they are equal, then
-** jump to instruction P2. Otherwise, continue to the next instruction.
-**
-** The least significant byte of P1 may be either 0x00 or 0x01. If either
-** operand is NULL (and thus if the result is unknown) then take the jump
-** only if the least significant byte of P1 is 0x01.
-**
-** The second least significant byte of P1 must be an affinity character -
-** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values
-** according to the affinity before the comparison is made. If the byte is
-** 0x00, then numeric affinity is used.
-**
-** Once any conversions have taken place, and neither value is NULL,
-** the values are compared. If both values are blobs, or both are text,
-** then memcmp() is used to determine the results of the comparison. If
-** both values are numeric, then a numeric comparison is used. If the
-** two values are of different types, then they are inequal.
-**
-** If P2 is zero, do not jump. Instead, push an integer 1 onto the
-** stack if the jump would have been taken, or a 0 if not. Push a
-** NULL if either operand was NULL.
-**
-** If P3 is not NULL it is a pointer to a collating sequence (a CollSeq
-** structure) that defines how to compare text.
-*/
-/* Opcode: Ne P1 P2 P3
-**
-** This works just like the Eq opcode except that the jump is taken if
-** the operands from the stack are not equal. See the Eq opcode for
-** additional information.
-*/
-/* Opcode: Lt P1 P2 P3
-**
-** This works just like the Eq opcode except that the jump is taken if
-** the 2nd element down on the stack is less than the top of the stack.
-** See the Eq opcode for additional information.
-*/
-/* Opcode: Le P1 P2 P3
-**
-** This works just like the Eq opcode except that the jump is taken if
-** the 2nd element down on the stack is less than or equal to the
-** top of the stack. See the Eq opcode for additional information.
-*/
-/* Opcode: Gt P1 P2 P3
-**
-** This works just like the Eq opcode except that the jump is taken if
-** the 2nd element down on the stack is greater than the top of the stack.
-** See the Eq opcode for additional information.
-*/
-/* Opcode: Ge P1 P2 P3
-**
-** This works just like the Eq opcode except that the jump is taken if
-** the 2nd element down on the stack is greater than or equal to the
-** top of the stack. See the Eq opcode for additional information.
-*/
-case OP_Eq: /* same as TK_EQ */
-case OP_Ne: /* same as TK_NE */
-case OP_Lt: /* same as TK_LT */
-case OP_Le: /* same as TK_LE */
-case OP_Gt: /* same as TK_GT */
-case OP_Ge: { /* same as TK_GE */
- Mem *pNos;
- int flags;
- int res;
- char affinity;
-
- pNos = &pTos[-1];
- flags = pTos->flags|pNos->flags;
-
- /* If either value is a NULL P2 is not zero, take the jump if the least
- ** significant byte of P1 is true. If P2 is zero, then push a NULL onto
- ** the stack.
- */
- if( flags&MEM_Null ){
- popStack(&pTos, 2);
- if( pOp->p2 ){
- if( (pOp->p1&0xFF) ) pc = pOp->p2-1;
- }else{
- pTos++;
- pTos->flags = MEM_Null;
- }
- break;
- }
-
- affinity = (pOp->p1>>8)&0xFF;
- if( affinity ){
- applyAffinity(pNos, affinity, db->enc);
- applyAffinity(pTos, affinity, db->enc);
- }
-
- assert( pOp->p3type==P3_COLLSEQ || pOp->p3==0 );
- res = sqlite3MemCompare(pNos, pTos, (CollSeq*)pOp->p3);
- switch( pOp->opcode ){
- case OP_Eq: res = res==0; break;
- case OP_Ne: res = res!=0; break;
- case OP_Lt: res = res<0; break;
- case OP_Le: res = res<=0; break;
- case OP_Gt: res = res>0; break;
- default: res = res>=0; break;
- }
-
- popStack(&pTos, 2);
- if( pOp->p2 ){
- if( res ){
- pc = pOp->p2-1;
- }
- }else{
- pTos++;
- pTos->flags = MEM_Int;
- pTos->i = res;
- }
- break;
-}
-
-/* Opcode: And * * *
-**
-** Pop two values off the stack. Take the logical AND of the
-** two values and push the resulting boolean value back onto the
-** stack.
-*/
-/* Opcode: Or * * *
-**
-** Pop two values off the stack. Take the logical OR of the
-** two values and push the resulting boolean value back onto the
-** stack.
-*/
-case OP_And: /* same as TK_AND */
-case OP_Or: { /* same as TK_OR */
- Mem *pNos = &pTos[-1];
- int v1, v2; /* 0==TRUE, 1==FALSE, 2==UNKNOWN or NULL */
-
- assert( pNos>=p->aStack );
- if( pTos->flags & MEM_Null ){
- v1 = 2;
- }else{
- Integerify(pTos);
- v1 = pTos->i==0;
- }
- if( pNos->flags & MEM_Null ){
- v2 = 2;
- }else{
- Integerify(pNos);
- v2 = pNos->i==0;
- }
- if( pOp->opcode==OP_And ){
- static const unsigned char and_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 };
- v1 = and_logic[v1*3+v2];
- }else{
- static const unsigned char or_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 };
- v1 = or_logic[v1*3+v2];
- }
- popStack(&pTos, 2);
- pTos++;
- if( v1==2 ){
- pTos->flags = MEM_Null;
- }else{
- pTos->i = v1==0;
- pTos->flags = MEM_Int;
- }
- break;
-}
-
-/* Opcode: Negative * * *
-**
-** Treat the top of the stack as a numeric quantity. Replace it
-** with its additive inverse. If the top of the stack is NULL
-** its value is unchanged.
-*/
-/* Opcode: AbsValue * * *
-**
-** Treat the top of the stack as a numeric quantity. Replace it
-** with its absolute value. If the top of the stack is NULL
-** its value is unchanged.
-*/
-case OP_Negative: /* same as TK_UMINUS */
-case OP_AbsValue: {
- assert( pTos>=p->aStack );
- if( pTos->flags & MEM_Real ){
- Release(pTos);
- if( pOp->opcode==OP_Negative || pTos->r<0.0 ){
- pTos->r = -pTos->r;
- }
- pTos->flags = MEM_Real;
- }else if( pTos->flags & MEM_Int ){
- Release(pTos);
- if( pOp->opcode==OP_Negative || pTos->i<0 ){
- pTos->i = -pTos->i;
- }
- pTos->flags = MEM_Int;
- }else if( pTos->flags & MEM_Null ){
- /* Do nothing */
- }else{
- Realify(pTos);
- if( pOp->opcode==OP_Negative || pTos->r<0.0 ){
- pTos->r = -pTos->r;
- }
- pTos->flags = MEM_Real;
- }
- break;
-}
-
-/* Opcode: Not * * *
-**
-** Interpret the top of the stack as a boolean value. Replace it
-** with its complement. If the top of the stack is NULL its value
-** is unchanged.
-*/
-case OP_Not: { /* same as TK_NOT */
- assert( pTos>=p->aStack );
- if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
- Integerify(pTos);
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos->i = !pTos->i;
- pTos->flags = MEM_Int;
- break;
-}
-
-/* Opcode: BitNot * * *
-**
-** Interpret the top of the stack as an value. Replace it
-** with its ones-complement. If the top of the stack is NULL its
-** value is unchanged.
-*/
-case OP_BitNot: { /* same as TK_BITNOT */
- assert( pTos>=p->aStack );
- if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
- Integerify(pTos);
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos->i = ~pTos->i;
- pTos->flags = MEM_Int;
- break;
-}
-
-/* Opcode: Noop * * *
-**
-** Do nothing. This instruction is often useful as a jump
-** destination.
-*/
-case OP_Noop: {
- break;
-}
-
-/* Opcode: If P1 P2 *
-**
-** Pop a single boolean from the stack. If the boolean popped is
-** true, then jump to p2. Otherwise continue to the next instruction.
-** An integer is false if zero and true otherwise. A string is
-** false if it has zero length and true otherwise.
-**
-** If the value popped of the stack is NULL, then take the jump if P1
-** is true and fall through if P1 is false.
-*/
-/* Opcode: IfNot P1 P2 *
-**
-** Pop a single boolean from the stack. If the boolean popped is
-** false, then jump to p2. Otherwise continue to the next instruction.
-** An integer is false if zero and true otherwise. A string is
-** false if it has zero length and true otherwise.
-**
-** If the value popped of the stack is NULL, then take the jump if P1
-** is true and fall through if P1 is false.
-*/
-case OP_If:
-case OP_IfNot: {
- int c;
- assert( pTos>=p->aStack );
- if( pTos->flags & MEM_Null ){
- c = pOp->p1;
- }else{
- c = sqlite3VdbeIntValue(pTos);
- if( pOp->opcode==OP_IfNot ) c = !c;
- }
- Release(pTos);
- pTos--;
- if( c ) pc = pOp->p2-1;
- break;
-}
-
-/* Opcode: IsNull P1 P2 *
-**
-** If any of the top abs(P1) values on the stack are NULL, then jump
-** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack
-** unchanged.
-*/
-case OP_IsNull: { /* same as TK_ISNULL */
- int i, cnt;
- Mem *pTerm;
- cnt = pOp->p1;
- if( cnt<0 ) cnt = -cnt;
- pTerm = &pTos[1-cnt];
- assert( pTerm>=p->aStack );
- for(i=0; i<cnt; i++, pTerm++){
- if( pTerm->flags & MEM_Null ){
- pc = pOp->p2-1;
- break;
- }
- }
- if( pOp->p1>0 ) popStack(&pTos, cnt);
- break;
-}
-
-/* Opcode: NotNull P1 P2 *
-**
-** Jump to P2 if the top P1 values on the stack are all not NULL. Pop the
-** stack if P1 times if P1 is greater than zero. If P1 is less than
-** zero then leave the stack unchanged.
-*/
-case OP_NotNull: { /* same as TK_NOTNULL */
- int i, cnt;
- cnt = pOp->p1;
- if( cnt<0 ) cnt = -cnt;
- assert( &pTos[1-cnt] >= p->aStack );
- for(i=0; i<cnt && (pTos[1+i-cnt].flags & MEM_Null)==0; i++){}
- if( i>=cnt ) pc = pOp->p2-1;
- if( pOp->p1>0 ) popStack(&pTos, cnt);
- break;
-}
-
-/* Opcode: SetNumColumns P1 P2 *
-**
-** Before the OP_Column opcode can be executed on a cursor, this
-** opcode must be called to set the number of fields in the table.
-**
-** This opcode sets the number of columns for cursor P1 to P2.
-*/
-case OP_SetNumColumns: {
- assert( (pOp->p1)<p->nCursor );
- assert( p->apCsr[pOp->p1]!=0 );
- p->apCsr[pOp->p1]->nField = pOp->p2;
- break;
-}
-
-/* Opcode: IdxColumn P1 * *
-**
-** P1 is a cursor opened on an index. Push the first field from the
-** current index key onto the stack.
-*/
-/* Opcode: Column P1 P2 *
-**
-** Interpret the data that cursor P1 points to as a structure built using
-** the MakeRecord instruction. (See the MakeRecord opcode for additional
-** information about the format of the data.) Push onto the stack the value
-** of the P2-th column contained in the data.
-**
-** If the KeyAsData opcode has previously executed on this cursor, then the
-** field might be extracted from the key rather than the data.
-**
-** If P1 is negative, then the record is stored on the stack rather than in
-** a table. For P1==-1, the top of the stack is used. For P1==-2, the
-** next on the stack is used. And so forth. The value pushed is always
-** just a pointer into the record which is stored further down on the
-** stack. The column value is not copied. The number of columns in the
-** record is stored on the stack just above the record itself.
-*/
-case OP_IdxColumn:
-case OP_Column: {
- u32 payloadSize; /* Number of bytes in the record */
- int p1 = pOp->p1; /* P1 value of the opcode */
- int p2 = pOp->p2; /* column number to retrieve */
- Cursor *pC = 0; /* The VDBE cursor */
- char *zRec; /* Pointer to complete record-data */
- BtCursor *pCrsr; /* The BTree cursor */
- u32 *aType; /* aType[i] holds the numeric type of the i-th column */
- u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
- u32 nField; /* number of fields in the record */
- u32 szHdr; /* Number of bytes in the record header */
- int len; /* The length of the serialized data for the column */
- int offset = 0; /* Offset into the data */
- int idx; /* Index into the header */
- int i; /* Loop counter */
- char *zData; /* Part of the record being decoded */
- Mem sMem; /* For storing the record being decoded */
-
- sMem.flags = 0;
- assert( p1<p->nCursor );
- pTos++;
- pTos->flags = MEM_Null;
-
- /* This block sets the variable payloadSize to be the total number of
- ** bytes in the record.
- **
- ** zRec is set to be the complete text of the record if it is available.
- ** The complete record text is always available for pseudo-tables and
- ** when we are decoded a record from the stack. If the record is stored
- ** in a cursor, the complete record text might be available in the
- ** pC->aRow cache. Or it might not be. If the data is unavailable,
- ** zRec is set to NULL.
- **
- ** We also compute the number of columns in the record. For cursors,
- ** the number of columns is stored in the Cursor.nField element. For
- ** records on the stack, the next entry down on the stack is an integer
- ** which is the number of records.
- */
- assert( p1<0 || p->apCsr[p1]!=0 );
- if( p1<0 ){
- /* Take the record off of the stack */
- Mem *pRec = &pTos[p1];
- Mem *pCnt = &pRec[-1];
- assert( pRec>=p->aStack );
- assert( pRec->flags & MEM_Blob );
- payloadSize = pRec->n;
- zRec = pRec->z;
- assert( pCnt>=p->aStack );
- assert( pCnt->flags & MEM_Int );
- nField = pCnt->i;
- pCrsr = 0;
- }else if( (pC = p->apCsr[p1])->pCursor!=0 ){
- /* The record is stored in a B-Tree */
- sqlite3VdbeCursorMoveto(pC);
- zRec = 0;
- pCrsr = pC->pCursor;
- if( pC->nullRow ){
- payloadSize = 0;
- }else if( pC->cacheValid ){
- payloadSize = pC->payloadSize;
- zRec = pC->aRow;
- }else if( pC->keyAsData ){
- i64 payloadSize64;
- sqlite3BtreeKeySize(pCrsr, &payloadSize64);
- payloadSize = payloadSize64;
- }else{
- sqlite3BtreeDataSize(pCrsr, &payloadSize);
- }
- nField = pC->nField;
- }else if( pC->pseudoTable ){
- /* The record is the sole entry of a pseudo-table */
- payloadSize = pC->nData;
- zRec = pC->pData;
- pC->cacheValid = 0;
- assert( payloadSize==0 || zRec!=0 );
- nField = pC->nField;
- pCrsr = 0;
- }else{
- zRec = 0;
- payloadSize = 0;
- pCrsr = 0;
- nField = 0;
- }
-
- /* If payloadSize is 0, then just push a NULL onto the stack. */
- if( payloadSize==0 ){
- pTos->flags = MEM_Null;
- break;
- }
-
- assert( p2<nField );
-
- /* Read and parse the table header. Store the results of the parse
- ** into the record header cache fields of the cursor.
- */
- if( pC && pC->cacheValid ){
- aType = pC->aType;
- aOffset = pC->aOffset;
- }else{
- int avail; /* Number of bytes of available data */
- if( pC && pC->aType ){
- aType = pC->aType;
- }else{
- aType = sqliteMallocRaw( 2*nField*sizeof(aType) );
- }
- aOffset = &aType[nField];
- if( aType==0 ){
- goto no_mem;
- }
-
- /* Figure out how many bytes are in the header */
- if( zRec ){
- zData = zRec;
- }else{
- if( pC->keyAsData ){
- zData = (char*)sqlite3BtreeKeyFetch(pCrsr, &avail);
- }else{
- zData = (char*)sqlite3BtreeDataFetch(pCrsr, &avail);
- }
- /* If KeyFetch()/DataFetch() managed to get the entire payload,
- ** save the payload in the pC->aRow cache. That will save us from
- ** having to make additional calls to fetch the content portion of
- ** the record.
- */
- if( avail>=payloadSize ){
- zRec = pC->aRow = zData;
- }else{
- pC->aRow = 0;
- }
- }
- idx = sqlite3GetVarint32(zData, &szHdr);
-
-
- /* The KeyFetch() or DataFetch() above are fast and will get the entire
- ** record header in most cases. But they will fail to get the complete
- ** record header if the record header does not fit on a single page
- ** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to
- ** acquire the complete header text.
- */
- if( !zRec && avail<szHdr ){
- rc = sqlite3VdbeMemFromBtree(pCrsr, 0, szHdr, pC->keyAsData, &sMem);
- if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
- }
- zData = sMem.z;
- }
-
- /* Scan the header and use it to fill in the aType[] and aOffset[]
- ** arrays. aType[i] will contain the type integer for the i-th
- ** column and aOffset[i] will contain the offset from the beginning
- ** of the record to the start of the data for the i-th column
- */
- offset = szHdr;
- i = 0;
- while( idx<szHdr && i<nField && offset<=payloadSize ){
- aOffset[i] = offset;
- idx += sqlite3GetVarint32(&zData[idx], &aType[i]);
- offset += sqlite3VdbeSerialTypeLen(aType[i]);
- i++;
- }
- Release(&sMem);
- sMem.flags = MEM_Null;
-
- /* The header should end at the start of data and the data should
- ** end at last byte of the record. If this is not the case then
- ** we are dealing with a malformed record.
- */
- if( idx!=szHdr || offset!=payloadSize ){
- sqliteFree(aType);
- if( pC ) pC->aType = 0;
- rc = SQLITE_CORRUPT;
- break;
- }
-
- /* Remember all aType and aColumn information if we have a cursor
- ** to remember it in. */
- if( pC ){
- pC->payloadSize = payloadSize;
- pC->aType = aType;
- pC->aOffset = aOffset;
- pC->cacheValid = 1;
- }
- }
-
- /* Get the column information.
- */
- if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
- }
- if( zRec ){
- zData = &zRec[aOffset[p2]];
- }else{
- len = sqlite3VdbeSerialTypeLen(aType[p2]);
- sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->keyAsData, &sMem);
- zData = sMem.z;
- }
- sqlite3VdbeSerialGet(zData, aType[p2], pTos);
- pTos->enc = db->enc;
-
- /* If we dynamically allocated space to hold the data (in the
- ** sqlite3VdbeMemFromBtree() call above) then transfer control of that
- ** dynamically allocated space over to the pTos structure rather.
- ** This prevents a memory copy.
- */
- if( (sMem.flags & MEM_Dyn)!=0 ){
- assert( pTos->flags & MEM_Ephem );
- assert( pTos->flags & (MEM_Str|MEM_Blob) );
- assert( pTos->z==sMem.z );
- assert( sMem.flags & MEM_Term );
- pTos->flags &= ~MEM_Ephem;
- pTos->flags |= MEM_Dyn|MEM_Term;
- }
-
- /* pTos->z might be pointing to sMem.zShort[]. Fix that so that we
- ** can abandon sMem */
- rc = sqlite3VdbeMemMakeWriteable(pTos);
-
- /* Release the aType[] memory if we are not dealing with cursor */
- if( !pC ){
- sqliteFree(aType);
- }
- break;
-}
-
-/* Opcode MakeRecord P1 P2 P3
-**
-** Convert the top abs(P1) entries of the stack into a single entry
-** suitable for use as a data record in a database table or as a key
-** in an index. The details of the format are irrelavant as long as
-** the OP_Column opcode can decode the record later and as long as the
-** sqlite3VdbeRecordCompare function will correctly compare two encoded
-** records. Refer to source code comments for the details of the record
-** format.
-**
-** The original stack entries are popped from the stack if P1>0 but
-** remain on the stack if P1<0.
-**
-** The P2 argument is divided into two 16-bit words before it is processed.
-** If the hi-word is non-zero, then an extra integer is read from the stack
-** and appended to the record as a varint. If the low-word of P2 is not
-** zero and one or more of the entries are NULL, then jump to the value of
-** the low-word of P2. This feature can be used to skip a uniqueness test
-** on indices.
-**
-** P3 may be a string that is P1 characters long. The nth character of the
-** string indicates the column affinity that should be used for the nth
-** field of the index key (i.e. the first character of P3 corresponds to the
-** lowest element on the stack).
-**
-** Character Column affinity
-** ------------------------------
-** 'n' NUMERIC
-** 'i' INTEGER
-** 't' TEXT
-** 'o' NONE
-**
-** If P3 is NULL then all index fields have the affinity NONE.
-*/
-case OP_MakeRecord: {
- /* Assuming the record contains N fields, the record format looks
- ** like this:
- **
- ** ------------------------------------------------------------------------
- ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 |
- ** ------------------------------------------------------------------------
- **
- ** Data(0) is taken from the lowest element of the stack and data(N-1) is
- ** the top of the stack.
- **
- ** Each type field is a varint representing the serial type of the
- ** corresponding data element (see sqlite3VdbeSerialType()). The
- ** hdr-size field is also a varint which is the offset from the beginning
- ** of the record to data0.
- */
- unsigned char *zNewRecord;
- unsigned char *zCsr;
- Mem *pRec;
- Mem *pRowid = 0;
- int nData = 0; /* Number of bytes of data space */
- int nHdr = 0; /* Number of bytes of header space */
- int nByte = 0; /* Space required for this record */
- u32 serial_type; /* Type field */
- int containsNull = 0; /* True if any of the data fields are NULL */
- char zTemp[NBFS]; /* Space to hold small records */
- Mem *pData0;
-
- int leaveOnStack; /* If true, leave the entries on the stack */
- int nField; /* Number of fields in the record */
- int jumpIfNull; /* Jump here if non-zero and any entries are NULL. */
- int addRowid; /* True to append a rowid column at the end */
- char *zAffinity; /* The affinity string for the record */
-
- leaveOnStack = ((pOp->p1<0)?1:0);
- nField = pOp->p1 * (leaveOnStack?-1:1);
- jumpIfNull = (pOp->p2 & 0x00FFFFFF);
- addRowid = ((pOp->p2>>24) & 0x0000FFFF)?1:0;
- zAffinity = pOp->p3;
-
- pData0 = &pTos[1-nField];
- assert( pData0>=p->aStack );
- containsNull = 0;
-
- /* Loop through the elements that will make up the record to figure
- ** out how much space is required for the new record.
- */
- for(pRec=pData0; pRec<=pTos; pRec++){
- if( zAffinity ){
- applyAffinity(pRec, zAffinity[pRec-pData0], db->enc);
- }
- if( pRec->flags&MEM_Null ){
- containsNull = 1;
- }
- serial_type = sqlite3VdbeSerialType(pRec);
- nData += sqlite3VdbeSerialTypeLen(serial_type);
- nHdr += sqlite3VarintLen(serial_type);
- }
-
- /* If we have to append a varint rowid to this record, set 'rowid'
- ** to the value of the rowid and increase nByte by the amount of space
- ** required to store it and the 0x00 seperator byte.
- */
- if( addRowid ){
- pRowid = &pTos[0-nField];
- assert( pRowid>=p->aStack );
- Integerify(pRowid);
- serial_type = sqlite3VdbeSerialType(pRowid);
- nData += sqlite3VdbeSerialTypeLen(serial_type);
- nHdr += sqlite3VarintLen(serial_type);
- }
-
- /* Add the initial header varint and total the size */
- nHdr += sqlite3VarintLen(nHdr);
- nByte = nHdr+nData;
-
- /* Allocate space for the new record. */
- if( nByte>sizeof(zTemp) ){
- zNewRecord = sqliteMallocRaw(nByte);
- if( !zNewRecord ){
- goto no_mem;
- }
- }else{
- zNewRecord = zTemp;
- }
-
- /* Write the record */
- zCsr = zNewRecord;
- zCsr += sqlite3PutVarint(zCsr, nHdr);
- for(pRec=pData0; pRec<=pTos; pRec++){
- serial_type = sqlite3VdbeSerialType(pRec);
- zCsr += sqlite3PutVarint(zCsr, serial_type); /* serial type */
- }
- if( addRowid ){
- zCsr += sqlite3PutVarint(zCsr, sqlite3VdbeSerialType(pRowid));
- }
- for(pRec=pData0; pRec<=pTos; pRec++){
- zCsr += sqlite3VdbeSerialPut(zCsr, pRec); /* serial data */
- }
- if( addRowid ){
- zCsr += sqlite3VdbeSerialPut(zCsr, pRowid);
- }
-
- /* If zCsr has not been advanced exactly nByte bytes, then one
- ** of the sqlite3PutVarint() or sqlite3VdbeSerialPut() calls above
- ** failed. This indicates a corrupted memory cell or code bug.
- */
- if( zCsr!=(zNewRecord+nByte) ){
- rc = SQLITE_INTERNAL;
- goto abort_due_to_error;
- }
-
- /* Pop entries off the stack if required. Push the new record on. */
- if( !leaveOnStack ){
- popStack(&pTos, nField+addRowid);
- }
- pTos++;
- pTos->n = nByte;
- if( nByte<=sizeof(zTemp) ){
- assert( zNewRecord==(unsigned char *)zTemp );
- pTos->z = pTos->zShort;
- memcpy(pTos->zShort, zTemp, nByte);
- pTos->flags = MEM_Blob | MEM_Short;
- }else{
- assert( zNewRecord!=(unsigned char *)zTemp );
- pTos->z = zNewRecord;
- pTos->flags = MEM_Blob | MEM_Dyn;
- pTos->xDel = 0;
- }
-
- /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */
- if( jumpIfNull && containsNull ){
- pc = jumpIfNull - 1;
- }
- break;
-}
-
-/* Opcode: Statement P1 * *
-**
-** Begin an individual statement transaction which is part of a larger
-** BEGIN..COMMIT transaction. This is needed so that the statement
-** can be rolled back after an error without having to roll back the
-** entire transaction. The statement transaction will automatically
-** commit when the VDBE halts.
-**
-** The statement is begun on the database file with index P1. The main
-** database file has an index of 0 and the file used for temporary tables
-** has an index of 1.
-*/
-case OP_Statement: {
- int i = pOp->p1;
- Btree *pBt;
- if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt) && !(db->autoCommit) ){
- assert( sqlite3BtreeIsInTrans(pBt) );
- if( !sqlite3BtreeIsInStmt(pBt) ){
- rc = sqlite3BtreeBeginStmt(pBt);
- }
- }
- break;
-}
-
-/* Opcode: AutoCommit P1 P2 *
-**
-** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll
-** back any currently active btree transactions. If there are any active
-** VMs (apart from this one), then the COMMIT or ROLLBACK statement fails.
-**
-** This instruction causes the VM to halt.
-*/
-case OP_AutoCommit: {
- u8 i = pOp->p1;
- u8 rollback = pOp->p2;
-
- assert( i==1 || i==0 );
- assert( i==1 || rollback==0 );
-
- assert( db->activeVdbeCnt>0 ); /* At least this one VM is active */
-
- if( db->activeVdbeCnt>1 && i && !db->autoCommit ){
- /* If this instruction implements a COMMIT or ROLLBACK, other VMs are
- ** still running, and a transaction is active, return an error indicating
- ** that the other VMs must complete first.
- */
- sqlite3SetString(&p->zErrMsg, "cannot ", rollback?"rollback":"commit",
- " transaction - SQL statements in progress", 0);
- rc = SQLITE_ERROR;
- }else if( i!=db->autoCommit ){
- db->autoCommit = i;
- if( pOp->p2 ){
- assert( i==1 );
- sqlite3RollbackAll(db);
- }else if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
- p->pTos = pTos;
- p->pc = pc;
- db->autoCommit = 1-i;
- p->rc = SQLITE_BUSY;
- return SQLITE_BUSY;
- }
- return SQLITE_DONE;
- }else{
- sqlite3SetString(&p->zErrMsg,
- (!i)?"cannot start a transaction within a transaction":(
- (rollback)?"cannot rollback - no transaction is active":
- "cannot commit - no transaction is active"), 0);
-
- rc = SQLITE_ERROR;
- }
- break;
-}
-
-/* Opcode: Transaction P1 P2 *
-**
-** Begin a transaction. The transaction ends when a Commit or Rollback
-** opcode is encountered. Depending on the ON CONFLICT setting, the
-** transaction might also be rolled back if an error is encountered.
-**
-** P1 is the index of the database file on which the transaction is
-** started. Index 0 is the main database file and index 1 is the
-** file used for temporary tables.
-**
-** If P2 is non-zero, then a write-transaction is started. A RESERVED lock is
-** obtained on the database file when a write-transaction is started. No
-** other process can start another write transaction while this transaction is
-** underway. Starting a write transaction also creates a rollback journal. A
-** write transaction must be started before any changes can be made to the
-** database. If P2 is 2 or greater then an EXCLUSIVE lock is also obtained
-** on the file.
-**
-** If P2 is zero, then a read-lock is obtained on the database file.
-*/
-case OP_Transaction: {
- int i = pOp->p1;
- Btree *pBt;
-
- assert( i>=0 && i<db->nDb );
- pBt = db->aDb[i].pBt;
-
- if( pBt ){
- rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
- if( rc==SQLITE_BUSY ){
- p->pc = pc;
- p->rc = SQLITE_BUSY;
- p->pTos = pTos;
- return SQLITE_BUSY;
- }
- if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){
- goto abort_due_to_error;
- }
- }
- break;
-}
-
-/* Opcode: ReadCookie P1 P2 *
-**
-** Read cookie number P2 from database P1 and push it onto the stack.
-** P2==0 is the schema version. P2==1 is the database format.
-** P2==2 is the recommended pager cache size, and so forth. P1==0 is
-** the main database file and P1==1 is the database file used to store
-** temporary tables.
-**
-** There must be a read-lock on the database (either a transaction
-** must be started or there must be an open cursor) before
-** executing this instruction.
-*/
-case OP_ReadCookie: {
- int iMeta;
- assert( pOp->p2<SQLITE_N_BTREE_META );
- assert( pOp->p1>=0 && pOp->p1<db->nDb );
- assert( db->aDb[pOp->p1].pBt!=0 );
- /* The indexing of meta values at the schema layer is off by one from
- ** the indexing in the btree layer. The btree considers meta[0] to
- ** be the number of free pages in the database (a read-only value)
- ** and meta[1] to be the schema cookie. The schema layer considers
- ** meta[1] to be the schema cookie. So we have to shift the index
- ** by one in the following statement.
- */
- rc = sqlite3BtreeGetMeta(db->aDb[pOp->p1].pBt, 1 + pOp->p2, (u32 *)&iMeta);
- pTos++;
- pTos->i = iMeta;
- pTos->flags = MEM_Int;
- break;
-}
-
-/* Opcode: SetCookie P1 P2 *
-**
-** Write the top of the stack into cookie number P2 of database P1.
-** P2==0 is the schema version. P2==1 is the database format.
-** P2==2 is the recommended pager cache size, and so forth. P1==0 is
-** the main database file and P1==1 is the database file used to store
-** temporary tables.
-**
-** A transaction must be started before executing this opcode.
-*/
-case OP_SetCookie: {
- Db *pDb;
- assert( pOp->p2<SQLITE_N_BTREE_META );
- assert( pOp->p1>=0 && pOp->p1<db->nDb );
- pDb = &db->aDb[pOp->p1];
- assert( pDb->pBt!=0 );
- assert( pTos>=p->aStack );
- Integerify(pTos);
- /* See note about index shifting on OP_ReadCookie */
- rc = sqlite3BtreeUpdateMeta(pDb->pBt, 1+pOp->p2, (int)pTos->i);
- if( pOp->p2==0 ){
- /* When the schema cookie changes, record the new cookie internally */
- pDb->schema_cookie = pTos->i;
- db->flags |= SQLITE_InternChanges;
- }
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos--;
- break;
-}
-
-/* Opcode: VerifyCookie P1 P2 *
-**
-** Check the value of global database parameter number 0 (the
-** schema version) and make sure it is equal to P2.
-** P1 is the database number which is 0 for the main database file
-** and 1 for the file holding temporary tables and some higher number
-** for auxiliary databases.
-**
-** The cookie changes its value whenever the database schema changes.
-** This operation is used to detect when that the cookie has changed
-** and that the current process needs to reread the schema.
-**
-** Either a transaction needs to have been started or an OP_Open needs
-** to be executed (to establish a read lock) before this opcode is
-** invoked.
-*/
-case OP_VerifyCookie: {
- int iMeta;
- Btree *pBt;
- assert( pOp->p1>=0 && pOp->p1<db->nDb );
- pBt = db->aDb[pOp->p1].pBt;
- if( pBt ){
- rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&iMeta);
- }else{
- rc = SQLITE_OK;
- iMeta = 0;
- }
- if( rc==SQLITE_OK && iMeta!=pOp->p2 ){
- sqlite3SetString(&p->zErrMsg, "database schema has changed", (char*)0);
- rc = SQLITE_SCHEMA;
- }
- break;
-}
-
-/* Opcode: OpenRead P1 P2 P3
-**
-** Open a read-only cursor for the database table whose root page is
-** P2 in a database file. The database file is determined by an
-** integer from the top of the stack. 0 means the main database and
-** 1 means the database used for temporary tables. Give the new
-** cursor an identifier of P1. The P1 values need not be contiguous
-** but all P1 values should be small integers. It is an error for
-** P1 to be negative.
-**
-** If P2==0 then take the root page number from the next of the stack.
-**
-** There will be a read lock on the database whenever there is an
-** open cursor. If the database was unlocked prior to this instruction
-** then a read lock is acquired as part of this instruction. A read
-** lock allows other processes to read the database but prohibits
-** any other process from modifying the database. The read lock is
-** released when all cursors are closed. If this instruction attempts
-** to get a read lock but fails, the script terminates with an
-** SQLITE_BUSY error code.
-**
-** The P3 value is a pointer to a KeyInfo structure that defines the
-** content and collating sequence of indices. P3 is NULL for cursors
-** that are not pointing to indices.
-**
-** See also OpenWrite.
-*/
-/* Opcode: OpenWrite P1 P2 P3
-**
-** Open a read/write cursor named P1 on the table or index whose root
-** page is P2. If P2==0 then take the root page number from the stack.
-**
-** The P3 value is a pointer to a KeyInfo structure that defines the
-** content and collating sequence of indices. P3 is NULL for cursors
-** that are not pointing to indices.
-**
-** This instruction works just like OpenRead except that it opens the cursor
-** in read/write mode. For a given table, there can be one or more read-only
-** cursors or a single read/write cursor but not both.
-**
-** See also OpenRead.
-*/
-case OP_OpenRead:
-case OP_OpenWrite: {
- int i = pOp->p1;
- int p2 = pOp->p2;
- int wrFlag;
- Btree *pX;
- int iDb;
- Cursor *pCur;
-
- assert( pTos>=p->aStack );
- Integerify(pTos);
- iDb = pTos->i;
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos--;
- assert( iDb>=0 && iDb<db->nDb );
- pX = db->aDb[iDb].pBt;
- assert( pX!=0 );
- wrFlag = pOp->opcode==OP_OpenWrite;
- if( p2<=0 ){
- assert( pTos>=p->aStack );
- Integerify(pTos);
- p2 = pTos->i;
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos--;
- if( p2<2 ){
- sqlite3SetString(&p->zErrMsg, "root page number less than 2", (char*)0);
- rc = SQLITE_INTERNAL;
- break;
- }
- }
- assert( i>=0 );
- pCur = allocateCursor(p, i);
- if( pCur==0 ) goto no_mem;
- pCur->nullRow = 1;
- if( pX==0 ) break;
- /* We always provide a key comparison function. If the table being
- ** opened is of type INTKEY, the comparision function will be ignored. */
- rc = sqlite3BtreeCursor(pX, p2, wrFlag,
- sqlite3VdbeRecordCompare, pOp->p3,
- &pCur->pCursor);
- pCur->pKeyInfo = (KeyInfo*)pOp->p3;
- if( pCur->pKeyInfo ){
- pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
- pCur->pKeyInfo->enc = p->db->enc;
- }else{
- pCur->pIncrKey = &pCur->bogusIncrKey;
- }
- switch( rc ){
- case SQLITE_BUSY: {
- p->pc = pc;
- p->rc = SQLITE_BUSY;
- p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */
- return SQLITE_BUSY;
- }
- case SQLITE_OK: {
- int flags = sqlite3BtreeFlags(pCur->pCursor);
- pCur->intKey = (flags & BTREE_INTKEY)!=0;
- pCur->zeroData = (flags & BTREE_ZERODATA)!=0;
- break;
- }
- case SQLITE_EMPTY: {
- rc = SQLITE_OK;
- break;
- }
- default: {
- goto abort_due_to_error;
- }
- }
- break;
-}
-
-/* Opcode: OpenTemp P1 * P3
-**
-** Open a new cursor to a transient table.
-** The transient cursor is always opened read/write even if
-** the main database is read-only. The transient table is deleted
-** automatically when the cursor is closed.
-**
-** The cursor points to a BTree table if P3==0 and to a BTree index
-** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure
-** that defines the format of keys in the index.
-**
-** This opcode is used for tables that exist for the duration of a single
-** SQL statement only. Tables created using CREATE TEMPORARY TABLE
-** are opened using OP_OpenRead or OP_OpenWrite. "Temporary" in the
-** context of this opcode means for the duration of a single SQL statement
-** whereas "Temporary" in the context of CREATE TABLE means for the duration
-** of the connection to the database. Same word; different meanings.
-*/
-case OP_OpenTemp: {
- int i = pOp->p1;
- Cursor *pCx;
- assert( i>=0 );
- pCx = allocateCursor(p, i);
- if( pCx==0 ) goto no_mem;
- pCx->nullRow = 1;
- rc = sqlite3BtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt);
- if( rc==SQLITE_OK ){
- rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
- }
- if( rc==SQLITE_OK ){
- /* If a transient index is required, create it by calling
- ** sqlite3BtreeCreateTable() with the BTREE_ZERODATA flag before
- ** opening it. If a transient table is required, just use the
- ** automatically created table with root-page 1 (an INTKEY table).
- */
- if( pOp->p3 ){
- int pgno;
- assert( pOp->p3type==P3_KEYINFO );
- rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA);
- if( rc==SQLITE_OK ){
- assert( pgno==MASTER_ROOT+1 );
- rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, sqlite3VdbeRecordCompare,
- pOp->p3, &pCx->pCursor);
- pCx->pKeyInfo = (KeyInfo*)pOp->p3;
- pCx->pKeyInfo->enc = p->db->enc;
- pCx->pIncrKey = &pCx->pKeyInfo->incrKey;
- }
- }else{
- rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, 0, &pCx->pCursor);
- pCx->intKey = 1;
- pCx->pIncrKey = &pCx->bogusIncrKey;
- }
- }
- break;
-}
-
-/* Opcode: OpenPseudo P1 * *
-**
-** Open a new cursor that points to a fake table that contains a single
-** row of data. Any attempt to write a second row of data causes the
-** first row to be deleted. All data is deleted when the cursor is
-** closed.
-**
-** A pseudo-table created by this opcode is useful for holding the
-** NEW or OLD tables in a trigger.
-*/
-case OP_OpenPseudo: {
- int i = pOp->p1;
- Cursor *pCx;
- assert( i>=0 );
- pCx = allocateCursor(p, i);
- if( pCx==0 ) goto no_mem;
- pCx->nullRow = 1;
- pCx->pseudoTable = 1;
- pCx->pIncrKey = &pCx->bogusIncrKey;
- break;
-}
-
-/* Opcode: Close P1 * *
-**
-** Close a cursor previously opened as P1. If P1 is not
-** currently open, this instruction is a no-op.
-*/
-case OP_Close: {
- int i = pOp->p1;
- if( i>=0 && i<p->nCursor ){
- sqlite3VdbeFreeCursor(p->apCsr[i]);
- p->apCsr[i] = 0;
- }
- break;
-}
-
-/* Opcode: MoveGe P1 P2 *
-**
-** Pop the top of the stack and use its value as a key. Reposition
-** cursor P1 so that it points to the smallest entry that is greater
-** than or equal to the key that was popped ffrom the stack.
-** If there are no records greater than or equal to the key and P2
-** is not zero, then jump to P2.
-**
-** See also: Found, NotFound, Distinct, MoveLt, MoveGt, MoveLe
-*/
-/* Opcode: MoveGt P1 P2 *
-**
-** Pop the top of the stack and use its value as a key. Reposition
-** cursor P1 so that it points to the smallest entry that is greater
-** than the key from the stack.
-** If there are no records greater than the key and P2 is not zero,
-** then jump to P2.
-**
-** See also: Found, NotFound, Distinct, MoveLt, MoveGe, MoveLe
-*/
-/* Opcode: MoveLt P1 P2 *
-**
-** Pop the top of the stack and use its value as a key. Reposition
-** cursor P1 so that it points to the largest entry that is less
-** than the key from the stack.
-** If there are no records less than the key and P2 is not zero,
-** then jump to P2.
-**
-** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLe
-*/
-/* Opcode: MoveLe P1 P2 *
-**
-** Pop the top of the stack and use its value as a key. Reposition
-** cursor P1 so that it points to the largest entry that is less than
-** or equal to the key that was popped from the stack.
-** If there are no records less than or eqal to the key and P2 is not zero,
-** then jump to P2.
-**
-** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt
-*/
-case OP_MoveLt:
-case OP_MoveLe:
-case OP_MoveGe:
-case OP_MoveGt: {
- int i = pOp->p1;
- Cursor *pC;
-
- assert( pTos>=p->aStack );
- assert( i>=0 && i<p->nCursor );
- pC = p->apCsr[i];
- assert( pC!=0 );
- if( pC->pCursor!=0 ){
- int res, oc;
- oc = pOp->opcode;
- pC->nullRow = 0;
- *pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe;
- if( pC->intKey ){
- i64 iKey;
- assert( !pOp->p3 );
- Integerify(pTos);
- iKey = intToKey(pTos->i);
- if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){
- pC->movetoTarget = iKey;
- pC->deferredMoveto = 1;
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos--;
- break;
- }
- sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, &res);
- pC->lastRecno = pTos->i;
- pC->recnoIsValid = res==0;
- }else{
- Stringify(pTos, db->enc);
- sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
- pC->recnoIsValid = 0;
- }
- pC->deferredMoveto = 0;
- pC->cacheValid = 0;
- *pC->pIncrKey = 0;
- sqlite3_search_count++;
- if( oc==OP_MoveGe || oc==OP_MoveGt ){
- if( res<0 ){
- sqlite3BtreeNext(pC->pCursor, &res);
- pC->recnoIsValid = 0;
- }else{
- res = 0;
- }
- }else{
- assert( oc==OP_MoveLt || oc==OP_MoveLe );
- if( res>=0 ){
- sqlite3BtreePrevious(pC->pCursor, &res);
- pC->recnoIsValid = 0;
- }else{
- /* res might be negative because the table is empty. Check to
- ** see if this is the case.
- */
- res = sqlite3BtreeEof(pC->pCursor);
- }
- }
- if( res ){
- if( pOp->p2>0 ){
- pc = pOp->p2 - 1;
- }else{
- pC->nullRow = 1;
- }
- }
- }
- Release(pTos);
- pTos--;
- break;
-}
-
-/* Opcode: Distinct P1 P2 *
-**
-** Use the top of the stack as a string key. If a record with that key does
-** not exist in the table of cursor P1, then jump to P2. If the record
-** does already exist, then fall thru. The cursor is left pointing
-** at the record if it exists. The key is not popped from the stack.
-**
-** This operation is similar to NotFound except that this operation
-** does not pop the key from the stack.
-**
-** See also: Found, NotFound, MoveTo, IsUnique, NotExists
-*/
-/* Opcode: Found P1 P2 *
-**
-** Use the top of the stack as a string key. If a record with that key
-** does exist in table of P1, then jump to P2. If the record
-** does not exist, then fall thru. The cursor is left pointing
-** to the record if it exists. The key is popped from the stack.
-**
-** See also: Distinct, NotFound, MoveTo, IsUnique, NotExists
-*/
-/* Opcode: NotFound P1 P2 *
-**
-** Use the top of the stack as a string key. If a record with that key
-** does not exist in table of P1, then jump to P2. If the record
-** does exist, then fall thru. The cursor is left pointing to the
-** record if it exists. The key is popped from the stack.
-**
-** The difference between this operation and Distinct is that
-** Distinct does not pop the key from the stack.
-**
-** See also: Distinct, Found, MoveTo, NotExists, IsUnique
-*/
-case OP_Distinct:
-case OP_NotFound:
-case OP_Found: {
- int i = pOp->p1;
- int alreadyExists = 0;
- Cursor *pC;
- assert( pTos>=p->aStack );
- assert( i>=0 && i<p->nCursor );
- assert( p->apCsr[i]!=0 );
- if( (pC = p->apCsr[i])->pCursor!=0 ){
- int res, rx;
- assert( pC->intKey==0 );
- Stringify(pTos, db->enc);
- rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
- alreadyExists = rx==SQLITE_OK && res==0;
- pC->deferredMoveto = 0;
- pC->cacheValid = 0;
- }
- if( pOp->opcode==OP_Found ){
- if( alreadyExists ) pc = pOp->p2 - 1;
- }else{
- if( !alreadyExists ) pc = pOp->p2 - 1;
- }
- if( pOp->opcode!=OP_Distinct ){
- Release(pTos);
- pTos--;
- }
- break;
-}
-
-/* Opcode: IsUnique P1 P2 *
-**
-** The top of the stack is an integer record number. Call this
-** record number R. The next on the stack is an index key created
-** using MakeIdxKey. Call it K. This instruction pops R from the
-** stack but it leaves K unchanged.
-**
-** P1 is an index. So it has no data and its key consists of a
-** record generated by OP_MakeIdxKey. This key contains one or more
-** fields followed by a ROWID field.
-**
-** This instruction asks if there is an entry in P1 where the
-** fields matches K but the rowid is different from R.
-** If there is no such entry, then there is an immediate
-** jump to P2. If any entry does exist where the index string
-** matches K but the record number is not R, then the record
-** number for that entry is pushed onto the stack and control
-** falls through to the next instruction.
-**
-** See also: Distinct, NotFound, NotExists, Found
-*/
-case OP_IsUnique: {
- int i = pOp->p1;
- Mem *pNos = &pTos[-1];
- Cursor *pCx;
- BtCursor *pCrsr;
- i64 R;
-
- /* Pop the value R off the top of the stack
- */
- assert( pNos>=p->aStack );
- Integerify(pTos);
- R = pTos->i;
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos--;
- assert( i>=0 && i<=p->nCursor );
- pCx = p->apCsr[i];
- assert( pCx!=0 );
- pCrsr = pCx->pCursor;
- if( pCrsr!=0 ){
- int res, rc;
- i64 v; /* The record number on the P1 entry that matches K */
- char *zKey; /* The value of K */
- int nKey; /* Number of bytes in K */
- int len; /* Number of bytes in K without the rowid at the end */
- int szRowid; /* Size of the rowid column at the end of zKey */
-
- /* Make sure K is a string and make zKey point to K
- */
- Stringify(pNos, db->enc);
- zKey = pNos->z;
- nKey = pNos->n;
-
- szRowid = sqlite3VdbeIdxRowidLen(nKey, zKey);
- len = nKey-szRowid;
-
- /* Search for an entry in P1 where all but the last four bytes match K.
- ** If there is no such entry, jump immediately to P2.
- */
- assert( pCx->deferredMoveto==0 );
- pCx->cacheValid = 0;
- rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
- if( res<0 ){
- rc = sqlite3BtreeNext(pCrsr, &res);
- if( res ){
- pc = pOp->p2 - 1;
- break;
- }
- }
- rc = sqlite3VdbeIdxKeyCompare(pCx, len, zKey, &res);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
- if( res>0 ){
- pc = pOp->p2 - 1;
- break;
- }
-
- /* At this point, pCrsr is pointing to an entry in P1 where all but
- ** the final entry (the rowid) matches K. Check to see if the
- ** final rowid column is different from R. If it equals R then jump
- ** immediately to P2.
- */
- rc = sqlite3VdbeIdxRowid(pCrsr, &v);
- if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
- }
- if( v==R ){
- pc = pOp->p2 - 1;
- break;
- }
-
- /* The final varint of the key is different from R. Push it onto
- ** the stack. (The record number of an entry that violates a UNIQUE
- ** constraint.)
- */
- pTos++;
- pTos->i = v;
- pTos->flags = MEM_Int;
- }
- break;
-}
-
-/* Opcode: NotExists P1 P2 *
-**
-** Use the top of the stack as a integer key. If a record with that key
-** does not exist in table of P1, then jump to P2. If the record
-** does exist, then fall thru. The cursor is left pointing to the
-** record if it exists. The integer key is popped from the stack.
-**
-** The difference between this operation and NotFound is that this
-** operation assumes the key is an integer and NotFound assumes it
-** is a string.
-**
-** See also: Distinct, Found, MoveTo, NotFound, IsUnique
-*/
-case OP_NotExists: {
- int i = pOp->p1;
- Cursor *pC;
- BtCursor *pCrsr;
- assert( pTos>=p->aStack );
- assert( i>=0 && i<p->nCursor );
- assert( p->apCsr[i]!=0 );
- if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
- int res, rx;
- u64 iKey;
- assert( pTos->flags & MEM_Int );
- assert( p->apCsr[i]->intKey );
- iKey = intToKey(pTos->i);
- rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res);
- pC->lastRecno = pTos->i;
- pC->recnoIsValid = res==0;
- pC->nullRow = 0;
- pC->cacheValid = 0;
- if( rx!=SQLITE_OK || res!=0 ){
- pc = pOp->p2 - 1;
- pC->recnoIsValid = 0;
- }
- }
- Release(pTos);
- pTos--;
- break;
-}
-
-/* Opcode: NewRecno P1 * *
-**
-** Get a new integer record number used as the key to a table.
-** The record number is not previously used as a key in the database
-** table that cursor P1 points to. The new record number is pushed
-** onto the stack.
-*/
-case OP_NewRecno: {
- int i = pOp->p1;
- i64 v = 0;
- Cursor *pC;
- assert( i>=0 && i<p->nCursor );
- assert( p->apCsr[i]!=0 );
- if( (pC = p->apCsr[i])->pCursor==0 ){
- /* The zero initialization above is all that is needed */
- }else{
- /* The next rowid or record number (different terms for the same
- ** thing) is obtained in a two-step algorithm.
- **
- ** First we attempt to find the largest existing rowid and add one
- ** to that. But if the largest existing rowid is already the maximum
- ** positive integer, we have to fall through to the second
- ** probabilistic algorithm
- **
- ** The second algorithm is to select a rowid at random and see if
- ** it already exists in the table. If it does not exist, we have
- ** succeeded. If the random rowid does exist, we select a new one
- ** and try again, up to 1000 times.
- **
- ** For a table with less than 2 billion entries, the probability
- ** of not finding a unused rowid is about 1.0e-300. This is a
- ** non-zero probability, but it is still vanishingly small and should
- ** never cause a problem. You are much, much more likely to have a
- ** hardware failure than for this algorithm to fail.
- **
- ** The analysis in the previous paragraph assumes that you have a good
- ** source of random numbers. Is a library function like lrand48()
- ** good enough? Maybe. Maybe not. It's hard to know whether there
- ** might be subtle bugs is some implementations of lrand48() that
- ** could cause problems. To avoid uncertainty, SQLite uses its own
- ** random number generator based on the RC4 algorithm.
- **
- ** To promote locality of reference for repetitive inserts, the
- ** first few attempts at chosing a random rowid pick values just a little
- ** larger than the previous rowid. This has been shown experimentally
- ** to double the speed of the COPY operation.
- */
- int res, rx=SQLITE_OK, cnt;
- i64 x;
- cnt = 0;
- assert( (sqlite3BtreeFlags(pC->pCursor) & BTREE_INTKEY)!=0 );
- assert( (sqlite3BtreeFlags(pC->pCursor) & BTREE_ZERODATA)==0 );
- if( !pC->useRandomRowid ){
- if( pC->nextRowidValid ){
- v = pC->nextRowid;
- }else{
- rx = sqlite3BtreeLast(pC->pCursor, &res);
- if( res ){
- v = 1;
- }else{
- sqlite3BtreeKeySize(pC->pCursor, &v);
- v = keyToInt(v);
- if( v==0x7fffffffffffffff ){
- pC->useRandomRowid = 1;
- }else{
- v++;
- }
- }
- }
- if( v<0x7fffffffffffffff ){
- pC->nextRowidValid = 1;
- pC->nextRowid = v+1;
- }else{
- pC->nextRowidValid = 0;
- }
- }
- if( pC->useRandomRowid ){
- v = db->priorNewRowid;
- cnt = 0;
- do{
- if( v==0 || cnt>2 ){
- sqlite3Randomness(sizeof(v), &v);
- if( cnt<5 ) v &= 0xffffff;
- }else{
- unsigned char r;
- sqlite3Randomness(1, &r);
- v += r + 1;
- }
- if( v==0 ) continue;
- x = intToKey(v);
- rx = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)x, &res);
- cnt++;
- }while( cnt<1000 && rx==SQLITE_OK && res==0 );
- db->priorNewRowid = v;
- if( rx==SQLITE_OK && res==0 ){
- rc = SQLITE_FULL;
- goto abort_due_to_error;
- }
- }
- pC->recnoIsValid = 0;
- pC->deferredMoveto = 0;
- pC->cacheValid = 0;
- }
- pTos++;
- pTos->i = v;
- pTos->flags = MEM_Int;
- break;
-}
-
-/* Opcode: PutIntKey P1 P2 *
-**
-** Write an entry into the table of cursor P1. A new entry is
-** created if it doesn't already exist or the data for an existing
-** entry is overwritten. The data is the value on the top of the
-** stack. The key is the next value down on the stack. The key must
-** be an integer. The stack is popped twice by this instruction.
-**
-** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
-** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P2 is set,
-** then rowid is stored for subsequent return by the
-** sqlite3_last_insert_rowid() function (otherwise it's unmodified).
-*/
-/* Opcode: PutStrKey P1 * *
-**
-** Write an entry into the table of cursor P1. A new entry is
-** created if it doesn't already exist or the data for an existing
-** entry is overwritten. The data is the value on the top of the
-** stack. The key is the next value down on the stack. The key must
-** be a string. The stack is popped twice by this instruction.
-**
-** P1 may not be a pseudo-table opened using the OpenPseudo opcode.
-*/
-case OP_PutIntKey:
-case OP_PutStrKey: {
- Mem *pNos = &pTos[-1];
- int i = pOp->p1;
- Cursor *pC;
- assert( pNos>=p->aStack );
- assert( i>=0 && i<p->nCursor );
- assert( p->apCsr[i]!=0 );
- if( ((pC = p->apCsr[i])->pCursor!=0 || pC->pseudoTable) ){
- char *zKey;
- i64 nKey;
- i64 iKey;
- if( pOp->opcode==OP_PutStrKey ){
- Stringify(pNos, db->enc);
- nKey = pNos->n;
- zKey = pNos->z;
- }else{
- assert( pNos->flags & MEM_Int );
-
- /* If the table is an INTKEY table, set nKey to the value of
- ** the integer key, and zKey to NULL. Otherwise, set nKey to
- ** sizeof(i64) and point zKey at iKey. iKey contains the integer
- ** key in the on-disk byte order.
- */
- iKey = intToKey(pNos->i);
- if( pC->intKey ){
- nKey = intToKey(pNos->i);
- zKey = 0;
- }else{
- nKey = sizeof(i64);
- zKey = (char*)&iKey;
- }
-
- if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
- if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->i;
- if( pC->nextRowidValid && pTos->i>=pC->nextRowid ){
- pC->nextRowidValid = 0;
- }
- }
- if( pTos->flags & MEM_Null ){
- pTos->z = 0;
- pTos->n = 0;
- }else{
- assert( pTos->flags & (MEM_Blob|MEM_Str) );
- }
- if( pC->pseudoTable ){
- /* PutStrKey does not work for pseudo-tables.
- ** The following assert makes sure we are not trying to use
- ** PutStrKey on a pseudo-table
- */
- assert( pOp->opcode==OP_PutIntKey );
- sqliteFree(pC->pData);
- pC->iKey = iKey;
- pC->nData = pTos->n;
- if( pTos->flags & MEM_Dyn ){
- pC->pData = pTos->z;
- pTos->flags = MEM_Null;
- }else{
- pC->pData = sqliteMallocRaw( pC->nData+2 );
- if( !pC->pData ) goto no_mem;
- memcpy(pC->pData, pTos->z, pC->nData);
- pC->pData[pC->nData] = 0;
- pC->pData[pC->nData+1] = 0;
- }
- pC->nullRow = 0;
- }else{
- rc = sqlite3BtreeInsert(pC->pCursor, zKey, nKey, pTos->z, pTos->n);
- }
- pC->recnoIsValid = 0;
- pC->deferredMoveto = 0;
- pC->cacheValid = 0;
- }
- popStack(&pTos, 2);
- break;
-}
-
-/* Opcode: Delete P1 P2 *
-**
-** Delete the record at which the P1 cursor is currently pointing.
-**
-** The cursor will be left pointing at either the next or the previous
-** record in the table. If it is left pointing at the next record, then
-** the next Next instruction will be a no-op. Hence it is OK to delete
-** a record from within an Next loop.
-**
-** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
-** incremented (otherwise not).
-**
-** If P1 is a pseudo-table, then this instruction is a no-op.
-*/
-case OP_Delete: {
- int i = pOp->p1;
- Cursor *pC;
- assert( i>=0 && i<p->nCursor );
- pC = p->apCsr[i];
- assert( pC!=0 );
- if( pC->pCursor!=0 ){
- sqlite3VdbeCursorMoveto(pC);
- rc = sqlite3BtreeDelete(pC->pCursor);
- pC->nextRowidValid = 0;
- pC->cacheValid = 0;
- }
- if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
- break;
-}
-
-/* Opcode: ResetCount P1 * *
-**
-** This opcode resets the VMs internal change counter to 0. If P1 is true,
-** then the value of the change counter is copied to the database handle
-** change counter (returned by subsequent calls to sqlite3_changes())
-** before it is reset. This is used by trigger programs.
-*/
-case OP_ResetCount: {
- if( pOp->p1 ){
- sqlite3VdbeSetChanges(db, p->nChange);
- }
- p->nChange = 0;
- break;
-}
-
-/* Opcode: KeyAsData P1 P2 *
-**
-** Turn the key-as-data mode for cursor P1 either on (if P2==1) or
-** off (if P2==0). In key-as-data mode, the OP_Column opcode pulls
-** data off of the key rather than the data. This is used for
-** processing compound selects.
-*/
-case OP_KeyAsData: {
- int i = pOp->p1;
- Cursor *pC;
- assert( i>=0 && i<p->nCursor );
- pC = p->apCsr[i];
- assert( pC!=0 );
- pC->keyAsData = pOp->p2;
- break;
-}
-
-/* Opcode: RowData P1 * *
-**
-** Push onto the stack the complete row data for cursor P1.
-** There is no interpretation of the data. It is just copied
-** onto the stack exactly as it is found in the database file.
-**
-** If the cursor is not pointing to a valid row, a NULL is pushed
-** onto the stack.
-*/
-/* Opcode: RowKey P1 * *
-**
-** Push onto the stack the complete row key for cursor P1.
-** There is no interpretation of the key. It is just copied
-** onto the stack exactly as it is found in the database file.
-**
-** If the cursor is not pointing to a valid row, a NULL is pushed
-** onto the stack.
-*/
-case OP_RowKey:
-case OP_RowData: {
- int i = pOp->p1;
- Cursor *pC;
- u32 n;
-
- pTos++;
- assert( i>=0 && i<p->nCursor );
- pC = p->apCsr[i];
- assert( pC!=0 );
- if( pC->nullRow ){
- pTos->flags = MEM_Null;
- }else if( pC->pCursor!=0 ){
- BtCursor *pCrsr = pC->pCursor;
- sqlite3VdbeCursorMoveto(pC);
- if( pC->nullRow ){
- pTos->flags = MEM_Null;
- break;
- }else if( pC->keyAsData || pOp->opcode==OP_RowKey ){
- i64 n64;
- assert( !pC->intKey );
- sqlite3BtreeKeySize(pCrsr, &n64);
- n = n64;
- }else{
- sqlite3BtreeDataSize(pCrsr, &n);
- }
- pTos->n = n;
- if( n<=NBFS ){
- pTos->flags = MEM_Blob | MEM_Short;
- pTos->z = pTos->zShort;
- }else{
- char *z = sqliteMallocRaw( n );
- if( z==0 ) goto no_mem;
- pTos->flags = MEM_Blob | MEM_Dyn;
- pTos->xDel = 0;
- pTos->z = z;
- }
- if( pC->keyAsData || pOp->opcode==OP_RowKey ){
- sqlite3BtreeKey(pCrsr, 0, n, pTos->z);
- }else{
- sqlite3BtreeData(pCrsr, 0, n, pTos->z);
- }
- }else if( pC->pseudoTable ){
- pTos->n = pC->nData;
- pTos->z = pC->pData;
- pTos->flags = MEM_Blob|MEM_Ephem;
- }else{
- pTos->flags = MEM_Null;
- }
- break;
-}
-
-/* Opcode: Recno P1 * *
-**
-** Push onto the stack an integer which is the first 4 bytes of the
-** the key to the current entry in a sequential scan of the database
-** file P1. The sequential scan should have been started using the
-** Next opcode.
-*/
-case OP_Recno: {
- int i = pOp->p1;
- Cursor *pC;
- i64 v;
-
- assert( i>=0 && i<p->nCursor );
- pC = p->apCsr[i];
- assert( pC!=0 );
- sqlite3VdbeCursorMoveto(pC);
- pTos++;
- if( pC->recnoIsValid ){
- v = pC->lastRecno;
- }else if( pC->pseudoTable ){
- v = keyToInt(pC->iKey);
- }else if( pC->nullRow || pC->pCursor==0 ){
- pTos->flags = MEM_Null;
- break;
- }else{
- assert( pC->pCursor!=0 );
- sqlite3BtreeKeySize(pC->pCursor, &v);
- v = keyToInt(v);
- }
- pTos->i = v;
- pTos->flags = MEM_Int;
- break;
-}
-
-/* Opcode: FullKey P1 * *
-**
-** Extract the complete key from the record that cursor P1 is currently
-** pointing to and push the key onto the stack as a string.
-**
-** Compare this opcode to Recno. The Recno opcode extracts the first
-** 4 bytes of the key and pushes those bytes onto the stack as an
-** integer. This instruction pushes the entire key as a string.
-**
-** This opcode may not be used on a pseudo-table.
-*/
-case OP_FullKey: {
- int i = pOp->p1;
- BtCursor *pCrsr;
- Cursor *pC;
-
- assert( i>=0 && i<p->nCursor );
- assert( p->apCsr[i]!=0 );
- assert( p->apCsr[i]->keyAsData );
- assert( !p->apCsr[i]->pseudoTable );
- pTos++;
- pTos->flags = MEM_Null;
- if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
- i64 amt;
- char *z;
-
- sqlite3VdbeCursorMoveto(pC);
- assert( pC->intKey==0 );
- sqlite3BtreeKeySize(pCrsr, &amt);
- if( amt<=0 ){
- rc = SQLITE_CORRUPT;
- goto abort_due_to_error;
- }
- if( amt>NBFS ){
- z = sqliteMallocRaw( amt );
- if( z==0 ) goto no_mem;
- pTos->flags = MEM_Blob | MEM_Dyn;
- pTos->xDel = 0;
- }else{
- z = pTos->zShort;
- pTos->flags = MEM_Blob | MEM_Short;
- }
- sqlite3BtreeKey(pCrsr, 0, amt, z);
- pTos->z = z;
- pTos->n = amt;
- }
- break;
-}
-
-/* Opcode: NullRow P1 * *
-**
-** Move the cursor P1 to a null row. Any OP_Column operations
-** that occur while the cursor is on the null row will always push
-** a NULL onto the stack.
-*/
-case OP_NullRow: {
- int i = pOp->p1;
- Cursor *pC;
-
- assert( i>=0 && i<p->nCursor );
- pC = p->apCsr[i];
- assert( pC!=0 );
- pC->nullRow = 1;
- pC->recnoIsValid = 0;
- break;
-}
-
-/* Opcode: Last P1 P2 *
-**
-** The next use of the Recno or Column or Next instruction for P1
-** will refer to the last entry in the database table or index.
-** If the table or index is empty and P2>0, then jump immediately to P2.
-** If P2 is 0 or if the table or index is not empty, fall through
-** to the following instruction.
-*/
-case OP_Last: {
- int i = pOp->p1;
- Cursor *pC;
- BtCursor *pCrsr;
-
- assert( i>=0 && i<p->nCursor );
- pC = p->apCsr[i];
- assert( pC!=0 );
- if( (pCrsr = pC->pCursor)!=0 ){
- int res;
- rc = sqlite3BtreeLast(pCrsr, &res);
- pC->nullRow = res;
- pC->deferredMoveto = 0;
- pC->cacheValid = 0;
- if( res && pOp->p2>0 ){
- pc = pOp->p2 - 1;
- }
- }else{
- pC->nullRow = 0;
- }
- break;
-}
-
-/* Opcode: Rewind P1 P2 *
-**
-** The next use of the Recno or Column or Next instruction for P1
-** will refer to the first entry in the database table or index.
-** If the table or index is empty and P2>0, then jump immediately to P2.
-** If P2 is 0 or if the table or index is not empty, fall through
-** to the following instruction.
-*/
-case OP_Rewind: {
- int i = pOp->p1;
- Cursor *pC;
- BtCursor *pCrsr;
- int res;
-
- assert( i>=0 && i<p->nCursor );
- pC = p->apCsr[i];
- assert( pC!=0 );
- if( (pCrsr = pC->pCursor)!=0 ){
- rc = sqlite3BtreeFirst(pCrsr, &res);
- pC->atFirst = res==0;
- pC->deferredMoveto = 0;
- pC->cacheValid = 0;
- }else{
- res = 1;
- }
- pC->nullRow = res;
- if( res && pOp->p2>0 ){
- pc = pOp->p2 - 1;
- }
- break;
-}
-
-/* Opcode: Next P1 P2 *
-**
-** Advance cursor P1 so that it points to the next key/data pair in its
-** table or index. If there are no more key/value pairs then fall through
-** to the following instruction. But if the cursor advance was successful,
-** jump immediately to P2.
-**
-** See also: Prev
-*/
-/* Opcode: Prev P1 P2 *
-**
-** Back up cursor P1 so that it points to the previous key/data pair in its
-** table or index. If there is no previous key/value pairs then fall through
-** to the following instruction. But if the cursor backup was successful,
-** jump immediately to P2.
-*/
-case OP_Prev:
-case OP_Next: {
- Cursor *pC;
- BtCursor *pCrsr;
-
- CHECK_FOR_INTERRUPT;
- assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- pC = p->apCsr[pOp->p1];
- assert( pC!=0 );
- if( (pCrsr = pC->pCursor)!=0 ){
- int res;
- if( pC->nullRow ){
- res = 1;
- }else{
- assert( pC->deferredMoveto==0 );
- rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
- sqlite3BtreePrevious(pCrsr, &res);
- pC->nullRow = res;
- pC->cacheValid = 0;
- }
- if( res==0 ){
- pc = pOp->p2 - 1;
- sqlite3_search_count++;
- }
- }else{
- pC->nullRow = 1;
- }
- pC->recnoIsValid = 0;
- break;
-}
-
-/* Opcode: IdxPut P1 P2 P3
-**
-** The top of the stack holds a SQL index key made using the
-** MakeIdxKey instruction. This opcode writes that key into the
-** index P1. Data for the entry is nil.
-**
-** If P2==1, then the key must be unique. If the key is not unique,
-** the program aborts with a SQLITE_CONSTRAINT error and the database
-** is rolled back. If P3 is not null, then it becomes part of the
-** error message returned with the SQLITE_CONSTRAINT.
-*/
-case OP_IdxPut: {
- int i = pOp->p1;
- Cursor *pC;
- BtCursor *pCrsr;
- assert( pTos>=p->aStack );
- assert( i>=0 && i<p->nCursor );
- assert( p->apCsr[i]!=0 );
- assert( pTos->flags & MEM_Blob );
- if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
- int nKey = pTos->n;
- const char *zKey = pTos->z;
- if( pOp->p2 ){
- int res;
- int len;
-
- /* 'len' is the length of the key minus the rowid at the end */
- len = nKey - sqlite3VdbeIdxRowidLen(nKey, zKey);
-
- rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
- while( res!=0 && !sqlite3BtreeEof(pCrsr) ){
- int c;
- if( sqlite3VdbeIdxKeyCompare(pC, len, zKey, &c)==SQLITE_OK && c==0 ){
- rc = SQLITE_CONSTRAINT;
- if( pOp->p3 && pOp->p3[0] ){
- sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0);
- }
- goto abort_due_to_error;
- }
- if( res<0 ){
- sqlite3BtreeNext(pCrsr, &res);
- res = +1;
- }else{
- break;
- }
- }
- }
- assert( pC->intKey==0 );
- rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0);
- assert( pC->deferredMoveto==0 );
- pC->cacheValid = 0;
- }
- Release(pTos);
- pTos--;
- break;
-}
-
-/* Opcode: IdxDelete P1 * *
-**
-** The top of the stack is an index key built using the MakeIdxKey opcode.
-** This opcode removes that entry from the index.
-*/
-case OP_IdxDelete: {
- int i = pOp->p1;
- Cursor *pC;
- BtCursor *pCrsr;
- assert( pTos>=p->aStack );
- assert( pTos->flags & MEM_Blob );
- assert( i>=0 && i<p->nCursor );
- assert( p->apCsr[i]!=0 );
- if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
- int rx, res;
- rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
- if( rx==SQLITE_OK && res==0 ){
- rc = sqlite3BtreeDelete(pCrsr);
- }
- assert( pC->deferredMoveto==0 );
- pC->cacheValid = 0;
- }
- Release(pTos);
- pTos--;
- break;
-}
-
-/* Opcode: IdxRecno P1 * *
-**
-** Push onto the stack an integer which is the varint located at the
-** end of the index key pointed to by cursor P1. These integer should be
-** the record number of the table entry to which this index entry points.
-**
-** See also: Recno, MakeIdxKey.
-*/
-case OP_IdxRecno: {
- int i = pOp->p1;
- BtCursor *pCrsr;
- Cursor *pC;
-
- assert( i>=0 && i<p->nCursor );
- assert( p->apCsr[i]!=0 );
- pTos++;
- pTos->flags = MEM_Null;
- if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
- i64 rowid;
-
- assert( pC->deferredMoveto==0 );
- assert( pC->intKey==0 );
- if( pC->nullRow ){
- pTos->flags = MEM_Null;
- }else{
- rc = sqlite3VdbeIdxRowid(pCrsr, &rowid);
- if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
- }
- pTos->flags = MEM_Int;
- pTos->i = rowid;
- }
- }
- break;
-}
-
-/* Opcode: IdxGT P1 P2 *
-**
-** The top of the stack is an index entry that omits the ROWID. Compare
-** the top of stack against the index that P1 is currently pointing to.
-** Ignore the ROWID on the P1 index.
-**
-** The top of the stack might have fewer columns that P1.
-**
-** If the P1 index entry is greater than the top of the stack
-** then jump to P2. Otherwise fall through to the next instruction.
-** In either case, the stack is popped once.
-*/
-/* Opcode: IdxGE P1 P2 P3
-**
-** The top of the stack is an index entry that omits the ROWID. Compare
-** the top of stack against the index that P1 is currently pointing to.
-** Ignore the ROWID on the P1 index.
-**
-** If the P1 index entry is greater than or equal to the top of the stack
-** then jump to P2. Otherwise fall through to the next instruction.
-** In either case, the stack is popped once.
-**
-** If P3 is the "+" string (or any other non-NULL string) then the
-** index taken from the top of the stack is temporarily increased by
-** an epsilon prior to the comparison. This make the opcode work
-** like IdxGT except that if the key from the stack is a prefix of
-** the key in the cursor, the result is false whereas it would be
-** true with IdxGT.
-*/
-/* Opcode: IdxLT P1 P2 P3
-**
-** The top of the stack is an index entry that omits the ROWID. Compare
-** the top of stack against the index that P1 is currently pointing to.
-** Ignore the ROWID on the P1 index.
-**
-** If the P1 index entry is less than the top of the stack
-** then jump to P2. Otherwise fall through to the next instruction.
-** In either case, the stack is popped once.
-**
-** If P3 is the "+" string (or any other non-NULL string) then the
-** index taken from the top of the stack is temporarily increased by
-** an epsilon prior to the comparison. This makes the opcode work
-** like IdxLE.
-*/
-case OP_IdxLT:
-case OP_IdxGT:
-case OP_IdxGE: {
- int i= pOp->p1;
- BtCursor *pCrsr;
- Cursor *pC;
-
- assert( i>=0 && i<p->nCursor );
- assert( p->apCsr[i]!=0 );
- assert( pTos>=p->aStack );
- if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
- int res, rc;
-
- assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */
- Stringify(pTos, db->enc);
- assert( pC->deferredMoveto==0 );
- *pC->pIncrKey = pOp->p3!=0;
- assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT );
- rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, pTos->z, &res);
- *pC->pIncrKey = 0;
- if( rc!=SQLITE_OK ){
- break;
- }
- if( pOp->opcode==OP_IdxLT ){
- res = -res;
- }else if( pOp->opcode==OP_IdxGE ){
- res++;
- }
- if( res>0 ){
- pc = pOp->p2 - 1 ;
- }
- }
- Release(pTos);
- pTos--;
- break;
-}
-
-/* Opcode: IdxIsNull P1 P2 *
-**
-** The top of the stack contains an index entry such as might be generated
-** by the MakeIdxKey opcode. This routine looks at the first P1 fields of
-** that key. If any of the first P1 fields are NULL, then a jump is made
-** to address P2. Otherwise we fall straight through.
-**
-** The index entry is always popped from the stack.
-*/
-case OP_IdxIsNull: {
- int i = pOp->p1;
- int k, n;
- const char *z;
- u32 serial_type;
-
- assert( pTos>=p->aStack );
- assert( pTos->flags & MEM_Blob );
- z = pTos->z;
- n = pTos->n;
- k = sqlite3GetVarint32(z, &serial_type);
- for(; k<n && i>0; i--){
- k += sqlite3GetVarint32(&z[k], &serial_type);
- if( serial_type==0 ){ /* Serial type 0 is a NULL */
- pc = pOp->p2-1;
- break;
- }
- }
- Release(pTos);
- pTos--;
- break;
-}
-
-/* Opcode: Destroy P1 P2 *
-**
-** Delete an entire database table or index whose root page in the database
-** file is given by P1.
-**
-** The table being destroyed is in the main database file if P2==0. If
-** P2==1 then the table to be clear is in the auxiliary database file
-** that is used to store tables create using CREATE TEMPORARY TABLE.
-**
-** See also: Clear
-*/
-case OP_Destroy: {
- rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
- break;
-}
-
-/* Opcode: Clear P1 P2 *
-**
-** Delete all contents of the database table or index whose root page
-** in the database file is given by P1. But, unlike Destroy, do not
-** remove the table or index from the database file.
-**
-** The table being clear is in the main database file if P2==0. If
-** P2==1 then the table to be clear is in the auxiliary database file
-** that is used to store tables create using CREATE TEMPORARY TABLE.
-**
-** See also: Destroy
-*/
-case OP_Clear: {
- rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
- break;
-}
-
-/* Opcode: CreateTable P1 * *
-**
-** Allocate a new table in the main database file if P2==0 or in the
-** auxiliary database file if P2==1. Push the page number
-** for the root page of the new table onto the stack.
-**
-** The difference between a table and an index is this: A table must
-** have a 4-byte integer key and can have arbitrary data. An index
-** has an arbitrary key but no data.
-**
-** See also: CreateIndex
-*/
-/* Opcode: CreateIndex P1 * *
-**
-** Allocate a new index in the main database file if P2==0 or in the
-** auxiliary database file if P2==1. Push the page number of the
-** root page of the new index onto the stack.
-**
-** See documentation on OP_CreateTable for additional information.
-*/
-case OP_CreateIndex:
-case OP_CreateTable: {
- int pgno;
- int flags;
- Db *pDb;
- assert( pOp->p1>=0 && pOp->p1<db->nDb );
- pDb = &db->aDb[pOp->p1];
- assert( pDb->pBt!=0 );
- if( pOp->opcode==OP_CreateTable ){
- /* flags = BTREE_INTKEY; */
- flags = BTREE_LEAFDATA|BTREE_INTKEY;
- }else{
- flags = BTREE_ZERODATA;
- }
- rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
- pTos++;
- if( rc==SQLITE_OK ){
- pTos->i = pgno;
- pTos->flags = MEM_Int;
- }else{
- pTos->flags = MEM_Null;
- }
- break;
-}
-
-/* Opcode: ParseSchema P1 * P3
-**
-** Read and parse all entries from the SQLITE_MASTER table of database P1
-** that match the WHERE clause P3.
-**
-** This opcode invokes the parser to create a new virtual machine,
-** then runs the new virtual machine. It is thus a reentrant opcode.
-*/
-case OP_ParseSchema: {
- char *zSql;
- int iDb = pOp->p1;
- const char *zMaster;
- InitData initData;
-
- assert( iDb>=0 && iDb<db->nDb );
- if( !DbHasProperty(db, iDb, DB_SchemaLoaded) ) break;
- zMaster = iDb==1 ? TEMP_MASTER_NAME : MASTER_NAME;
- initData.db = db;
- initData.pzErrMsg = &p->zErrMsg;
- zSql = sqlite3MPrintf(
- "SELECT name, rootpage, sql, %d FROM '%q'.%s WHERE %s",
- pOp->p1, db->aDb[iDb].zName, zMaster, pOp->p3);
- if( zSql==0 ) goto no_mem;
- sqlite3SafetyOff(db);
- assert( db->init.busy==0 );
- db->init.busy = 1;
- rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
- db->init.busy = 0;
- sqlite3SafetyOn(db);
- sqliteFree(zSql);
- break;
-}
-
-/* Opcode: DropTable P1 * P3
-**
-** Remove the internal (in-memory) data structures that describe
-** the table named P3 in database P1. This is called after a table
-** is dropped in order to keep the internal representation of the
-** schema consistent with what is on disk.
-*/
-case OP_DropTable: {
- sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p3);
- break;
-}
-
-/* Opcode: DropIndex P1 * P3
-**
-** Remove the internal (in-memory) data structures that describe
-** the index named P3 in database P1. This is called after an index
-** is dropped in order to keep the internal representation of the
-** schema consistent with what is on disk.
-*/
-case OP_DropIndex: {
- sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p3);
- break;
-}
-
-/* Opcode: DropTrigger P1 * P3
-**
-** Remove the internal (in-memory) data structures that describe
-** the trigger named P3 in database P1. This is called after a trigger
-** is dropped in order to keep the internal representation of the
-** schema consistent with what is on disk.
-*/
-case OP_DropTrigger: {
- sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p3);
- break;
-}
-
-
-/* Opcode: IntegrityCk * P2 *
-**
-** Do an analysis of the currently open database. Push onto the
-** stack the text of an error message describing any problems.
-** If there are no errors, push a "ok" onto the stack.
-**
-** The root page numbers of all tables in the database are integer
-** values on the stack. This opcode pulls as many integers as it
-** can off of the stack and uses those numbers as the root pages.
-**
-** If P2 is not zero, the check is done on the auxiliary database
-** file, not the main database file.
-**
-** This opcode is used for testing purposes only.
-*/
-case OP_IntegrityCk: {
- int nRoot;
- int *aRoot;
- int j;
- char *z;
-
- for(nRoot=0; &pTos[-nRoot]>=p->aStack; nRoot++){
- if( (pTos[-nRoot].flags & MEM_Int)==0 ) break;
- }
- assert( nRoot>0 );
- aRoot = sqliteMallocRaw( sizeof(int*)*(nRoot+1) );
- if( aRoot==0 ) goto no_mem;
- for(j=0; j<nRoot; j++){
- Mem *pMem = &pTos[-j];
- aRoot[j] = pMem->i;
- }
- aRoot[j] = 0;
- popStack(&pTos, nRoot);
- pTos++;
- z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot);
- if( z==0 || z[0]==0 ){
- if( z ) sqliteFree(z);
- pTos->z = "ok";
- pTos->n = 2;
- pTos->flags = MEM_Str | MEM_Static | MEM_Term;
- }else{
- pTos->z = z;
- pTos->n = strlen(z);
- pTos->flags = MEM_Str | MEM_Dyn | MEM_Term;
- pTos->xDel = 0;
- }
- pTos->enc = SQLITE_UTF8;
- sqlite3VdbeChangeEncoding(pTos, db->enc);
- sqliteFree(aRoot);
- break;
-}
-
-/* Opcode: ListWrite * * *
-**
-** Write the integer on the top of the stack
-** into the temporary storage list.
-*/
-case OP_ListWrite: {
- Keylist *pKeylist;
- assert( pTos>=p->aStack );
- pKeylist = p->pList;
- if( pKeylist==0 || pKeylist->nUsed>=pKeylist->nKey ){
- pKeylist = sqliteMallocRaw( sizeof(Keylist)+999*sizeof(pKeylist->aKey[0]) );
- if( pKeylist==0 ) goto no_mem;
- pKeylist->nKey = 1000;
- pKeylist->nRead = 0;
- pKeylist->nUsed = 0;
- pKeylist->pNext = p->pList;
- p->pList = pKeylist;
- }
- Integerify(pTos);
- pKeylist->aKey[pKeylist->nUsed++] = pTos->i;
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos--;
- break;
-}
-
-/* Opcode: ListRewind * * *
-**
-** Rewind the temporary buffer back to the beginning.
-*/
-case OP_ListRewind: {
- /* What this opcode codes, really, is reverse the order of the
- ** linked list of Keylist structures so that they are read out
- ** in the same order that they were read in. */
- Keylist *pRev, *pTop;
- pRev = 0;
- while( p->pList ){
- pTop = p->pList;
- p->pList = pTop->pNext;
- pTop->pNext = pRev;
- pRev = pTop;
- }
- p->pList = pRev;
- break;
-}
-
-/* Opcode: ListRead * P2 *
-**
-** Attempt to read an integer from the temporary storage buffer
-** and push it onto the stack. If the storage buffer is empty,
-** push nothing but instead jump to P2.
-*/
-case OP_ListRead: {
- Keylist *pKeylist;
- CHECK_FOR_INTERRUPT;
- pKeylist = p->pList;
- if( pKeylist!=0 ){
- assert( pKeylist->nRead>=0 );
- assert( pKeylist->nRead<pKeylist->nUsed );
- assert( pKeylist->nRead<pKeylist->nKey );
- pTos++;
- pTos->i = pKeylist->aKey[pKeylist->nRead++];
- pTos->flags = MEM_Int;
- if( pKeylist->nRead>=pKeylist->nUsed ){
- p->pList = pKeylist->pNext;
- sqliteFree(pKeylist);
- }
- }else{
- pc = pOp->p2 - 1;
- }
- break;
-}
-
-/* Opcode: ListReset * * *
-**
-** Reset the temporary storage buffer so that it holds nothing.
-*/
-case OP_ListReset: {
- if( p->pList ){
- sqlite3VdbeKeylistFree(p->pList);
- p->pList = 0;
- }
- break;
-}
-
-/* Opcode: ContextPush * * *
-**
-** Save the current Vdbe context such that it can be restored by a ContextPop
-** opcode. The context stores the last insert row id, the last statement change
-** count, and the current statement change count.
-*/
-case OP_ContextPush: {
- int i = p->contextStackTop++;
- Context *pContext;
-
- assert( i>=0 );
- /* FIX ME: This should be allocated as part of the vdbe at compile-time */
- if( i>=p->contextStackDepth ){
- p->contextStackDepth = i+1;
- p->contextStack = sqliteRealloc(p->contextStack, sizeof(Context)*(i+1));
- if( p->contextStack==0 ) goto no_mem;
- }
- pContext = &p->contextStack[i];
- pContext->lastRowid = db->lastRowid;
- pContext->nChange = p->nChange;
- pContext->pList = p->pList;
- p->pList = 0;
- break;
-}
-
-/* Opcode: ContextPop * * *
-**
-** Restore the Vdbe context to the state it was in when contextPush was last
-** executed. The context stores the last insert row id, the last statement
-** change count, and the current statement change count.
-*/
-case OP_ContextPop: {
- Context *pContext = &p->contextStack[--p->contextStackTop];
- assert( p->contextStackTop>=0 );
- db->lastRowid = pContext->lastRowid;
- p->nChange = pContext->nChange;
- sqlite3VdbeKeylistFree(p->pList);
- p->pList = pContext->pList;
- break;
-}
-
-/* Opcode: SortPut * * *
-**
-** The TOS is the key and the NOS is the data. Pop both from the stack
-** and put them on the sorter. The key and data should have been
-** made using SortMakeKey and SortMakeRec, respectively.
-*/
-case OP_SortPut: {
- Mem *pNos = &pTos[-1];
- Sorter *pSorter;
- assert( pNos>=p->aStack );
- if( Dynamicify(pTos, db->enc) ) goto no_mem;
- pSorter = sqliteMallocRaw( sizeof(Sorter) );
- if( pSorter==0 ) goto no_mem;
- pSorter->pNext = p->pSort;
- p->pSort = pSorter;
- assert( pTos->flags & MEM_Dyn );
- pSorter->nKey = pTos->n;
- pSorter->zKey = pTos->z;
- pSorter->data.flags = MEM_Null;
- rc = sqlite3VdbeMemMove(&pSorter->data, pNos);
- pTos -= 2;
- break;
-}
-
-/* Opcode: Sort * * P3
-**
-** Sort all elements on the sorter. The algorithm is a
-** mergesort. The P3 argument is a pointer to a KeyInfo structure
-** that describes the keys to be sorted.
-*/
-case OP_Sort: {
- int i;
- KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3;
- Sorter *pElem;
- Sorter *apSorter[NSORT];
- pKeyInfo->enc = p->db->enc;
- for(i=0; i<NSORT; i++){
- apSorter[i] = 0;
- }
- while( p->pSort ){
- pElem = p->pSort;
- p->pSort = pElem->pNext;
- pElem->pNext = 0;
- for(i=0; i<NSORT-1; i++){
- if( apSorter[i]==0 ){
- apSorter[i] = pElem;
- break;
- }else{
- pElem = Merge(apSorter[i], pElem, pKeyInfo);
- apSorter[i] = 0;
- }
- }
- if( i>=NSORT-1 ){
- apSorter[NSORT-1] = Merge(apSorter[NSORT-1],pElem, pKeyInfo);
- }
- }
- pElem = 0;
- for(i=0; i<NSORT; i++){
- pElem = Merge(apSorter[i], pElem, pKeyInfo);
- }
- p->pSort = pElem;
- break;
-}
-
-/* Opcode: SortNext * P2 *
-**
-** Push the data for the topmost element in the sorter onto the
-** stack, then remove the element from the sorter. If the sorter
-** is empty, push nothing on the stack and instead jump immediately
-** to instruction P2.
-*/
-case OP_SortNext: {
- Sorter *pSorter = p->pSort;
- CHECK_FOR_INTERRUPT;
- if( pSorter!=0 ){
- p->pSort = pSorter->pNext;
- pTos++;
- pTos->flags = MEM_Null;
- rc = sqlite3VdbeMemMove(pTos, &pSorter->data);
- sqliteFree(pSorter->zKey);
- sqliteFree(pSorter);
- }else{
- pc = pOp->p2 - 1;
- }
- break;
-}
-
-/* Opcode: SortReset * * *
-**
-** Remove any elements that remain on the sorter.
-*/
-case OP_SortReset: {
- sqlite3VdbeSorterReset(p);
- break;
-}
-
-/* Opcode: MemStore P1 P2 *
-**
-** Write the top of the stack into memory location P1.
-** P1 should be a small integer since space is allocated
-** for all memory locations between 0 and P1 inclusive.
-**
-** After the data is stored in the memory location, the
-** stack is popped once if P2 is 1. If P2 is zero, then
-** the original data remains on the stack.
-*/
-case OP_MemStore: {
- assert( pTos>=p->aStack );
- assert( pOp->p1>=0 && pOp->p1<p->nMem );
- rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], pTos);
- pTos--;
-
- /* If P2 is 0 then fall thru to the next opcode, OP_MemLoad, that will
- ** restore the top of the stack to its original value.
- */
- if( pOp->p2 ){
- break;
- }
-}
-/* Opcode: MemLoad P1 * *
-**
-** Push a copy of the value in memory location P1 onto the stack.
-**
-** If the value is a string, then the value pushed is a pointer to
-** the string that is stored in the memory location. If the memory
-** location is subsequently changed (using OP_MemStore) then the
-** value pushed onto the stack will change too.
-*/
-case OP_MemLoad: {
- int i = pOp->p1;
- assert( i>=0 && i<p->nMem );
- pTos++;
- sqlite3VdbeMemShallowCopy(pTos, &p->aMem[i], MEM_Ephem);
- break;
-}
-
-/* Opcode: MemIncr P1 P2 *
-**
-** Increment the integer valued memory cell P1 by 1. If P2 is not zero
-** and the result after the increment is greater than zero, then jump
-** to P2.
-**
-** This instruction throws an error if the memory cell is not initially
-** an integer.
-*/
-case OP_MemIncr: {
- int i = pOp->p1;
- Mem *pMem;
- assert( i>=0 && i<p->nMem );
- pMem = &p->aMem[i];
- assert( pMem->flags==MEM_Int );
- pMem->i++;
- if( pOp->p2>0 && pMem->i>0 ){
- pc = pOp->p2 - 1;
- }
- break;
-}
-
-/* Opcode: AggReset P1 P2 P3
-**
-** Reset the aggregator so that it no longer contains any data.
-** Future aggregator elements will contain P2 values each and be sorted
-** using the KeyInfo structure pointed to by P3.
-**
-** If P1 is non-zero, then only a single aggregator row is available (i.e.
-** there is no GROUP BY expression). In this case it is illegal to invoke
-** OP_AggFocus.
-*/
-case OP_AggReset: {
- assert( !pOp->p3 || pOp->p3type==P3_KEYINFO );
- if( pOp->p1 ){
- rc = sqlite3VdbeAggReset(0, &p->agg, (KeyInfo *)pOp->p3);
- p->agg.nMem = pOp->p2; /* Agg.nMem is used by AggInsert() */
- rc = AggInsert(&p->agg, 0, 0);
- }else{
- rc = sqlite3VdbeAggReset(db, &p->agg, (KeyInfo *)pOp->p3);
- p->agg.nMem = pOp->p2;
- }
- if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
- }
- p->agg.apFunc = sqliteMalloc( p->agg.nMem*sizeof(p->agg.apFunc[0]) );
- if( p->agg.apFunc==0 ) goto no_mem;
- break;
-}
-
-/* Opcode: AggInit * P2 P3
-**
-** Initialize the function parameters for an aggregate function.
-** The aggregate will operate out of aggregate column P2.
-** P3 is a pointer to the FuncDef structure for the function.
-*/
-case OP_AggInit: {
- int i = pOp->p2;
- assert( i>=0 && i<p->agg.nMem );
- p->agg.apFunc[i] = (FuncDef*)pOp->p3;
- break;
-}
-
-/* Opcode: AggFunc * P2 P3
-**
-** Execute the step function for an aggregate. The
-** function has P2 arguments. P3 is a pointer to the FuncDef
-** structure that specifies the function.
-**
-** The top of the stack must be an integer which is the index of
-** the aggregate column that corresponds to this aggregate function.
-** Ideally, this index would be another parameter, but there are
-** no free parameters left. The integer is popped from the stack.
-*/
-case OP_AggFunc: {
- int n = pOp->p2;
- int i;
- Mem *pMem, *pRec;
- sqlite3_context ctx;
- sqlite3_value **apVal;
-
- assert( n>=0 );
- assert( pTos->flags==MEM_Int );
- pRec = &pTos[-n];
- assert( pRec>=p->aStack );
-
- apVal = p->apArg;
- assert( apVal || n==0 );
-
- for(i=0; i<n; i++, pRec++){
- apVal[i] = pRec;
- storeTypeInfo(pRec, db->enc);
- }
- i = pTos->i;
- assert( i>=0 && i<p->agg.nMem );
- ctx.pFunc = (FuncDef*)pOp->p3;
- pMem = &p->agg.pCurrent->aMem[i];
- ctx.s.z = pMem->zShort; /* Space used for small aggregate contexts */
- ctx.pAgg = pMem->z;
- ctx.cnt = ++pMem->i;
- ctx.isError = 0;
- ctx.isStep = 1;
- ctx.pColl = 0;
- if( ctx.pFunc->needCollSeq ){
- assert( pOp>p->aOp );
- assert( pOp[-1].p3type==P3_COLLSEQ );
- assert( pOp[-1].opcode==OP_CollSeq );
- ctx.pColl = (CollSeq *)pOp[-1].p3;
- }
- (ctx.pFunc->xStep)(&ctx, n, apVal);
- pMem->z = ctx.pAgg;
- pMem->flags = MEM_AggCtx;
- popStack(&pTos, n+1);
- if( ctx.isError ){
- rc = SQLITE_ERROR;
- }
- break;
-}
-
-/* Opcode: AggFocus * P2 *
-**
-** Pop the top of the stack and use that as an aggregator key. If
-** an aggregator with that same key already exists, then make the
-** aggregator the current aggregator and jump to P2. If no aggregator
-** with the given key exists, create one and make it current but
-** do not jump.
-**
-** The order of aggregator opcodes is important. The order is:
-** AggReset AggFocus AggNext. In other words, you must execute
-** AggReset first, then zero or more AggFocus operations, then
-** zero or more AggNext operations. You must not execute an AggFocus
-** in between an AggNext and an AggReset.
-*/
-case OP_AggFocus: {
- char *zKey;
- int nKey;
- int res;
- assert( pTos>=p->aStack );
- Stringify(pTos, db->enc);
- zKey = pTos->z;
- nKey = pTos->n;
- assert( p->agg.pBtree );
- assert( p->agg.pCsr );
- rc = sqlite3BtreeMoveto(p->agg.pCsr, zKey, nKey, &res);
- if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
- }
- if( res==0 ){
- rc = sqlite3BtreeData(p->agg.pCsr, 0, sizeof(AggElem*),
- (char *)&p->agg.pCurrent);
- pc = pOp->p2 - 1;
- }else{
- rc = AggInsert(&p->agg, zKey, nKey);
- }
- if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
- }
- Release(pTos);
- pTos--;
- break;
-}
-
-/* Opcode: AggSet * P2 *
-**
-** Move the top of the stack into the P2-th field of the current
-** aggregate. String values are duplicated into new memory.
-*/
-case OP_AggSet: {
- AggElem *pFocus;
- int i = pOp->p2;
- pFocus = p->agg.pCurrent;
- assert( pTos>=p->aStack );
- if( pFocus==0 ) goto no_mem;
- assert( i>=0 && i<p->agg.nMem );
- rc = sqlite3VdbeMemMove(&pFocus->aMem[i], pTos);
- pTos--;
- break;
-}
-
-/* Opcode: AggGet * P2 *
-**
-** Push a new entry onto the stack which is a copy of the P2-th field
-** of the current aggregate. Strings are not duplicated so
-** string values will be ephemeral.
-*/
-case OP_AggGet: {
- AggElem *pFocus;
- int i = pOp->p2;
- pFocus = p->agg.pCurrent;
- if( pFocus==0 ) goto no_mem;
- assert( i>=0 && i<p->agg.nMem );
- pTos++;
- sqlite3VdbeMemShallowCopy(pTos, &pFocus->aMem[i], MEM_Ephem);
- if( pTos->flags&MEM_Str ){
- sqlite3VdbeChangeEncoding(pTos, db->enc);
- }
- break;
-}
-
-/* Opcode: AggNext * P2 *
-**
-** Make the next aggregate value the current aggregate. The prior
-** aggregate is deleted. If all aggregate values have been consumed,
-** jump to P2.
-**
-** The order of aggregator opcodes is important. The order is:
-** AggReset AggFocus AggNext. In other words, you must execute
-** AggReset first, then zero or more AggFocus operations, then
-** zero or more AggNext operations. You must not execute an AggFocus
-** in between an AggNext and an AggReset.
-*/
-case OP_AggNext: {
- int res;
- assert( rc==SQLITE_OK );
- CHECK_FOR_INTERRUPT;
- if( p->agg.searching==0 ){
- p->agg.searching = 1;
- if( p->agg.pCsr ){
- rc = sqlite3BtreeFirst(p->agg.pCsr, &res);
- }else{
- res = 0;
- }
- }else{
- if( p->agg.pCsr ){
- rc = sqlite3BtreeNext(p->agg.pCsr, &res);
- }else{
- res = 1;
- }
- }
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
- if( res!=0 ){
- pc = pOp->p2 - 1;
- }else{
- int i;
- sqlite3_context ctx;
- Mem *aMem;
-
- if( p->agg.pCsr ){
- rc = sqlite3BtreeData(p->agg.pCsr, 0, sizeof(AggElem*),
- (char *)&p->agg.pCurrent);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
- }
- aMem = p->agg.pCurrent->aMem;
- for(i=0; i<p->agg.nMem; i++){
- FuncDef *pFunc = p->agg.apFunc[i];
- Mem *pMem = &aMem[i];
- if( pFunc==0 || pFunc->xFinalize==0 ) continue;
- ctx.s.flags = MEM_Null;
- ctx.s.z = pMem->zShort;
- ctx.pAgg = (void*)pMem->z;
- ctx.cnt = pMem->i;
- ctx.isStep = 0;
- ctx.pFunc = pFunc;
- pFunc->xFinalize(&ctx);
- pMem->z = ctx.pAgg;
- if( pMem->z && pMem->z!=pMem->zShort ){
- sqliteFree( pMem->z );
- }
- *pMem = ctx.s;
- if( pMem->flags & MEM_Short ){
- pMem->z = pMem->zShort;
- }
- }
- }
- break;
-}
-
-/* Opcode: Vacuum * * *
-**
-** Vacuum the entire database. This opcode will cause other virtual
-** machines to be created and run. It may not be called from within
-** a transaction.
-*/
-case OP_Vacuum: {
- if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
- rc = sqlite3RunVacuum(&p->zErrMsg, db);
- if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
- break;
-}
-
-/* An other opcode is illegal...
-*/
-default: {
- sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",pOp->opcode);
- sqlite3SetString(&p->zErrMsg, "unknown opcode ", zBuf, (char*)0);
- rc = SQLITE_INTERNAL;
- break;
-}
-
-/*****************************************************************************
-** The cases of the switch statement above this line should all be indented
-** by 6 spaces. But the left-most 6 spaces have been removed to improve the
-** readability. From this point on down, the normal indentation rules are
-** restored.
-*****************************************************************************/
- }
-
-#ifdef VDBE_PROFILE
- {
- long long elapse = hwtime() - start;
- pOp->cycles += elapse;
- pOp->cnt++;
-#if 0
- fprintf(stdout, "%10lld ", elapse);
- sqlite3VdbePrintOp(stdout, origPc, &p->aOp[origPc]);
-#endif
- }
-#endif
-
- /* The following code adds nothing to the actual functionality
- ** of the program. It is only here for testing and debugging.
- ** On the other hand, it does burn CPU cycles every time through
- ** the evaluator loop. So we can leave it out when NDEBUG is defined.
- */
-#ifndef NDEBUG
- /* Sanity checking on the top element of the stack */
- if( pTos>=p->aStack ){
- sqlite3VdbeMemSanity(pTos, db->enc);
- }
- if( pc<-1 || pc>=p->nOp ){
- sqlite3SetString(&p->zErrMsg, "jump destination out of range", (char*)0);
- rc = SQLITE_INTERNAL;
- }
- if( p->trace && pTos>=p->aStack ){
- int i;
- fprintf(p->trace, "Stack:");
- for(i=0; i>-5 && &pTos[i]>=p->aStack; i--){
- if( pTos[i].flags & MEM_Null ){
- fprintf(p->trace, " NULL");
- }else if( (pTos[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
- fprintf(p->trace, " si:%lld", pTos[i].i);
- }else if( pTos[i].flags & MEM_Int ){
- fprintf(p->trace, " i:%lld", pTos[i].i);
- }else if( pTos[i].flags & MEM_Real ){
- fprintf(p->trace, " r:%g", pTos[i].r);
- }else{
- char zBuf[100];
- sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf, 100);
- fprintf(p->trace, " ");
- fprintf(p->trace, "%s", zBuf);
- }
- }
- if( rc!=0 ) fprintf(p->trace," rc=%d",rc);
- fprintf(p->trace,"\n");
- }
-#endif
- } /* The end of the for(;;) loop the loops through opcodes */
-
- /* If we reach this point, it means that execution is finished.
- */
-vdbe_halt:
- if( rc ){
- p->rc = rc;
- rc = SQLITE_ERROR;
- }else{
- rc = SQLITE_DONE;
- }
- sqlite3VdbeHalt(p);
- p->pTos = pTos;
- return rc;
-
- /* Jump to here if a malloc() fails. It's hard to get a malloc()
- ** to fail on a modern VM computer, so this code is untested.
- */
-no_mem:
- sqlite3SetString(&p->zErrMsg, "out of memory", (char*)0);
- rc = SQLITE_NOMEM;
- goto vdbe_halt;
-
- /* Jump to here for an SQLITE_MISUSE error.
- */
-abort_due_to_misuse:
- rc = SQLITE_MISUSE;
- /* Fall thru into abort_due_to_error */
-
- /* Jump to here for any other kind of fatal error. The "rc" variable
- ** should hold the error number.
- */
-abort_due_to_error:
- if( p->zErrMsg==0 ){
- if( sqlite3_malloc_failed ) rc = SQLITE_NOMEM;
- sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0);
- }
- goto vdbe_halt;
-
- /* Jump to here if the sqlite3_interrupt() API sets the interrupt
- ** flag.
- */
-abort_due_to_interrupt:
- assert( db->flags & SQLITE_Interrupt );
- db->flags &= ~SQLITE_Interrupt;
- if( db->magic!=SQLITE_MAGIC_BUSY ){
- rc = SQLITE_MISUSE;
- }else{
- rc = SQLITE_INTERRUPT;
- }
- p->rc = rc;
- sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0);
- goto vdbe_halt;
-}
diff --git a/kopete/plugins/statistics/sqlite/vdbe.h b/kopete/plugins/statistics/sqlite/vdbe.h
deleted file mode 100644
index 490417a4..00000000
--- a/kopete/plugins/statistics/sqlite/vdbe.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** Header file for the Virtual DataBase Engine (VDBE)
-**
-** This header defines the interface to the virtual database engine
-** or VDBE. The VDBE implements an abstract machine that runs a
-** simple program to access and modify the underlying database.
-**
-** $Id$
-*/
-#ifndef _SQLITE_VDBE_H_
-#define _SQLITE_VDBE_H_
-#include <stdio.h>
-
-/*
-** A single VDBE is an opaque structure named "Vdbe". Only routines
-** in the source file sqliteVdbe.c are allowed to see the insides
-** of this structure.
-*/
-typedef struct Vdbe Vdbe;
-
-/*
-** A single instruction of the virtual machine has an opcode
-** and as many as three operands. The instruction is recorded
-** as an instance of the following structure:
-*/
-struct VdbeOp {
- u8 opcode; /* What operation to perform */
- int p1; /* First operand */
- int p2; /* Second parameter (often the jump destination) */
- char *p3; /* Third parameter */
- int p3type; /* P3_STATIC, P3_DYNAMIC or P3_POINTER */
-#ifdef VDBE_PROFILE
- int cnt; /* Number of times this instruction was executed */
- long long cycles; /* Total time spend executing this instruction */
-#endif
-};
-typedef struct VdbeOp VdbeOp;
-
-/*
-** A smaller version of VdbeOp used for the VdbeAddOpList() function because
-** it takes up less space.
-*/
-struct VdbeOpList {
- u8 opcode; /* What operation to perform */
- signed char p1; /* First operand */
- short int p2; /* Second parameter (often the jump destination) */
- char *p3; /* Third parameter */
-};
-typedef struct VdbeOpList VdbeOpList;
-
-/*
-** Allowed values of VdbeOp.p3type
-*/
-#define P3_NOTUSED 0 /* The P3 parameter is not used */
-#define P3_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */
-#define P3_STATIC (-2) /* Pointer to a static string */
-#define P3_POINTER (-3) /* P3 is a pointer to some structure or object */
-#define P3_COLLSEQ (-4) /* P3 is a pointer to a CollSeq structure */
-#define P3_FUNCDEF (-5) /* P3 is a pointer to a FuncDef structure */
-#define P3_KEYINFO (-6) /* P3 is a pointer to a KeyInfo structure */
-#define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */
-
-/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
-** is made. That copy is freed when the Vdbe is finalized. But if the
-** argument is P3_KEYINFO_HANDOFF, the passed in pointer is used. It still
-** gets freed when the Vdbe is finalized so it still should be obtained
-** from a single sqliteMalloc(). But no copy is made and the calling
-** function should *not* try to free the KeyInfo.
-*/
-#define P3_KEYINFO_HANDOFF (-7)
-
-/*
-** The following macro converts a relative address in the p2 field
-** of a VdbeOp structure into a negative number so that
-** sqlite3VdbeAddOpList() knows that the address is relative. Calling
-** the macro again restores the address.
-*/
-#define ADDR(X) (-1-(X))
-
-/*
-** The makefile scans the vdbe.c source file and creates the "opcodes.h"
-** header file that defines a number for each opcode used by the VDBE.
-*/
-#include "opcodes.h"
-
-/*
-** Prototypes for the VDBE interface. See comments on the implementation
-** for a description of what each of these routines does.
-*/
-Vdbe *sqlite3VdbeCreate(sqlite3*);
-void sqlite3VdbeCreateCallback(Vdbe*, int*);
-int sqlite3VdbeAddOp(Vdbe*,int,int,int);
-int sqlite3VdbeOp3(Vdbe*,int,int,int,const char *zP3,int);
-int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
-void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
-void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
-void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
-void sqlite3VdbeDequoteP3(Vdbe*, int addr);
-int sqlite3VdbeFindOp(Vdbe*, int, int, int);
-VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
-int sqlite3VdbeMakeLabel(Vdbe*);
-void sqlite3VdbeDelete(Vdbe*);
-void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
-int sqlite3VdbeFinalize(Vdbe*);
-void sqlite3VdbeResolveLabel(Vdbe*, int);
-int sqlite3VdbeCurrentAddr(Vdbe*);
-void sqlite3VdbeTrace(Vdbe*,FILE*);
-int sqlite3VdbeReset(Vdbe*);
-int sqliteVdbeSetVariables(Vdbe*,int,const char**);
-void sqlite3VdbeSetNumCols(Vdbe*,int);
-int sqlite3VdbeSetColName(Vdbe*, int, const char *, int);
-void sqlite3VdbeCountChanges(Vdbe*);
-
-#ifndef NDEBUG
- void sqlite3VdbeComment(Vdbe*, const char*, ...);
-# define VdbeComment(X) sqlite3VdbeComment X
-#else
-# define VdbeComment(X)
-#endif
-
-#endif
diff --git a/kopete/plugins/statistics/sqlite/vdbeInt.h b/kopete/plugins/statistics/sqlite/vdbeInt.h
deleted file mode 100644
index a929cb95..00000000
--- a/kopete/plugins/statistics/sqlite/vdbeInt.h
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
-** 2003 September 6
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This is the header file for information that is private to the
-** VDBE. This information used to all be at the top of the single
-** source code file "vdbe.c". When that file became too big (over
-** 6000 lines long) it was split up into several smaller files and
-** this header information was factored out.
-*/
-
-/*
-** intToKey() and keyToInt() used to transform the rowid. But with
-** the latest versions of the design they are no-ops.
-*/
-#define keyToInt(X) (X)
-#define intToKey(X) (X)
-
-/*
-** The makefile scans the vdbe.c source file and creates the following
-** array of string constants which are the names of all VDBE opcodes. This
-** array is defined in a separate source code file named opcode.c which is
-** automatically generated by the makefile.
-*/
-extern char *sqlite3OpcodeNames[];
-
-/*
-** SQL is translated into a sequence of instructions to be
-** executed by a virtual machine. Each instruction is an instance
-** of the following structure.
-*/
-typedef struct VdbeOp Op;
-
-/*
-** Boolean values
-*/
-typedef unsigned char Bool;
-
-/*
-** A cursor is a pointer into a single BTree within a database file.
-** The cursor can seek to a BTree entry with a particular key, or
-** loop over all entries of the Btree. You can also insert new BTree
-** entries or retrieve the key or data from the entry that the cursor
-** is currently pointing to.
-**
-** Every cursor that the virtual machine has open is represented by an
-** instance of the following structure.
-**
-** If the Cursor.isTriggerRow flag is set it means that this cursor is
-** really a single row that represents the NEW or OLD pseudo-table of
-** a row trigger. The data for the row is stored in Cursor.pData and
-** the rowid is in Cursor.iKey.
-*/
-struct Cursor {
- BtCursor *pCursor; /* The cursor structure of the backend */
- i64 lastRecno; /* Last recno from a Next or NextIdx operation */
- i64 nextRowid; /* Next rowid returned by OP_NewRowid */
- Bool zeroed; /* True if zeroed out and ready for reuse */
- Bool recnoIsValid; /* True if lastRecno is valid */
- Bool keyAsData; /* The OP_Column command works on key instead of data */
- Bool atFirst; /* True if pointing to first entry */
- Bool useRandomRowid; /* Generate new record numbers semi-randomly */
- Bool nullRow; /* True if pointing to a row with no data */
- Bool nextRowidValid; /* True if the nextRowid field is valid */
- Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */
- Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
- Bool intKey; /* True if the table requires integer keys */
- Bool zeroData; /* True if table contains keys only - no data */
- u8 bogusIncrKey; /* Something for pIncrKey to point to if pKeyInfo==0 */
- i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
- Btree *pBt; /* Separate file holding temporary table */
- int nData; /* Number of bytes in pData */
- char *pData; /* Data for a NEW or OLD pseudo-table */
- i64 iKey; /* Key for the NEW or OLD pseudo-table row */
- u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */
- KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
- int nField; /* Number of fields in the header */
-
- /* Cached information about the header for the data record that the
- ** cursor is currently pointing to. Only valid if cacheValid is true.
- ** zRow might point to (ephemeral) data for the current row, or it might
- ** be NULL. */
- Bool cacheValid; /* True if the cache is valid */
- int payloadSize; /* Total number of bytes in the record */
- u32 *aType; /* Type values for all entries in the record */
- u32 *aOffset; /* Cached offsets to the start of each columns data */
- u8 *aRow; /* Data for the current row, if all on one page */
-};
-typedef struct Cursor Cursor;
-
-/*
-** Number of bytes of string storage space available to each stack
-** layer without having to malloc. NBFS is short for Number of Bytes
-** For Strings.
-*/
-#define NBFS 32
-
-/*
-** Internally, the vdbe manipulates nearly all SQL values as Mem
-** structures. Each Mem struct may cache multiple representations (string,
-** integer etc.) of the same value. A value (and therefore Mem structure)
-** has the following properties:
-**
-** Each value has a manifest type. The manifest type of the value stored
-** in a Mem struct is returned by the MemType(Mem*) macro. The type is
-** one of SQLITE_NULL, SQLITE_INTEGER, SQLITE_REAL, SQLITE_TEXT or
-** SQLITE_BLOB.
-*/
-struct Mem {
- i64 i; /* Integer value */
- int n; /* Number of characters in string value, including '\0' */
- u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
- u8 type; /* One of MEM_Null, MEM_Str, etc. */
- u8 enc; /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */
- double r; /* Real value */
- char *z; /* String or BLOB value */
- void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
- char zShort[NBFS]; /* Space for short strings */
-};
-typedef struct Mem Mem;
-
-/*
-** A sorter builds a list of elements to be sorted. Each element of
-** the list is an instance of the following structure.
-*/
-typedef struct Sorter Sorter;
-struct Sorter {
- int nKey; /* Number of bytes in the key */
- char *zKey; /* The key by which we will sort */
- Mem data;
- Sorter *pNext; /* Next in the list */
-};
-
-/*
-** Number of buckets used for merge-sort.
-*/
-#define NSORT 30
-
-/* One or more of the following flags are set to indicate the validOK
-** representations of the value stored in the Mem struct.
-**
-** If the MEM_Null flag is set, then the value is an SQL NULL value.
-** No other flags may be set in this case.
-**
-** If the MEM_Str flag is set then Mem.z points at a string representation.
-** Usually this is encoded in the same unicode encoding as the main
-** database (see below for exceptions). If the MEM_Term flag is also
-** set, then the string is nul terminated. The MEM_Int and MEM_Real
-** flags may coexist with the MEM_Str flag.
-**
-** Multiple of these values can appear in Mem.flags. But only one
-** at a time can appear in Mem.type.
-*/
-#define MEM_Null 0x0001 /* Value is NULL */
-#define MEM_Str 0x0002 /* Value is a string */
-#define MEM_Int 0x0004 /* Value is an integer */
-#define MEM_Real 0x0008 /* Value is a real number */
-#define MEM_Blob 0x0010 /* Value is a BLOB */
-
-/* Whenever Mem contains a valid string or blob representation, one of
-** the following flags must be set to determine the memory management
-** policy for Mem.z. The MEM_Term flag tells us whether or not the
-** string is \000 or \u0000 terminated
-*/
-#define MEM_Term 0x0020 /* String rep is nul terminated */
-#define MEM_Dyn 0x0040 /* Need to call sqliteFree() on Mem.z */
-#define MEM_Static 0x0080 /* Mem.z points to a static string */
-#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */
-#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */
-
-/* The following MEM_ value appears only in AggElem.aMem.s.flag fields.
-** It indicates that the corresponding AggElem.aMem.z points to a
-** aggregate function context that needs to be finalized.
-*/
-#define MEM_AggCtx 0x0400 /* Mem.z points to an agg function context */
-
-
-/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
-** additional information about auxiliary information bound to arguments
-** of the function. This is used to implement the sqlite3_get_auxdata()
-** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data
-** that can be associated with a constant argument to a function. This
-** allows functions such as "regexp" to compile their constant regular
-** expression argument once and reused the compiled code for multiple
-** invocations.
-*/
-struct VdbeFunc {
- FuncDef *pFunc; /* The definition of the function */
- int nAux; /* Number of entries allocated for apAux[] */
- struct AuxData {
- void *pAux; /* Aux data for the i-th argument */
- void (*xDelete)(void *); /* Destructor for the aux data */
- } apAux[1]; /* One slot for each function argument */
-};
-typedef struct VdbeFunc VdbeFunc;
-
-/*
-** The "context" argument for a installable function. A pointer to an
-** instance of this structure is the first argument to the routines used
-** implement the SQL functions.
-**
-** There is a typedef for this structure in sqlite.h. So all routines,
-** even the public interface to SQLite, can use a pointer to this structure.
-** But this file is the only place where the internal details of this
-** structure are known.
-**
-** This structure is defined inside of vdbe.c because it uses substructures
-** (Mem) which are only defined there.
-*/
-struct sqlite3_context {
- FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
- VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
- Mem s; /* The return value is stored here */
- void *pAgg; /* Aggregate context */
- u8 isError; /* Set to true for an error */
- u8 isStep; /* Current in the step function */
- int cnt; /* Number of times that the step function has been called */
- CollSeq *pColl;
-};
-
-/*
-** An Agg structure describes an Aggregator. Each Agg consists of
-** zero or more Aggregator elements (AggElem). Each AggElem contains
-** a key and one or more values. The values are used in processing
-** aggregate functions in a SELECT. The key is used to implement
-** the GROUP BY clause of a select.
-*/
-typedef struct Agg Agg;
-typedef struct AggElem AggElem;
-struct Agg {
- int nMem; /* Number of values stored in each AggElem */
- AggElem *pCurrent; /* The AggElem currently in focus */
- FuncDef **apFunc; /* Information about aggregate functions */
- Btree *pBtree; /* The tmp. btree used to group elements, if required. */
- BtCursor *pCsr; /* Read/write cursor to the table in pBtree */
- int nTab; /* Root page of the table in pBtree */
- u8 searching; /* True between the first AggNext and AggReset */
-};
-struct AggElem {
- char *zKey; /* The key to this AggElem */
- int nKey; /* Number of bytes in the key, including '\0' at end */
- Mem aMem[1]; /* The values for this AggElem */
-};
-
-/*
-** A Set structure is used for quick testing to see if a value
-** is part of a small set. Sets are used to implement code like
-** this:
-** x.y IN ('hi','hoo','hum')
-*/
-typedef struct Set Set;
-struct Set {
- Hash hash; /* A set is just a hash table */
- HashElem *prev; /* Previously accessed hash elemen */
-};
-
-/*
-** A Keylist is a bunch of keys into a table. The keylist can
-** grow without bound. The keylist stores the ROWIDs of database
-** records that need to be deleted or updated.
-*/
-typedef struct Keylist Keylist;
-struct Keylist {
- int nKey; /* Number of slots in aKey[] */
- int nUsed; /* Next unwritten slot in aKey[] */
- int nRead; /* Next unread slot in aKey[] */
- Keylist *pNext; /* Next block of keys */
- i64 aKey[1]; /* One or more keys. Extra space allocated as needed */
-};
-
-/*
-** A Context stores the last insert rowid, the last statement change count,
-** and the current statement change count (i.e. changes since last statement).
-** The current keylist is also stored in the context.
-** Elements of Context structure type make up the ContextStack, which is
-** updated by the ContextPush and ContextPop opcodes (used by triggers).
-** The context is pushed before executing a trigger a popped when the
-** trigger finishes.
-*/
-typedef struct Context Context;
-struct Context {
- int lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
- int nChange; /* Statement changes (Vdbe.nChanges) */
- Keylist *pList; /* Records that will participate in a DELETE or UPDATE */
-};
-
-/*
-** An instance of the virtual machine. This structure contains the complete
-** state of the virtual machine.
-**
-** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile()
-** is really a pointer to an instance of this structure.
-*/
-struct Vdbe {
- sqlite3 *db; /* The whole database */
- Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
- FILE *trace; /* Write an execution trace here, if not NULL */
- int nOp; /* Number of instructions in the program */
- int nOpAlloc; /* Number of slots allocated for aOp[] */
- Op *aOp; /* Space to hold the virtual machine's program */
- int nLabel; /* Number of labels used */
- int nLabelAlloc; /* Number of slots allocated in aLabel[] */
- int *aLabel; /* Space to hold the labels */
- Mem *aStack; /* The operand stack, except string values */
- Mem *pTos; /* Top entry in the operand stack */
- Mem **apArg; /* Arguments to currently executing user function */
- Mem *aColName; /* Column names to return */
- int nCursor; /* Number of slots in apCsr[] */
- Cursor **apCsr; /* One element of this array for each open cursor */
- Sorter *pSort; /* A linked list of objects to be sorted */
- int nVar; /* Number of entries in aVar[] */
- Mem *aVar; /* Values for the OP_Variable opcode. */
- char **azVar; /* Name of variables */
- int okVar; /* True if azVar[] has been initialized */
- int magic; /* Magic number for sanity checking */
- int nMem; /* Number of memory locations currently allocated */
- Mem *aMem; /* The memory locations */
- Agg agg; /* Aggregate information */
- int nCallback; /* Number of callbacks invoked so far */
- Keylist *pList; /* A list of ROWIDs */
- int contextStackTop; /* Index of top element in the context stack */
- int contextStackDepth; /* The size of the "context" stack */
- Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
- int pc; /* The program counter */
- int rc; /* Value to return */
- unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
- int errorAction; /* Recovery action to do in case of an error */
- int inTempTrans; /* True if temp database is transactioned */
- int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */
- int returnDepth; /* Next unused element in returnStack[] */
- int nResColumn; /* Number of columns in one row of the result set */
- char **azResColumn; /* Values for one row of result */
- int popStack; /* Pop the stack this much on entry to VdbeExec() */
- char *zErrMsg; /* Error message written here */
- u8 resOnStack; /* True if there are result values on the stack */
- u8 explain; /* True if EXPLAIN present on SQL command */
- u8 changeCntOn; /* True to update the change-counter */
- u8 aborted; /* True if ROLLBACK in another VM causes an abort */
- int nChange; /* Number of db changes made since last reset */
-};
-
-/*
-** The following are allowed values for Vdbe.magic
-*/
-#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */
-#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */
-#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */
-#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */
-
-/*
-** Function prototypes
-*/
-void sqlite3VdbeFreeCursor(Cursor*);
-void sqlite3VdbeSorterReset(Vdbe*);
-int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *);
-void sqlite3VdbeKeylistFree(Keylist*);
-void sqliteVdbePopStack(Vdbe*,int);
-int sqlite3VdbeCursorMoveto(Cursor*);
-#if !defined(NDEBUG) || defined(VDBE_PROFILE)
-void sqlite3VdbePrintOp(FILE*, int, Op*);
-#endif
-void sqlite3VdbePrintSql(Vdbe*);
-int sqlite3VdbeSerialTypeLen(u32);
-u32 sqlite3VdbeSerialType(Mem*);
-int sqlite3VdbeSerialPut(unsigned char*, Mem*);
-int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
-void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
-
-int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
-int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*);
-int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
-int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
-int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*);
-int sqlite3VdbeIdxRowidLen(int,const u8*);
-int sqlite3VdbeExec(Vdbe*);
-int sqlite3VdbeList(Vdbe*);
-int sqlite3VdbeHalt(Vdbe*);
-int sqlite3VdbeChangeEncoding(Mem *, int);
-int sqlite3VdbeMemCopy(Mem*, const Mem*);
-void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
-int sqlite3VdbeMemMove(Mem*, Mem*);
-int sqlite3VdbeMemNulTerminate(Mem*);
-int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
-void sqlite3VdbeMemSetInt64(Mem*, i64);
-void sqlite3VdbeMemSetDouble(Mem*, double);
-void sqlite3VdbeMemSetNull(Mem*);
-int sqlite3VdbeMemMakeWriteable(Mem*);
-int sqlite3VdbeMemDynamicify(Mem*);
-int sqlite3VdbeMemStringify(Mem*, int);
-i64 sqlite3VdbeIntValue(Mem*);
-int sqlite3VdbeMemIntegerify(Mem*);
-double sqlite3VdbeRealValue(Mem*);
-int sqlite3VdbeMemRealify(Mem*);
-int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
-void sqlite3VdbeMemRelease(Mem *p);
-#ifndef NDEBUG
-void sqlite3VdbeMemSanity(Mem*, u8);
-#endif
-int sqlite3VdbeMemTranslate(Mem*, u8);
-void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf);
-int sqlite3VdbeMemHandleBom(Mem *pMem);
diff --git a/kopete/plugins/statistics/sqlite/vdbeapi.c b/kopete/plugins/statistics/sqlite/vdbeapi.c
deleted file mode 100644
index f6047f6f..00000000
--- a/kopete/plugins/statistics/sqlite/vdbeapi.c
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
-** 2004 May 26
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-**
-** This file contains code use to implement APIs that are part of the
-** VDBE.
-*/
-#include "sqliteInt.h"
-#include "vdbeInt.h"
-
-/**************************** sqlite3_value_ *******************************
-** The following routines extract information from a Mem or sqlite3_value
-** structure.
-*/
-const void *sqlite3_value_blob(sqlite3_value *pVal){
- Mem *p = (Mem*)pVal;
- if( p->flags & (MEM_Blob|MEM_Str) ){
- return p->z;
- }else{
- return sqlite3_value_text(pVal);
- }
-}
-int sqlite3_value_bytes(sqlite3_value *pVal){
- return sqlite3ValueBytes(pVal, SQLITE_UTF8);
-}
-int sqlite3_value_bytes16(sqlite3_value *pVal){
- return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE);
-}
-double sqlite3_value_double(sqlite3_value *pVal){
- return sqlite3VdbeRealValue((Mem*)pVal);
-}
-int sqlite3_value_int(sqlite3_value *pVal){
- return sqlite3VdbeIntValue((Mem*)pVal);
-}
-sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
- return sqlite3VdbeIntValue((Mem*)pVal);
-}
-const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
- return (const char *)sqlite3ValueText(pVal, SQLITE_UTF8);
-}
-const void *sqlite3_value_text16(sqlite3_value* pVal){
- return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
-}
-const void *sqlite3_value_text16be(sqlite3_value *pVal){
- return sqlite3ValueText(pVal, SQLITE_UTF16BE);
-}
-const void *sqlite3_value_text16le(sqlite3_value *pVal){
- return sqlite3ValueText(pVal, SQLITE_UTF16LE);
-}
-int sqlite3_value_type(sqlite3_value* pVal){
- return pVal->type;
-}
-
-/**************************** sqlite3_result_ *******************************
-** The following routines are used by user-defined functions to specify
-** the function result.
-*/
-void sqlite3_result_blob(
- sqlite3_context *pCtx,
- const void *z,
- int n,
- void (*xDel)(void *)
-){
- assert( n>0 );
- sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, xDel);
-}
-void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
- sqlite3VdbeMemSetDouble(&pCtx->s, rVal);
-}
-void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
- pCtx->isError = 1;
- sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
-}
-void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
- pCtx->isError = 1;
- sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
-}
-void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
- sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal);
-}
-void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
- sqlite3VdbeMemSetInt64(&pCtx->s, iVal);
-}
-void sqlite3_result_null(sqlite3_context *pCtx){
- sqlite3VdbeMemSetNull(&pCtx->s);
-}
-void sqlite3_result_text(
- sqlite3_context *pCtx,
- const char *z,
- int n,
- void (*xDel)(void *)
-){
- sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, xDel);
-}
-void sqlite3_result_text16(
- sqlite3_context *pCtx,
- const void *z,
- int n,
- void (*xDel)(void *)
-){
- sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, xDel);
-}
-void sqlite3_result_text16be(
- sqlite3_context *pCtx,
- const void *z,
- int n,
- void (*xDel)(void *)
-){
- sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16BE, xDel);
-}
-void sqlite3_result_text16le(
- sqlite3_context *pCtx,
- const void *z,
- int n,
- void (*xDel)(void *)
-){
- sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16LE, xDel);
-}
-void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
- sqlite3VdbeMemCopy(&pCtx->s, pValue);
-}
-
-
-/*
-** Execute the statement pStmt, either until a row of data is ready, the
-** statement is completely executed or an error occurs.
-*/
-int sqlite3_step(sqlite3_stmt *pStmt){
- Vdbe *p = (Vdbe*)pStmt;
- sqlite3 *db;
- int rc;
-
- if( p==0 || p->magic!=VDBE_MAGIC_RUN ){
- return SQLITE_MISUSE;
- }
- if( p->aborted ){
- return SQLITE_ABORT;
- }
- db = p->db;
- if( sqlite3SafetyOn(db) ){
- p->rc = SQLITE_MISUSE;
- return SQLITE_MISUSE;
- }
- if( p->pc<0 ){
- /* Invoke the trace callback if there is one
- */
- if( (db = p->db)->xTrace && !db->init.busy ){
- assert( p->nOp>0 );
- assert( p->aOp[p->nOp-1].opcode==OP_Noop );
- assert( p->aOp[p->nOp-1].p3!=0 );
- assert( p->aOp[p->nOp-1].p3type==P3_DYNAMIC );
- sqlite3SafetyOff(db);
- db->xTrace(db->pTraceArg, p->aOp[p->nOp-1].p3);
- if( sqlite3SafetyOn(db) ){
- p->rc = SQLITE_MISUSE;
- return SQLITE_MISUSE;
- }
- }
-
- /* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned
- ** on in debugging mode.
- */
-#ifdef SQLITE_DEBUG
- if( (db->flags & SQLITE_SqlTrace)!=0 ){
- sqlite3DebugPrintf("SQL-trace: %s\n", p->aOp[p->nOp-1].p3);
- }
-#endif /* SQLITE_DEBUG */
-
- db->activeVdbeCnt++;
- p->pc = 0;
- }
- if( p->explain ){
- rc = sqlite3VdbeList(p);
- }else{
- rc = sqlite3VdbeExec(p);
- }
-
- if( sqlite3SafetyOff(db) ){
- rc = SQLITE_MISUSE;
- }
-
- sqlite3Error(p->db, rc, p->zErrMsg);
- return rc;
-}
-
-/*
-** Extract the user data from a sqlite3_context structure and return a
-** pointer to it.
-*/
-void *sqlite3_user_data(sqlite3_context *p){
- assert( p && p->pFunc );
- return p->pFunc->pUserData;
-}
-
-/*
-** Allocate or return the aggregate context for a user function. A new
-** context is allocated on the first call. Subsequent calls return the
-** same context that was returned on prior calls.
-**
-** This routine is defined here in vdbe.c because it depends on knowing
-** the internals of the sqlite3_context structure which is only defined in
-** this source file.
-*/
-void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
- assert( p && p->pFunc && p->pFunc->xStep );
- if( p->pAgg==0 ){
- if( nByte<=NBFS ){
- p->pAgg = (void*)p->s.z;
- memset(p->pAgg, 0, nByte);
- }else{
- p->pAgg = sqliteMalloc( nByte );
- }
- }
- return p->pAgg;
-}
-
-/*
-** Return the auxilary data pointer, if any, for the iArg'th argument to
-** the user-function defined by pCtx.
-*/
-void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
- VdbeFunc *pVdbeFunc = pCtx->pVdbeFunc;
- if( !pVdbeFunc || iArg>=pVdbeFunc->nAux || iArg<0 ){
- return 0;
- }
- return pVdbeFunc->apAux[iArg].pAux;
-}
-
-/*
-** Set the auxilary data pointer and delete function, for the iArg'th
-** argument to the user-function defined by pCtx. Any previous value is
-** deleted by calling the delete function specified when it was set.
-*/
-void sqlite3_set_auxdata(
- sqlite3_context *pCtx,
- int iArg,
- void *pAux,
- void (*xDelete)(void*)
-){
- struct AuxData *pAuxData;
- VdbeFunc *pVdbeFunc;
- if( iArg<0 ) return;
-
- pVdbeFunc = pCtx->pVdbeFunc;
- if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){
- int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg;
- pCtx->pVdbeFunc = pVdbeFunc = sqliteRealloc(pVdbeFunc, nMalloc);
- if( !pVdbeFunc ) return;
- memset(&pVdbeFunc->apAux[pVdbeFunc->nAux], 0,
- sizeof(struct AuxData)*(iArg+1-pVdbeFunc->nAux));
- pVdbeFunc->nAux = iArg+1;
- pVdbeFunc->pFunc = pCtx->pFunc;
- }
-
- pAuxData = &pVdbeFunc->apAux[iArg];
- if( pAuxData->pAux && pAuxData->xDelete ){
- pAuxData->xDelete(pAuxData->pAux);
- }
- pAuxData->pAux = pAux;
- pAuxData->xDelete = xDelete;
-}
-
-/*
-** Return the number of times the Step function of a aggregate has been
-** called.
-**
-** This routine is defined here in vdbe.c because it depends on knowing
-** the internals of the sqlite3_context structure which is only defined in
-** this source file.
-*/
-int sqlite3_aggregate_count(sqlite3_context *p){
- assert( p && p->pFunc && p->pFunc->xStep );
- return p->cnt;
-}
-
-/*
-** Return the number of columns in the result set for the statement pStmt.
-*/
-int sqlite3_column_count(sqlite3_stmt *pStmt){
- Vdbe *pVm = (Vdbe *)pStmt;
- return pVm ? pVm->nResColumn : 0;
-}
-
-/*
-** Return the number of values available from the current row of the
-** currently executing statement pStmt.
-*/
-int sqlite3_data_count(sqlite3_stmt *pStmt){
- Vdbe *pVm = (Vdbe *)pStmt;
- if( pVm==0 || !pVm->resOnStack ) return 0;
- return pVm->nResColumn;
-}
-
-
-/*
-** Check to see if column iCol of the given statement is valid. If
-** it is, return a pointer to the Mem for the value of that column.
-** If iCol is not valid, return a pointer to a Mem which has a value
-** of NULL.
-*/
-static Mem *columnMem(sqlite3_stmt *pStmt, int i){
- Vdbe *pVm = (Vdbe *)pStmt;
- int vals = sqlite3_data_count(pStmt);
- if( i>=vals || i<0 ){
- static Mem nullMem;
- if( nullMem.flags==0 ){ nullMem.flags = MEM_Null; }
- sqlite3Error(pVm->db, SQLITE_RANGE, 0);
- return &nullMem;
- }
- return &pVm->pTos[(1-vals)+i];
-}
-
-/**************************** sqlite3_column_ *******************************
-** The following routines are used to access elements of the current row
-** in the result set.
-*/
-const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_blob( columnMem(pStmt,i) );
-}
-int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_bytes( columnMem(pStmt,i) );
-}
-int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_bytes16( columnMem(pStmt,i) );
-}
-double sqlite3_column_double(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_double( columnMem(pStmt,i) );
-}
-int sqlite3_column_int(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_int( columnMem(pStmt,i) );
-}
-sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_int64( columnMem(pStmt,i) );
-}
-const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_text( columnMem(pStmt,i) );
-}
-const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_text16( columnMem(pStmt,i) );
-}
-int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_type( columnMem(pStmt,i) );
-}
-
-/*
-** Convert the N-th element of pStmt->pColName[] into a string using
-** xFunc() then return that string. If N is out of range, return 0.
-** If useType is 1, then use the second set of N elements (the datatype
-** names) instead of the first set.
-*/
-static const void *columnName(
- sqlite3_stmt *pStmt,
- int N,
- const void *(*xFunc)(Mem*),
- int useType
-){
- Vdbe *p = (Vdbe *)pStmt;
- int n = sqlite3_column_count(pStmt);
-
- if( p==0 || N>=n || N<0 ){
- return 0;
- }
- if( useType ){
- N += n;
- }
- return xFunc(&p->aColName[N]);
-}
-
-
-/*
-** Return the name of the Nth column of the result set returned by SQL
-** statement pStmt.
-*/
-const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 0);
-}
-
-/*
-** Return the name of the 'i'th column of the result set of SQL statement
-** pStmt, encoded as UTF-16.
-*/
-const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 0);
-}
-
-/*
-** Return the column declaration type (if applicable) of the 'i'th column
-** of the result set of SQL statement pStmt, encoded as UTF-8.
-*/
-const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 1);
-}
-
-/*
-** Return the column declaration type (if applicable) of the 'i'th column
-** of the result set of SQL statement pStmt, encoded as UTF-16.
-*/
-const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 1);
-}
-
-/******************************* sqlite3_bind_ ***************************
-**
-** Routines used to attach values to wildcards in a compiled SQL statement.
-*/
-/*
-** Unbind the value bound to variable i in virtual machine p. This is the
-** the same as binding a NULL value to the column. If the "i" parameter is
-** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK.
-**
-** The error code stored in database p->db is overwritten with the return
-** value in any case.
-*/
-static int vdbeUnbind(Vdbe *p, int i){
- Mem *pVar;
- if( p==0 || p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
- sqlite3Error(p->db, SQLITE_MISUSE, 0);
- return SQLITE_MISUSE;
- }
- if( i<1 || i>p->nVar ){
- sqlite3Error(p->db, SQLITE_RANGE, 0);
- return SQLITE_RANGE;
- }
- i--;
- pVar = &p->aVar[i];
- sqlite3VdbeMemRelease(pVar);
- pVar->flags = MEM_Null;
- sqlite3Error(p->db, SQLITE_OK, 0);
- return SQLITE_OK;
-}
-
-/*
-** Bind a text or BLOB value.
-*/
-static int bindText(
- sqlite3_stmt *pStmt,
- int i,
- const void *zData,
- int nData,
- void (*xDel)(void*),
- int encoding
-){
- Vdbe *p = (Vdbe *)pStmt;
- Mem *pVar;
- int rc;
-
- rc = vdbeUnbind(p, i);
- if( rc || zData==0 ){
- return rc;
- }
- pVar = &p->aVar[i-1];
- rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
- if( rc ){
- return rc;
- }
- if( rc==SQLITE_OK && encoding!=0 ){
- rc = sqlite3VdbeChangeEncoding(pVar, p->db->enc);
- }
- return rc;
-}
-
-
-/*
-** Bind a blob value to an SQL statement variable.
-*/
-int sqlite3_bind_blob(
- sqlite3_stmt *pStmt,
- int i,
- const void *zData,
- int nData,
- void (*xDel)(void*)
-){
- return bindText(pStmt, i, zData, nData, xDel, 0);
-}
-int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
- int rc;
- Vdbe *p = (Vdbe *)pStmt;
- rc = vdbeUnbind(p, i);
- if( rc==SQLITE_OK ){
- sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
- }
- return rc;
-}
-int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
- return sqlite3_bind_int64(p, i, (i64)iValue);
-}
-int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
- int rc;
- Vdbe *p = (Vdbe *)pStmt;
- rc = vdbeUnbind(p, i);
- if( rc==SQLITE_OK ){
- sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
- }
- return rc;
-}
-int sqlite3_bind_null(sqlite3_stmt* p, int i){
- return vdbeUnbind((Vdbe *)p, i);
-}
-int sqlite3_bind_text(
- sqlite3_stmt *pStmt,
- int i,
- const char *zData,
- int nData,
- void (*xDel)(void*)
-){
- return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
-}
-int sqlite3_bind_text16(
- sqlite3_stmt *pStmt,
- int i,
- const void *zData,
- int nData,
- void (*xDel)(void*)
-){
- return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
-}
-
-/*
-** Return the number of wildcards that can be potentially bound to.
-** This routine is added to support DBD::SQLite.
-*/
-int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
- Vdbe *p = (Vdbe*)pStmt;
- return p ? p->nVar : 0;
-}
-
-/*
-** Create a mapping from variable numbers to variable names
-** in the Vdbe.azVar[] array, if such a mapping does not already
-** exist.
-*/
-static void createVarMap(Vdbe *p){
- if( !p->okVar ){
- int j;
- Op *pOp;
- for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){
- if( pOp->opcode==OP_Variable ){
- assert( pOp->p1>0 && pOp->p1<=p->nVar );
- p->azVar[pOp->p1-1] = pOp->p3;
- }
- }
- p->okVar = 1;
- }
-}
-
-/*
-** Return the name of a wildcard parameter. Return NULL if the index
-** is out of range or if the wildcard is unnamed.
-**
-** The result is always UTF-8.
-*/
-const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
- Vdbe *p = (Vdbe*)pStmt;
- if( p==0 || i<1 || i>p->nVar ){
- return 0;
- }
- createVarMap(p);
- return p->azVar[i-1];
-}
-
-/*
-** Given a wildcard parameter name, return the index of the variable
-** with that name. If there is no variable with the given name,
-** return 0.
-*/
-int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
- Vdbe *p = (Vdbe*)pStmt;
- int i;
- if( p==0 ){
- return 0;
- }
- createVarMap(p);
- for(i=0; i<p->nVar; i++){
- const char *z = p->azVar[i];
- if( z && strcmp(z,zName)==0 ){
- return i+1;
- }
- }
- return 0;
-}
diff --git a/kopete/plugins/statistics/sqlite/vdbeaux.c b/kopete/plugins/statistics/sqlite/vdbeaux.c
deleted file mode 100644
index fa9751da..00000000
--- a/kopete/plugins/statistics/sqlite/vdbeaux.c
+++ /dev/null
@@ -1,1806 +0,0 @@
-/*
-** 2003 September 6
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains code used for creating, destroying, and populating
-** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior
-** to version 2.8.7, all this code was combined into the vdbe.c source file.
-** But that file was getting too big so this subroutines were split out.
-*/
-#include "sqliteInt.h"
-#include "os.h"
-#include <ctype.h>
-#include "vdbeInt.h"
-
-
-/*
-** When debugging the code generator in a symbolic debugger, one can
-** set the sqlite3_vdbe_addop_trace to 1 and all opcodes will be printed
-** as they are added to the instruction stream.
-*/
-#ifndef NDEBUG
-int sqlite3_vdbe_addop_trace = 0;
-#endif
-
-
-/*
-** Create a new virtual database engine.
-*/
-Vdbe *sqlite3VdbeCreate(sqlite3 *db){
- Vdbe *p;
- p = sqliteMalloc( sizeof(Vdbe) );
- if( p==0 ) return 0;
- p->db = db;
- if( db->pVdbe ){
- db->pVdbe->pPrev = p;
- }
- p->pNext = db->pVdbe;
- p->pPrev = 0;
- db->pVdbe = p;
- p->magic = VDBE_MAGIC_INIT;
- return p;
-}
-
-/*
-** Turn tracing on or off
-*/
-void sqlite3VdbeTrace(Vdbe *p, FILE *trace){
- p->trace = trace;
-}
-
-/*
-** Resize the Vdbe.aOp array so that it contains at least N
-** elements.
-*/
-static void resizeOpArray(Vdbe *p, int N){
- if( p->nOpAlloc<N ){
- int oldSize = p->nOpAlloc;
- p->nOpAlloc = N+100;
- p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op));
- if( p->aOp ){
- memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));
- }
- }
-}
-
-/*
-** Add a new instruction to the list of instructions current in the
-** VDBE. Return the address of the new instruction.
-**
-** Parameters:
-**
-** p Pointer to the VDBE
-**
-** op The opcode for this instruction
-**
-** p1, p2 First two of the three possible operands.
-**
-** Use the sqlite3VdbeResolveLabel() function to fix an address and
-** the sqlite3VdbeChangeP3() function to change the value of the P3
-** operand.
-*/
-int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
- int i;
- VdbeOp *pOp;
-
- i = p->nOp;
- p->nOp++;
- assert( p->magic==VDBE_MAGIC_INIT );
- resizeOpArray(p, i+1);
- if( p->aOp==0 ){
- return 0;
- }
- pOp = &p->aOp[i];
- pOp->opcode = op;
- pOp->p1 = p1;
- pOp->p2 = p2;
- pOp->p3 = 0;
- pOp->p3type = P3_NOTUSED;
-#ifndef NDEBUG
- if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
-#endif
- return i;
-}
-
-/*
-** Add an opcode that includes the p3 value.
-*/
-int sqlite3VdbeOp3(Vdbe *p, int op, int p1, int p2, const char *zP3,int p3type){
- int addr = sqlite3VdbeAddOp(p, op, p1, p2);
- sqlite3VdbeChangeP3(p, addr, zP3, p3type);
- return addr;
-}
-
-/*
-** Create a new symbolic label for an instruction that has yet to be
-** coded. The symbolic label is really just a negative number. The
-** label can be used as the P2 value of an operation. Later, when
-** the label is resolved to a specific address, the VDBE will scan
-** through its operation list and change all values of P2 which match
-** the label into the resolved address.
-**
-** The VDBE knows that a P2 value is a label because labels are
-** always negative and P2 values are suppose to be non-negative.
-** Hence, a negative P2 value is a label that has yet to be resolved.
-**
-** Zero is returned if a malloc() fails.
-*/
-int sqlite3VdbeMakeLabel(Vdbe *p){
- int i;
- i = p->nLabel++;
- assert( p->magic==VDBE_MAGIC_INIT );
- if( i>=p->nLabelAlloc ){
- p->nLabelAlloc = p->nLabelAlloc*2 + 10;
- p->aLabel = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0]));
- }
- if( p->aLabel ){
- p->aLabel[i] = -1;
- }
- return -1-i;
-}
-
-/*
-** Resolve label "x" to be the address of the next instruction to
-** be inserted. The parameter "x" must have been obtained from
-** a prior call to sqlite3VdbeMakeLabel().
-*/
-void sqlite3VdbeResolveLabel(Vdbe *p, int x){
- int j = -1-x;
- assert( p->magic==VDBE_MAGIC_INIT );
- assert( j>=0 && j<p->nLabel );
- if( p->aLabel ){
- p->aLabel[j] = p->nOp;
- }
-}
-
-/*
-** Loop through the program looking for P2 values that are negative.
-** Each such value is a label. Resolve the label by setting the P2
-** value to its correct non-zero value.
-**
-** This routine is called once after all opcodes have been inserted.
-*/
-static void resolveP2Values(Vdbe *p){
- int i;
- Op *pOp;
- int *aLabel = p->aLabel;
- if( aLabel==0 ) return;
- for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
- if( pOp->p2>=0 ) continue;
- assert( -1-pOp->p2<p->nLabel );
- pOp->p2 = aLabel[-1-pOp->p2];
- }
- sqliteFree(p->aLabel);
- p->aLabel = 0;
-}
-
-/*
-** Return the address of the next instruction to be inserted.
-*/
-int sqlite3VdbeCurrentAddr(Vdbe *p){
- assert( p->magic==VDBE_MAGIC_INIT );
- return p->nOp;
-}
-
-/*
-** Add a whole list of operations to the operation stack. Return the
-** address of the first operation added.
-*/
-int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
- int addr;
- assert( p->magic==VDBE_MAGIC_INIT );
- resizeOpArray(p, p->nOp + nOp);
- if( p->aOp==0 ){
- return 0;
- }
- addr = p->nOp;
- if( nOp>0 ){
- int i;
- VdbeOpList const *pIn = aOp;
- for(i=0; i<nOp; i++, pIn++){
- int p2 = pIn->p2;
- VdbeOp *pOut = &p->aOp[i+addr];
- pOut->opcode = pIn->opcode;
- pOut->p1 = pIn->p1;
- pOut->p2 = p2<0 ? addr + ADDR(p2) : p2;
- pOut->p3 = pIn->p3;
- pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED;
-#ifndef NDEBUG
- if( sqlite3_vdbe_addop_trace ){
- sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
- }
-#endif
- }
- p->nOp += nOp;
- }
- return addr;
-}
-
-/*
-** Change the value of the P1 operand for a specific instruction.
-** This routine is useful when a large program is loaded from a
-** static array using sqlite3VdbeAddOpList but we want to make a
-** few minor changes to the program.
-*/
-void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
- assert( p->magic==VDBE_MAGIC_INIT );
- if( p && addr>=0 && p->nOp>addr && p->aOp ){
- p->aOp[addr].p1 = val;
- }
-}
-
-/*
-** Change the value of the P2 operand for a specific instruction.
-** This routine is useful for setting a jump destination.
-*/
-void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
- assert( val>=0 );
- assert( p->magic==VDBE_MAGIC_INIT );
- if( p && addr>=0 && p->nOp>addr && p->aOp ){
- p->aOp[addr].p2 = val;
- }
-}
-
-/*
-** Change the value of the P3 operand for a specific instruction.
-** This routine is useful when a large program is loaded from a
-** static array using sqlite3VdbeAddOpList but we want to make a
-** few minor changes to the program.
-**
-** If n>=0 then the P3 operand is dynamic, meaning that a copy of
-** the string is made into memory obtained from sqliteMalloc().
-** A value of n==0 means copy bytes of zP3 up to and including the
-** first null byte. If n>0 then copy n+1 bytes of zP3.
-**
-** If n==P3_STATIC it means that zP3 is a pointer to a constant static
-** string and we can just copy the pointer. n==P3_POINTER means zP3 is
-** a pointer to some object other than a string. n==P3_COLLSEQ and
-** n==P3_KEYINFO mean that zP3 is a pointer to a CollSeq or KeyInfo
-** structure. A copy is made of KeyInfo structures into memory obtained
-** from sqliteMalloc.
-**
-** If addr<0 then change P3 on the most recently inserted instruction.
-*/
-void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
- Op *pOp;
- assert( p->magic==VDBE_MAGIC_INIT );
- if( p==0 || p->aOp==0 ) return;
- if( addr<0 || addr>=p->nOp ){
- addr = p->nOp - 1;
- if( addr<0 ) return;
- }
- pOp = &p->aOp[addr];
- if( pOp->p3 && pOp->p3type==P3_DYNAMIC ){
- sqliteFree(pOp->p3);
- pOp->p3 = 0;
- }
- if( zP3==0 ){
- pOp->p3 = 0;
- pOp->p3type = P3_NOTUSED;
- }else if( n==P3_KEYINFO ){
- KeyInfo *pKeyInfo;
- int nField, nByte;
- nField = ((KeyInfo*)zP3)->nField;
- nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]);
- pKeyInfo = sqliteMallocRaw( nByte );
- pOp->p3 = (char*)pKeyInfo;
- if( pKeyInfo ){
- memcpy(pKeyInfo, zP3, nByte);
- pOp->p3type = P3_KEYINFO;
- }else{
- pOp->p3type = P3_NOTUSED;
- }
- }else if( n==P3_KEYINFO_HANDOFF ){
- pOp->p3 = (char*)zP3;
- pOp->p3type = P3_KEYINFO;
- }else if( n<0 ){
- pOp->p3 = (char*)zP3;
- pOp->p3type = n;
- }else{
- if( n==0 ) n = strlen(zP3);
- pOp->p3 = sqliteStrNDup(zP3, n);
- pOp->p3type = P3_DYNAMIC;
- }
-}
-
-#ifndef NDEBUG
-/*
-** Replace the P3 field of the most recently coded instruction with
-** comment text.
-*/
-void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
- va_list ap;
- assert( p->nOp>0 );
- assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 );
- va_start(ap, zFormat);
- sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC);
- va_end(ap);
-}
-#endif
-
-/*
-** If the P3 operand to the specified instruction appears
-** to be a quoted string token, then this procedure removes
-** the quotes.
-**
-** The quoting operator can be either a grave ascent (ASCII 0x27)
-** or a double quote character (ASCII 0x22). Two quotes in a row
-** resolve to be a single actual quote character within the string.
-*/
-void sqlite3VdbeDequoteP3(Vdbe *p, int addr){
- Op *pOp;
- assert( p->magic==VDBE_MAGIC_INIT );
- if( p->aOp==0 ) return;
- if( addr<0 || addr>=p->nOp ){
- addr = p->nOp - 1;
- if( addr<0 ) return;
- }
- pOp = &p->aOp[addr];
- if( pOp->p3==0 || pOp->p3[0]==0 ) return;
- if( pOp->p3type==P3_STATIC ){
- pOp->p3 = sqliteStrDup(pOp->p3);
- pOp->p3type = P3_DYNAMIC;
- }
- assert( pOp->p3type==P3_DYNAMIC );
- sqlite3Dequote(pOp->p3);
-}
-
-/*
-** Search the current program starting at instruction addr for the given
-** opcode and P2 value. Return the address plus 1 if found and 0 if not
-** found.
-*/
-int sqlite3VdbeFindOp(Vdbe *p, int addr, int op, int p2){
- int i;
- assert( p->magic==VDBE_MAGIC_INIT );
- for(i=addr; i<p->nOp; i++){
- if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return i+1;
- }
- return 0;
-}
-
-/*
-** Return the opcode for a given address.
-*/
-VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
- assert( p->magic==VDBE_MAGIC_INIT );
- assert( addr>=0 && addr<p->nOp );
- return &p->aOp[addr];
-}
-
-/*
-** Compute a string that describes the P3 parameter for an opcode.
-** Use zTemp for any required temporary buffer space.
-*/
-static char *displayP3(Op *pOp, char *zTemp, int nTemp){
- char *zP3;
- assert( nTemp>=20 );
- switch( pOp->p3type ){
- case P3_POINTER: {
- sprintf(zTemp, "ptr(%#x)", (int)pOp->p3);
- zP3 = zTemp;
- break;
- }
- case P3_KEYINFO: {
- int i, j;
- KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3;
- sprintf(zTemp, "keyinfo(%d", pKeyInfo->nField);
- i = strlen(zTemp);
- for(j=0; j<pKeyInfo->nField; j++){
- CollSeq *pColl = pKeyInfo->aColl[j];
- if( pColl ){
- int n = strlen(pColl->zName);
- if( i+n>nTemp-6 ){
- strcpy(&zTemp[i],",...");
- break;
- }
- zTemp[i++] = ',';
- if( pKeyInfo->aSortOrder && pKeyInfo->aSortOrder[j] ){
- zTemp[i++] = '-';
- }
- strcpy(&zTemp[i], pColl->zName);
- i += n;
- }else if( i+4<nTemp-6 ){
- strcpy(&zTemp[i],",nil");
- i += 4;
- }
- }
- zTemp[i++] = ')';
- zTemp[i] = 0;
- assert( i<nTemp );
- zP3 = zTemp;
- break;
- }
- case P3_COLLSEQ: {
- CollSeq *pColl = (CollSeq*)pOp->p3;
- sprintf(zTemp, "collseq(%.20s)", pColl->zName);
- zP3 = zTemp;
- break;
- }
- case P3_FUNCDEF: {
- FuncDef *pDef = (FuncDef*)pOp->p3;
- char zNum[30];
- sprintf(zTemp, "%.*s", nTemp, pDef->zName);
- sprintf(zNum,"(%d)", pDef->nArg);
- if( strlen(zTemp)+strlen(zNum)+1<=nTemp ){
- strcat(zTemp, zNum);
- }
- zP3 = zTemp;
- break;
- }
- default: {
- zP3 = pOp->p3;
- if( zP3==0 || pOp->opcode==OP_Noop ){
- zP3 = "";
- }
- }
- }
- return zP3;
-}
-
-
-#if !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
-/*
-** Print a single opcode. This routine is used for debugging only.
-*/
-void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
- char *zP3;
- char zPtr[50];
- static const char *zFormat1 = "%4d %-13s %4d %4d %s\n";
- if( pOut==0 ) pOut = stdout;
- zP3 = displayP3(pOp, zPtr, sizeof(zPtr));
- fprintf(pOut, zFormat1,
- pc, sqlite3OpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3);
- fflush(pOut);
-}
-#endif
-
-/*
-** Release an array of N Mem elements
-*/
-static void releaseMemArray(Mem *p, int N){
- if( p ){
- while( N-->0 ){
- sqlite3VdbeMemRelease(p++);
- }
- }
-}
-
-/*
-** Give a listing of the program in the virtual machine.
-**
-** The interface is the same as sqlite3VdbeExec(). But instead of
-** running the code, it invokes the callback once for each instruction.
-** This feature is used to implement "EXPLAIN".
-*/
-int sqlite3VdbeList(
- Vdbe *p /* The VDBE */
-){
- sqlite3 *db = p->db;
- int i;
- int rc = SQLITE_OK;
-
- assert( p->explain );
-
- /* Even though this opcode does not put dynamic strings onto the
- ** the stack, they may become dynamic if the user calls
- ** sqlite3_column_text16(), causing a translation to UTF-16 encoding.
- */
- if( p->pTos==&p->aStack[4] ){
- releaseMemArray(p->aStack, 5);
- }
- p->resOnStack = 0;
-
- i = p->pc++;
- if( i>=p->nOp ){
- p->rc = SQLITE_OK;
- rc = SQLITE_DONE;
- }else if( db->flags & SQLITE_Interrupt ){
- db->flags &= ~SQLITE_Interrupt;
- if( db->magic!=SQLITE_MAGIC_BUSY ){
- p->rc = SQLITE_MISUSE;
- }else{
- p->rc = SQLITE_INTERRUPT;
- }
- rc = SQLITE_ERROR;
- sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0);
- }else{
- Op *pOp = &p->aOp[i];
- Mem *pMem = p->aStack;
- pMem->flags = MEM_Int;
- pMem->type = SQLITE_INTEGER;
- pMem->i = i; /* Program counter */
- pMem++;
-
- pMem->flags = MEM_Static|MEM_Str|MEM_Term;
- pMem->z = sqlite3OpcodeNames[pOp->opcode]; /* Opcode */
- pMem->n = strlen(pMem->z);
- pMem->type = SQLITE_TEXT;
- pMem->enc = SQLITE_UTF8;
- pMem++;
-
- pMem->flags = MEM_Int;
- pMem->i = pOp->p1; /* P1 */
- pMem->type = SQLITE_INTEGER;
- pMem++;
-
- pMem->flags = MEM_Int;
- pMem->i = pOp->p2; /* P2 */
- pMem->type = SQLITE_INTEGER;
- pMem++;
-
- pMem->flags = MEM_Short|MEM_Str|MEM_Term; /* P3 */
- pMem->z = displayP3(pOp, pMem->zShort, sizeof(pMem->zShort));
- pMem->type = SQLITE_TEXT;
- pMem->enc = SQLITE_UTF8;
-
- p->nResColumn = 5;
- p->pTos = pMem;
- p->rc = SQLITE_OK;
- p->resOnStack = 1;
- rc = SQLITE_ROW;
- }
- return rc;
-}
-
-/*
-** Print the SQL that was used to generate a VDBE program.
-*/
-void sqlite3VdbePrintSql(Vdbe *p){
-#ifdef SQLITE_DEBUG
- int nOp = p->nOp;
- VdbeOp *pOp;
- if( nOp<1 ) return;
- pOp = &p->aOp[nOp-1];
- if( pOp->opcode==OP_Noop && pOp->p3!=0 ){
- const char *z = pOp->p3;
- while( isspace(*(u8*)z) ) z++;
- printf("SQL: [%s]\n", z);
- }
-#endif
-}
-
-/*
-** Prepare a virtual machine for execution. This involves things such
-** as allocating stack space and initializing the program counter.
-** After the VDBE has be prepped, it can be executed by one or more
-** calls to sqlite3VdbeExec().
-**
-** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
-** VDBE_MAGIC_RUN.
-*/
-void sqlite3VdbeMakeReady(
- Vdbe *p, /* The VDBE */
- int nVar, /* Number of '?' see in the SQL statement */
- int nMem, /* Number of memory cells to allocate */
- int nCursor, /* Number of cursors to allocate */
- int isExplain /* True if the EXPLAIN keywords is present */
-){
- int n;
-
- assert( p!=0 );
- assert( p->magic==VDBE_MAGIC_INIT );
-
- /* There should be at least one opcode.
- */
- assert( p->nOp>0 );
-
- /* No instruction ever pushes more than a single element onto the
- ** stack. And the stack never grows on successive executions of the
- ** same loop. So the total number of instructions is an upper bound
- ** on the maximum stack depth required.
- **
- ** Allocation all the stack space we will ever need.
- */
- if( p->aStack==0 ){
- resolveP2Values(p);
- assert( nVar>=0 );
- n = isExplain ? 10 : p->nOp;
- p->aStack = sqliteMalloc(
- n*sizeof(p->aStack[0]) /* aStack */
- + n*sizeof(Mem*) /* apArg */
- + nVar*sizeof(Mem) /* aVar */
- + nVar*sizeof(char*) /* azVar */
- + nMem*sizeof(Mem) /* aMem */
- + nCursor*sizeof(Cursor*) /* apCsr */
- );
- if( !sqlite3_malloc_failed ){
- p->aMem = &p->aStack[n];
- p->nMem = nMem;
- p->aVar = &p->aMem[nMem];
- p->nVar = nVar;
- p->okVar = 0;
- p->apArg = (Mem**)&p->aVar[nVar];
- p->azVar = (char**)&p->apArg[n];
- p->apCsr = (Cursor**)&p->azVar[nVar];
- p->nCursor = nCursor;
- for(n=0; n<nVar; n++){
- p->aVar[n].flags = MEM_Null;
- }
- for(n=0; n<nMem; n++){
- p->aMem[n].flags = MEM_Null;
- }
- }
- }
-
-#ifdef SQLITE_DEBUG
- if( (p->db->flags & SQLITE_VdbeListing)!=0
- || sqlite3OsFileExists("vdbe_explain")
- ){
- int i;
- printf("VDBE Program Listing:\n");
- sqlite3VdbePrintSql(p);
- for(i=0; i<p->nOp; i++){
- sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
- }
- }
- if( sqlite3OsFileExists("vdbe_trace") ){
- p->trace = stdout;
- }
-#endif
- p->pTos = &p->aStack[-1];
- p->pc = -1;
- p->rc = SQLITE_OK;
- p->uniqueCnt = 0;
- p->returnDepth = 0;
- p->errorAction = OE_Abort;
- p->popStack = 0;
- p->explain |= isExplain;
- p->magic = VDBE_MAGIC_RUN;
- p->nChange = 0;
-#ifdef VDBE_PROFILE
- {
- int i;
- for(i=0; i<p->nOp; i++){
- p->aOp[i].cnt = 0;
- p->aOp[i].cycles = 0;
- }
- }
-#endif
-}
-
-
-/*
-** Remove any elements that remain on the sorter for the VDBE given.
-*/
-void sqlite3VdbeSorterReset(Vdbe *p){
- while( p->pSort ){
- Sorter *pSorter = p->pSort;
- p->pSort = pSorter->pNext;
- sqliteFree(pSorter->zKey);
- sqlite3VdbeMemRelease(&pSorter->data);
- sqliteFree(pSorter);
- }
-}
-
-/*
-** Free all resources allociated with AggElem pElem, an element of
-** aggregate pAgg.
-*/
-void freeAggElem(AggElem *pElem, Agg *pAgg){
- int i;
- for(i=0; i<pAgg->nMem; i++){
- Mem *pMem = &pElem->aMem[i];
- if( pAgg->apFunc && pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
- sqlite3_context ctx;
- ctx.pFunc = pAgg->apFunc[i];
- ctx.s.flags = MEM_Null;
- ctx.pAgg = pMem->z;
- ctx.cnt = pMem->i;
- ctx.isStep = 0;
- ctx.isError = 0;
- (*pAgg->apFunc[i]->xFinalize)(&ctx);
- pMem->z = ctx.pAgg;
- if( pMem->z!=0 && pMem->z!=pMem->zShort ){
- sqliteFree(pMem->z);
- }
- sqlite3VdbeMemRelease(&ctx.s);
- }else{
- sqlite3VdbeMemRelease(pMem);
- }
- }
- sqliteFree(pElem);
-}
-
-/*
-** Reset an Agg structure. Delete all its contents.
-**
-** For installable aggregate functions, if the step function has been
-** called, make sure the finalizer function has also been called. The
-** finalizer might need to free memory that was allocated as part of its
-** private context. If the finalizer has not been called yet, call it
-** now.
-**
-** If db is NULL, then this is being called from sqliteVdbeReset(). In
-** this case clean up all references to the temp-table used for
-** aggregates (if it was ever opened).
-**
-** If db is not NULL, then this is being called from with an OP_AggReset
-** opcode. Open the temp-table, if it has not already been opened and
-** delete the contents of the table used for aggregate information, ready
-** for the next round of aggregate processing.
-*/
-int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
- int rc = 0;
- BtCursor *pCsr = pAgg->pCsr;
-
- assert( (pCsr && pAgg->nTab>0) || (!pCsr && pAgg->nTab==0)
- || sqlite3_malloc_failed );
-
- /* If pCsr is not NULL, then the table used for aggregate information
- ** is open. Loop through it and free the AggElem* structure pointed at
- ** by each entry. If the finalizer has not been called for an AggElem,
- ** do that too. Finally, clear the btree table itself.
- */
- if( pCsr ){
- int res;
- assert( pAgg->pBtree );
- assert( pAgg->nTab>0 );
-
- rc=sqlite3BtreeFirst(pCsr, &res);
- while( res==0 && rc==SQLITE_OK ){
- AggElem *pElem;
- rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem);
- if( res!=SQLITE_OK ){
- return rc;
- }
- assert( pAgg->apFunc!=0 );
- freeAggElem(pElem, pAgg);
- rc=sqlite3BtreeNext(pCsr, &res);
- }
- if( rc!=SQLITE_OK ){
- return rc;
- }
-
- sqlite3BtreeCloseCursor(pCsr);
- sqlite3BtreeClearTable(pAgg->pBtree, pAgg->nTab);
- }else{
- /* The cursor may not be open because the aggregator was never used,
- ** or it could be that it was used but there was no GROUP BY clause.
- */
- if( pAgg->pCurrent ){
- freeAggElem(pAgg->pCurrent, pAgg);
- }
- }
-
- /* If db is not NULL and we have not yet and we have not yet opened
- ** the temporary btree then do so and create the table to store aggregate
- ** information.
- **
- ** If db is NULL, then close the temporary btree if it is open.
- */
- if( db ){
- if( !pAgg->pBtree ){
- assert( pAgg->nTab==0 );
- rc = sqlite3BtreeFactory(db, ":memory:", 0, TEMP_PAGES, &pAgg->pBtree);
- if( rc!=SQLITE_OK ) return rc;
- sqlite3BtreeBeginTrans(pAgg->pBtree, 1);
- rc = sqlite3BtreeCreateTable(pAgg->pBtree, &pAgg->nTab, 0);
- if( rc!=SQLITE_OK ) return rc;
- }
- assert( pAgg->nTab!=0 );
-
- rc = sqlite3BtreeCursor(pAgg->pBtree, pAgg->nTab, 1,
- sqlite3VdbeRecordCompare, pKeyInfo, &pAgg->pCsr);
- if( rc!=SQLITE_OK ) return rc;
- }else{
- if( pAgg->pBtree ){
- sqlite3BtreeClose(pAgg->pBtree);
- pAgg->pBtree = 0;
- pAgg->nTab = 0;
- }
- pAgg->pCsr = 0;
- }
-
- if( pAgg->apFunc ){
- sqliteFree(pAgg->apFunc);
- pAgg->apFunc = 0;
- }
- pAgg->pCurrent = 0;
- pAgg->nMem = 0;
- pAgg->searching = 0;
- return SQLITE_OK;
-}
-
-
-/*
-** Delete a keylist
-*/
-void sqlite3VdbeKeylistFree(Keylist *p){
- while( p ){
- Keylist *pNext = p->pNext;
- sqliteFree(p);
- p = pNext;
- }
-}
-
-/*
-** Close a cursor and release all the resources that cursor happens
-** to hold.
-*/
-void sqlite3VdbeFreeCursor(Cursor *pCx){
- if( pCx==0 ){
- return;
- }
- if( pCx->pCursor ){
- sqlite3BtreeCloseCursor(pCx->pCursor);
- }
- if( pCx->pBt ){
- sqlite3BtreeClose(pCx->pBt);
- }
- sqliteFree(pCx->pData);
- sqliteFree(pCx->aType);
- sqliteFree(pCx);
-}
-
-/*
-** Close all cursors
-*/
-static void closeAllCursors(Vdbe *p){
- int i;
- if( p->apCsr==0 ) return;
- for(i=0; i<p->nCursor; i++){
- sqlite3VdbeFreeCursor(p->apCsr[i]);
- p->apCsr[i] = 0;
- }
-}
-
-/*
-** Clean up the VM after execution.
-**
-** This routine will automatically close any cursors, lists, and/or
-** sorters that were left open. It also deletes the values of
-** variables in the aVar[] array.
-*/
-static void Cleanup(Vdbe *p){
- int i;
- if( p->aStack ){
- releaseMemArray(p->aStack, 1 + (p->pTos - p->aStack));
- p->pTos = &p->aStack[-1];
- }
- closeAllCursors(p);
- releaseMemArray(p->aMem, p->nMem);
- if( p->pList ){
- sqlite3VdbeKeylistFree(p->pList);
- p->pList = 0;
- }
- if( p->contextStack ){
- for(i=0; i<p->contextStackTop; i++){
- sqlite3VdbeKeylistFree(p->contextStack[i].pList);
- }
- sqliteFree(p->contextStack);
- }
- sqlite3VdbeSorterReset(p);
- sqlite3VdbeAggReset(0, &p->agg, 0);
- p->contextStack = 0;
- p->contextStackDepth = 0;
- p->contextStackTop = 0;
- sqliteFree(p->zErrMsg);
- p->zErrMsg = 0;
-}
-
-/*
-** Set the number of result columns that will be returned by this SQL
-** statement. This is now set at compile time, rather than during
-** execution of the vdbe program so that sqlite3_column_count() can
-** be called on an SQL statement before sqlite3_step().
-*/
-void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
- Mem *pColName;
- int n;
- assert( 0==p->nResColumn );
- p->nResColumn = nResColumn;
- n = nResColumn*2;
- p->aColName = pColName = (Mem*)sqliteMalloc( sizeof(Mem)*n );
- if( p->aColName==0 ) return;
- while( n-- > 0 ){
- (pColName++)->flags = MEM_Null;
- }
-}
-
-/*
-** Set the name of the idx'th column to be returned by the SQL statement.
-** zName must be a pointer to a nul terminated string.
-**
-** This call must be made after a call to sqlite3VdbeSetNumCols().
-**
-** If N==P3_STATIC it means that zName is a pointer to a constant static
-** string and we can just copy the pointer. If it is P3_DYNAMIC, then
-** the string is freed using sqliteFree() when the vdbe is finished with
-** it. Otherwise, N bytes of zName are copied.
-*/
-int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
- int rc;
- Mem *pColName;
- assert( idx<(2*p->nResColumn) );
- if( sqlite3_malloc_failed ) return SQLITE_NOMEM;
- assert( p->aColName!=0 );
- pColName = &(p->aColName[idx]);
- if( N==P3_DYNAMIC || N==P3_STATIC ){
- rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC);
- }else{
- rc = sqlite3VdbeMemSetStr(pColName, zName, N, SQLITE_UTF8,SQLITE_TRANSIENT);
- }
- if( rc==SQLITE_OK && N==P3_DYNAMIC ){
- pColName->flags = (pColName->flags&(~MEM_Static))|MEM_Dyn;
- pColName->xDel = 0;
- }
- return rc;
-}
-
-/*
-** A read or write transaction may or may not be active on database handle
-** db. If a transaction is active, commit it. If there is a
-** write-transaction spanning more than one database file, this routine
-** takes care of the master journal trickery.
-*/
-static int vdbeCommit(sqlite3 *db){
- int i;
- int nTrans = 0; /* Number of databases with an active write-transaction */
- int rc = SQLITE_OK;
- int needXcommit = 0;
-
- for(i=0; i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( pBt && sqlite3BtreeIsInTrans(pBt) ){
- needXcommit = 1;
- if( i!=1 ) nTrans++;
- }
- }
-
- /* If there are any write-transactions at all, invoke the commit hook */
- if( needXcommit && db->xCommitCallback ){
- int rc;
- sqlite3SafetyOff(db);
- rc = db->xCommitCallback(db->pCommitArg);
- sqlite3SafetyOn(db);
- if( rc ){
- return SQLITE_CONSTRAINT;
- }
- }
-
- /* The simple case - no more than one database file (not counting the
- ** TEMP database) has a transaction active. There is no need for the
- ** master-journal.
- **
- ** If the return value of sqlite3BtreeGetFilename() is a zero length
- ** string, it means the main database is :memory:. In that case we do
- ** not support atomic multi-file commits, so use the simple case then
- ** too.
- */
- if( 0==strlen(sqlite3BtreeGetFilename(db->aDb[0].pBt)) || nTrans<=1 ){
- for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ){
- rc = sqlite3BtreeSync(pBt, 0);
- }
- }
-
- /* Do the commit only if all databases successfully synced */
- if( rc==SQLITE_OK ){
- for(i=0; i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ){
- sqlite3BtreeCommit(pBt);
- }
- }
- }
- }
-
- /* The complex case - There is a multi-file write-transaction active.
- ** This requires a master journal file to ensure the transaction is
- ** committed atomicly.
- */
- else{
- char *zMaster = 0; /* File-name for the master journal */
- char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
- OsFile master;
-
- /* Select a master journal file name */
- do {
- u32 random;
- sqliteFree(zMaster);
- sqlite3Randomness(sizeof(random), &random);
- zMaster = sqlite3MPrintf("%s-mj%08X", zMainFile, random&0x7fffffff);
- if( !zMaster ){
- return SQLITE_NOMEM;
- }
- }while( sqlite3OsFileExists(zMaster) );
-
- /* Open the master journal. */
- memset(&master, 0, sizeof(master));
- rc = sqlite3OsOpenExclusive(zMaster, &master, 0);
- if( rc!=SQLITE_OK ){
- sqliteFree(zMaster);
- return rc;
- }
-
- /* Write the name of each database file in the transaction into the new
- ** master journal file. If an error occurs at this point close
- ** and delete the master journal file. All the individual journal files
- ** still have 'null' as the master journal pointer, so they will roll
- ** back independantly if a failure occurs.
- */
- for(i=0; i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( i==1 ) continue; /* Ignore the TEMP database */
- if( pBt && sqlite3BtreeIsInTrans(pBt) ){
- char const *zFile = sqlite3BtreeGetJournalname(pBt);
- if( zFile[0]==0 ) continue; /* Ignore :memory: databases */
- rc = sqlite3OsWrite(&master, zFile, strlen(zFile)+1);
- if( rc!=SQLITE_OK ){
- sqlite3OsClose(&master);
- sqlite3OsDelete(zMaster);
- sqliteFree(zMaster);
- return rc;
- }
- }
- }
-
-
- /* Sync the master journal file. Before doing this, open the directory
- ** the master journal file is store in so that it gets synced too.
- */
- zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
- rc = sqlite3OsOpenDirectory(zMainFile, &master);
- if( rc!=SQLITE_OK ){
- sqlite3OsClose(&master);
- sqlite3OsDelete(zMaster);
- sqliteFree(zMaster);
- return rc;
- }
- rc = sqlite3OsSync(&master);
- if( rc!=SQLITE_OK ){
- sqlite3OsClose(&master);
- sqliteFree(zMaster);
- return rc;
- }
-
- /* Sync all the db files involved in the transaction. The same call
- ** sets the master journal pointer in each individual journal. If
- ** an error occurs here, do not delete the master journal file.
- **
- ** If the error occurs during the first call to sqlite3BtreeSync(),
- ** then there is a chance that the master journal file will be
- ** orphaned. But we cannot delete it, in case the master journal
- ** file name was written into the journal file before the failure
- ** occured.
- */
- for(i=0; i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( pBt && sqlite3BtreeIsInTrans(pBt) ){
- rc = sqlite3BtreeSync(pBt, zMaster);
- if( rc!=SQLITE_OK ){
- sqlite3OsClose(&master);
- sqliteFree(zMaster);
- return rc;
- }
- }
- }
- sqlite3OsClose(&master);
-
- /* Delete the master journal file. This commits the transaction. After
- ** doing this the directory is synced again before any individual
- ** transaction files are deleted.
- */
- rc = sqlite3OsDelete(zMaster);
- assert( rc==SQLITE_OK );
- sqliteFree(zMaster);
- zMaster = 0;
- rc = sqlite3OsSyncDirectory(zMainFile);
- if( rc!=SQLITE_OK ){
- /* This is not good. The master journal file has been deleted, but
- ** the directory sync failed. There is no completely safe course of
- ** action from here. The individual journals contain the name of the
- ** master journal file, but there is no way of knowing if that
- ** master journal exists now or if it will exist after the operating
- ** system crash that may follow the fsync() failure.
- */
- assert(0);
- sqliteFree(zMaster);
- return rc;
- }
-
- /* All files and directories have already been synced, so the following
- ** calls to sqlite3BtreeCommit() are only closing files and deleting
- ** journals. If something goes wrong while this is happening we don't
- ** really care. The integrity of the transaction is already guaranteed,
- ** but some stray 'cold' journals may be lying around. Returning an
- ** error code won't help matters.
- */
- for(i=0; i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ){
- sqlite3BtreeCommit(pBt);
- }
- }
- }
-
- return rc;
-}
-
-/*
-** Find every active VM other than pVdbe and change its status to
-** aborted. This happens when one VM causes a rollback due to an
-** ON CONFLICT ROLLBACK clause (for example). The other VMs must be
-** aborted so that they do not have data rolled out from underneath
-** them leading to a segfault.
-*/
-static void abortOtherActiveVdbes(Vdbe *pVdbe){
- Vdbe *pOther;
- for(pOther=pVdbe->db->pVdbe; pOther; pOther=pOther->pNext){
- if( pOther==pVdbe ) continue;
- if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
- closeAllCursors(pOther);
- pOther->aborted = 1;
- }
-}
-
-/*
-** This routine checks that the sqlite3.activeVdbeCnt count variable
-** matches the number of vdbe's in the list sqlite3.pVdbe that are
-** currently active. An assertion fails if the two counts do not match.
-** This is an internal self-check only - it is not an essential processing
-** step.
-**
-** This is a no-op if NDEBUG is defined.
-*/
-#ifndef NDEBUG
-static void checkActiveVdbeCnt(sqlite3 *db){
- Vdbe *p;
- int cnt = 0;
- p = db->pVdbe;
- while( p ){
- if( p->magic==VDBE_MAGIC_RUN && p->pc>=0 ){
- cnt++;
- }
- p = p->pNext;
- }
- assert( cnt==db->activeVdbeCnt );
-}
-#else
-#define checkActiveVdbeCnt(x)
-#endif
-
-/*
-** This routine is called the when a VDBE tries to halt. If the VDBE
-** has made changes and is in autocommit mode, then commit those
-** changes. If a rollback is needed, then do the rollback.
-**
-** This routine is the only way to move the state of a VM from
-** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT.
-**
-** Return an error code. If the commit could not complete because of
-** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it
-** means the close did not happen and needs to be repeated.
-*/
-int sqlite3VdbeHalt(Vdbe *p){
- sqlite3 *db = p->db;
- int i;
- int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */
-
- if( p->magic!=VDBE_MAGIC_RUN ){
- /* Already halted. Nothing to do. */
- assert( p->magic==VDBE_MAGIC_HALT );
- return SQLITE_OK;
- }
- closeAllCursors(p);
- checkActiveVdbeCnt(db);
- if( db->autoCommit && db->activeVdbeCnt==1 ){
- if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
- /* The auto-commit flag is true, there are no other active queries
- ** using this handle and the vdbe program was successful or hit an
- ** 'OR FAIL' constraint. This means a commit is required.
- */
- int rc = vdbeCommit(db);
- if( rc==SQLITE_BUSY ){
- return SQLITE_BUSY;
- }else if( rc!=SQLITE_OK ){
- p->rc = rc;
- xFunc = sqlite3BtreeRollback;
- }
- }else{
- xFunc = sqlite3BtreeRollback;
- }
- }else{
- if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
- xFunc = sqlite3BtreeCommitStmt;
- }else if( p->errorAction==OE_Abort ){
- xFunc = sqlite3BtreeRollbackStmt;
- }else{
- xFunc = sqlite3BtreeRollback;
- db->autoCommit = 1;
- abortOtherActiveVdbes(p);
- }
- }
-
- /* If xFunc is not NULL, then it is one of sqlite3BtreeRollback,
- ** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on
- ** each backend. If an error occurs and the return code is still
- ** SQLITE_OK, set the return code to the new error value.
- */
- for(i=0; xFunc && i<db->nDb; i++){
- int rc;
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ){
- rc = xFunc(pBt);
- if( p->rc==SQLITE_OK ) p->rc = rc;
- }
- }
-
- /* If this was an INSERT, UPDATE or DELETE, set the change counter. */
- if( p->changeCntOn ){
- if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
- sqlite3VdbeSetChanges(db, p->nChange);
- }else{
- sqlite3VdbeSetChanges(db, 0);
- }
- p->nChange = 0;
- }
-
- /* Rollback or commit any schema changes that occurred. */
- if( p->rc!=SQLITE_OK ){
- sqlite3RollbackInternalChanges(db);
- }else if( db->flags & SQLITE_InternChanges ){
- sqlite3CommitInternalChanges(db);
- }
-
- /* We have successfully halted and closed the VM. Record this fact. */
- if( p->pc>=0 ){
- db->activeVdbeCnt--;
- }
- p->magic = VDBE_MAGIC_HALT;
- checkActiveVdbeCnt(db);
-
- return SQLITE_OK;
-}
-
-/*
-** Clean up a VDBE after execution but do not delete the VDBE just yet.
-** Write any error messages into *pzErrMsg. Return the result code.
-**
-** After this routine is run, the VDBE should be ready to be executed
-** again.
-**
-** To look at it another way, this routine resets the state of the
-** virtual machine from VDBE_MAGIC_RUN or VDBE_MAGIC_HALT back to
-** VDBE_MAGIC_INIT.
-*/
-int sqlite3VdbeReset(Vdbe *p){
- if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
- sqlite3Error(p->db, SQLITE_MISUSE, 0);
- return SQLITE_MISUSE;
- }
-
- /* If the VM did not run to completion or if it encountered an
- ** error, then it might not have been halted properly. So halt
- ** it now.
- */
- sqlite3VdbeHalt(p);
-
- /* Transfer the error code and error message from the VDBE into the
- ** main database structure.
- */
- if( p->zErrMsg ){
- sqlite3Error(p->db, p->rc, "%s", p->zErrMsg);
- sqliteFree(p->zErrMsg);
- p->zErrMsg = 0;
- }else if( p->rc ){
- sqlite3Error(p->db, p->rc, 0);
- }else{
- sqlite3Error(p->db, SQLITE_OK, 0);
- }
-
- /* Reclaim all memory used by the VDBE
- */
- Cleanup(p);
-
- /* Save profiling information from this VDBE run.
- */
- assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || sqlite3_malloc_failed==1 );
-#ifdef VDBE_PROFILE
- {
- FILE *out = fopen("vdbe_profile.out", "a");
- if( out ){
- int i;
- fprintf(out, "---- ");
- for(i=0; i<p->nOp; i++){
- fprintf(out, "%02x", p->aOp[i].opcode);
- }
- fprintf(out, "\n");
- for(i=0; i<p->nOp; i++){
- fprintf(out, "%6d %10lld %8lld ",
- p->aOp[i].cnt,
- p->aOp[i].cycles,
- p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0
- );
- sqlite3VdbePrintOp(out, i, &p->aOp[i]);
- }
- fclose(out);
- }
- }
-#endif
- p->magic = VDBE_MAGIC_INIT;
- p->aborted = 0;
- return p->rc;
-}
-
-/*
-** Clean up and delete a VDBE after execution. Return an integer which is
-** the result code. Write any error message text into *pzErrMsg.
-*/
-int sqlite3VdbeFinalize(Vdbe *p){
- int rc = SQLITE_OK;
- sqlite3 *db = p->db;
-
- if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
- rc = sqlite3VdbeReset(p);
- }else if( p->magic!=VDBE_MAGIC_INIT ){
- /* sqlite3Error(p->db, SQLITE_MISUSE, 0); */
- return SQLITE_MISUSE;
- }
- sqlite3VdbeDelete(p);
- if( rc==SQLITE_SCHEMA ){
- sqlite3ResetInternalSchema(db, 0);
- }
- return rc;
-}
-
-/*
-** Call the destructor for each auxdata entry in pVdbeFunc for which
-** the corresponding bit in mask is clear. Auxdata entries beyond 31
-** are always destroyed. To destroy all auxdata entries, call this
-** routine with mask==0.
-*/
-void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
- int i;
- for(i=0; i<pVdbeFunc->nAux; i++){
- struct AuxData *pAux = &pVdbeFunc->apAux[i];
- if( (i>31 || !(mask&(1<<i))) && pAux->pAux ){
- if( pAux->xDelete ){
- pAux->xDelete(pAux->pAux);
- }
- pAux->pAux = 0;
- }
- }
-}
-
-/*
-** Delete an entire VDBE.
-*/
-void sqlite3VdbeDelete(Vdbe *p){
- int i;
- if( p==0 ) return;
- Cleanup(p);
- if( p->pPrev ){
- p->pPrev->pNext = p->pNext;
- }else{
- assert( p->db->pVdbe==p );
- p->db->pVdbe = p->pNext;
- }
- if( p->pNext ){
- p->pNext->pPrev = p->pPrev;
- }
- if( p->aOp ){
- for(i=0; i<p->nOp; i++){
- Op *pOp = &p->aOp[i];
- if( pOp->p3type==P3_DYNAMIC || pOp->p3type==P3_KEYINFO ){
- sqliteFree(pOp->p3);
- }
- if( pOp->p3type==P3_VDBEFUNC ){
- VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3;
- sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
- sqliteFree(pVdbeFunc);
- }
- }
- sqliteFree(p->aOp);
- }
- releaseMemArray(p->aVar, p->nVar);
- sqliteFree(p->aLabel);
- sqliteFree(p->aStack);
- releaseMemArray(p->aColName, p->nResColumn*2);
- sqliteFree(p->aColName);
- p->magic = VDBE_MAGIC_DEAD;
- sqliteFree(p);
-}
-
-/*
-** If a MoveTo operation is pending on the given cursor, then do that
-** MoveTo now. Return an error code. If no MoveTo is pending, this
-** routine does nothing and returns SQLITE_OK.
-*/
-int sqlite3VdbeCursorMoveto(Cursor *p){
- if( p->deferredMoveto ){
- int res;
- extern int sqlite3_search_count;
- assert( p->intKey );
- if( p->intKey ){
- sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, &res);
- }else{
- sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,sizeof(i64),&res);
- }
- *p->pIncrKey = 0;
- p->lastRecno = keyToInt(p->movetoTarget);
- p->recnoIsValid = res==0;
- if( res<0 ){
- sqlite3BtreeNext(p->pCursor, &res);
- }
- sqlite3_search_count++;
- p->deferredMoveto = 0;
- p->cacheValid = 0;
- }
- return SQLITE_OK;
-}
-
-/*
-** The following functions:
-**
-** sqlite3VdbeSerialType()
-** sqlite3VdbeSerialTypeLen()
-** sqlite3VdbeSerialRead()
-** sqlite3VdbeSerialLen()
-** sqlite3VdbeSerialWrite()
-**
-** encapsulate the code that serializes values for storage in SQLite
-** data and index records. Each serialized value consists of a
-** 'serial-type' and a blob of data. The serial type is an 8-byte unsigned
-** integer, stored as a varint.
-**
-** In an SQLite index record, the serial type is stored directly before
-** the blob of data that it corresponds to. In a table record, all serial
-** types are stored at the start of the record, and the blobs of data at
-** the end. Hence these functions allow the caller to handle the
-** serial-type and data blob seperately.
-**
-** The following table describes the various storage classes for data:
-**
-** serial type bytes of data type
-** -------------- --------------- ---------------
-** 0 0 NULL
-** 1 1 signed integer
-** 2 2 signed integer
-** 3 3 signed integer
-** 4 4 signed integer
-** 5 6 signed integer
-** 6 8 signed integer
-** 7 8 IEEE float
-** 8-11 reserved for expansion
-** N>=12 and even (N-12)/2 BLOB
-** N>=13 and odd (N-13)/2 text
-**
-*/
-
-/*
-** Return the serial-type for the value stored in pMem.
-*/
-u32 sqlite3VdbeSerialType(Mem *pMem){
- int flags = pMem->flags;
-
- if( flags&MEM_Null ){
- return 0;
- }
- if( flags&MEM_Int ){
- /* Figure out whether to use 1, 2, 4 or 8 bytes. */
- i64 i = pMem->i;
- if( i>=-127 && i<=127 ) return 1;
- if( i>=-32767 && i<=32767 ) return 2;
- if( i>=-8388607 && i<=8388607 ) return 3;
- if( i>=-2147483647 && i<=2147483647 ) return 4;
- if( i>=-140737488355328L && i<=140737488355328L ) return 5;
- return 6;
- }
- if( flags&MEM_Real ){
- return 7;
- }
- if( flags&MEM_Str ){
- int n = pMem->n;
- assert( n>=0 );
- return ((n*2) + 13);
- }
- if( flags&MEM_Blob ){
- return (pMem->n*2 + 12);
- }
- return 0;
-}
-
-/*
-** Return the length of the data corresponding to the supplied serial-type.
-*/
-int sqlite3VdbeSerialTypeLen(u32 serial_type){
- if( serial_type>=12 ){
- return (serial_type-12)/2;
- }else{
- static const u8 aSize[] = { 0, 1, 2, 3, 4, 6, 8, 8, 0, 0, 0, 0 };
- return aSize[serial_type];
- }
-}
-
-/*
-** Write the serialized data blob for the value stored in pMem into
-** buf. It is assumed that the caller has allocated sufficient space.
-** Return the number of bytes written.
-*/
-int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem){
- u32 serial_type = sqlite3VdbeSerialType(pMem);
- int len;
-
- /* NULL */
- if( serial_type==0 ){
- return 0;
- }
-
- /* Integer and Real */
- if( serial_type<=7 ){
- u64 v;
- int i;
- if( serial_type==7 ){
- v = *(u64*)&pMem->r;
- }else{
- v = *(u64*)&pMem->i;
- }
- len = i = sqlite3VdbeSerialTypeLen(serial_type);
- while( i-- ){
- buf[i] = (v&0xFF);
- v >>= 8;
- }
- return len;
- }
-
- /* String or blob */
- assert( serial_type>=12 );
- len = sqlite3VdbeSerialTypeLen(serial_type);
- memcpy(buf, pMem->z, len);
- return len;
-}
-
-/*
-** Deserialize the data blob pointed to by buf as serial type serial_type
-** and store the result in pMem. Return the number of bytes read.
-*/
-int sqlite3VdbeSerialGet(
- const unsigned char *buf, /* Buffer to deserialize from */
- u32 serial_type, /* Serial type to deserialize */
- Mem *pMem /* Memory cell to write value into */
-){
- int len;
-
- if( serial_type==0 ){
- /* NULL */
- pMem->flags = MEM_Null;
- return 0;
- }
- len = sqlite3VdbeSerialTypeLen(serial_type);
- if( serial_type<=7 ){
- /* Integer and Real */
- if( serial_type<=4 ){
- /* 32-bit integer type. This is handled by a special case for
- ** performance reasons. */
- int v = buf[0];
- int n;
- if( v&0x80 ){
- v |= -256;
- }
- for(n=1; n<len; n++){
- v = (v<<8) | buf[n];
- }
- pMem->flags = MEM_Int;
- pMem->i = v;
- return n;
- }else{
- u64 v = 0;
- int n;
-
- if( buf[0]&0x80 ){
- v = -1;
- }
- for(n=0; n<len; n++){
- v = (v<<8) | buf[n];
- }
- if( serial_type==7 ){
- pMem->flags = MEM_Real;
- pMem->r = *(double*)&v;
- }else{
- pMem->flags = MEM_Int;
- pMem->i = *(i64*)&v;
- }
- }
- }else{
- /* String or blob */
- assert( serial_type>=12 );
- pMem->z = (char *)buf;
- pMem->n = len;
- pMem->xDel = 0;
- if( serial_type&0x01 ){
- pMem->flags = MEM_Str | MEM_Ephem;
- }else{
- pMem->flags = MEM_Blob | MEM_Ephem;
- }
- }
- return len;
-}
-
-/*
-** This function compares the two table rows or index records specified by
-** {nKey1, pKey1} and {nKey2, pKey2}, returning a negative, zero
-** or positive integer if {nKey1, pKey1} is less than, equal to or
-** greater than {nKey2, pKey2}. Both Key1 and Key2 must be byte strings
-** composed by the OP_MakeRecord opcode of the VDBE.
-*/
-int sqlite3VdbeRecordCompare(
- void *userData,
- int nKey1, const void *pKey1,
- int nKey2, const void *pKey2
-){
- KeyInfo *pKeyInfo = (KeyInfo*)userData;
- u32 d1, d2; /* Offset into aKey[] of next data element */
- u32 idx1, idx2; /* Offset into aKey[] of next header element */
- u32 szHdr1, szHdr2; /* Number of bytes in header */
- int i = 0;
- int nField;
- int rc = 0;
- const unsigned char *aKey1 = (const unsigned char *)pKey1;
- const unsigned char *aKey2 = (const unsigned char *)pKey2;
-
- Mem mem1;
- Mem mem2;
- mem1.enc = pKeyInfo->enc;
- mem2.enc = pKeyInfo->enc;
-
- idx1 = sqlite3GetVarint32(pKey1, &szHdr1);
- d1 = szHdr1;
- idx2 = sqlite3GetVarint32(pKey2, &szHdr2);
- d2 = szHdr2;
- nField = pKeyInfo->nField;
- while( idx1<szHdr1 && idx2<szHdr2 ){
- u32 serial_type1;
- u32 serial_type2;
-
- /* Read the serial types for the next element in each key. */
- idx1 += sqlite3GetVarint32(&aKey1[idx1], &serial_type1);
- if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break;
- idx2 += sqlite3GetVarint32(&aKey2[idx2], &serial_type2);
- if( d2>=nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break;
-
- /* Assert that there is enough space left in each key for the blob of
- ** data to go with the serial type just read. This assert may fail if
- ** the file is corrupted. Then read the value from each key into mem1
- ** and mem2 respectively.
- */
- d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
- d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2);
-
- rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0);
- sqlite3VdbeMemRelease(&mem1);
- sqlite3VdbeMemRelease(&mem2);
- if( rc!=0 ){
- break;
- }
- i++;
- }
-
- /* One of the keys ran out of fields, but all the fields up to that point
- ** were equal. If the incrKey flag is true, then the second key is
- ** treated as larger.
- */
- if( rc==0 ){
- if( pKeyInfo->incrKey ){
- rc = -1;
- }else if( d1<nKey1 ){
- rc = 1;
- }else if( d2<nKey2 ){
- rc = -1;
- }
- }
-
- if( pKeyInfo->aSortOrder && i<pKeyInfo->nField && pKeyInfo->aSortOrder[i] ){
- rc = -rc;
- }
-
- return rc;
-}
-
-/*
-** The argument is an index entry composed using the OP_MakeRecord opcode.
-** The last entry in this record should be an integer (specifically
-** an integer rowid). This routine returns the number of bytes in
-** that integer.
-*/
-int sqlite3VdbeIdxRowidLen(int nKey, const u8 *aKey){
- u32 szHdr; /* Size of the header */
- u32 typeRowid; /* Serial type of the rowid */
-
- sqlite3GetVarint32(aKey, &szHdr);
- sqlite3GetVarint32(&aKey[szHdr-1], &typeRowid);
- return sqlite3VdbeSerialTypeLen(typeRowid);
-}
-
-
-/*
-** pCur points at an index entry created using the OP_MakeRecord opcode.
-** Read the rowid (the last field in the record) and store it in *rowid.
-** Return SQLITE_OK if everything works, or an error code otherwise.
-*/
-int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
- i64 nCellKey;
- int rc;
- u32 szHdr; /* Size of the header */
- u32 typeRowid; /* Serial type of the rowid */
- u32 lenRowid; /* Size of the rowid */
- Mem m, v;
-
- sqlite3BtreeKeySize(pCur, &nCellKey);
- if( nCellKey<=0 ){
- return SQLITE_CORRUPT;
- }
- rc = sqlite3VdbeMemFromBtree(pCur, 0, nCellKey, 1, &m);
- if( rc ){
- return rc;
- }
- sqlite3GetVarint32(m.z, &szHdr);
- sqlite3GetVarint32(&m.z[szHdr-1], &typeRowid);
- lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
- sqlite3VdbeSerialGet(&m.z[m.n-lenRowid], typeRowid, &v);
- *rowid = v.i;
- sqlite3VdbeMemRelease(&m);
- return SQLITE_OK;
-}
-
-/*
-** Compare the key of the index entry that cursor pC is point to against
-** the key string in pKey (of length nKey). Write into *pRes a number
-** that is negative, zero, or positive if pC is less than, equal to,
-** or greater than pKey. Return SQLITE_OK on success.
-**
-** pKey is either created without a rowid or is truncated so that it
-** omits the rowid at the end. The rowid at the end of the index entry
-** is ignored as well.
-*/
-int sqlite3VdbeIdxKeyCompare(
- Cursor *pC, /* The cursor to compare against */
- int nKey, const u8 *pKey, /* The key to compare */
- int *res /* Write the comparison result here */
-){
- i64 nCellKey;
- int rc;
- BtCursor *pCur = pC->pCursor;
- int lenRowid;
- Mem m;
-
- sqlite3BtreeKeySize(pCur, &nCellKey);
- if( nCellKey<=0 ){
- *res = 0;
- return SQLITE_OK;
- }
- rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m);
- if( rc ){
- return rc;
- }
- lenRowid = sqlite3VdbeIdxRowidLen(m.n, m.z);
- *res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey);
- sqlite3VdbeMemRelease(&m);
- return SQLITE_OK;
-}
-
-/*
-** This routine sets the value to be returned by subsequent calls to
-** sqlite3_changes() on the database handle 'db'.
-*/
-void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){
- db->nChange = nChange;
- db->nTotalChange += nChange;
-}
-
-/*
-** Set a flag in the vdbe to update the change counter when it is finalised
-** or reset.
-*/
-void sqlite3VdbeCountChanges(Vdbe *p){
- p->changeCntOn = 1;
-}
diff --git a/kopete/plugins/statistics/sqlite/vdbemem.c b/kopete/plugins/statistics/sqlite/vdbemem.c
deleted file mode 100644
index c6cd94e6..00000000
--- a/kopete/plugins/statistics/sqlite/vdbemem.c
+++ /dev/null
@@ -1,724 +0,0 @@
-/*
-** 2004 May 26
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-**
-** This file contains code use to manipulate "Mem" structure. A "Mem"
-** stores a single value in the VDBE. Mem is an opaque structure visible
-** only within the VDBE. Interface routines refer to a Mem using the
-** name sqlite_value
-*/
-#include "sqliteInt.h"
-#include "os.h"
-#include <ctype.h>
-#include "vdbeInt.h"
-
-/*
-** If pMem is an object with a valid string representation, this routine
-** ensures the internal encoding for the string representation is
-** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE.
-**
-** If pMem is not a string object, or the encoding of the string
-** representation is already stored using the requested encoding, then this
-** routine is a no-op.
-**
-** SQLITE_OK is returned if the conversion is successful (or not required).
-** SQLITE_NOMEM may be returned if a malloc() fails during conversion
-** between formats.
-*/
-int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
- if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
- return SQLITE_OK;
- }
- return sqlite3VdbeMemTranslate(pMem, desiredEnc);
-}
-
-/*
-** Make the given Mem object MEM_Dyn.
-**
-** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
-*/
-int sqlite3VdbeMemDynamicify(Mem *pMem){
- int n = pMem->n;
- u8 *z;
- if( (pMem->flags & (MEM_Ephem|MEM_Static|MEM_Short))==0 ){
- return SQLITE_OK;
- }
- assert( (pMem->flags & MEM_Dyn)==0 );
- assert( pMem->flags & (MEM_Str|MEM_Blob) );
- z = sqliteMallocRaw( n+2 );
- if( z==0 ){
- return SQLITE_NOMEM;
- }
- pMem->flags |= MEM_Dyn|MEM_Term;
- pMem->xDel = 0;
- memcpy(z, pMem->z, n );
- z[n] = 0;
- z[n+1] = 0;
- pMem->z = z;
- pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short);
- return SQLITE_OK;
-}
-
-/*
-** Make the given Mem object either MEM_Short or MEM_Dyn so that bytes
-** of the Mem.z[] array can be modified.
-**
-** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
-*/
-int sqlite3VdbeMemMakeWriteable(Mem *pMem){
- int n;
- u8 *z;
- if( (pMem->flags & (MEM_Ephem|MEM_Static))==0 ){
- return SQLITE_OK;
- }
- assert( (pMem->flags & MEM_Dyn)==0 );
- assert( pMem->flags & (MEM_Str|MEM_Blob) );
- if( (n = pMem->n)+2<sizeof(pMem->zShort) ){
- z = pMem->zShort;
- pMem->flags |= MEM_Short|MEM_Term;
- }else{
- z = sqliteMallocRaw( n+2 );
- if( z==0 ){
- return SQLITE_NOMEM;
- }
- pMem->flags |= MEM_Dyn|MEM_Term;
- pMem->xDel = 0;
- }
- memcpy(z, pMem->z, n );
- z[n] = 0;
- z[n+1] = 0;
- pMem->z = z;
- pMem->flags &= ~(MEM_Ephem|MEM_Static);
- return SQLITE_OK;
-}
-
-/*
-** Make sure the given Mem is \u0000 terminated.
-*/
-int sqlite3VdbeMemNulTerminate(Mem *pMem){
- /* In SQLite, a string without a nul terminator occurs when a string
- ** is loaded from disk (in this case the memory management is ephemeral),
- ** or when it is supplied by the user as a bound variable or function
- ** return value. Therefore, the memory management of the string must be
- ** either ephemeral, static or controlled by a user-supplied destructor.
- */
- assert(
- !(pMem->flags&MEM_Str) || /* it's not a string, or */
- (pMem->flags&MEM_Term) || /* it's nul term. already, or */
- (pMem->flags&(MEM_Ephem|MEM_Static)) || /* it's static or ephem, or */
- (pMem->flags&MEM_Dyn && pMem->xDel) /* external management */
- );
- if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){
- return SQLITE_OK; /* Nothing to do */
- }
-
- if( pMem->flags & (MEM_Static|MEM_Ephem) ){
- return sqlite3VdbeMemMakeWriteable(pMem);
- }else{
- char *z = sqliteMalloc(pMem->n+2);
- if( !z ) return SQLITE_NOMEM;
- memcpy(z, pMem->z, pMem->n);
- z[pMem->n] = 0;
- z[pMem->n+1] = 0;
- pMem->xDel(pMem->z);
- pMem->xDel = 0;
- pMem->z = z;
- }
- return SQLITE_OK;
-}
-
-/*
-** Add MEM_Str to the set of representations for the given Mem. Numbers
-** are converted using sqlite3_snprintf(). Converting a BLOB to a string
-** is a no-op.
-**
-** Existing representations MEM_Int and MEM_Real are *not* invalidated.
-**
-** A MEM_Null value will never be passed to this function. This function is
-** used for converting values to text for returning to the user (i.e. via
-** sqlite3_value_text()), or for ensuring that values to be used as btree
-** keys are strings. In the former case a NULL pointer is returned the
-** user and the later is an internal programming error.
-*/
-int sqlite3VdbeMemStringify(Mem *pMem, int enc){
- int rc = SQLITE_OK;
- int fg = pMem->flags;
- u8 *z = pMem->zShort;
-
- assert( !(fg&(MEM_Str|MEM_Blob)) );
- assert( fg&(MEM_Int|MEM_Real) );
-
- /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8
- ** string representation of the value. Then, if the required encoding
- ** is UTF-16le or UTF-16be do a translation.
- **
- ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
- */
- if( fg & MEM_Real ){
- sqlite3_snprintf(NBFS, z, "%.15g", pMem->r);
- }else{
- assert( fg & MEM_Int );
- sqlite3_snprintf(NBFS, z, "%lld", pMem->i);
- }
- pMem->n = strlen(z);
- pMem->z = z;
- pMem->enc = SQLITE_UTF8;
- pMem->flags |= MEM_Str | MEM_Short | MEM_Term;
- sqlite3VdbeChangeEncoding(pMem, enc);
- return rc;
-}
-
-/*
-** Release any memory held by the Mem. This may leave the Mem in an
-** inconsistent state, for example with (Mem.z==0) and
-** (Mem.type==SQLITE_TEXT).
-*/
-void sqlite3VdbeMemRelease(Mem *p){
- if( p->flags & MEM_Dyn ){
- if( p->xDel ){
- p->xDel((void *)p->z);
- }else{
- sqliteFree(p->z);
- }
- p->z = 0;
- p->xDel = 0;
- }
-}
-
-/*
-** Return some kind of integer value which is the best we can do
-** at representing the value that *pMem describes as an integer.
-** If pMem is an integer, then the value is exact. If pMem is
-** a floating-point then the value returned is the integer part.
-** If pMem is a string or blob, then we make an attempt to convert
-** it into a integer and return that. If pMem is NULL, return 0.
-**
-** If pMem is a string, its encoding might be changed.
-*/
-i64 sqlite3VdbeIntValue(Mem *pMem){
- int flags = pMem->flags;
- if( flags & MEM_Int ){
- return pMem->i;
- }else if( flags & MEM_Real ){
- return (i64)pMem->r;
- }else if( flags & (MEM_Str|MEM_Blob) ){
- i64 value;
- if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
- || sqlite3VdbeMemNulTerminate(pMem) ){
- return SQLITE_NOMEM;
- }
- assert( pMem->z );
- sqlite3atoi64(pMem->z, &value);
- return value;
- }else{
- return 0;
- }
-}
-
-/*
-** Convert pMem to type integer. Invalidate any prior representations.
-*/
-int sqlite3VdbeMemIntegerify(Mem *pMem){
- pMem->i = sqlite3VdbeIntValue(pMem);
- sqlite3VdbeMemRelease(pMem);
- pMem->flags = MEM_Int;
- return SQLITE_OK;
-}
-
-/*
-** Return the best representation of pMem that we can get into a
-** double. If pMem is already a double or an integer, return its
-** value. If it is a string or blob, try to convert it to a double.
-** If it is a NULL, return 0.0.
-*/
-double sqlite3VdbeRealValue(Mem *pMem){
- if( pMem->flags & MEM_Real ){
- return pMem->r;
- }else if( pMem->flags & MEM_Int ){
- return (double)pMem->i;
- }else if( pMem->flags & (MEM_Str|MEM_Blob) ){
- if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
- || sqlite3VdbeMemNulTerminate(pMem) ){
- return SQLITE_NOMEM;
- }
- assert( pMem->z );
- return sqlite3AtoF(pMem->z, 0);
- }else{
- return 0.0;
- }
-}
-
-/*
-** Convert pMem so that it is of type MEM_Real. Invalidate any
-** prior representations.
-*/
-int sqlite3VdbeMemRealify(Mem *pMem){
- pMem->r = sqlite3VdbeRealValue(pMem);
- sqlite3VdbeMemRelease(pMem);
- pMem->flags = MEM_Real;
- return SQLITE_OK;
-}
-
-/*
-** Delete any previous value and set the value stored in *pMem to NULL.
-*/
-void sqlite3VdbeMemSetNull(Mem *pMem){
- sqlite3VdbeMemRelease(pMem);
- pMem->flags = MEM_Null;
- pMem->type = SQLITE_NULL;
-}
-
-/*
-** Delete any previous value and set the value stored in *pMem to val,
-** manifest type INTEGER.
-*/
-void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
- sqlite3VdbeMemRelease(pMem);
- pMem->i = val;
- pMem->flags = MEM_Int;
- pMem->type = SQLITE_INTEGER;
-}
-
-/*
-** Delete any previous value and set the value stored in *pMem to val,
-** manifest type REAL.
-*/
-void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
- sqlite3VdbeMemRelease(pMem);
- pMem->r = val;
- pMem->flags = MEM_Real;
- pMem->type = SQLITE_FLOAT;
-}
-
-/*
-** Make an shallow copy of pFrom into pTo. Prior contents of
-** pTo are overwritten. The pFrom->z field is not duplicated. If
-** pFrom->z is used, then pTo->z points to the same thing as pFrom->z
-** and flags gets srcType (either MEM_Ephem or MEM_Static).
-*/
-void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
- memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort));
- pTo->xDel = 0;
- if( pTo->flags & (MEM_Str|MEM_Blob) ){
- pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short|MEM_Ephem);
- assert( srcType==MEM_Ephem || srcType==MEM_Static );
- pTo->flags |= srcType;
- }
-}
-
-/*
-** Make a full copy of pFrom into pTo. Prior contents of pTo are
-** freed before the copy is made.
-*/
-int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
- int rc;
- if( pTo->flags & MEM_Dyn ){
- sqlite3VdbeMemRelease(pTo);
- }
- sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Ephem);
- if( pTo->flags & MEM_Ephem ){
- rc = sqlite3VdbeMemMakeWriteable(pTo);
- }else{
- rc = SQLITE_OK;
- }
- return rc;
-}
-
-/*
-** Transfer the contents of pFrom to pTo. Any existing value in pTo is
-** freed. If pFrom contains ephemeral data, a copy is made.
-**
-** pFrom contains an SQL NULL when this routine returns. SQLITE_NOMEM
-** might be returned if pFrom held ephemeral data and we were unable
-** to allocate enough space to make a copy.
-*/
-int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
- int rc;
- if( pTo->flags & MEM_Dyn ){
- sqlite3VdbeMemRelease(pTo);
- }
- memcpy(pTo, pFrom, sizeof(Mem));
- if( pFrom->flags & MEM_Short ){
- pTo->z = pTo->zShort;
- }
- pFrom->flags = MEM_Null;
- pFrom->xDel = 0;
- if( pTo->flags & MEM_Ephem ){
- rc = sqlite3VdbeMemMakeWriteable(pTo);
- }else{
- rc = SQLITE_OK;
- }
- return rc;
-}
-
-/*
-** Change the value of a Mem to be a string or a BLOB.
-*/
-int sqlite3VdbeMemSetStr(
- Mem *pMem, /* Memory cell to set to string value */
- const char *z, /* String pointer */
- int n, /* Bytes in string, or negative */
- u8 enc, /* Encoding of z. 0 for BLOBs */
- void (*xDel)(void*) /* Destructor function */
-){
- sqlite3VdbeMemRelease(pMem);
- if( !z ){
- pMem->flags = MEM_Null;
- pMem->type = SQLITE_NULL;
- return SQLITE_OK;
- }
-
- pMem->z = (char *)z;
- if( xDel==SQLITE_STATIC ){
- pMem->flags = MEM_Static;
- }else if( xDel==SQLITE_TRANSIENT ){
- pMem->flags = MEM_Ephem;
- }else{
- pMem->flags = MEM_Dyn;
- pMem->xDel = xDel;
- }
-
- pMem->enc = enc;
- pMem->type = enc==0 ? SQLITE_BLOB : SQLITE_TEXT;
- pMem->n = n;
-
- switch( enc ){
- case 0:
- pMem->flags |= MEM_Blob;
- break;
-
- case SQLITE_UTF8:
- pMem->flags |= MEM_Str;
- if( n<0 ){
- pMem->n = strlen(z);
- pMem->flags |= MEM_Term;
- }
- break;
-
- case SQLITE_UTF16LE:
- case SQLITE_UTF16BE:
- pMem->flags |= MEM_Str;
- if( pMem->n<0 ){
- pMem->n = sqlite3utf16ByteLen(pMem->z,-1);
- pMem->flags |= MEM_Term;
- }
- if( sqlite3VdbeMemHandleBom(pMem) ){
- return SQLITE_NOMEM;
- }
- break;
-
- default:
- assert(0);
- }
- if( pMem->flags&MEM_Ephem ){
- return sqlite3VdbeMemMakeWriteable(pMem);
- }
- return SQLITE_OK;
-}
-
-/*
-** Compare the values contained by the two memory cells, returning
-** negative, zero or positive if pMem1 is less than, equal to, or greater
-** than pMem2. Sorting order is NULL's first, followed by numbers (integers
-** and reals) sorted numerically, followed by text ordered by the collating
-** sequence pColl and finally blob's ordered by memcmp().
-**
-** Two NULL values are considered equal by this function.
-*/
-int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
- int rc;
- int f1, f2;
- int combined_flags;
-
- /* Interchange pMem1 and pMem2 if the collating sequence specifies
- ** DESC order.
- */
- f1 = pMem1->flags;
- f2 = pMem2->flags;
- combined_flags = f1|f2;
-
- /* If one value is NULL, it is less than the other. If both values
- ** are NULL, return 0.
- */
- if( combined_flags&MEM_Null ){
- return (f2&MEM_Null) - (f1&MEM_Null);
- }
-
- /* If one value is a number and the other is not, the number is less.
- ** If both are numbers, compare as reals if one is a real, or as integers
- ** if both values are integers.
- */
- if( combined_flags&(MEM_Int|MEM_Real) ){
- if( !(f1&(MEM_Int|MEM_Real)) ){
- return 1;
- }
- if( !(f2&(MEM_Int|MEM_Real)) ){
- return -1;
- }
- if( (f1 & f2 & MEM_Int)==0 ){
- double r1, r2;
- if( (f1&MEM_Real)==0 ){
- r1 = pMem1->i;
- }else{
- r1 = pMem1->r;
- }
- if( (f2&MEM_Real)==0 ){
- r2 = pMem2->i;
- }else{
- r2 = pMem2->r;
- }
- if( r1<r2 ) return -1;
- if( r1>r2 ) return 1;
- return 0;
- }else{
- assert( f1&MEM_Int );
- assert( f2&MEM_Int );
- if( pMem1->i < pMem2->i ) return -1;
- if( pMem1->i > pMem2->i ) return 1;
- return 0;
- }
- }
-
- /* If one value is a string and the other is a blob, the string is less.
- ** If both are strings, compare using the collating functions.
- */
- if( combined_flags&MEM_Str ){
- if( (f1 & MEM_Str)==0 ){
- return 1;
- }
- if( (f2 & MEM_Str)==0 ){
- return -1;
- }
-
- assert( pMem1->enc==pMem2->enc );
- assert( pMem1->enc==SQLITE_UTF8 ||
- pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
-
- /* This assert may fail if the collation sequence is deleted after this
- ** vdbe program is compiled. The documentation defines this as an
- ** undefined condition. A crash is usual result.
- */
- assert( !pColl || pColl->xCmp );
-
- if( pColl ){
- if( pMem1->enc==pColl->enc ){
- return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
- }else{
- u8 origEnc = pMem1->enc;
- rc = pColl->xCmp(
- pColl->pUser,
- sqlite3ValueBytes((sqlite3_value*)pMem1, pColl->enc),
- sqlite3ValueText((sqlite3_value*)pMem1, pColl->enc),
- sqlite3ValueBytes((sqlite3_value*)pMem2, pColl->enc),
- sqlite3ValueText((sqlite3_value*)pMem2, pColl->enc)
- );
- sqlite3ValueBytes((sqlite3_value*)pMem1, origEnc);
- sqlite3ValueText((sqlite3_value*)pMem1, origEnc);
- sqlite3ValueBytes((sqlite3_value*)pMem2, origEnc);
- sqlite3ValueText((sqlite3_value*)pMem2, origEnc);
- return rc;
- }
- }
- /* If a NULL pointer was passed as the collate function, fall through
- ** to the blob case and use memcmp(). */
- }
-
- /* Both values must be blobs. Compare using memcmp(). */
- rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n);
- if( rc==0 ){
- rc = pMem1->n - pMem2->n;
- }
- return rc;
-}
-
-/*
-** Move data out of a btree key or data field and into a Mem structure.
-** The data or key is taken from the entry that pCur is currently pointing
-** to. offset and amt determine what portion of the data or key to retrieve.
-** key is true to get the key or false to get data. The result is written
-** into the pMem element.
-**
-** The pMem structure is assumed to be uninitialized. Any prior content
-** is overwritten without being freed.
-**
-** If this routine fails for any reason (malloc returns NULL or unable
-** to read from the disk) then the pMem is left in an inconsistent state.
-*/
-int sqlite3VdbeMemFromBtree(
- BtCursor *pCur, /* Cursor pointing at record to retrieve. */
- int offset, /* Offset from the start of data to return bytes from. */
- int amt, /* Number of bytes to return. */
- int key, /* If true, retrieve from the btree key, not data. */
- Mem *pMem /* OUT: Return data in this Mem structure. */
-){
- char *zData; /* Data from the btree layer */
- int available; /* Number of bytes available on the local btree page */
-
- if( key ){
- zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
- }else{
- zData = (char *)sqlite3BtreeDataFetch(pCur, &available);
- }
-
- pMem->n = amt;
- if( offset+amt<=available ){
- pMem->z = &zData[offset];
- pMem->flags = MEM_Blob|MEM_Ephem;
- }else{
- int rc;
- if( amt>NBFS-2 ){
- zData = (char *)sqliteMallocRaw(amt+2);
- if( !zData ){
- return SQLITE_NOMEM;
- }
- pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term;
- pMem->xDel = 0;
- }else{
- zData = &(pMem->zShort[0]);
- pMem->flags = MEM_Blob|MEM_Short|MEM_Term;
- }
- pMem->z = zData;
- pMem->enc = 0;
- pMem->type = SQLITE_BLOB;
-
- if( key ){
- rc = sqlite3BtreeKey(pCur, offset, amt, zData);
- }else{
- rc = sqlite3BtreeData(pCur, offset, amt, zData);
- }
- zData[amt] = 0;
- zData[amt+1] = 0;
- if( rc!=SQLITE_OK ){
- if( amt>NBFS ){
- sqliteFree(zData);
- }
- return rc;
- }
- }
-
- return SQLITE_OK;
-}
-
-#ifndef NDEBUG
-/*
-** Perform various checks on the memory cell pMem. An assert() will
-** fail if pMem is internally inconsistent.
-*/
-void sqlite3VdbeMemSanity(Mem *pMem, u8 db_enc){
- int flags = pMem->flags;
- assert( flags!=0 ); /* Must define some type */
- if( pMem->flags & (MEM_Str|MEM_Blob) ){
- int x = pMem->flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
- assert( x!=0 ); /* Strings must define a string subtype */
- assert( (x & (x-1))==0 ); /* Only one string subtype can be defined */
- assert( pMem->z!=0 ); /* Strings must have a value */
- /* Mem.z points to Mem.zShort iff the subtype is MEM_Short */
- assert( (pMem->flags & MEM_Short)==0 || pMem->z==pMem->zShort );
- assert( (pMem->flags & MEM_Short)!=0 || pMem->z!=pMem->zShort );
- /* No destructor unless there is MEM_Dyn */
- assert( pMem->xDel==0 || (pMem->flags & MEM_Dyn)!=0 );
-
- if( (flags & MEM_Str) ){
- assert( pMem->enc==SQLITE_UTF8 ||
- pMem->enc==SQLITE_UTF16BE ||
- pMem->enc==SQLITE_UTF16LE
- );
- /* If the string is UTF-8 encoded and nul terminated, then pMem->n
- ** must be the length of the string. (Later:) If the database file
- ** has been corrupted, '\000' characters might have been inserted
- ** into the middle of the string. In that case, the strlen() might
- ** be less.
- */
- if( pMem->enc==SQLITE_UTF8 && (flags & MEM_Term) ){
- assert( strlen(pMem->z)<=pMem->n );
- assert( pMem->z[pMem->n]==0 );
- }
- }
- }else{
- /* Cannot define a string subtype for non-string objects */
- assert( (pMem->flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short))==0 );
- assert( pMem->xDel==0 );
- }
- /* MEM_Null excludes all other types */
- assert( (pMem->flags&(MEM_Str|MEM_Int|MEM_Real|MEM_Blob))==0
- || (pMem->flags&MEM_Null)==0 );
- if( (pMem->flags & (MEM_Int|MEM_Real))==(MEM_Int|MEM_Real) ){
- assert( pMem->r==pMem->i );
- }
-}
-#endif
-
-/* This function is only available internally, it is not part of the
-** external API. It works in a similar way to sqlite3_value_text(),
-** except the data returned is in the encoding specified by the second
-** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or
-** SQLITE_UTF8.
-*/
-const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
- if( !pVal ) return 0;
- assert( enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE || enc==SQLITE_UTF8);
-
- if( pVal->flags&MEM_Null ){
- return 0;
- }
- if( pVal->flags&MEM_Str ){
- sqlite3VdbeChangeEncoding(pVal, enc);
- }else if( !(pVal->flags&MEM_Blob) ){
- sqlite3VdbeMemStringify(pVal, enc);
- }
- return (const void *)(pVal->z);
-}
-
-/*
-** Create a new sqlite3_value object.
-*/
-sqlite3_value* sqlite3ValueNew(){
- Mem *p = sqliteMalloc(sizeof(*p));
- if( p ){
- p->flags = MEM_Null;
- p->type = SQLITE_NULL;
- }
- return p;
-}
-
-/*
-** Change the string value of an sqlite3_value object
-*/
-void sqlite3ValueSetStr(
- sqlite3_value *v,
- int n,
- const void *z,
- u8 enc,
- void (*xDel)(void*)
-){
- if( v ) sqlite3VdbeMemSetStr((Mem *)v, z, n, enc, xDel);
-}
-
-/*
-** Free an sqlite3_value object
-*/
-void sqlite3ValueFree(sqlite3_value *v){
- if( !v ) return;
- sqlite3ValueSetStr(v, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
- sqliteFree(v);
-}
-
-/*
-** Return the number of bytes in the sqlite3_value object assuming
-** that it uses the encoding "enc"
-*/
-int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
- Mem *p = (Mem*)pVal;
- if( (p->flags & MEM_Blob)!=0 || sqlite3ValueText(pVal, enc) ){
- return p->n;
- }
- return 0;
-}
diff --git a/kopete/plugins/statistics/sqlite/where.c b/kopete/plugins/statistics/sqlite/where.c
deleted file mode 100644
index 08c174e9..00000000
--- a/kopete/plugins/statistics/sqlite/where.c
+++ /dev/null
@@ -1,1210 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This module contains C code that generates VDBE code used to process
-** the WHERE clause of SQL statements.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-
-/*
-** The query generator uses an array of instances of this structure to
-** help it analyze the subexpressions of the WHERE clause. Each WHERE
-** clause subexpression is separated from the others by an AND operator.
-*/
-typedef struct ExprInfo ExprInfo;
-struct ExprInfo {
- Expr *p; /* Pointer to the subexpression */
- u8 indexable; /* True if this subexprssion is usable by an index */
- short int idxLeft; /* p->pLeft is a column in this table number. -1 if
- ** p->pLeft is not the column of any table */
- short int idxRight; /* p->pRight is a column in this table number. -1 if
- ** p->pRight is not the column of any table */
- unsigned prereqLeft; /* Bitmask of tables referenced by p->pLeft */
- unsigned prereqRight; /* Bitmask of tables referenced by p->pRight */
- unsigned prereqAll; /* Bitmask of tables referenced by p */
-};
-
-/*
-** An instance of the following structure keeps track of a mapping
-** between VDBE cursor numbers and bitmasks. The VDBE cursor numbers
-** are small integers contained in SrcList_item.iCursor and Expr.iTable
-** fields. For any given WHERE clause, we want to track which cursors
-** are being used, so we assign a single bit in a 32-bit word to track
-** that cursor. Then a 32-bit integer is able to show the set of all
-** cursors being used.
-*/
-typedef struct ExprMaskSet ExprMaskSet;
-struct ExprMaskSet {
- int n; /* Number of assigned cursor values */
- int ix[31]; /* Cursor assigned to each bit */
-};
-
-/*
-** Determine the number of elements in an array.
-*/
-#define ARRAYSIZE(X) (sizeof(X)/sizeof(X[0]))
-
-/*
-** This routine is used to divide the WHERE expression into subexpressions
-** separated by the AND operator.
-**
-** aSlot[] is an array of subexpressions structures.
-** There are nSlot spaces left in this array. This routine attempts to
-** split pExpr into subexpressions and fills aSlot[] with those subexpressions.
-** The return value is the number of slots filled.
-*/
-static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){
- int cnt = 0;
- if( pExpr==0 || nSlot<1 ) return 0;
- if( nSlot==1 || pExpr->op!=TK_AND ){
- aSlot[0].p = pExpr;
- return 1;
- }
- if( pExpr->pLeft->op!=TK_AND ){
- aSlot[0].p = pExpr->pLeft;
- cnt = 1 + exprSplit(nSlot-1, &aSlot[1], pExpr->pRight);
- }else{
- cnt = exprSplit(nSlot, aSlot, pExpr->pLeft);
- cnt += exprSplit(nSlot-cnt, &aSlot[cnt], pExpr->pRight);
- }
- return cnt;
-}
-
-/*
-** Initialize an expression mask set
-*/
-#define initMaskSet(P) memset(P, 0, sizeof(*P))
-
-/*
-** Return the bitmask for the given cursor. Assign a new bitmask
-** if this is the first time the cursor has been seen.
-*/
-static int getMask(ExprMaskSet *pMaskSet, int iCursor){
- int i;
- for(i=0; i<pMaskSet->n; i++){
- if( pMaskSet->ix[i]==iCursor ) return 1<<i;
- }
- if( i==pMaskSet->n && i<ARRAYSIZE(pMaskSet->ix) ){
- pMaskSet->n++;
- pMaskSet->ix[i] = iCursor;
- return 1<<i;
- }
- return 0;
-}
-
-/*
-** Destroy an expression mask set
-*/
-#define freeMaskSet(P) /* NO-OP */
-
-/*
-** This routine walks (recursively) an expression tree and generates
-** a bitmask indicating which tables are used in that expression
-** tree.
-**
-** In order for this routine to work, the calling function must have
-** previously invoked sqlite3ExprResolveIds() on the expression. See
-** the header comment on that routine for additional information.
-** The sqlite3ExprResolveIds() routines looks for column names and
-** sets their opcodes to TK_COLUMN and their Expr.iTable fields to
-** the VDBE cursor number of the table.
-*/
-static int exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
- unsigned int mask = 0;
- if( p==0 ) return 0;
- if( p->op==TK_COLUMN ){
- mask = getMask(pMaskSet, p->iTable);
- if( mask==0 ) mask = -1;
- return mask;
- }
- if( p->pRight ){
- mask = exprTableUsage(pMaskSet, p->pRight);
- }
- if( p->pLeft ){
- mask |= exprTableUsage(pMaskSet, p->pLeft);
- }
- if( p->pList ){
- int i;
- for(i=0; i<p->pList->nExpr; i++){
- mask |= exprTableUsage(pMaskSet, p->pList->a[i].pExpr);
- }
- }
- return mask;
-}
-
-/*
-** Return TRUE if the given operator is one of the operators that is
-** allowed for an indexable WHERE clause. The allowed operators are
-** "=", "<", ">", "<=", ">=", and "IN".
-*/
-static int allowedOp(int op){
- assert( TK_GT==TK_LE-1 && TK_LE==TK_LT-1 && TK_LT==TK_GE-1 && TK_EQ==TK_GT-1);
- return op==TK_IN || (op>=TK_EQ && op<=TK_GE);
-}
-
-/*
-** Swap two integers.
-*/
-#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
-
-/*
-** Return the index in the SrcList that uses cursor iCur. If iCur is
-** used by the first entry in SrcList return 0. If iCur is used by
-** the second entry return 1. And so forth.
-**
-** SrcList is the set of tables in the FROM clause in the order that
-** they will be processed. The value returned here gives us an index
-** of which tables will be processed first.
-*/
-static int tableOrder(SrcList *pList, int iCur){
- int i;
- for(i=0; i<pList->nSrc; i++){
- if( pList->a[i].iCursor==iCur ) return i;
- }
- return -1;
-}
-
-/*
-** The input to this routine is an ExprInfo structure with only the
-** "p" field filled in. The job of this routine is to analyze the
-** subexpression and populate all the other fields of the ExprInfo
-** structure.
-*/
-static void exprAnalyze(SrcList *pSrc, ExprMaskSet *pMaskSet, ExprInfo *pInfo){
- Expr *pExpr = pInfo->p;
- pInfo->prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
- pInfo->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
- pInfo->prereqAll = exprTableUsage(pMaskSet, pExpr);
- pInfo->indexable = 0;
- pInfo->idxLeft = -1;
- pInfo->idxRight = -1;
- if( allowedOp(pExpr->op) && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
- if( pExpr->pRight && pExpr->pRight->op==TK_COLUMN ){
- pInfo->idxRight = pExpr->pRight->iTable;
- pInfo->indexable = 1;
- }
- if( pExpr->pLeft->op==TK_COLUMN ){
- pInfo->idxLeft = pExpr->pLeft->iTable;
- pInfo->indexable = 1;
- }
- }
- if( pInfo->indexable ){
- assert( pInfo->idxLeft!=pInfo->idxRight );
-
- /* We want the expression to be of the form "X = expr", not "expr = X".
- ** So flip it over if necessary. If the expression is "X = Y", then
- ** we want Y to come from an earlier table than X.
- **
- ** The collating sequence rule is to always choose the left expression.
- ** So if we do a flip, we also have to move the collating sequence.
- */
- if( tableOrder(pSrc,pInfo->idxLeft)<tableOrder(pSrc,pInfo->idxRight) ){
- assert( pExpr->op!=TK_IN );
- SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl);
- SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
- if( pExpr->op>=TK_GT ){
- assert( TK_LT==TK_GT+2 );
- assert( TK_GE==TK_LE+2 );
- assert( TK_GT>TK_EQ );
- assert( TK_GT<TK_LE );
- assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE );
- pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT;
- }
- SWAP(unsigned, pInfo->prereqLeft, pInfo->prereqRight);
- SWAP(short int, pInfo->idxLeft, pInfo->idxRight);
- }
- }
-
-}
-
-/*
-** pOrderBy is an ORDER BY clause from a SELECT statement. pTab is the
-** left-most table in the FROM clause of that same SELECT statement and
-** the table has a cursor number of "base".
-**
-** This routine attempts to find an index for pTab that generates the
-** correct record sequence for the given ORDER BY clause. The return value
-** is a pointer to an index that does the job. NULL is returned if the
-** table has no index that will generate the correct sort order.
-**
-** If there are two or more indices that generate the correct sort order
-** and pPreferredIdx is one of those indices, then return pPreferredIdx.
-**
-** nEqCol is the number of columns of pPreferredIdx that are used as
-** equality constraints. Any index returned must have exactly this same
-** set of columns. The ORDER BY clause only matches index columns beyond the
-** the first nEqCol columns.
-**
-** All terms of the ORDER BY clause must be either ASC or DESC. The
-** *pbRev value is set to 1 if the ORDER BY clause is all DESC and it is
-** set to 0 if the ORDER BY clause is all ASC.
-*/
-static Index *findSortingIndex(
- Parse *pParse,
- Table *pTab, /* The table to be sorted */
- int base, /* Cursor number for pTab */
- ExprList *pOrderBy, /* The ORDER BY clause */
- Index *pPreferredIdx, /* Use this index, if possible and not NULL */
- int nEqCol, /* Number of index columns used with == constraints */
- int *pbRev /* Set to 1 if ORDER BY is DESC */
-){
- int i, j;
- Index *pMatch;
- Index *pIdx;
- int sortOrder;
- sqlite3 *db = pParse->db;
-
- assert( pOrderBy!=0 );
- assert( pOrderBy->nExpr>0 );
- sortOrder = pOrderBy->a[0].sortOrder;
- for(i=0; i<pOrderBy->nExpr; i++){
- Expr *p;
- if( pOrderBy->a[i].sortOrder!=sortOrder ){
- /* Indices can only be used if all ORDER BY terms are either
- ** DESC or ASC. Indices cannot be used on a mixture. */
- return 0;
- }
- p = pOrderBy->a[i].pExpr;
- if( p->op!=TK_COLUMN || p->iTable!=base ){
- /* Can not use an index sort on anything that is not a column in the
- ** left-most table of the FROM clause */
- return 0;
- }
- }
-
- /* If we get this far, it means the ORDER BY clause consists only of
- ** ascending columns in the left-most table of the FROM clause. Now
- ** check for a matching index.
- */
- pMatch = 0;
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- int nExpr = pOrderBy->nExpr;
- if( pIdx->nColumn < nEqCol || pIdx->nColumn < nExpr ) continue;
- for(i=j=0; i<nEqCol; i++){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pOrderBy->a[j].pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- if( pPreferredIdx->aiColumn[i]!=pIdx->aiColumn[i] ) break;
- if( pPreferredIdx->keyInfo.aColl[i]!=pIdx->keyInfo.aColl[i] ) break;
- if( j<nExpr &&
- pOrderBy->a[j].pExpr->iColumn==pIdx->aiColumn[i] &&
- pColl==pIdx->keyInfo.aColl[i]
- ){
- j++;
- }
- }
- if( i<nEqCol ) continue;
- for(i=0; i+j<nExpr; i++){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pOrderBy->a[i+j].pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- if( pOrderBy->a[i+j].pExpr->iColumn!=pIdx->aiColumn[i+nEqCol] ||
- pColl!=pIdx->keyInfo.aColl[i+nEqCol] ) break;
- }
- if( i+j>=nExpr ){
- pMatch = pIdx;
- if( pIdx==pPreferredIdx ) break;
- }
- }
- if( pMatch && pbRev ){
- *pbRev = sortOrder==SQLITE_SO_DESC;
- }
- return pMatch;
-}
-
-/*
-** Disable a term in the WHERE clause. Except, do not disable the term
-** if it controls a LEFT OUTER JOIN and it did not originate in the ON
-** or USING clause of that join.
-**
-** Consider the term t2.z='ok' in the following queries:
-**
-** (1) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x WHERE t2.z='ok'
-** (2) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x AND t2.z='ok'
-** (3) SELECT * FROM t1, t2 WHERE t1.a=t2.x AND t2.z='ok'
-**
-** The t2.z='ok' is disabled in the in (2) because it did not originate
-** in the ON clause. The term is disabled in (3) because it is not part
-** of a LEFT OUTER JOIN. In (1), the term is not disabled.
-**
-** Disabling a term causes that term to not be tested in the inner loop
-** of the join. Disabling is an optimization. We would get the correct
-** results if nothing were ever disabled, but joins might run a little
-** slower. The trick is to disable as much as we can without disabling
-** too much. If we disabled in (1), we'd get the wrong answer.
-** See ticket #813.
-*/
-static void disableTerm(WhereLevel *pLevel, Expr **ppExpr){
- Expr *pExpr = *ppExpr;
- if( pLevel->iLeftJoin==0 || ExprHasProperty(pExpr, EP_FromJoin) ){
- *ppExpr = 0;
- }
-}
-
-/*
-** Generate code that builds a probe for an index. Details:
-**
-** * Check the top nColumn entries on the stack. If any
-** of those entries are NULL, jump immediately to brk,
-** which is the loop exit, since no index entry will match
-** if any part of the key is NULL.
-**
-** * Construct a probe entry from the top nColumn entries in
-** the stack with affinities appropriate for index pIdx.
-*/
-static void buildIndexProbe(Vdbe *v, int nColumn, int brk, Index *pIdx){
- sqlite3VdbeAddOp(v, OP_NotNull, -nColumn, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
- sqlite3IndexAffinityStr(v, pIdx);
-}
-
-/*
-** Generate code for an equality term of the WHERE clause. An equality
-** term can be either X=expr or X IN (...). pTerm is the X.
-*/
-static void codeEqualityTerm(
- Parse *pParse, /* The parsing context */
- ExprInfo *pTerm, /* The term of the WHERE clause to be coded */
- int brk, /* Jump here to abandon the loop */
- WhereLevel *pLevel /* When level of the FROM clause we are working on */
-){
- Expr *pX = pTerm->p;
- if( pX->op!=TK_IN ){
- assert( pX->op==TK_EQ );
- sqlite3ExprCode(pParse, pX->pRight);
- }else{
- int iTab = pX->iTable;
- Vdbe *v = pParse->pVdbe;
- sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
- sqlite3VdbeAddOp(v, OP_KeyAsData, iTab, 1);
- pLevel->inP2 = sqlite3VdbeAddOp(v, OP_IdxColumn, iTab, 0);
- pLevel->inOp = OP_Next;
- pLevel->inP1 = iTab;
- }
- disableTerm(pLevel, &pTerm->p);
-}
-
-
-/*
-** Generate the beginning of the loop used for WHERE clause processing.
-** The return value is a pointer to an (opaque) structure that contains
-** information needed to terminate the loop. Later, the calling routine
-** should invoke sqlite3WhereEnd() with the return value of this function
-** in order to complete the WHERE clause processing.
-**
-** If an error occurs, this routine returns NULL.
-**
-** The basic idea is to do a nested loop, one loop for each table in
-** the FROM clause of a select. (INSERT and UPDATE statements are the
-** same as a SELECT with only a single table in the FROM clause.) For
-** example, if the SQL is this:
-**
-** SELECT * FROM t1, t2, t3 WHERE ...;
-**
-** Then the code generated is conceptually like the following:
-**
-** foreach row1 in t1 do \ Code generated
-** foreach row2 in t2 do |-- by sqlite3WhereBegin()
-** foreach row3 in t3 do /
-** ...
-** end \ Code generated
-** end |-- by sqlite3WhereEnd()
-** end /
-**
-** There are Btree cursors associated with each table. t1 uses cursor
-** number pTabList->a[0].iCursor. t2 uses the cursor pTabList->a[1].iCursor.
-** And so forth. This routine generates code to open those VDBE cursors
-** and sqlite3WhereEnd() generates the code to close them.
-**
-** If the WHERE clause is empty, the foreach loops must each scan their
-** entire tables. Thus a three-way join is an O(N^3) operation. But if
-** the tables have indices and there are terms in the WHERE clause that
-** refer to those indices, a complete table scan can be avoided and the
-** code will run much faster. Most of the work of this routine is checking
-** to see if there are indices that can be used to speed up the loop.
-**
-** Terms of the WHERE clause are also used to limit which rows actually
-** make it to the "..." in the middle of the loop. After each "foreach",
-** terms of the WHERE clause that use only terms in that loop and outer
-** loops are evaluated and if false a jump is made around all subsequent
-** inner loops (or around the "..." if the test occurs within the inner-
-** most loop)
-**
-** OUTER JOINS
-**
-** An outer join of tables t1 and t2 is conceptally coded as follows:
-**
-** foreach row1 in t1 do
-** flag = 0
-** foreach row2 in t2 do
-** start:
-** ...
-** flag = 1
-** end
-** if flag==0 then
-** move the row2 cursor to a null row
-** goto start
-** fi
-** end
-**
-** ORDER BY CLAUSE PROCESSING
-**
-** *ppOrderBy is a pointer to the ORDER BY clause of a SELECT statement,
-** if there is one. If there is no ORDER BY clause or if this routine
-** is called from an UPDATE or DELETE statement, then ppOrderBy is NULL.
-**
-** If an index can be used so that the natural output order of the table
-** scan is correct for the ORDER BY clause, then that index is used and
-** *ppOrderBy is set to NULL. This is an optimization that prevents an
-** unnecessary sort of the result set if an index appropriate for the
-** ORDER BY clause already exists.
-**
-** If the where clause loops cannot be arranged to provide the correct
-** output order, then the *ppOrderBy is unchanged.
-*/
-WhereInfo *sqlite3WhereBegin(
- Parse *pParse, /* The parser context */
- SrcList *pTabList, /* A list of all tables to be scanned */
- Expr *pWhere, /* The WHERE clause */
- int pushKey, /* If TRUE, leave the table key on the stack */
- ExprList **ppOrderBy /* An ORDER BY clause, or NULL */
-){
- int i; /* Loop counter */
- WhereInfo *pWInfo; /* Will become the return value of this function */
- Vdbe *v = pParse->pVdbe; /* The virtual database engine */
- int brk, cont = 0; /* Addresses used during code generation */
- int nExpr; /* Number of subexpressions in the WHERE clause */
- int loopMask; /* One bit set for each outer loop */
- int haveKey = 0; /* True if KEY is on the stack */
- ExprInfo *pTerm; /* A single term in the WHERE clause; ptr to aExpr[] */
- ExprMaskSet maskSet; /* The expression mask set */
- int iDirectEq[32]; /* Term of the form ROWID==X for the N-th table */
- int iDirectLt[32]; /* Term of the form ROWID<X or ROWID<=X */
- int iDirectGt[32]; /* Term of the form ROWID>X or ROWID>=X */
- ExprInfo aExpr[101]; /* The WHERE clause is divided into these terms */
-
- /* pushKey is only allowed if there is a single table (as in an INSERT or
- ** UPDATE statement)
- */
- assert( pushKey==0 || pTabList->nSrc==1 );
-
- /* Split the WHERE clause into separate subexpressions where each
- ** subexpression is separated by an AND operator. If the aExpr[]
- ** array fills up, the last entry might point to an expression which
- ** contains additional unfactored AND operators.
- */
- initMaskSet(&maskSet);
- memset(aExpr, 0, sizeof(aExpr));
- nExpr = exprSplit(ARRAYSIZE(aExpr), aExpr, pWhere);
- if( nExpr==ARRAYSIZE(aExpr) ){
- sqlite3ErrorMsg(pParse, "WHERE clause too complex - no more "
- "than %d terms allowed", (int)ARRAYSIZE(aExpr)-1);
- return 0;
- }
-
- /* Allocate and initialize the WhereInfo structure that will become the
- ** return value.
- */
- pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
- if( sqlite3_malloc_failed ){
- /* sqliteFree(pWInfo); // Leak memory when malloc fails */
- return 0;
- }
- pWInfo->pParse = pParse;
- pWInfo->pTabList = pTabList;
- pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
-
- /* Special case: a WHERE clause that is constant. Evaluate the
- ** expression and either jump over all of the code or fall thru.
- */
- if( pWhere && (pTabList->nSrc==0 || sqlite3ExprIsConstant(pWhere)) ){
- sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1);
- pWhere = 0;
- }
-
- /* Analyze all of the subexpressions.
- */
- for(pTerm=aExpr, i=0; i<nExpr; i++, pTerm++){
- TriggerStack *pStack;
- exprAnalyze(pTabList, &maskSet, pTerm);
-
- /* If we are executing a trigger body, remove all references to
- ** new.* and old.* tables from the prerequisite masks.
- */
- if( (pStack = pParse->trigStack)!=0 ){
- int x;
- if( (x=pStack->newIdx) >= 0 ){
- int mask = ~getMask(&maskSet, x);
- pTerm->prereqRight &= mask;
- pTerm->prereqLeft &= mask;
- pTerm->prereqAll &= mask;
- }
- if( (x=pStack->oldIdx) >= 0 ){
- int mask = ~getMask(&maskSet, x);
- pTerm->prereqRight &= mask;
- pTerm->prereqLeft &= mask;
- pTerm->prereqAll &= mask;
- }
- }
- }
-
- /* Figure out what index to use (if any) for each nested loop.
- ** Make pWInfo->a[i].pIdx point to the index to use for the i-th nested
- ** loop where i==0 is the outer loop and i==pTabList->nSrc-1 is the inner
- ** loop.
- **
- ** If terms exist that use the ROWID of any table, then set the
- ** iDirectEq[], iDirectLt[], or iDirectGt[] elements for that table
- ** to the index of the term containing the ROWID. We always prefer
- ** to use a ROWID which can directly access a table rather than an
- ** index which requires reading an index first to get the rowid then
- ** doing a second read of the actual database table.
- **
- ** Actually, if there are more than 32 tables in the join, only the
- ** first 32 tables are candidates for indices. This is (again) due
- ** to the limit of 32 bits in an integer bitmask.
- */
- loopMask = 0;
- for(i=0; i<pTabList->nSrc && i<ARRAYSIZE(iDirectEq); i++){
- int j;
- WhereLevel *pLevel = &pWInfo->a[i];
- int iCur = pTabList->a[i].iCursor; /* The cursor for this table */
- int mask = getMask(&maskSet, iCur); /* Cursor mask for this table */
- Table *pTab = pTabList->a[i].pTab;
- Index *pIdx;
- Index *pBestIdx = 0;
- int bestScore = 0;
-
- /* Check to see if there is an expression that uses only the
- ** ROWID field of this table. For terms of the form ROWID==expr
- ** set iDirectEq[i] to the index of the term. For terms of the
- ** form ROWID<expr or ROWID<=expr set iDirectLt[i] to the term index.
- ** For terms like ROWID>expr or ROWID>=expr set iDirectGt[i].
- **
- ** (Added:) Treat ROWID IN expr like ROWID=expr.
- */
- pLevel->iCur = -1;
- iDirectEq[i] = -1;
- iDirectLt[i] = -1;
- iDirectGt[i] = -1;
- for(pTerm=aExpr, j=0; j<nExpr; j++, pTerm++){
- Expr *pX = pTerm->p;
- if( pTerm->idxLeft==iCur && pX->pLeft->iColumn<0
- && (pTerm->prereqRight & loopMask)==pTerm->prereqRight ){
- switch( pX->op ){
- case TK_IN:
- case TK_EQ: iDirectEq[i] = j; break;
- case TK_LE:
- case TK_LT: iDirectLt[i] = j; break;
- case TK_GE:
- case TK_GT: iDirectGt[i] = j; break;
- }
- }
- }
- if( iDirectEq[i]>=0 ){
- loopMask |= mask;
- pLevel->pIdx = 0;
- continue;
- }
-
- /* Do a search for usable indices. Leave pBestIdx pointing to
- ** the "best" index. pBestIdx is left set to NULL if no indices
- ** are usable.
- **
- ** The best index is determined as follows. For each of the
- ** left-most terms that is fixed by an equality operator, add
- ** 8 to the score. The right-most term of the index may be
- ** constrained by an inequality. Add 1 if for an "x<..." constraint
- ** and add 2 for an "x>..." constraint. Chose the index that
- ** gives the best score.
- **
- ** This scoring system is designed so that the score can later be
- ** used to determine how the index is used. If the score&7 is 0
- ** then all constraints are equalities. If score&1 is not 0 then
- ** there is an inequality used as a termination key. (ex: "x<...")
- ** If score&2 is not 0 then there is an inequality used as the
- ** start key. (ex: "x>..."). A score or 4 is the special case
- ** of an IN operator constraint. (ex: "x IN ...").
- **
- ** The IN operator (as in "<expr> IN (...)") is treated the same as
- ** an equality comparison except that it can only be used on the
- ** left-most column of an index and other terms of the WHERE clause
- ** cannot be used in conjunction with the IN operator to help satisfy
- ** other columns of the index.
- */
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- int eqMask = 0; /* Index columns covered by an x=... term */
- int ltMask = 0; /* Index columns covered by an x<... term */
- int gtMask = 0; /* Index columns covered by an x>... term */
- int inMask = 0; /* Index columns covered by an x IN .. term */
- int nEq, m, score;
-
- if( pIdx->nColumn>32 ) continue; /* Ignore indices too many columns */
- for(pTerm=aExpr, j=0; j<nExpr; j++, pTerm++){
- Expr *pX = pTerm->p;
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pX->pLeft);
- if( !pColl && pX->pRight ){
- pColl = sqlite3ExprCollSeq(pParse, pX->pRight);
- }
- if( !pColl ){
- pColl = pParse->db->pDfltColl;
- }
- if( pTerm->idxLeft==iCur
- && (pTerm->prereqRight & loopMask)==pTerm->prereqRight ){
- int iColumn = pX->pLeft->iColumn;
- int k;
- char idxaff = pIdx->pTable->aCol[iColumn].affinity;
- for(k=0; k<pIdx->nColumn; k++){
- /* If the collating sequences or affinities don't match,
- ** ignore this index. */
- if( pColl!=pIdx->keyInfo.aColl[k] ) continue;
- if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue;
- if( pIdx->aiColumn[k]==iColumn ){
- switch( pX->op ){
- case TK_IN: {
- if( k==0 ) inMask |= 1;
- break;
- }
- case TK_EQ: {
- eqMask |= 1<<k;
- break;
- }
- case TK_LE:
- case TK_LT: {
- ltMask |= 1<<k;
- break;
- }
- case TK_GE:
- case TK_GT: {
- gtMask |= 1<<k;
- break;
- }
- default: {
- /* CANT_HAPPEN */
- assert( 0 );
- break;
- }
- }
- break;
- }
- }
- }
- }
-
- /* The following loop ends with nEq set to the number of columns
- ** on the left of the index with == constraints.
- */
- for(nEq=0; nEq<pIdx->nColumn; nEq++){
- m = (1<<(nEq+1))-1;
- if( (m & eqMask)!=m ) break;
- }
- score = nEq*8; /* Base score is 8 times number of == constraints */
- m = 1<<nEq;
- if( m & ltMask ) score++; /* Increase score for a < constraint */
- if( m & gtMask ) score+=2; /* Increase score for a > constraint */
- if( score==0 && inMask ) score = 4; /* Default score for IN constraint */
- if( score>bestScore ){
- pBestIdx = pIdx;
- bestScore = score;
- }
- }
- pLevel->pIdx = pBestIdx;
- pLevel->score = bestScore;
- pLevel->bRev = 0;
- loopMask |= mask;
- if( pBestIdx ){
- pLevel->iCur = pParse->nTab++;
- }
- }
-
- /* Check to see if the ORDER BY clause is or can be satisfied by the
- ** use of an index on the first table.
- */
- if( ppOrderBy && *ppOrderBy && pTabList->nSrc>0 ){
- Index *pSortIdx;
- Index *pIdx;
- Table *pTab;
- int bRev = 0;
-
- pTab = pTabList->a[0].pTab;
- pIdx = pWInfo->a[0].pIdx;
- if( pIdx && pWInfo->a[0].score==4 ){
- /* If there is already an IN index on the left-most table,
- ** it will not give the correct sort order.
- ** So, pretend that no suitable index is found.
- */
- pSortIdx = 0;
- }else if( iDirectEq[0]>=0 || iDirectLt[0]>=0 || iDirectGt[0]>=0 ){
- /* If the left-most column is accessed using its ROWID, then do
- ** not try to sort by index.
- */
- pSortIdx = 0;
- }else{
- int nEqCol = (pWInfo->a[0].score+4)/8;
- pSortIdx = findSortingIndex(pParse, pTab, pTabList->a[0].iCursor,
- *ppOrderBy, pIdx, nEqCol, &bRev);
- }
- if( pSortIdx && (pIdx==0 || pIdx==pSortIdx) ){
- if( pIdx==0 ){
- pWInfo->a[0].pIdx = pSortIdx;
- pWInfo->a[0].iCur = pParse->nTab++;
- }
- pWInfo->a[0].bRev = bRev;
- *ppOrderBy = 0;
- }
- }
-
- /* Open all tables in the pTabList and all indices used by those tables.
- */
- sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
- for(i=0; i<pTabList->nSrc; i++){
- Table *pTab;
- Index *pIx;
-
- pTab = pTabList->a[i].pTab;
- if( pTab->isTransient || pTab->pSelect ) continue;
- sqlite3OpenTableForReading(v, pTabList->a[i].iCursor, pTab);
- sqlite3CodeVerifySchema(pParse, pTab->iDb);
- if( (pIx = pWInfo->a[i].pIdx)!=0 ){
- sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0);
- sqlite3VdbeOp3(v, OP_OpenRead, pWInfo->a[i].iCur, pIx->tnum,
- (char*)&pIx->keyInfo, P3_KEYINFO);
- }
- }
-
- /* Generate the code to do the search
- */
- loopMask = 0;
- for(i=0; i<pTabList->nSrc; i++){
- int j, k;
- int iCur = pTabList->a[i].iCursor;
- Index *pIdx;
- WhereLevel *pLevel = &pWInfo->a[i];
-
- /* If this is the right table of a LEFT OUTER JOIN, allocate and
- ** initialize a memory cell that records if this table matches any
- ** row of the left table of the join.
- */
- if( i>0 && (pTabList->a[i-1].jointype & JT_LEFT)!=0 ){
- if( !pParse->nMem ) pParse->nMem++;
- pLevel->iLeftJoin = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
- VdbeComment((v, "# init LEFT JOIN no-match flag"));
- }
-
- pIdx = pLevel->pIdx;
- pLevel->inOp = OP_Noop;
- if( i<ARRAYSIZE(iDirectEq) && (k = iDirectEq[i])>=0 ){
- /* Case 1: We can directly reference a single row using an
- ** equality comparison against the ROWID field. Or
- ** we reference multiple rows using a "rowid IN (...)"
- ** construct.
- */
- assert( k<nExpr );
- pTerm = &aExpr[k];
- assert( pTerm->p!=0 );
- assert( pTerm->idxLeft==iCur );
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
- codeEqualityTerm(pParse, pTerm, brk, pLevel);
- cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 1, brk);
- haveKey = 0;
- sqlite3VdbeAddOp(v, OP_NotExists, iCur, brk);
- pLevel->op = OP_Noop;
- }else if( pIdx!=0 && pLevel->score>0 && pLevel->score%4==0 ){
- /* Case 2: There is an index and all terms of the WHERE clause that
- ** refer to the index use the "==" or "IN" operators.
- */
- int start;
- int nColumn = (pLevel->score+4)/8;
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
-
- /* For each column of the index, find the term of the WHERE clause that
- ** constraints that column. If the WHERE clause term is X=expr, then
- ** evaluation expr and leave the result on the stack */
- for(j=0; j<nColumn; j++){
- for(pTerm=aExpr, k=0; k<nExpr; k++, pTerm++){
- Expr *pX = pTerm->p;
- if( pX==0 ) continue;
- if( pTerm->idxLeft==iCur
- && (pTerm->prereqRight & loopMask)==pTerm->prereqRight
- && pX->pLeft->iColumn==pIdx->aiColumn[j]
- ){
- char idxaff = pIdx->pTable->aCol[pX->pLeft->iColumn].affinity;
- if( sqlite3IndexAffinityOk(pX, idxaff) ){
- codeEqualityTerm(pParse, pTerm, brk, pLevel);
- break;
- }
- }
- }
- }
- pLevel->iMem = pParse->nMem++;
- cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
- buildIndexProbe(v, nColumn, brk, pIdx);
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
-
- /* Generate code (1) to move to the first matching element of the table.
- ** Then generate code (2) that jumps to "brk" after the cursor is past
- ** the last matching element of the table. The code (1) is executed
- ** once to initialize the search, the code (2) is executed before each
- ** iteration of the scan to see if the scan has finished. */
- if( pLevel->bRev ){
- /* Scan in reverse order */
- sqlite3VdbeAddOp(v, OP_MoveLe, pLevel->iCur, brk);
- start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, OP_IdxLT, pLevel->iCur, brk);
- pLevel->op = OP_Prev;
- }else{
- /* Scan in the forward order */
- sqlite3VdbeAddOp(v, OP_MoveGe, pLevel->iCur, brk);
- start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeOp3(v, OP_IdxGE, pLevel->iCur, brk, "+", P3_STATIC);
- pLevel->op = OP_Next;
- }
- sqlite3VdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
- sqlite3VdbeAddOp(v, OP_IdxIsNull, nColumn, cont);
- sqlite3VdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
- if( i==pTabList->nSrc-1 && pushKey ){
- haveKey = 1;
- }else{
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
- haveKey = 0;
- }
- pLevel->p1 = pLevel->iCur;
- pLevel->p2 = start;
- }else if( i<ARRAYSIZE(iDirectLt) && (iDirectLt[i]>=0 || iDirectGt[i]>=0) ){
- /* Case 3: We have an inequality comparison against the ROWID field.
- */
- int testOp = OP_Noop;
- int start;
-
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
- cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
- if( iDirectGt[i]>=0 ){
- Expr *pX;
- k = iDirectGt[i];
- assert( k<nExpr );
- pTerm = &aExpr[k];
- pX = pTerm->p;
- assert( pX!=0 );
- assert( pTerm->idxLeft==iCur );
- sqlite3ExprCode(pParse, pX->pRight);
- sqlite3VdbeAddOp(v, OP_ForceInt, pX->op==TK_LT || pX->op==TK_GT, brk);
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, brk);
- disableTerm(pLevel, &pTerm->p);
- }else{
- sqlite3VdbeAddOp(v, OP_Rewind, iCur, brk);
- }
- if( iDirectLt[i]>=0 ){
- Expr *pX;
- k = iDirectLt[i];
- assert( k<nExpr );
- pTerm = &aExpr[k];
- pX = pTerm->p;
- assert( pX!=0 );
- assert( pTerm->idxLeft==iCur );
- sqlite3ExprCode(pParse, pX->pRight);
- pLevel->iMem = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
- if( pX->op==TK_LT || pX->op==TK_GT ){
- testOp = OP_Ge;
- }else{
- testOp = OP_Gt;
- }
- disableTerm(pLevel, &pTerm->p);
- }
- start = sqlite3VdbeCurrentAddr(v);
- pLevel->op = OP_Next;
- pLevel->p1 = iCur;
- pLevel->p2 = start;
- if( testOp!=OP_Noop ){
- sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
- sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, testOp, 0, brk);
- }
- haveKey = 0;
- }else if( pIdx==0 ){
- /* Case 4: There is no usable index. We must do a complete
- ** scan of the entire database table.
- */
- int start;
-
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
- cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_Rewind, iCur, brk);
- start = sqlite3VdbeCurrentAddr(v);
- pLevel->op = OP_Next;
- pLevel->p1 = iCur;
- pLevel->p2 = start;
- haveKey = 0;
- }else{
- /* Case 5: The WHERE clause term that refers to the right-most
- ** column of the index is an inequality. For example, if
- ** the index is on (x,y,z) and the WHERE clause is of the
- ** form "x=5 AND y<10" then this case is used. Only the
- ** right-most column can be an inequality - the rest must
- ** use the "==" operator.
- **
- ** This case is also used when there are no WHERE clause
- ** constraints but an index is selected anyway, in order
- ** to force the output order to conform to an ORDER BY.
- */
- int score = pLevel->score;
- int nEqColumn = score/8;
- int start;
- int leFlag=0, geFlag=0;
- int testOp;
-
- /* Evaluate the equality constraints
- */
- for(j=0; j<nEqColumn; j++){
- int iIdxCol = pIdx->aiColumn[j];
- for(pTerm=aExpr, k=0; k<nExpr; k++, pTerm++){
- Expr *pX = pTerm->p;
- if( pX==0 ) continue;
- if( pTerm->idxLeft==iCur
- && pX->op==TK_EQ
- && (pTerm->prereqRight & loopMask)==pTerm->prereqRight
- && pX->pLeft->iColumn==iIdxCol
- ){
- sqlite3ExprCode(pParse, pX->pRight);
- disableTerm(pLevel, &pTerm->p);
- break;
- }
- }
- }
-
- /* Duplicate the equality term values because they will all be
- ** used twice: once to make the termination key and once to make the
- ** start key.
- */
- for(j=0; j<nEqColumn; j++){
- sqlite3VdbeAddOp(v, OP_Dup, nEqColumn-1, 0);
- }
-
- /* Labels for the beginning and end of the loop
- */
- cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
-
- /* Generate the termination key. This is the key value that
- ** will end the search. There is no termination key if there
- ** are no equality terms and no "X<..." term.
- **
- ** 2002-Dec-04: On a reverse-order scan, the so-called "termination"
- ** key computed here really ends up being the start key.
- */
- if( (score & 1)!=0 ){
- for(pTerm=aExpr, k=0; k<nExpr; k++, pTerm++){
- Expr *pX = pTerm->p;
- if( pX==0 ) continue;
- if( pTerm->idxLeft==iCur
- && (pX->op==TK_LT || pX->op==TK_LE)
- && (pTerm->prereqRight & loopMask)==pTerm->prereqRight
- && pX->pLeft->iColumn==pIdx->aiColumn[j]
- ){
- sqlite3ExprCode(pParse, pX->pRight);
- leFlag = pX->op==TK_LE;
- disableTerm(pLevel, &pTerm->p);
- break;
- }
- }
- testOp = OP_IdxGE;
- }else{
- testOp = nEqColumn>0 ? OP_IdxGE : OP_Noop;
- leFlag = 1;
- }
- if( testOp!=OP_Noop ){
- int nCol = nEqColumn + (score & 1);
- pLevel->iMem = pParse->nMem++;
- buildIndexProbe(v, nCol, brk, pIdx);
- if( pLevel->bRev ){
- int op = leFlag ? OP_MoveLe : OP_MoveLt;
- sqlite3VdbeAddOp(v, op, pLevel->iCur, brk);
- }else{
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
- }
- }else if( pLevel->bRev ){
- sqlite3VdbeAddOp(v, OP_Last, pLevel->iCur, brk);
- }
-
- /* Generate the start key. This is the key that defines the lower
- ** bound on the search. There is no start key if there are no
- ** equality terms and if there is no "X>..." term. In
- ** that case, generate a "Rewind" instruction in place of the
- ** start key search.
- **
- ** 2002-Dec-04: In the case of a reverse-order search, the so-called
- ** "start" key really ends up being used as the termination key.
- */
- if( (score & 2)!=0 ){
- for(pTerm=aExpr, k=0; k<nExpr; k++, pTerm++){
- Expr *pX = pTerm->p;
- if( pX==0 ) continue;
- if( pTerm->idxLeft==iCur
- && (pX->op==TK_GT || pX->op==TK_GE)
- && (pTerm->prereqRight & loopMask)==pTerm->prereqRight
- && pX->pLeft->iColumn==pIdx->aiColumn[j]
- ){
- sqlite3ExprCode(pParse, pX->pRight);
- geFlag = pX->op==TK_GE;
- disableTerm(pLevel, &pTerm->p);
- break;
- }
- }
- }else{
- geFlag = 1;
- }
- if( nEqColumn>0 || (score&2)!=0 ){
- int nCol = nEqColumn + ((score&2)!=0);
- buildIndexProbe(v, nCol, brk, pIdx);
- if( pLevel->bRev ){
- pLevel->iMem = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
- testOp = OP_IdxLT;
- }else{
- int op = geFlag ? OP_MoveGe : OP_MoveGt;
- sqlite3VdbeAddOp(v, op, pLevel->iCur, brk);
- }
- }else if( pLevel->bRev ){
- testOp = OP_Noop;
- }else{
- sqlite3VdbeAddOp(v, OP_Rewind, pLevel->iCur, brk);
- }
-
- /* Generate the the top of the loop. If there is a termination
- ** key we have to test for that key and abort at the top of the
- ** loop.
- */
- start = sqlite3VdbeCurrentAddr(v);
- if( testOp!=OP_Noop ){
- sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, testOp, pLevel->iCur, brk);
- if( (leFlag && !pLevel->bRev) || (!geFlag && pLevel->bRev) ){
- sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
- }
- }
- sqlite3VdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
- sqlite3VdbeAddOp(v, OP_IdxIsNull, nEqColumn + (score & 1), cont);
- sqlite3VdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
- if( i==pTabList->nSrc-1 && pushKey ){
- haveKey = 1;
- }else{
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
- haveKey = 0;
- }
-
- /* Record the instruction used to terminate the loop.
- */
- pLevel->op = pLevel->bRev ? OP_Prev : OP_Next;
- pLevel->p1 = pLevel->iCur;
- pLevel->p2 = start;
- }
- loopMask |= getMask(&maskSet, iCur);
-
- /* Insert code to test every subexpression that can be completely
- ** computed using the current set of tables.
- */
- for(pTerm=aExpr, j=0; j<nExpr; j++, pTerm++){
- if( pTerm->p==0 ) continue;
- if( (pTerm->prereqAll & loopMask)!=pTerm->prereqAll ) continue;
- if( pLevel->iLeftJoin && !ExprHasProperty(pTerm->p,EP_FromJoin) ){
- continue;
- }
- if( haveKey ){
- haveKey = 0;
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
- }
- sqlite3ExprIfFalse(pParse, pTerm->p, cont, 1);
- pTerm->p = 0;
- }
- brk = cont;
-
- /* For a LEFT OUTER JOIN, generate code that will record the fact that
- ** at least one row of the right table has matched the left table.
- */
- if( pLevel->iLeftJoin ){
- pLevel->top = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
- VdbeComment((v, "# record LEFT JOIN hit"));
- for(pTerm=aExpr, j=0; j<nExpr; j++, pTerm++){
- if( pTerm->p==0 ) continue;
- if( (pTerm->prereqAll & loopMask)!=pTerm->prereqAll ) continue;
- if( haveKey ){
- /* Cannot happen. "haveKey" can only be true if pushKey is true
- ** an pushKey can only be true for DELETE and UPDATE and there are
- ** no outer joins with DELETE and UPDATE.
- */
- haveKey = 0;
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
- }
- sqlite3ExprIfFalse(pParse, pTerm->p, cont, 1);
- pTerm->p = 0;
- }
- }
- }
- pWInfo->iContinue = cont;
- if( pushKey && !haveKey ){
- sqlite3VdbeAddOp(v, OP_Recno, pTabList->a[0].iCursor, 0);
- }
- freeMaskSet(&maskSet);
- return pWInfo;
-}
-
-/*
-** Generate the end of the WHERE loop. See comments on
-** sqlite3WhereBegin() for additional information.
-*/
-void sqlite3WhereEnd(WhereInfo *pWInfo){
- Vdbe *v = pWInfo->pParse->pVdbe;
- int i;
- WhereLevel *pLevel;
- SrcList *pTabList = pWInfo->pTabList;
-
- for(i=pTabList->nSrc-1; i>=0; i--){
- pLevel = &pWInfo->a[i];
- sqlite3VdbeResolveLabel(v, pLevel->cont);
- if( pLevel->op!=OP_Noop ){
- sqlite3VdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);
- }
- sqlite3VdbeResolveLabel(v, pLevel->brk);
- if( pLevel->inOp!=OP_Noop ){
- sqlite3VdbeAddOp(v, pLevel->inOp, pLevel->inP1, pLevel->inP2);
- }
- if( pLevel->iLeftJoin ){
- int addr;
- addr = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iLeftJoin, 0);
- sqlite3VdbeAddOp(v, OP_NotNull, 1, addr+4 + (pLevel->iCur>=0));
- sqlite3VdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0);
- if( pLevel->iCur>=0 ){
- sqlite3VdbeAddOp(v, OP_NullRow, pLevel->iCur, 0);
- }
- sqlite3VdbeAddOp(v, OP_Goto, 0, pLevel->top);
- }
- }
- sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
- for(i=0; i<pTabList->nSrc; i++){
- Table *pTab = pTabList->a[i].pTab;
- assert( pTab!=0 );
- if( pTab->isTransient || pTab->pSelect ) continue;
- pLevel = &pWInfo->a[i];
- sqlite3VdbeAddOp(v, OP_Close, pTabList->a[i].iCursor, 0);
- if( pLevel->pIdx!=0 ){
- sqlite3VdbeAddOp(v, OP_Close, pLevel->iCur, 0);
- }
- }
- sqliteFree(pWInfo);
- return;
-}
diff --git a/kopete/plugins/statistics/statisticsdb.cpp b/kopete/plugins/statistics/statisticsdb.cpp
index c0a41232..8f25623e 100644
--- a/kopete/plugins/statistics/statisticsdb.cpp
+++ b/kopete/plugins/statistics/statisticsdb.cpp
@@ -16,7 +16,7 @@
#include <tqfile.h>
-#include "sqlite/sqlite3.h"
+#include "sqlite3.h"
#include <kgenericfactory.h>
#include <kaboutdata.h>
diff --git a/kopete/plugins/texteffect/CMakeLists.txt b/kopete/plugins/texteffect/CMakeLists.txt
new file mode 100644
index 00000000..e88a0e34
--- /dev/null
+++ b/kopete/plugins/texteffect/CMakeLists.txt
@@ -0,0 +1,51 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( icons )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_texteffect.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_texteffect_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+
+
+##### kopete_texteffect (module) ################
+
+tde_add_kpart( kopete_texteffect AUTOMOC
+ SOURCES
+ texteffectplugin.cpp texteffectconfig.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_texteffect (module) ############
+
+tde_add_kpart( kcm_kopete_texteffect AUTOMOC
+ SOURCES
+ texteffectconfig.cpp texteffectprefs.ui texteffectpreferences.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/texteffect/icons/CMakeLists.txt b/kopete/plugins/texteffect/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/plugins/texteffect/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/plugins/translator/CMakeLists.txt b/kopete/plugins/translator/CMakeLists.txt
new file mode 100644
index 00000000..5dd274db
--- /dev/null
+++ b/kopete/plugins/translator/CMakeLists.txt
@@ -0,0 +1,51 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_translator.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES kopete_translator_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+install( FILES translatorui.rc translatorchatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_translator )
+
+
+##### kopete_translator (module) ################
+
+tde_add_kpart( kopete_translator AUTOMOC
+ SOURCES
+ translatordialog.cpp translatorguiclient.cpp
+ translatorlanguages.cpp translatorplugin.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_translator (module) ############
+
+tde_add_kpart( kcm_kopete_translator AUTOMOC
+ SOURCES
+ translatorprefsbase.ui translatorprefs.cpp
+ translatorlanguages.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/plugins/translator/translatorguiclient.cpp b/kopete/plugins/translator/translatorguiclient.cpp
index 6af66f37..ef5ac9ac 100644
--- a/kopete/plugins/translator/translatorguiclient.cpp
+++ b/kopete/plugins/translator/translatorguiclient.cpp
@@ -23,7 +23,7 @@
#include <kaction.h>
#include <klocale.h>
-#include "kopetemessagemanager.h"
+#include "kopetechatsession.h"
#include "kopeteview.h"
#include "kopetecontact.h"
#include "kopetemetacontact.h"
diff --git a/kopete/plugins/translator/translatorplugin.cpp b/kopete/plugins/translator/translatorplugin.cpp
index 0767e24e..9bff86f2 100644
--- a/kopete/plugins/translator/translatorplugin.cpp
+++ b/kopete/plugins/translator/translatorplugin.cpp
@@ -35,7 +35,7 @@
#include "kopetemetacontact.h"
#include "kopetecontactlist.h"
-#include "kopetemessagemanagerfactory.h"
+#include "kopetechatsessionmanager.h"
#include "kopetecontact.h"
#include "translatorplugin.h"
diff --git a/kopete/plugins/webpresence/CMakeLists.txt b/kopete/plugins/webpresence/CMakeLists.txt
new file mode 100644
index 00000000..bcba1176
--- /dev/null
+++ b/kopete/plugins/webpresence/CMakeLists.txt
@@ -0,0 +1,59 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES
+ kopete_webpresence.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR} )
+
+install( FILES
+ kopete_webpresence_config.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+
+install( FILES
+ webpresence_html.xsl webpresence_html_images.xsl
+ webpresence_xhtml.xsl webpresence_xhtml_images.xsl
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/webpresence )
+
+
+##### kopete_webpresence (module) ###############
+
+tde_add_kpart( kopete_webpresence AUTOMOC
+ SOURCES
+ webpresenceplugin.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kcm_kopete_webpresence (module) ###########
+
+tde_add_kpart( kcm_kopete_webpresence AUTOMOC
+ SOURCES
+ webpresencepreferences.cpp webpresenceprefs.ui
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/CMakeLists.txt b/kopete/protocols/CMakeLists.txt
new file mode 100644
index 00000000..14127078
--- /dev/null
+++ b/kopete/protocols/CMakeLists.txt
@@ -0,0 +1,22 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_TESTBED testbed )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_GROUPWISE groupwise )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_MSN msn )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_IRC irc )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_OSCAR oscar )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_YAHOO yahoo )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_WINPOPUP winpopup )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_SMS sms )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_JABBER jabber )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_GADU gadu )
+tde_conditional_add_subdirectory( BUILD_KOPETE_PROTOCOL_MEANWHILE meanwhile )
diff --git a/kopete/protocols/gadu/CMakeLists.txt b/kopete/protocols/gadu/CMakeLists.txt
new file mode 100644
index 00000000..bb5326d4
--- /dev/null
+++ b/kopete/protocols/gadu/CMakeLists.txt
@@ -0,0 +1,50 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include( ConfigureChecks.cmake )
+
+add_subdirectory( ui )
+add_subdirectory( icons )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+ ${GADU_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_gadu.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kopete_gadu (module) ######################
+
+tde_add_kpart( kopete_gadu AUTOMOC
+ SOURCES
+ gaduaway.cpp gadueditcontact.cpp gaducommands.cpp
+ gadueditaccount.cpp gadusession.cpp gaducontact.cpp
+ gaduaddcontactpage.cpp gaduprotocol.cpp gaduaccount.cpp
+ gadupubdir.cpp gaduregisteraccount.cpp gaducontactlist.cpp
+ gadurichtextformat.cpp gadudccserver.cpp gadudcctransaction.cpp
+ gadudcc.cpp
+ LINK gaduui-static kopete-shared ${GADU_LIBRARIES}
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/gadu/ConfigureChecks.cmake b/kopete/protocols/gadu/ConfigureChecks.cmake
new file mode 100644
index 00000000..1511e879
--- /dev/null
+++ b/kopete/protocols/gadu/ConfigureChecks.cmake
@@ -0,0 +1,15 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+pkg_search_module( GADU libgadu )
+if( NOT GADU_FOUND )
+ tde_message_fatal( "libgadu is required, but was not found on your system" )
+endif( )
diff --git a/kopete/protocols/gadu/gadueditcontact.h b/kopete/protocols/gadu/gadueditcontact.h
index e9413a2b..f135d55a 100644
--- a/kopete/protocols/gadu/gadueditcontact.h
+++ b/kopete/protocols/gadu/gadueditcontact.h
@@ -31,7 +31,6 @@ class TQLabel;
class TQString;
class TQWidget;
class GaduContact;
-class GaduContactsList::ContactLine;
class TQListViewItem;
class GaduEditContact : public KDialogBase
diff --git a/kopete/protocols/gadu/icons/CMakeLists.txt b/kopete/protocols/gadu/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/protocols/gadu/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/protocols/gadu/libgadu/COPYING b/kopete/protocols/gadu/libgadu/COPYING
deleted file mode 100644
index 071eee49..00000000
--- a/kopete/protocols/gadu/libgadu/COPYING
+++ /dev/null
@@ -1,504 +0,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL. It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it. You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
- When we speak of free software, we are referring to freedom of use,
-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 this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
- To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights. These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
- To protect each distributor, we want to make it very clear that
-there is no warranty for the free library. Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-
- Finally, software patents pose a constant threat to the existence of
-any free program. We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder. Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
- Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License. This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License. We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
- When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library. The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom. The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
- We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License. It also provides other free software developers Less
-of an advantage over competing non-free programs. These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries. However, the Lesser license provides advantages in certain
-special circumstances.
-
- For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard. To achieve this, non-free programs must be
-allowed to use the library. A more frequent case is that a free
-library does the same job as widely used non-free libraries. In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
- In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software. For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
- Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-
- GNU LESSER GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
- 6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (1) uses at run time a
- copy of the library already present on the user's computer system,
- rather than copying library functions into the executable, and (2)
- will operate properly with a modified version of the library, if
- the user installs one, as long as the modified version is
- interface-compatible with the version that the work was made with.
-
- c) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- d) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- e) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-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
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser 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 Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "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
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY 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
-LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
-
-
diff --git a/kopete/protocols/gadu/libgadu/Makefile.am b/kopete/protocols/gadu/libgadu/Makefile.am
deleted file mode 100644
index 94693d38..00000000
--- a/kopete/protocols/gadu/libgadu/Makefile.am
+++ /dev/null
@@ -1,12 +0,0 @@
-METASOURCES = AUTO
-noinst_LTLIBRARIES = libgadu_copy.la
-INCLUDES = $(SSL_INCLUDES) $(all_includes)
-libgadu_copy_la_LDFLAGS = $(SSL_LDFLAGS) $(all_libraries)
-libgadu_copy_la_LIBADD = $(LIBSSL) $(LIBPTHREAD)
-libgadu_copy_la_SOURCES = common.c \
- dcc.c \
- events.c \
- http.c \
- libgadu.c \
- pubdir50.c \
- pubdir.c
diff --git a/kopete/protocols/gadu/libgadu/common.c b/kopete/protocols/gadu/libgadu/common.c
deleted file mode 100644
index 9e20422a..00000000
--- a/kopete/protocols/gadu/libgadu/common.c
+++ /dev/null
@@ -1,827 +0,0 @@
-/* $Id$ */
-
-/*
- * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
- * Robert J. Wo�ny <speedy@ziew.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License Version
- * 2.1 as published by the Free Software Foundation.
- *
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifdef sun
-# include <sys/filio.h>
-#endif
-
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "libgadu.h"
-
-FILE *gg_debug_file = NULL;
-
-#ifndef GG_DEBUG_DISABLE
-
-/*
- * gg_debug() // funkcja wewn�trzna
- *
- * wy�wietla komunikat o danym poziomie, o ile u�ytkownik sobie tego �yczy.
- *
- * - level - poziom wiadomo�ci
- * - format... - tre�� wiadomo�ci (kompatybilna z printf())
- */
-void gg_debug(int level, const char *format, ...)
-{
- va_list ap;
- int old_errno = errno;
-
- if (gg_debug_handler) {
- va_start(ap, format);
- (*gg_debug_handler)(level, format, ap);
- va_end(ap);
-
- goto cleanup;
- }
-
- if ((gg_debug_level & level)) {
- va_start(ap, format);
- vfprintf((gg_debug_file) ? gg_debug_file : stderr, format, ap);
- va_end(ap);
- }
-
-cleanup:
- errno = old_errno;
-}
-
-#endif
-
-/*
- * gg_vsaprintf() // funkcja pomocnicza
- *
- * robi dok�adnie to samo, co vsprintf(), tyle �e alokuje sobie wcze�niej
- * miejsce na dane. powinno dzia�a� na tych maszynach, kt�re maj� funkcj�
- * vsnprintf() zgodn� z C99, jak i na wcze�niejszych.
- *
- * - format - opis wy�wietlanego tekstu jak dla printf()
- * - ap - lista argument�w dla printf()
- *
- * zaalokowany bufor, kt�ry nale�y p��niej zwolni�, lub NULL
- * je�li nie uda�o si� wykona� zadania.
- */
-char *gg_vsaprintf(const char *format, va_list ap)
-{
- int size = 0;
- const char *start;
- char *buf = NULL;
-
-#ifdef __GG_LIBGADU_HAVE_VA_COPY
- va_list aq;
-
- va_copy(aq, ap);
-#else
-# ifdef __GG_LIBGADU_HAVE___VA_COPY
- va_list aq;
-
- __va_copy(aq, ap);
-# endif
-#endif
-
- start = format;
-
-#ifndef __GG_LIBGADU_HAVE_C99_VSNPRINTF
- {
- int res;
- char *tmp;
-
- size = 128;
- do {
- size *= 2;
- if (!(tmp = realloc(buf, size))) {
- free(buf);
- return NULL;
- }
- buf = tmp;
- res = vsnprintf(buf, size, format, ap);
- } while (res == size - 1 || res == -1);
- }
-#else
- {
- char tmp[2];
-
- /* libce Solarisa przy buforze NULL zawsze zwracaj� -1, wi�c
- * musimy poda� co� istniej�cego jako cel printf()owania. */
- size = vsnprintf(tmp, sizeof(tmp), format, ap);
- if (!(buf = malloc(size + 1)))
- return NULL;
- }
-#endif
-
- format = start;
-
-#ifdef __GG_LIBGADU_HAVE_VA_COPY
- vsnprintf(buf, size + 1, format, aq);
- va_end(aq);
-#else
-# ifdef __GG_LIBGADU_HAVE___VA_COPY
- vsnprintf(buf, size + 1, format, aq);
- va_end(aq);
-# else
- vsnprintf(buf, size + 1, format, ap);
-# endif
-#endif
-
- return buf;
-}
-
-/*
- * gg_saprintf() // funkcja pomocnicza
- *
- * robi dok�adnie to samo, co sprintf(), tyle �e alokuje sobie wcze�niej
- * miejsce na dane. powinno dzia�a� na tych maszynach, kt�re maj� funkcj�
- * vsnprintf() zgodn� z C99, jak i na wcze�niejszych.
- *
- * - format... - tre�� taka sama jak w funkcji printf()
- *
- * zaalokowany bufor, kt�ry nale�y p��niej zwolni�, lub NULL
- * je�li nie uda�o si� wykona� zadania.
- */
-char *gg_saprintf(const char *format, ...)
-{
- va_list ap;
- char *res;
-
- va_start(ap, format);
- res = gg_vsaprintf(format, ap);
- va_end(ap);
-
- return res;
-}
-
-/*
- * gg_get_line() // funkcja pomocnicza
- *
- * podaje kolejn� lini� z bufora tekstowego. niszczy go bezpowrotnie, dziel�c
- * na kolejne stringi. zdarza si�, nie ma potrzeby pisania funkcji dubluj�cej
- * bufor �eby tylko mie� nieruszone dane wej�ciowe, skoro i tak nie b�d� nam
- * po�niej potrzebne. obcina `\r\n'.
- *
- * - ptr - wska�nik do zmiennej, kt�ra przechowuje aktualn� pozycj�
- * w przemiatanym buforze
- *
- * wska�nik do kolejnej linii tekstu lub NULL, je�li to ju� koniec bufora.
- */
-char *gg_get_line(char **ptr)
-{
- const char *foo;
- char *res;
-
- if (!ptr || !*ptr || !strcmp(*ptr, ""))
- return NULL;
-
- res = *ptr;
-
- if (!(foo = strchr(*ptr, '\n')))
- *ptr += strlen(*ptr);
- else {
- *ptr = foo + 1;
- if (strlen(res) > 1 && res[strlen(res) - 1] == '\r')
- res[strlen(res) - 1] = 0;
- }
-
- return res;
-}
-
-/*
- * gg_connect() // funkcja pomocnicza
- *
- * ��czy si� z serwerem. pierwszy argument jest typu (void *), �eby nie
- * musie� niczego inkludowa� w libgadu.h i nie psu� jaki� g�upich zale�no�ci
- * na dziwnych systemach.
- *
- * - addr - adres serwera (struct in_addr *)
- * - port - port serwera
- * - async - asynchroniczne po��czenie
- *
- * deskryptor gniazda lub -1 w przypadku b��du (kod b��du w zmiennej errno).
- */
-int gg_connect(void *addr, int port, int async)
-{
- int sock, one = 1, errno2;
- struct sockaddr_in sin;
- struct in_addr *a = addr;
- struct sockaddr_in myaddr;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async);
-
- if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_connect() socket() failed (errno=%d, %s)\n", errno, strerror(errno));
- return -1;
- }
-
- memset(&myaddr, 0, sizeof(myaddr));
- myaddr.sin_family = AF_INET;
-
- myaddr.sin_addr.s_addr = gg_local_ip;
-
- if (bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed (errno=%d, %s)\n", errno, strerror(errno));
- return -1;
- }
-
-#ifdef ASSIGN_SOCKETS_TO_THREADS
- gg_win32_thread_socket(0, sock);
-#endif
-
- if (async) {
-#ifdef FIONBIO
- if (ioctl(sock, FIONBIO, &one) == -1) {
-#else
- if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
-#endif
- gg_debug(GG_DEBUG_MISC, "// gg_connect() ioctl() failed (errno=%d, %s)\n", errno, strerror(errno));
- errno2 = errno;
- close(sock);
- errno = errno2;
- return -1;
- }
- }
-
- sin.sin_port = htons(port);
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = a->s_addr;
-
- if (connect(sock, (struct sockaddr*) &sin, sizeof(sin)) == -1) {
- if (errno && (!async || errno != EINPROGRESS)) {
- gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() failed (errno=%d, %s)\n", errno, strerror(errno));
- errno2 = errno;
- close(sock);
- errno = errno2;
- return -1;
- }
- gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() in progress\n");
- }
-
- return sock;
-}
-
-/*
- * gg_read_line() // funkcja pomocnicza
- *
- * czyta jedn� lini� tekstu z gniazda.
- *
- * - sock - deskryptor gniazda
- * - buf - wska�nik do bufora
- * - length - d�ugo�� bufora
- *
- * je�li trafi na b��d odczytu lub podano nieprawid�owe parametry, zwraca NULL.
- * inaczej zwraca buf.
- */
-char *gg_read_line(int sock, char *buf, int length)
-{
- int ret;
-
- if (!buf || length < 0)
- return NULL;
-
- for (; length > 1; buf++, length--) {
- do {
- if ((ret = read(sock, buf, 1)) == -1 && errno != EINTR) {
- gg_debug(GG_DEBUG_MISC, "// gg_read_line() error on read (errno=%d, %s)\n", errno, strerror(errno));
- *buf = 0;
- return NULL;
- } else if (ret == 0) {
- gg_debug(GG_DEBUG_MISC, "// gg_read_line() eof reached\n");
- *buf = 0;
- return NULL;
- }
- } while (ret == -1 && errno == EINTR);
-
- if (*buf == '\n') {
- buf++;
- break;
- }
- }
-
- *buf = 0;
- return buf;
-}
-
-/*
- * gg_chomp() // funkcja pomocnicza
- *
- * ucina "\r\n" lub "\n" z ko�ca linii.
- *
- * - line - linia do przyci�cia
- */
-void gg_chomp(char *line)
-{
- int len;
-
- if (!line)
- return;
-
- len = strlen(line);
-
- if (len > 0 && line[len - 1] == '\n')
- line[--len] = 0;
- if (len > 0 && line[len - 1] == '\r')
- line[--len] = 0;
-}
-
-/*
- * gg_urlencode() // funkcja wewn�trzna
- *
- * zamienia podany tekst na ci�g znak�w do formularza http. przydaje si�
- * przy r��nych us�ugach katalogu publicznego.
- *
- * - str - ci�g znak�w do zakodowania
- *
- * zaalokowany bufor, kt�ry nale�y p��niej zwolni� albo NULL
- * w przypadku b��du.
- */
-char *gg_urlencode(const char *str)
-{
- char *q, *buf, hex[] = "0123456789abcdef";
- const char *p;
- unsigned int size = 0;
-
- if (!str)
- str = "";
-
- for (p = str; *p; p++, size++) {
- if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == ' ') || (*p == '@') || (*p == '.') || (*p == '-'))
- size += 2;
- }
-
- if (!(buf = malloc(size + 1)))
- return NULL;
-
- for (p = str, q = buf; *p; p++, q++) {
- if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || (*p == '@') || (*p == '.') || (*p == '-'))
- *q = *p;
- else {
- if (*p == ' ')
- *q = '+';
- else {
- *q++ = '%';
- *q++ = hex[*p >> 4 & 15];
- *q = hex[*p & 15];
- }
- }
- }
-
- *q = 0;
-
- return buf;
-}
-
-/*
- * gg_http_hash() // funkcja wewn�trzna
- *
- * funkcja licz�ca hash dla adresu e-mail, has�a i paru innych.
- *
- * - format... - format kolejnych parametr�w ('s' je�li dany parametr jest
- * ci�giem znak�w lub 'u' je�li numerem GG)
- *
- * hash wykorzystywany przy rejestracji i wszelkich manipulacjach w�asnego
- * wpisu w katalogu publicznym.
- */
-int gg_http_hash(const char *format, ...)
-{
- unsigned int a, c, i, j;
- va_list ap;
- int b = -1;
-
- va_start(ap, format);
-
- for (j = 0; j < strlen(format); j++) {
- char *arg, buf[16];
-
- if (format[j] == 'u') {
- snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t));
- arg = buf;
- } else {
- if (!(arg = va_arg(ap, char*)))
- arg = "";
- }
-
- i = 0;
- while ((c = (unsigned char) arg[i++]) != 0) {
- a = (c ^ b) + (c << 8);
- b = (a >> 24) | (a << 8);
- }
- }
-
- va_end(ap);
-
- return (b < 0 ? -b : b);
-}
-
-/*
- * gg_gethostbyname() // funkcja pomocnicza
- *
- * odpowiednik gethostbyname() troszcz�cy si� o wsp��bie�no��, gdy mamy do
- * dyspozycji funkcj� gethostbyname_r().
- *
- * - hostname - nazwa serwera
- *
- * zwraca wska�nik na struktur� in_addr, kt�r� nale�y zwolni�.
- */
-struct in_addr *gg_gethostbyname(const char *hostname)
-{
- struct in_addr *addr = NULL;
-
-#ifdef HAVE_GETHOSTBYNAME_R
- char *tmpbuf = NULL, *buf = NULL;
- struct hostent *hp = NULL, *hp2 = NULL;
- int h_errnop, ret;
- size_t buflen = 1024;
- int new_errno;
-
- new_errno = ENOMEM;
-
- if (!(addr = malloc(sizeof(struct in_addr))))
- goto cleanup;
-
- if (!(hp = calloc(1, sizeof(*hp))))
- goto cleanup;
-
- if (!(buf = malloc(buflen)))
- goto cleanup;
-
- tmpbuf = buf;
-
- while ((ret = gethostbyname_r(hostname, hp, buf, buflen, &hp2, &h_errnop)) == ERANGE) {
- buflen *= 2;
-
- if (!(tmpbuf = realloc(buf, buflen)))
- break;
-
- buf = tmpbuf;
- }
-
- if (ret)
- new_errno = h_errnop;
-
- if (ret || !hp2 || !tmpbuf)
- goto cleanup;
-
- memcpy(addr, hp->h_addr, sizeof(struct in_addr));
-
- free(buf);
- free(hp);
-
- return addr;
-
-cleanup:
- errno = new_errno;
-
- if (addr)
- free(addr);
- if (hp)
- free(hp);
- if (buf)
- free(buf);
-
- return NULL;
-#else
- struct hostent *hp;
-
- if (!(addr = malloc(sizeof(struct in_addr)))) {
- goto cleanup;
- }
-
- if (!(hp = gethostbyname(hostname)))
- goto cleanup;
-
- memcpy(addr, hp->h_addr, sizeof(struct in_addr));
-
- return addr;
-
-cleanup:
- if (addr)
- free(addr);
-
- return NULL;
-#endif
-}
-
-#ifdef ASSIGN_SOCKETS_TO_THREADS
-
-typedef struct gg_win32_thread {
- int id;
- int socket;
- struct gg_win32_thread *next;
-} gg_win32_thread;
-
-struct gg_win32_thread *gg_win32_threads = 0;
-
-/*
- * gg_win32_thread_socket() // funkcja pomocnicza, tylko dla win32
- *
- * zwraca deskryptor gniazda, kt�re by�o ostatnio tworzone dla w�tku
- * o podanym identyfikatorze.
- *
- * je�li na win32 przy po��czeniach synchronicznych zapami�tamy w jakim
- * w�tku uruchomili�my funkcj�, kt�ra si� z czymkolwiek ��czy, to z osobnego
- * w�tku mo�emy anulowa� po��czenie poprzez gg_win32_thread_socket(watek, -1);
- *
- * - thread_id - id w�tku. je�li jest r�wne 0, brany jest aktualny w�tek,
- * je�li r�wne -1, usuwa wpis o podanym sockecie.
- * - socket - deskryptor gniazda. je�li r�wne 0, zwraca deskryptor gniazda
- * dla podanego w�tku, je�li r�wne -1, usuwa wpis, je�li co�
- * innego, ustawia dla podanego w�tku dany numer deskryptora.
- *
- * je�li socket jest r�wne 0, zwraca deskryptor gniazda dla podanego w�tku.
- */
-int gg_win32_thread_socket(int thread_id, int socket)
-{
- char close = (thread_id == -1) || socket == -1;
- gg_win32_thread *wsk = gg_win32_threads;
- gg_win32_thread **p_wsk = &gg_win32_threads;
-
- if (!thread_id)
- thread_id = GetCurrentThreadId();
-
- while (wsk) {
- if ((thread_id == -1 && wsk->socket == socket) || wsk->id == thread_id) {
- if (close) {
- /* socket zostaje usuniety */
- closesocket(wsk->socket);
- *p_wsk = wsk->next;
- free(wsk);
- return 1;
- } else if (!socket) {
- /* socket zostaje zwrocony */
- return wsk->socket;
- } else {
- /* socket zostaje ustawiony */
- wsk->socket = socket;
- return socket;
- }
- }
- p_wsk = &(wsk->next);
- wsk = wsk->next;
- }
-
- if (close && socket != -1)
- closesocket(socket);
- if (close || !socket)
- return 0;
-
- /* Dodaje nowy element */
- wsk = malloc(sizeof(gg_win32_thread));
- wsk->id = thread_id;
- wsk->socket = socket;
- wsk->next = 0;
- *p_wsk = wsk;
-
- return socket;
-}
-
-#endif /* ASSIGN_SOCKETS_TO_THREADS */
-
-static char gg_base64_charset[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-/*
- * gg_base64_encode()
- *
- * zapisuje ci�g znak�w w base64.
- *
- * - buf - ci�g znak�w.
- *
- * zaalokowany bufor.
- */
-char *gg_base64_encode(const char *buf)
-{
- char *out, *res;
- unsigned int i = 0, j = 0, k = 0, len = strlen(buf);
-
- res = out = malloc((len / 3 + 1) * 4 + 2);
-
- if (!res)
- return NULL;
-
- while (j <= len) {
- switch (i % 4) {
- case 0:
- k = (buf[j] & 252) >> 2;
- break;
- case 1:
- if (j < len)
- k = ((buf[j] & 3) << 4) | ((buf[j + 1] & 240) >> 4);
- else
- k = (buf[j] & 3) << 4;
-
- j++;
- break;
- case 2:
- if (j < len)
- k = ((buf[j] & 15) << 2) | ((buf[j + 1] & 192) >> 6);
- else
- k = (buf[j] & 15) << 2;
-
- j++;
- break;
- case 3:
- k = buf[j++] & 63;
- break;
- }
- *out++ = gg_base64_charset[k];
- i++;
- }
-
- if (i % 4)
- for (j = 0; j < 4 - (i % 4); j++, out++)
- *out = '=';
-
- *out = 0;
-
- return res;
-}
-
-/*
- * gg_base64_decode()
- *
- * dekoduje ci�g znak�w z base64.
- *
- * - buf - ci�g znak�w.
- *
- * zaalokowany bufor.
- */
-char *gg_base64_decode(const char *buf)
-{
- const char *foo2;
- char *res, *save, *foo, val;
- const char *end;
- unsigned int index = 0;
-
- if (!buf)
- return NULL;
-
- save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2);
-
- if (!save)
- return NULL;
-
- end = buf + strlen(buf);
-
- while (*buf && buf < end) {
- if (*buf == '\r' || *buf == '\n') {
- buf++;
- continue;
- }
- if (!(foo2 = strchr(gg_base64_charset, *buf))) {
- foo = gg_base64_charset;
- }
- else {
- foo = foo2;
- }
- val = (int)(foo - gg_base64_charset);
- buf++;
- switch (index) {
- case 0:
- *res |= val << 2;
- break;
- case 1:
- *res++ |= val >> 4;
- *res |= val << 4;
- break;
- case 2:
- *res++ |= val >> 2;
- *res |= val << 6;
- break;
- case 3:
- *res++ |= val;
- break;
- }
- index++;
- index %= 4;
- }
- *res = 0;
-
- return save;
-}
-
-/*
- * gg_proxy_auth() // funkcja wewn�trzna
- *
- * tworzy nag��wek autoryzacji dla proxy.
- *
- * zaalokowany tekst lub NULL, je�li proxy nie jest w��czone lub nie wymaga
- * autoryzacji.
- */
-char *gg_proxy_auth()
-{
- char *tmp, *enc, *out;
- unsigned int tmp_size;
-
- if (!gg_proxy_enabled || !gg_proxy_username || !gg_proxy_password)
- return NULL;
-
- if (!(tmp = malloc((tmp_size = strlen(gg_proxy_username) + strlen(gg_proxy_password) + 2))))
- return NULL;
-
- snprintf(tmp, tmp_size, "%s:%s", gg_proxy_username, gg_proxy_password);
-
- if (!(enc = gg_base64_encode(tmp))) {
- free(tmp);
- return NULL;
- }
-
- free(tmp);
-
- if (!(out = malloc(strlen(enc) + 40))) {
- free(enc);
- return NULL;
- }
-
- snprintf(out, strlen(enc) + 40, "Proxy-Authorization: Basic %s\r\n", enc);
-
- free(enc);
-
- return out;
-}
-
-static uint32_t gg_crc32_table[256];
-static int gg_crc32_initialized = 0;
-
-/*
- * gg_crc32_make_table() // funkcja wewn�trzna
- */
-static void gg_crc32_make_table()
-{
- uint32_t h = 1;
- unsigned int i, j;
-
- memset(gg_crc32_table, 0, sizeof(gg_crc32_table));
-
- for (i = 128; i; i >>= 1) {
- h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
-
- for (j = 0; j < 256; j += 2 * i)
- gg_crc32_table[i + j] = gg_crc32_table[j] ^ h;
- }
-
- gg_crc32_initialized = 1;
-}
-
-/*
- * gg_crc32()
- *
- * wyznacza sum� kontroln� CRC32 danego bloku danych.
- *
- * - crc - suma kontrola poprzedniego bloku danych lub 0 je�li pierwszy
- * - buf - bufor danych
- * - size - ilo�� danych
- *
- * suma kontrolna CRC32.
- */
-uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len)
-{
- if (!gg_crc32_initialized)
- gg_crc32_make_table();
-
- if (!buf || len < 0)
- return crc;
-
- crc ^= 0xffffffffL;
-
- while (len--)
- crc = (crc >> 8) ^ gg_crc32_table[(crc ^ *buf++) & 0xff];
-
- return crc ^ 0xffffffffL;
-}
-
-
-/*
- * Local variables:
- * c-indentation-style: k&r
- * c-basic-offset: 8
- * indent-tabs-mode: notnil
- * End:
- *
- * vim: shiftwidth=8:
- */
diff --git a/kopete/protocols/gadu/libgadu/compat.h b/kopete/protocols/gadu/libgadu/compat.h
deleted file mode 100644
index 8b9098fe..00000000
--- a/kopete/protocols/gadu/libgadu/compat.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* $Id$ */
-
-/*
- * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
- * Robert J. Wo¼ny <speedy@ziew.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License Version
- * 2.1 as published by the Free Software Foundation.
- *
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#ifndef __COMPAT_H
-#define __COMPAT_H
-
-#ifdef sun
-# define INADDR_NONE ((in_addr_t) 0xffffffff)
-#endif
-
-#endif
diff --git a/kopete/protocols/gadu/libgadu/dcc.c b/kopete/protocols/gadu/libgadu/dcc.c
deleted file mode 100644
index d6b3c7cc..00000000
--- a/kopete/protocols/gadu/libgadu/dcc.c
+++ /dev/null
@@ -1,1298 +0,0 @@
-/* $Id$ */
-
-/*
- * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl>
- * Tomasz Chiliñski <chilek@chilan.com>
- * Adam Wysocki <gophi@ekg.chmurka.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License Version
- * 2.1 as published by the Free Software Foundation.
- *
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifdef sun
-# include <sys/filio.h>
-#endif
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "compat.h"
-#include "libgadu.h"
-
-#ifndef GG_DEBUG_DISABLE
-/*
- * gg_dcc_debug_data() // funkcja wewnêtrzna
- *
- * wy¶wietla zrzut pakietu w hexie.
- *
- * - prefix - prefiks zrzutu pakietu
- * - fd - deskryptor gniazda
- * - buf - bufor z danymi
- * - size - rozmiar danych
- */
-static void gg_dcc_debug_data(const char *prefix, int fd, const void *buf, unsigned int size)
-{
- unsigned int i;
-
- gg_debug(GG_DEBUG_MISC, "++ gg_dcc %s (fd=%d,len=%d)", prefix, fd, size);
-
- for (i = 0; i < size; i++)
- gg_debug(GG_DEBUG_MISC, " %.2x", ((unsigned char*) buf)[i]);
-
- gg_debug(GG_DEBUG_MISC, "\n");
-}
-#else
-#define gg_dcc_debug_data(a,b,c,d) do { } while (0)
-#endif
-
-/*
- * gg_dcc_request()
- *
- * wysy³a informacjê o tym, ¿e dany klient powinien siê z nami po³±czyæ.
- * wykorzystywane, kiedy druga strona, której chcemy co¶ wys³aæ jest za
- * maskarad±.
- *
- * - sess - struktura opisuj±ca sesjê GG
- * - uin - numerek odbiorcy
- *
- * patrz gg_send_message_ctcp().
- */
-int gg_dcc_request(struct gg_session *sess, uin_t uin)
-{
- return gg_send_message_ctcp(sess, GG_CLASS_CTCP, uin, "\002", 1);
-}
-
-/*
- * gg_dcc_fill_filetime() // funkcja wewnêtrzna
- *
- * zamienia czas w postaci unixowej na windowsowy.
- *
- * - unix - czas w postaci unixowej
- * - filetime - czas w postaci windowsowej
- */
-static void gg_dcc_fill_filetime(uint32_t ut, uint32_t *ft)
-{
-#ifdef __GG_LIBGADU_HAVE_LONG_LONG
- unsigned long long tmp;
-
- tmp = ut;
- tmp += 11644473600LL;
- tmp *= 10000000LL;
-
-#ifndef __GG_LIBGADU_BIGENDIAN
- ft[0] = (uint32_t) tmp;
- ft[1] = (uint32_t) (tmp >> 32);
-#else
- ft[0] = gg_fix32((uint32_t) (tmp >> 32));
- ft[1] = gg_fix32((uint32_t) tmp);
-#endif
-
-#endif
-}
-
-/*
- * gg_dcc_fill_file_info()
- *
- * wype³nia pola struct gg_dcc niezbêdne do wys³ania pliku.
- *
- * - d - struktura opisuj±ca po³±czenie DCC
- * - filename - nazwa pliku
- *
- * 0, -1.
- */
-int gg_dcc_fill_file_info(struct gg_dcc *d, const char *filename)
-{
- return gg_dcc_fill_file_info2(d, filename, filename);
-}
-
-/*
- * gg_dcc_fill_file_info2()
- *
- * wype³nia pola struct gg_dcc niezbêdne do wys³ania pliku.
- *
- * - d - struktura opisuj±ca po³±czenie DCC
- * - filename - nazwa pliku
- * - local_filename - nazwa na lokalnym systemie plików
- *
- * 0, -1.
- */
-int gg_dcc_fill_file_info2(struct gg_dcc *d, const char *filename, const char *local_filename)
-{
- struct stat st;
- const char *name, *ext, *p;
- unsigned char *q;
- int i, j;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_fill_file_info2(%p, \"%s\", \"%s\");\n", d, filename, local_filename);
-
- if (!d || d->type != GG_SESSION_DCC_SEND) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() invalid arguments\n");
- errno = EINVAL;
- return -1;
- }
-
- if (stat(local_filename, &st) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() stat() failed (%s)\n", strerror(errno));
- return -1;
- }
-
- if ((st.st_mode & S_IFDIR)) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() that's a directory\n");
- errno = EINVAL;
- return -1;
- }
-
- if ((d->file_fd = open(local_filename, O_RDONLY)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() open() failed (%s)\n", strerror(errno));
- return -1;
- }
-
- memset(&d->file_info, 0, sizeof(d->file_info));
-
- if (!(st.st_mode & S_IWUSR))
- d->file_info.mode |= gg_fix32(GG_DCC_FILEATTR_READONLY);
-
- gg_dcc_fill_filetime(st.st_atime, d->file_info.atime);
- gg_dcc_fill_filetime(st.st_mtime, d->file_info.mtime);
- gg_dcc_fill_filetime(st.st_ctime, d->file_info.ctime);
-
- d->file_info.size = gg_fix32(st.st_size);
- d->file_info.mode = gg_fix32(0x20); /* FILE_ATTRIBUTE_ARCHIVE */
-
- if (!(name = strrchr(filename, '/')))
- name = filename;
- else
- name++;
-
- if (!(ext = strrchr(name, '.')))
- ext = name + strlen(name);
-
- for (i = 0, p = name; i < 8 && p < ext; i++, p++)
- d->file_info.short_filename[i] = toupper(name[i]);
-
- if (i == 8 && p < ext) {
- d->file_info.short_filename[6] = '~';
- d->file_info.short_filename[7] = '1';
- }
-
- if (strlen(ext) > 0) {
- for (j = 0; *ext && j < 4; j++, p++)
- d->file_info.short_filename[i + j] = toupper(ext[j]);
- }
-
- for (q = d->file_info.short_filename; *q; q++) {
- if (*q == 185) {
- *q = 165;
- } else if (*q == 230) {
- *q = 198;
- } else if (*q == 234) {
- *q = 202;
- } else if (*q == 179) {
- *q = 163;
- } else if (*q == 241) {
- *q = 209;
- } else if (*q == 243) {
- *q = 211;
- } else if (*q == 156) {
- *q = 140;
- } else if (*q == 159) {
- *q = 143;
- } else if (*q == 191) {
- *q = 175;
- }
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() short name \"%s\", dos name \"%s\"\n", name, d->file_info.short_filename);
- strncpy(d->file_info.filename, name, sizeof(d->file_info.filename) - 1);
-
- return 0;
-}
-
-/*
- * gg_dcc_transfer() // funkcja wewnêtrzna
- *
- * inicjuje proces wymiany pliku z danym klientem.
- *
- * - ip - adres ip odbiorcy
- * - port - port odbiorcy
- * - my_uin - w³asny numer
- * - peer_uin - numer obiorcy
- * - type - rodzaj wymiany (GG_SESSION_DCC_SEND lub GG_SESSION_DCC_GET)
- *
- * zaalokowana struct gg_dcc lub NULL je¶li wyst±pi³ b³±d.
- */
-static struct gg_dcc *gg_dcc_transfer(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin, int type)
-{
- struct gg_dcc *d = NULL;
- struct in_addr addr;
-
- addr.s_addr = ip;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_transfer(%s, %d, %ld, %ld, %s);\n", inet_ntoa(addr), port, my_uin, peer_uin, (type == GG_SESSION_DCC_SEND) ? "SEND" : "GET");
-
- if (!ip || ip == INADDR_NONE || !port || !my_uin || !peer_uin) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_transfer() invalid arguments\n");
- errno = EINVAL;
- return NULL;
- }
-
- if (!(d = (void*) calloc(1, sizeof(*d)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_transfer() not enough memory\n");
- return NULL;
- }
-
- d->check = GG_CHECK_WRITE;
- d->state = GG_STATE_CONNECTING;
- d->type = type;
- d->timeout = GG_DEFAULT_TIMEOUT;
- d->file_fd = -1;
- d->active = 1;
- d->fd = -1;
- d->uin = my_uin;
- d->peer_uin = peer_uin;
-
- if ((d->fd = gg_connect(&addr, port, 1)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_transfer() connection failed\n");
- free(d);
- return NULL;
- }
-
- return d;
-}
-
-/*
- * gg_dcc_get_file()
- *
- * inicjuje proces odbierania pliku od danego klienta, gdy ten wys³a³ do
- * nas ¿±danie po³±czenia.
- *
- * - ip - adres ip odbiorcy
- * - port - port odbiorcy
- * - my_uin - w³asny numer
- * - peer_uin - numer obiorcy
- *
- * zaalokowana struct gg_dcc lub NULL je¶li wyst±pi³ b³±d.
- */
-struct gg_dcc *gg_dcc_get_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin)
-{
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_get_file() handing over to gg_dcc_transfer()\n");
-
- return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_GET);
-}
-
-/*
- * gg_dcc_send_file()
- *
- * inicjuje proces wysy³ania pliku do danego klienta.
- *
- * - ip - adres ip odbiorcy
- * - port - port odbiorcy
- * - my_uin - w³asny numer
- * - peer_uin - numer obiorcy
- *
- * zaalokowana struct gg_dcc lub NULL je¶li wyst±pi³ b³±d.
- */
-struct gg_dcc *gg_dcc_send_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin)
-{
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_send_file() handing over to gg_dcc_transfer()\n");
-
- return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_SEND);
-}
-
-/*
- * gg_dcc_voice_chat()
- *
- * próbuje nawi±zaæ po³±czenie g³osowe.
- *
- * - ip - adres ip odbiorcy
- * - port - port odbiorcy
- * - my_uin - w³asny numer
- * - peer_uin - numer obiorcy
- *
- * zaalokowana struct gg_dcc lub NULL je¶li wyst±pi³ b³±d.
- */
-struct gg_dcc *gg_dcc_voice_chat(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin)
-{
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_chat() handing over to gg_dcc_transfer()\n");
-
- return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_VOICE);
-}
-
-/*
- * gg_dcc_set_type()
- *
- * po zdarzeniu GG_EVENT_DCC_CALLBACK nale¿y ustawiæ typ po³±czenia za
- * pomoc± tej funkcji.
- *
- * - d - struktura opisuj±ca po³±czenie
- * - type - typ po³±czenia (GG_SESSION_DCC_SEND lub GG_SESSION_DCC_VOICE)
- */
-void gg_dcc_set_type(struct gg_dcc *d, int type)
-{
- d->type = type;
- d->state = (type == GG_SESSION_DCC_SEND) ? GG_STATE_SENDING_FILE_INFO : GG_STATE_SENDING_VOICE_REQUEST;
-}
-
-/*
- * gg_dcc_callback() // funkcja wewnêtrzna
- *
- * wywo³ywana z struct gg_dcc->callback, odpala gg_dcc_watch_fd i umieszcza
- * rezultat w struct gg_dcc->event.
- *
- * - d - structura opisuj±ca po³±czenie
- *
- * 0, -1.
- */
-static int gg_dcc_callback(struct gg_dcc *d)
-{
- struct gg_event *e = gg_dcc_watch_fd(d);
-
- d->event = e;
-
- return (e != NULL) ? 0 : -1;
-}
-
-/*
- * gg_dcc_socket_create()
- *
- * tworzy gniazdo dla bezpo¶redniej komunikacji miêdzy klientami.
- *
- * - uin - w³asny numer
- * - port - preferowany port, je¶li równy 0 lub -1, próbuje domy¶lnego
- *
- * zaalokowana struct gg_dcc, któr± po¼niej nale¿y zwolniæ funkcj±
- * gg_dcc_free(), albo NULL je¶li wyst±pi³ b³±d.
- */
-struct gg_dcc *gg_dcc_socket_create(uin_t uin, uint16_t port)
-{
- struct gg_dcc *c;
- struct sockaddr_in sin;
- int sock, bound = 0, errno2;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_create_dcc_socket(%d, %d);\n", uin, port);
-
- if (!uin) {
- gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() invalid arguments\n");
- errno = EINVAL;
- return NULL;
- }
-
- if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() can't create socket (%s)\n", strerror(errno));
- return NULL;
- }
-
- if (!port)
- port = GG_DEFAULT_DCC_PORT;
-
- while (!bound) {
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- sin.sin_port = htons(port);
-
- gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() trying port %d\n", port);
- if (!bind(sock, (struct sockaddr*) &sin, sizeof(sin)))
- bound = 1;
- else {
- if (++port == 65535) {
- gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() no free port found\n");
- close(sock);
- return NULL;
- }
- }
- }
-
- if (listen(sock, 10)) {
- gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() unable to listen (%s)\n", strerror(errno));
- errno2 = errno;
- close(sock);
- errno = errno2;
- return NULL;
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() bound to port %d\n", port);
-
- if (!(c = malloc(sizeof(*c)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() not enough memory for struct\n");
- close(sock);
- return NULL;
- }
- memset(c, 0, sizeof(*c));
-
- c->port = c->id = port;
- c->fd = sock;
- c->type = GG_SESSION_DCC_SOCKET;
- c->uin = uin;
- c->timeout = -1;
- c->state = GG_STATE_LISTENING;
- c->check = GG_CHECK_READ;
- c->callback = gg_dcc_callback;
- c->destroy = gg_dcc_free;
-
- return c;
-}
-
-/*
- * gg_dcc_voice_send()
- *
- * wysy³a ramkê danych dla rozmowy g³osowej.
- *
- * - d - struktura opisuj±ca po³±czenie dcc
- * - buf - bufor z danymi
- * - length - rozmiar ramki
- *
- * 0, -1.
- */
-int gg_dcc_voice_send(struct gg_dcc *d, char *buf, int length)
-{
- struct packet_s {
- uint8_t type;
- uint32_t length;
- } GG_PACKED;
- struct packet_s packet;
-
- gg_debug(GG_DEBUG_FUNCTION, "++ gg_dcc_voice_send(%p, %p, %d);\n", d, buf, length);
- if (!d || !buf || length < 0 || d->type != GG_SESSION_DCC_VOICE) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() invalid argument\n");
- errno = EINVAL;
- return -1;
- }
-
- packet.type = 0x03; /* XXX */
- packet.length = gg_fix32(length);
-
- if (write(d->fd, &packet, sizeof(packet)) < (signed)sizeof(packet)) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() write() failed\n");
- return -1;
- }
- gg_dcc_debug_data("write", d->fd, &packet, sizeof(packet));
-
- if (write(d->fd, buf, length) < length) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() write() failed\n");
- return -1;
- }
- gg_dcc_debug_data("write", d->fd, buf, length);
-
- return 0;
-}
-
-#define gg_read(fd, buf, size) \
-{ \
- int tmp = read(fd, buf, size); \
- \
- if (tmp < (int) size) { \
- if (tmp == -1) { \
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno)); \
- } else if (tmp == 0) { \
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed, connection broken\n"); \
- } else { \
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (%d bytes, %d needed)\n", tmp, size); \
- } \
- e->type = GG_EVENT_DCC_ERROR; \
- e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; \
- return e; \
- } \
- gg_dcc_debug_data("read", fd, buf, size); \
-}
-
-#define gg_write(fd, buf, size) \
-{ \
- int tmp; \
- gg_dcc_debug_data("write", fd, buf, size); \
- tmp = write(fd, buf, size); \
- if (tmp < (int) size) { \
- if (tmp == -1) { \
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (errno=%d, %s)\n", errno, strerror(errno)); \
- } else { \
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (%d needed, %d done)\n", size, tmp); \
- } \
- e->type = GG_EVENT_DCC_ERROR; \
- e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; \
- return e; \
- } \
-}
-
-/*
- * gg_dcc_watch_fd()
- *
- * funkcja, któr± nale¿y wywo³aæ, gdy co¶ siê zmieni na gg_dcc->fd.
- *
- * - h - struktura zwrócona przez gg_create_dcc_socket()
- *
- * zaalokowana struct gg_event lub NULL, je¶li zabrak³o pamiêci na ni±.
- */
-struct gg_event *gg_dcc_watch_fd(struct gg_dcc *h)
-{
- struct gg_event *e;
- int foo;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_watch_fd(%p);\n", h);
-
- if (!h || (h->type != GG_SESSION_DCC && h->type != GG_SESSION_DCC_SOCKET && h->type != GG_SESSION_DCC_SEND && h->type != GG_SESSION_DCC_GET && h->type != GG_SESSION_DCC_VOICE)) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() invalid argument\n");
- errno = EINVAL;
- return NULL;
- }
-
- if (!(e = (void*) calloc(1, sizeof(*e)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() not enough memory\n");
- return NULL;
- }
-
- e->type = GG_EVENT_NONE;
-
- if (h->type == GG_SESSION_DCC_SOCKET) {
- struct sockaddr_in sin;
- struct gg_dcc *c;
- int fd, sin_len = sizeof(sin), one = 1;
-
- if ((fd = accept(h->fd, (struct sockaddr*) &sin, &sin_len)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() can't accept() new connection (errno=%d, %s)\n", errno, strerror(errno));
- return e;
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() new direct connection from %s:%d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));
-
-#ifdef FIONBIO
- if (ioctl(fd, FIONBIO, &one) == -1) {
-#else
- if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
-#endif
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() can't set nonblocking (errno=%d, %s)\n", errno, strerror(errno));
- close(fd);
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE;
- return e;
- }
-
- if (!(c = (void*) calloc(1, sizeof(*c)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() not enough memory for client data\n");
-
- free(e);
- close(fd);
- return NULL;
- }
-
- c->fd = fd;
- c->check = GG_CHECK_READ;
- c->state = GG_STATE_READING_UIN_1;
- c->type = GG_SESSION_DCC;
- c->timeout = GG_DEFAULT_TIMEOUT;
- c->file_fd = -1;
- c->remote_addr = sin.sin_addr.s_addr;
- c->remote_port = ntohs(sin.sin_port);
-
- e->type = GG_EVENT_DCC_NEW;
- e->event.dcc_new = c;
-
- return e;
- } else {
- struct gg_dcc_tiny_packet tiny;
- struct gg_dcc_small_packet small;
- struct gg_dcc_big_packet big;
- int size, tmp, res, res_size = sizeof(res);
- unsigned int utmp;
- char buf[1024], ack[] = "UDAG";
-
- struct gg_dcc_file_info_packet {
- struct gg_dcc_big_packet big;
- struct gg_file_info file_info;
- } GG_PACKED;
- struct gg_dcc_file_info_packet file_info_packet;
-
- switch (h->state) {
- case GG_STATE_READING_UIN_1:
- case GG_STATE_READING_UIN_2:
- {
- uin_t uin;
-
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_READING_UIN_%d\n", (h->state == GG_STATE_READING_UIN_1) ? 1 : 2);
-
- gg_read(h->fd, &uin, sizeof(uin));
-
- if (h->state == GG_STATE_READING_UIN_1) {
- h->state = GG_STATE_READING_UIN_2;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
- h->peer_uin = gg_fix32(uin);
- } else {
- h->state = GG_STATE_SENDING_ACK;
- h->check = GG_CHECK_WRITE;
- h->timeout = GG_DEFAULT_TIMEOUT;
- h->uin = gg_fix32(uin);
- e->type = GG_EVENT_DCC_CLIENT_ACCEPT;
- }
-
- return e;
- }
-
- case GG_STATE_SENDING_ACK:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_SENDING_ACK\n");
-
- gg_write(h->fd, ack, 4);
-
- h->state = GG_STATE_READING_TYPE;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- return e;
-
- case GG_STATE_READING_TYPE:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_TYPE\n");
-
- gg_read(h->fd, &small, sizeof(small));
-
- small.type = gg_fix32(small.type);
-
- switch (small.type) {
- case 0x0003: /* XXX */
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() callback\n");
- h->type = GG_SESSION_DCC_SEND;
- h->state = GG_STATE_SENDING_FILE_INFO;
- h->check = GG_CHECK_WRITE;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- e->type = GG_EVENT_DCC_CALLBACK;
-
- break;
-
- case 0x0002: /* XXX */
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() dialin\n");
- h->type = GG_SESSION_DCC_GET;
- h->state = GG_STATE_READING_REQUEST;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
- h->incoming = 1;
-
- break;
-
- default:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown dcc type (%.4x) from %ld\n", small.type, h->peer_uin);
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE;
- }
-
- return e;
-
- case GG_STATE_READING_REQUEST:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_REQUEST\n");
-
- gg_read(h->fd, &small, sizeof(small));
-
- small.type = gg_fix32(small.type);
-
- switch (small.type) {
- case 0x0001: /* XXX */
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() file transfer request\n");
- h->state = GG_STATE_READING_FILE_INFO;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
- break;
-
- case 0x0003: /* XXX */
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() voice chat request\n");
- h->state = GG_STATE_SENDING_VOICE_ACK;
- h->check = GG_CHECK_WRITE;
- h->timeout = GG_DCC_TIMEOUT_VOICE_ACK;
- h->type = GG_SESSION_DCC_VOICE;
- e->type = GG_EVENT_DCC_NEED_VOICE_ACK;
-
- break;
-
- default:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown dcc request (%.4x) from %ld\n", small.type, h->peer_uin);
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE;
- }
-
- return e;
-
- case GG_STATE_READING_FILE_INFO:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_INFO\n");
-
- gg_read(h->fd, &file_info_packet, sizeof(file_info_packet));
-
- memcpy(&h->file_info, &file_info_packet.file_info, sizeof(h->file_info));
-
- h->file_info.mode = gg_fix32(h->file_info.mode);
- h->file_info.size = gg_fix32(h->file_info.size);
-
- h->state = GG_STATE_SENDING_FILE_ACK;
- h->check = GG_CHECK_WRITE;
- h->timeout = GG_DCC_TIMEOUT_FILE_ACK;
-
- e->type = GG_EVENT_DCC_NEED_FILE_ACK;
-
- return e;
-
- case GG_STATE_SENDING_FILE_ACK:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_ACK\n");
-
- big.type = gg_fix32(0x0006); /* XXX */
- big.dunno1 = gg_fix32(h->offset);
- big.dunno2 = 0;
-
- gg_write(h->fd, &big, sizeof(big));
-
- h->state = GG_STATE_READING_FILE_HEADER;
- h->chunk_size = sizeof(big);
- h->chunk_offset = 0;
- if (!(h->chunk_buf = malloc(sizeof(big)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory\n");
- free(e);
- return NULL;
- }
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- return e;
-
- case GG_STATE_SENDING_VOICE_ACK:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_ACK\n");
-
- tiny.type = 0x01; /* XXX */
-
- gg_write(h->fd, &tiny, sizeof(tiny));
-
- h->state = GG_STATE_READING_VOICE_HEADER;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- h->offset = 0;
-
- return e;
-
- case GG_STATE_READING_FILE_HEADER:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_HEADER\n");
-
- tmp = read(h->fd, h->chunk_buf + h->chunk_offset, h->chunk_size - h->chunk_offset);
-
- if (tmp == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno));
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_NET;
- return e;
- }
-
- gg_dcc_debug_data("read", h->fd, h->chunk_buf + h->chunk_offset, h->chunk_size - h->chunk_offset);
-
- h->chunk_offset += tmp;
-
- if (h->chunk_offset < h->chunk_size)
- return e;
-
- memcpy(&big, h->chunk_buf, sizeof(big));
- free(h->chunk_buf);
- h->chunk_buf = NULL;
-
- big.type = gg_fix32(big.type);
- h->chunk_size = gg_fix32(big.dunno1);
- h->chunk_offset = 0;
-
- if (big.type == 0x0005) { /* XXX */
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() transfer refused\n");
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_REFUSED;
- return e;
- }
-
- if (h->chunk_size == 0) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() empty chunk, EOF\n");
- e->type = GG_EVENT_DCC_DONE;
- return e;
- }
-
- h->state = GG_STATE_GETTING_FILE;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
- h->established = 1;
-
- return e;
-
- case GG_STATE_READING_VOICE_HEADER:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_HEADER\n");
-
- gg_read(h->fd, &tiny, sizeof(tiny));
-
- switch (tiny.type) {
- case 0x03: /* XXX */
- h->state = GG_STATE_READING_VOICE_SIZE;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
- h->established = 1;
- break;
- case 0x04: /* XXX */
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() peer breaking connection\n");
- /* XXX zwracaæ odpowiedni event */
- default:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown request (%.2x)\n", tiny.type);
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE;
- }
-
- return e;
-
- case GG_STATE_READING_VOICE_SIZE:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_SIZE\n");
-
- gg_read(h->fd, &small, sizeof(small));
-
- small.type = gg_fix32(small.type);
-
- if (small.type < 16 || small.type > sizeof(buf)) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() invalid voice frame size (%d)\n", small.type);
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_NET;
-
- return e;
- }
-
- h->chunk_size = small.type;
- h->chunk_offset = 0;
-
- if (!(h->voice_buf = malloc(h->chunk_size))) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory for voice frame\n");
- free(e);
- return NULL;
- }
-
- h->state = GG_STATE_READING_VOICE_DATA;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- return e;
-
- case GG_STATE_READING_VOICE_DATA:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_DATA\n");
-
- tmp = read(h->fd, h->voice_buf + h->chunk_offset, h->chunk_size - h->chunk_offset);
- if (tmp < 1) {
- if (tmp == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno));
- } else {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed, connection broken\n");
- }
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_NET;
- return e;
- }
-
- gg_dcc_debug_data("read", h->fd, h->voice_buf + h->chunk_offset, tmp);
-
- h->chunk_offset += tmp;
-
- if (h->chunk_offset >= h->chunk_size) {
- e->type = GG_EVENT_DCC_VOICE_DATA;
- e->event.dcc_voice_data.data = h->voice_buf;
- e->event.dcc_voice_data.length = h->chunk_size;
- h->state = GG_STATE_READING_VOICE_HEADER;
- h->voice_buf = NULL;
- }
-
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- return e;
-
- case GG_STATE_CONNECTING:
- {
- uin_t uins[2];
-
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_CONNECTING\n");
-
- res = 0;
- if ((foo = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size)) || res) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() connection failed (fd=%d,errno=%d(%s),foo=%d,res=%d(%s))\n", h->fd, errno, strerror(errno), foo, res, strerror(res));
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE;
- return e;
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() connected, sending uins\n");
-
- uins[0] = gg_fix32(h->uin);
- uins[1] = gg_fix32(h->peer_uin);
-
- gg_write(h->fd, uins, sizeof(uins));
-
- h->state = GG_STATE_READING_ACK;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- return e;
- }
-
- case GG_STATE_READING_ACK:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_ACK\n");
-
- gg_read(h->fd, buf, 4);
-
- if (strncmp(buf, ack, 4)) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() did't get ack\n");
-
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE;
- return e;
- }
-
- h->check = GG_CHECK_WRITE;
- h->timeout = GG_DEFAULT_TIMEOUT;
- h->state = GG_STATE_SENDING_REQUEST;
-
- return e;
-
- case GG_STATE_SENDING_VOICE_REQUEST:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_REQUEST\n");
-
- small.type = gg_fix32(0x0003);
-
- gg_write(h->fd, &small, sizeof(small));
-
- h->state = GG_STATE_READING_VOICE_ACK;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- return e;
-
- case GG_STATE_SENDING_REQUEST:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_REQUEST\n");
-
- small.type = (h->type == GG_SESSION_DCC_GET) ? gg_fix32(0x0003) : gg_fix32(0x0002); /* XXX */
-
- gg_write(h->fd, &small, sizeof(small));
-
- switch (h->type) {
- case GG_SESSION_DCC_GET:
- h->state = GG_STATE_READING_REQUEST;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
- break;
-
- case GG_SESSION_DCC_SEND:
- h->state = GG_STATE_SENDING_FILE_INFO;
- h->check = GG_CHECK_WRITE;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- if (h->file_fd == -1)
- e->type = GG_EVENT_DCC_NEED_FILE_INFO;
- break;
-
- case GG_SESSION_DCC_VOICE:
- h->state = GG_STATE_SENDING_VOICE_REQUEST;
- h->check = GG_CHECK_WRITE;
- h->timeout = GG_DEFAULT_TIMEOUT;
- break;
- }
-
- return e;
-
- case GG_STATE_SENDING_FILE_INFO:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_INFO\n");
-
- if (h->file_fd == -1) {
- e->type = GG_EVENT_DCC_NEED_FILE_INFO;
- return e;
- }
-
- small.type = gg_fix32(0x0001); /* XXX */
-
- gg_write(h->fd, &small, sizeof(small));
-
- file_info_packet.big.type = gg_fix32(0x0003); /* XXX */
- file_info_packet.big.dunno1 = 0;
- file_info_packet.big.dunno2 = 0;
-
- memcpy(&file_info_packet.file_info, &h->file_info, sizeof(h->file_info));
-
- /* zostaj± teraz u nas, wiêc odwracamy z powrotem */
- h->file_info.size = gg_fix32(h->file_info.size);
- h->file_info.mode = gg_fix32(h->file_info.mode);
-
- gg_write(h->fd, &file_info_packet, sizeof(file_info_packet));
-
- h->state = GG_STATE_READING_FILE_ACK;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DCC_TIMEOUT_FILE_ACK;
-
- return e;
-
- case GG_STATE_READING_FILE_ACK:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_ACK\n");
-
- gg_read(h->fd, &big, sizeof(big));
-
- /* XXX sprawdzaæ wynik */
- h->offset = gg_fix32(big.dunno1);
-
- h->state = GG_STATE_SENDING_FILE_HEADER;
- h->check = GG_CHECK_WRITE;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- e->type = GG_EVENT_DCC_ACK;
-
- return e;
-
- case GG_STATE_READING_VOICE_ACK:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_ACK\n");
-
- gg_read(h->fd, &tiny, sizeof(tiny));
-
- if (tiny.type != 0x01) {
- gg_debug(GG_DEBUG_MISC, "// invalid reply (%.2x), connection refused\n", tiny.type);
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_REFUSED;
- return e;
- }
-
- h->state = GG_STATE_READING_VOICE_HEADER;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- e->type = GG_EVENT_DCC_ACK;
-
- return e;
-
- case GG_STATE_SENDING_FILE_HEADER:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_HEADER\n");
-
- h->chunk_offset = 0;
-
- if ((h->chunk_size = h->file_info.size - h->offset) > 4096) {
- h->chunk_size = 4096;
- big.type = gg_fix32(0x0003); /* XXX */
- } else
- big.type = gg_fix32(0x0002); /* XXX */
-
- big.dunno1 = gg_fix32(h->chunk_size);
- big.dunno2 = 0;
-
- gg_write(h->fd, &big, sizeof(big));
-
- h->state = GG_STATE_SENDING_FILE;
- h->check = GG_CHECK_WRITE;
- h->timeout = GG_DEFAULT_TIMEOUT;
- h->established = 1;
-
- return e;
-
- case GG_STATE_SENDING_FILE:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE\n");
-
- if ((utmp = h->chunk_size - h->chunk_offset) > sizeof(buf))
- utmp = sizeof(buf);
-
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() offset=%d, size=%d\n", h->offset, h->file_info.size);
-
- /* koniec pliku? */
- if (h->file_info.size == 0) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof on empty file\n");
- e->type = GG_EVENT_DCC_DONE;
-
- return e;
- }
-
- lseek(h->file_fd, h->offset, SEEK_SET);
-
- size = read(h->file_fd, buf, utmp);
-
- /* b³±d */
- if (size == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno, strerror(errno));
-
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_FILE;
-
- return e;
- }
-
- /* koniec pliku? */
- if (size == 0) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof\n");
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_EOF;
-
- return e;
- }
-
- /* je¶li wczytali¶my wiêcej, utnijmy. */
- if (h->offset + size > h->file_info.size) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() too much (read=%d, ofs=%d, size=%d)\n", size, h->offset, h->file_info.size);
- size = h->file_info.size - h->offset;
-
- if (size < 1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() reached EOF after cutting\n");
- e->type = GG_EVENT_DCC_DONE;
- return e;
- }
- }
-
- tmp = write(h->fd, buf, size);
-
- if (tmp == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (%s)\n", strerror(errno));
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_NET;
- return e;
- }
-
- h->offset += size;
-
- if (h->offset >= h->file_info.size) {
- e->type = GG_EVENT_DCC_DONE;
- return e;
- }
-
- h->chunk_offset += size;
-
- if (h->chunk_offset >= h->chunk_size) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() chunk finished\n");
- h->state = GG_STATE_SENDING_FILE_HEADER;
- h->timeout = GG_DEFAULT_TIMEOUT;
- } else {
- h->state = GG_STATE_SENDING_FILE;
- h->timeout = GG_DCC_TIMEOUT_SEND;
- }
-
- h->check = GG_CHECK_WRITE;
-
- return e;
-
- case GG_STATE_GETTING_FILE:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_GETTING_FILE\n");
-
- if ((utmp = h->chunk_size - h->chunk_offset) > sizeof(buf))
- utmp = sizeof(buf);
-
- size = read(h->fd, buf, utmp);
-
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() ofs=%d, size=%d, read()=%d\n", h->offset, h->file_info.size, size);
-
- /* b³±d */
- if (size == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno, strerror(errno));
-
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_NET;
-
- return e;
- }
-
- /* koniec? */
- if (size == 0) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof\n");
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_EOF;
-
- return e;
- }
-
- tmp = write(h->file_fd, buf, size);
-
- if (tmp == -1 || tmp < size) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (%d:fd=%d:res=%d:%s)\n", tmp, h->file_fd, size, strerror(errno));
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_NET;
- return e;
- }
-
- h->offset += size;
-
- if (h->offset >= h->file_info.size) {
- e->type = GG_EVENT_DCC_DONE;
- return e;
- }
-
- h->chunk_offset += size;
-
- if (h->chunk_offset >= h->chunk_size) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() chunk finished\n");
- h->state = GG_STATE_READING_FILE_HEADER;
- h->timeout = GG_DEFAULT_TIMEOUT;
- h->chunk_offset = 0;
- h->chunk_size = sizeof(big);
- if (!(h->chunk_buf = malloc(sizeof(big)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory\n");
- free(e);
- return NULL;
- }
- } else {
- h->state = GG_STATE_GETTING_FILE;
- h->timeout = GG_DCC_TIMEOUT_GET;
- }
-
- h->check = GG_CHECK_READ;
-
- return e;
-
- default:
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_???\n");
- e->type = GG_EVENT_DCC_ERROR;
- e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE;
-
- return e;
- }
- }
-
- return e;
-}
-
-#undef gg_read
-#undef gg_write
-
-/*
- * gg_dcc_free()
- *
- * zwalnia pamiêæ po strukturze po³±czenia dcc.
- *
- * - d - zwalniana struktura
- */
-void gg_dcc_free(struct gg_dcc *d)
-{
- gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_free(%p);\n", d);
-
- if (!d)
- return;
-
- if (d->fd != -1)
- close(d->fd);
-
- if (d->chunk_buf) {
- free(d->chunk_buf);
- d->chunk_buf = NULL;
- }
-
- free(d);
-}
-
-/*
- * Local variables:
- * c-indentation-style: k&r
- * c-basic-offset: 8
- * indent-tabs-mode: notnil
- * End:
- *
- * vim: shiftwidth=8:
- */
diff --git a/kopete/protocols/gadu/libgadu/events.c b/kopete/protocols/gadu/libgadu/events.c
deleted file mode 100644
index 1bf67690..00000000
--- a/kopete/protocols/gadu/libgadu/events.c
+++ /dev/null
@@ -1,1580 +0,0 @@
-/* $Id$ */
-
-/*
- * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl>
- * Robert J. Wo�ny <speedy@ziew.org>
- * Arkadiusz Mi�kiewicz <arekm@pld-linux.org>
- * Adam Wysocki <gophi@ekg.chmurka.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License Version
- * 2.1 as published by the Free Software Foundation.
- *
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "libgadu-config.h"
-
-#include <errno.h>
-#ifdef __GG_LIBGADU_HAVE_PTHREAD
-# include <pthread.h>
-#endif
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
-# include <openssl/err.h>
-# include <openssl/x509.h>
-#endif
-
-#include "compat.h"
-#include "libgadu.h"
-
-/*
- * gg_event_free()
- *
- * zwalnia pami�� zajmowan� przez informacj� o zdarzeniu.
- *
- * - e - wska�nik do informacji o zdarzeniu
- */
-void gg_event_free(struct gg_event *e)
-{
- gg_debug(GG_DEBUG_FUNCTION, "** gg_event_free(%p);\n", e);
-
- if (!e)
- return;
-
- switch (e->type) {
- case GG_EVENT_MSG:
- free(e->event.msg.message);
- free(e->event.msg.formats);
- free(e->event.msg.recipients);
- break;
-
- case GG_EVENT_NOTIFY:
- free(e->event.notify);
- break;
-
- case GG_EVENT_NOTIFY60:
- {
- int i;
-
- for (i = 0; e->event.notify60[i].uin; i++)
- free(e->event.notify60[i].descr);
-
- free(e->event.notify60);
-
- break;
- }
-
- case GG_EVENT_STATUS60:
- free(e->event.status60.descr);
- break;
-
- case GG_EVENT_STATUS:
- free(e->event.status.descr);
- break;
-
- case GG_EVENT_NOTIFY_DESCR:
- free(e->event.notify_descr.notify);
- free(e->event.notify_descr.descr);
- break;
-
- case GG_EVENT_DCC_VOICE_DATA:
- free(e->event.dcc_voice_data.data);
- break;
-
- case GG_EVENT_PUBDIR50_SEARCH_REPLY:
- case GG_EVENT_PUBDIR50_READ:
- case GG_EVENT_PUBDIR50_WRITE:
- gg_pubdir50_free(e->event.pubdir50);
- break;
-
- case GG_EVENT_USERLIST:
- free(e->event.userlist.reply);
- break;
-
- case GG_EVENT_IMAGE_REPLY:
- free(e->event.image_reply.filename);
- free(e->event.image_reply.image);
- break;
- }
-
- free(e);
-}
-
-/*
- * gg_image_queue_remove()
- *
- * usuwa z kolejki dany wpis.
- *
- * - s - sesja
- * - q - kolejka
- * - freeq - czy zwolni� kolejk�
- *
- * 0/-1
- */
-int gg_image_queue_remove(struct gg_session *s, struct gg_image_queue *q, int freeq)
-{
- if (!s || !q) {
- errno = EFAULT;
- return -1;
- }
-
- if (s->images == q)
- s->images = q->next;
- else {
- struct gg_image_queue *qq;
-
- for (qq = s->images; qq; qq = qq->next) {
- if (qq->next == q) {
- qq->next = q->next;
- break;
- }
- }
- }
-
- if (freeq) {
- free(q->image);
- free(q->filename);
- free(q);
- }
-
- return 0;
-}
-
-/*
- * gg_image_queue_parse() // funkcja wewn�trzna
- *
- * parsuje przychodz�cy pakiet z obrazkiem.
- *
- * - e - opis zdarzenia
- * -
- */
-static void gg_image_queue_parse(struct gg_event *e, char *p, unsigned int len, struct gg_session *sess, uin_t sender)
-{
- struct gg_msg_image_reply *i = (void*) p;
- struct gg_image_queue *q, *qq;
-
- if (!p || !sess || !e) {
- errno = EFAULT;
- return;
- }
-
- /* znajd� dany obrazek w kolejce danej sesji */
-
- for (qq = sess->images, q = NULL; qq; qq = qq->next) {
- if (sender == qq->sender && i->size == qq->size && i->crc32 == qq->crc32) {
- q = qq;
- break;
- }
- }
-
- if (!q) {
- gg_debug(GG_DEBUG_MISC, "// gg_image_queue_parse() unknown image from %d, size=%d, crc32=%.8x\n", sender, i->size, i->crc32);
- return;
- }
-
- if (p[0] == 0x05) {
- int i, ok = 0;
-
- q->done = 0;
-
- len -= sizeof(struct gg_msg_image_reply);
- p += sizeof(struct gg_msg_image_reply);
-
- /* sprawd�, czy mamy tekst zako�czony \0 */
-
- for (i = 0; i < len; i++) {
- if (!p[i]) {
- ok = 1;
- break;
- }
- }
-
- if (!ok) {
- gg_debug(GG_DEBUG_MISC, "// gg_image_queue_parse() malformed packet from %d, unlimited filename\n", sender);
- return;
- }
-
- if (!(q->filename = strdup(p))) {
- gg_debug(GG_DEBUG_MISC, "// gg_image_queue_parse() not enough memory for filename\n");
- return;
- }
-
- len -= strlen(p) + 1;
- p += strlen(p) + 1;
- } else {
- len -= sizeof(struct gg_msg_image_reply);
- p += sizeof(struct gg_msg_image_reply);
- }
-
- if (q->done + len > q->size)
- len = q->size - q->done;
-
- memcpy(q->image + q->done, p, len);
- q->done += len;
-
- /* je�li sko�czono odbiera� obrazek, wygeneruj zdarzenie */
-
- if (q->done >= q->size) {
- e->type = GG_EVENT_IMAGE_REPLY;
- e->event.image_reply.sender = sender;
- e->event.image_reply.size = q->size;
- e->event.image_reply.crc32 = q->crc32;
- e->event.image_reply.filename = q->filename;
- e->event.image_reply.image = q->image;
-
- gg_image_queue_remove(sess, q, 0);
-
- free(q);
- }
-}
-
-/*
- * gg_handle_recv_msg() // funkcja wewn�trzna
- *
- * obs�uguje pakiet z przychodz�c� wiadomo�ci�, rozbijaj�c go na dodatkowe
- * struktury (konferencje, kolorki) w razie potrzeby.
- *
- * - h - nag��wek pakietu
- * - e - opis zdarzenia
- *
- * 0, -1.
- */
-static int gg_handle_recv_msg(struct gg_header *h, struct gg_event *e, struct gg_session *sess)
-{
- struct gg_recv_msg *r = (struct gg_recv_msg*) ((char*) h + sizeof(struct gg_header));
- char *p, *packet_end = (char*) r + h->length;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_handle_recv_msg(%p, %p);\n", h, e);
-
- if (!r->seq && !r->msgclass) {
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() oops, silently ignoring the bait\n");
- e->type = GG_EVENT_NONE;
- return 0;
- }
-
- for (p = (char*) r + sizeof(*r); *p; p++) {
- if (*p == 0x02 && p == packet_end - 1) {
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() received ctcp packet\n");
- break;
- }
- if (p >= packet_end) {
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() malformed packet, message out of bounds (0)\n");
- goto malformed;
- }
- }
-
- p++;
-
- /* przeanalizuj dodatkowe opcje */
- while (p < packet_end) {
- switch (*p) {
- case 0x01: /* konferencja */
- {
- struct gg_msg_recipients *m = (void*) p;
- uint32_t i, count;
-
- p += sizeof(*m);
-
- if (p > packet_end) {
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1)\n");
- goto malformed;
- }
-
- count = gg_fix32(m->count);
-
- if (p + count * sizeof(uin_t) > packet_end || p + count * sizeof(uin_t) < p || count > 0xffff) {
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1.5)\n");
- goto malformed;
- }
-
- if (!(e->event.msg.recipients = (void*) malloc(count * sizeof(uin_t)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for recipients data\n");
- goto fail;
- }
-
- for (i = 0; i < count; i++, p += sizeof(uint32_t)) {
- uint32_t u;
- memcpy(&u, p, sizeof(uint32_t));
- e->event.msg.recipients[i] = gg_fix32(u);
- }
-
- e->event.msg.recipients_count = count;
-
- break;
- }
-
- case 0x02: /* richtext */
- {
- uint16_t len;
- char *buf;
-
- if (p + 3 > packet_end) {
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (2)\n");
- goto malformed;
- }
-
- memcpy(&len, p + 1, sizeof(uint16_t));
- len = gg_fix16(len);
-
- if (!(buf = malloc(len))) {
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for richtext data\n");
- goto fail;
- }
-
- p += 3;
-
- if (p + len > packet_end) {
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (3)\n");
- free(buf);
- goto malformed;
- }
-
- memcpy(buf, p, len);
-
- e->event.msg.formats = buf;
- e->event.msg.formats_length = len;
-
- p += len;
-
- break;
- }
-
- case 0x04: /* image_request */
- {
- struct gg_msg_image_request *i = (void*) p;
-
- if (p + sizeof(*i) > packet_end) {
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (3)\n");
- goto malformed;
- }
-
- e->event.image_request.sender = gg_fix32(r->sender);
- e->event.image_request.size = gg_fix32(i->size);
- e->event.image_request.crc32 = gg_fix32(i->crc32);
-
- e->type = GG_EVENT_IMAGE_REQUEST;
-
- return 0;
- }
-
- case 0x05: /* image_reply */
- case 0x06:
- {
- struct gg_msg_image_reply *rep = (void*) p;
-
- if (p + sizeof(struct gg_msg_image_reply) == packet_end) {
-
- /* pusta odpowied� - klient po drugiej stronie nie ma ��danego obrazka */
-
- e->type = GG_EVENT_IMAGE_REPLY;
- e->event.image_reply.sender = gg_fix32(r->sender);
- e->event.image_reply.size = 0;
- e->event.image_reply.crc32 = gg_fix32(rep->crc32);
- e->event.image_reply.filename = NULL;
- e->event.image_reply.image = NULL;
- return 0;
-
- } else if (p + sizeof(struct gg_msg_image_reply) + 1 > packet_end) {
-
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (4)\n");
- goto malformed;
- }
-
- rep->size = gg_fix32(rep->size);
- rep->crc32 = gg_fix32(rep->crc32);
- gg_image_queue_parse(e, p, (unsigned int)(packet_end - p), sess, gg_fix32(r->sender));
-
- return 0;
- }
-
- default:
- {
- gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() unknown payload 0x%.2x\n", *p);
- p = packet_end;
- }
- }
- }
-
- e->type = GG_EVENT_MSG;
- e->event.msg.msgclass = gg_fix32(r->msgclass);
- e->event.msg.sender = gg_fix32(r->sender);
- e->event.msg.time = gg_fix32(r->time);
- e->event.msg.message = strdup((char*) r + sizeof(*r));
-
- return 0;
-
-malformed:
- e->type = GG_EVENT_NONE;
-
- free(e->event.msg.recipients);
- free(e->event.msg.formats);
-
- return 0;
-
-fail:
- free(e->event.msg.recipients);
- free(e->event.msg.formats);
- return -1;
-}
-
-/*
- * gg_watch_fd_connected() // funkcja wewn�trzna
- *
- * patrzy na gniazdo, odbiera pakiet i wype�nia struktur� zdarzenia.
- *
- * - sess - struktura opisuj�ca sesj�
- * - e - opis zdarzenia
- *
- * 0, -1.
- */
-static int gg_watch_fd_connected(struct gg_session *sess, struct gg_event *e)
-{
- struct gg_header *h = NULL;
- char *p;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd_connected(%p, %p);\n", sess, e);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (!(h = gg_recv_packet(sess))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() gg_recv_packet failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail;
- }
-
- p = (char*) h + sizeof(struct gg_header);
-
- switch (h->type) {
- case GG_RECV_MSG:
- {
- if (h->length >= sizeof(struct gg_recv_msg))
- if (gg_handle_recv_msg(h, e, sess))
- goto fail;
-
- break;
- }
-
- case GG_NOTIFY_REPLY:
- {
- struct gg_notify_reply *n = (void*) p;
- unsigned int count, i;
- char *tmp;
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n");
-
- if (h->length < sizeof(*n)) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() incomplete packet\n");
- errno = EINVAL;
- goto fail;
- }
-
- if (gg_fix32(n->status) == GG_STATUS_BUSY_DESCR || gg_fix32(n->status) == GG_STATUS_NOT_AVAIL_DESCR || gg_fix32(n->status) == GG_STATUS_AVAIL_DESCR) {
- e->type = GG_EVENT_NOTIFY_DESCR;
-
- if (!(e->event.notify_descr.notify = (void*) malloc(sizeof(*n) * 2))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
- goto fail;
- }
- e->event.notify_descr.notify[1].uin = 0;
- memcpy(e->event.notify_descr.notify, p, sizeof(*n));
- e->event.notify_descr.notify[0].uin = gg_fix32(e->event.notify_descr.notify[0].uin);
- e->event.notify_descr.notify[0].status = gg_fix32(e->event.notify_descr.notify[0].status);
- e->event.notify_descr.notify[0].remote_port = gg_fix16(e->event.notify_descr.notify[0].remote_port);
-
- count = h->length - sizeof(*n);
- if (!(tmp = malloc(count + 1))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
- goto fail;
- }
- memcpy(tmp, p + sizeof(*n), count);
- tmp[count] = 0;
- e->event.notify_descr.descr = tmp;
-
- } else {
- e->type = GG_EVENT_NOTIFY;
-
- if (!(e->event.notify = (void*) malloc(h->length + 2 * sizeof(*n)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
- goto fail;
- }
-
- memcpy(e->event.notify, p, h->length);
- count = h->length / sizeof(*n);
- e->event.notify[count].uin = 0;
-
- for (i = 0; i < count; i++) {
- e->event.notify[i].uin = gg_fix32(e->event.notify[i].uin);
- e->event.notify[i].status = gg_fix32(e->event.notify[i].status);
- e->event.notify[i].remote_port = gg_fix16(e->event.notify[i].remote_port);
- }
- }
-
- break;
- }
-
- case GG_STATUS:
- {
- struct gg_status *s = (void*) p;
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n");
-
- if (h->length >= sizeof(*s)) {
- e->type = GG_EVENT_STATUS;
- memcpy(&e->event.status, p, sizeof(*s));
- e->event.status.uin = gg_fix32(e->event.status.uin);
- e->event.status.status = gg_fix32(e->event.status.status);
- if (h->length > sizeof(*s)) {
- int len = h->length - sizeof(*s);
- char *buf = malloc(len + 1);
- if (buf) {
- memcpy(buf, p + sizeof(*s), len);
- buf[len] = 0;
- }
- e->event.status.descr = buf;
- } else
- e->event.status.descr = NULL;
- }
-
- break;
- }
-
- case GG_NOTIFY_REPLY60:
- {
- struct gg_notify_reply60 *n = (void*) p;
- unsigned int length = h->length, i = 0;
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n");
-
- e->type = GG_EVENT_NOTIFY60;
- e->event.notify60 = malloc(sizeof(*e->event.notify60));
-
- if (!e->event.notify60) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
- goto fail;
- }
-
- e->event.notify60[0].uin = 0;
-
- while (length >= sizeof(struct gg_notify_reply60)) {
- uin_t uin = gg_fix32(n->uin);
- char *tmp;
-
- e->event.notify60[i].uin = uin & 0x00ffffff;
- e->event.notify60[i].status = n->status;
- e->event.notify60[i].remote_ip = n->remote_ip;
- e->event.notify60[i].remote_port = gg_fix16(n->remote_port);
- e->event.notify60[i].version = n->version;
- e->event.notify60[i].image_size = n->image_size;
- e->event.notify60[i].descr = NULL;
- e->event.notify60[i].time = 0;
-
- if (uin & 0x40000000)
- e->event.notify60[i].version |= GG_HAS_AUDIO_MASK;
- if (uin & 0x08000000)
- e->event.notify60[i].version |= GG_ERA_OMNIX_MASK;
-
- if (GG_S_D(n->status)) {
- unsigned char descr_len = *((char*) n + sizeof(struct gg_notify_reply60));
-
- if (descr_len < length) {
- if (!(e->event.notify60[i].descr = malloc(descr_len + 1))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
- goto fail;
- }
-
- memcpy(e->event.notify60[i].descr, (char*) n + sizeof(struct gg_notify_reply60) + 1, descr_len);
- e->event.notify60[i].descr[descr_len] = 0;
-
- /* XXX czas */
- }
-
- length -= sizeof(struct gg_notify_reply60) + descr_len + 1;
- n = (void*) ((char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1);
- } else {
- length -= sizeof(struct gg_notify_reply60);
- n = (void*) ((char*) n + sizeof(struct gg_notify_reply60));
- }
-
- if (!(tmp = realloc(e->event.notify60, (i + 2) * sizeof(*e->event.notify60)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
- free(e->event.notify60);
- goto fail;
- }
-
- e->event.notify60 = (void*) tmp;
- e->event.notify60[++i].uin = 0;
- }
-
- break;
- }
-
- case GG_STATUS60:
- {
- struct gg_status60 *s = (void*) p;
- uint32_t uin;
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n");
-
- if (h->length < sizeof(*s))
- break;
-
- uin = gg_fix32(s->uin);
-
- e->type = GG_EVENT_STATUS60;
- e->event.status60.uin = uin & 0x00ffffff;
- e->event.status60.status = s->status;
- e->event.status60.remote_ip = s->remote_ip;
- e->event.status60.remote_port = gg_fix16(s->remote_port);
- e->event.status60.version = s->version;
- e->event.status60.image_size = s->image_size;
- e->event.status60.descr = NULL;
- e->event.status60.time = 0;
-
- if (uin & 0x40000000)
- e->event.status60.version |= GG_HAS_AUDIO_MASK;
- if (uin & 0x08000000)
- e->event.status60.version |= GG_ERA_OMNIX_MASK;
-
- if (h->length > sizeof(*s)) {
- int len = h->length - sizeof(*s);
- char *buf = malloc(len + 1);
-
- if (buf) {
- memcpy(buf, (char*) p + sizeof(*s), len);
- buf[len] = 0;
- }
-
- e->event.status60.descr = buf;
-
- if (len > 4 && p[h->length - 5] == 0) {
- uint32_t t;
- memcpy(&t, p + h->length - 4, sizeof(uint32_t));
- e->event.status60.time = gg_fix32(t);
- }
- }
-
- break;
- }
-
- case GG_SEND_MSG_ACK:
- {
- struct gg_send_msg_ack *s = (void*) p;
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a message ack\n");
-
- if (h->length < sizeof(*s))
- break;
-
- e->type = GG_EVENT_ACK;
- e->event.ack.status = gg_fix32(s->status);
- e->event.ack.recipient = gg_fix32(s->recipient);
- e->event.ack.seq = gg_fix32(s->seq);
-
- break;
- }
-
- case GG_PONG:
- {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a pong\n");
-
- e->type = GG_EVENT_PONG;
- sess->last_pong = time(NULL);
-
- break;
- }
-
- case GG_DISCONNECTING:
- {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received disconnection warning\n");
- e->type = GG_EVENT_DISCONNECT;
- break;
- }
-
- case GG_PUBDIR50_REPLY:
- {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received pubdir/search reply\n");
- if (gg_pubdir50_handle_reply(e, p, h->length) == -1)
- goto fail;
- break;
- }
-
- case GG_USERLIST_REPLY:
- {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist reply\n");
-
- if (h->length < 1)
- break;
-
- /* je�li odpowied� na eksport, wywo�aj zdarzenie tylko
- * gdy otrzymano wszystkie odpowiedzi */
- if (p[0] == GG_USERLIST_PUT_REPLY || p[0] == GG_USERLIST_PUT_MORE_REPLY) {
- if (--sess->userlist_blocks)
- break;
-
- p[0] = GG_USERLIST_PUT_REPLY;
- }
-
- if (h->length > 1) {
- char *tmp;
- unsigned int len = (sess->userlist_reply) ? strlen(sess->userlist_reply) : 0;
-
- gg_debug(GG_DEBUG_MISC, "userlist_reply=%p, len=%d\n", sess->userlist_reply, len);
-
- if (!(tmp = realloc(sess->userlist_reply, len + h->length))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for userlist reply\n");
- free(sess->userlist_reply);
- sess->userlist_reply = NULL;
- goto fail;
- }
-
- sess->userlist_reply = tmp;
- sess->userlist_reply[len + h->length - 1] = 0;
- memcpy(sess->userlist_reply + len, p + 1, h->length - 1);
- }
-
- if (p[0] == GG_USERLIST_GET_MORE_REPLY)
- break;
-
- e->type = GG_EVENT_USERLIST;
- e->event.userlist.type = p[0];
- e->event.userlist.reply = sess->userlist_reply;
- sess->userlist_reply = NULL;
-
- break;
- }
-
- default:
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received unknown packet 0x%.2x\n", h->type);
- }
-
- free(h);
- return 0;
-
-fail:
- free(h);
- return -1;
-}
-
-/*
- * gg_watch_fd()
- *
- * funkcja, kt�r� nale�y wywo�a�, gdy co� si� stanie z obserwowanym
- * deskryptorem. zwraca klientowi informacj� o tym, co si� dzieje.
- *
- * - sess - opis sesji
- *
- * wska�nik do struktury gg_event, kt�r� trzeba zwolni� p��niej
- * za pomoc� gg_event_free(). jesli rodzaj zdarzenia jest r�wny
- * GG_EVENT_NONE, nale�y je zignorowa�. je�li zwr�ci�o NULL,
- * sta�o si� co� niedobrego -- albo zabrak�o pami�ci albo zerwa�o
- * po��czenie.
- */
-struct gg_event *gg_watch_fd(struct gg_session *sess)
-{
- struct gg_event *e;
- int res = 0;
- int port = 0;
- int errno2 = 0;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd(%p);\n", sess);
-
- if (!sess) {
- errno = EFAULT;
- return NULL;
- }
-
- if (!(e = (void*) calloc(1, sizeof(*e)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() not enough memory for event data\n");
- return NULL;
- }
-
- e->type = GG_EVENT_NONE;
-
- switch (sess->state) {
- case GG_STATE_RESOLVING:
- {
- struct in_addr addr;
- int failed = 0;
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_RESOLVING\n");
-
- if (read(sess->fd, &addr, sizeof(addr)) < (signed)sizeof(addr) || addr.s_addr == INADDR_NONE) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() resolving failed\n");
- failed = 1;
- errno2 = errno;
- }
-
- close(sess->fd);
- sess->fd = -1;
-
-#ifndef __GG_LIBGADU_HAVE_PTHREAD
- waitpid(sess->pid, NULL, 0);
- sess->pid = -1;
-#else
- if (sess->resolver) {
- pthread_cancel(*((pthread_t*) sess->resolver));
- free(sess->resolver);
- sess->resolver = NULL;
- }
-#endif
-
- if (failed) {
- errno = errno2;
- goto fail_resolving;
- }
-
- /* je�li jeste�my w resolverze i mamy ustawiony port
- * proxy, znaczy, �e resolvowali�my proxy. zatem
- * wpiszmy jego adres. */
- if (sess->proxy_port)
- sess->proxy_addr = addr.s_addr;
-
- /* zapiszmy sobie adres huba i adres serwera (do
- * bezpo�redniego po��czenia, je�li hub le�y)
- * z resolvera. */
- if (sess->proxy_addr && sess->proxy_port)
- port = sess->proxy_port;
- else {
- sess->server_addr = sess->hub_addr = addr.s_addr;
- port = GG_APPMSG_PORT;
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() resolved, connecting to %s:%d\n", inet_ntoa(addr), port);
-
- /* ��czymy si� albo z hubem, albo z proxy, zale�nie
- * od tego, co resolvowali�my. */
- if ((sess->fd = gg_connect(&addr, port, sess->async)) == -1) {
- /* je�li w trybie asynchronicznym gg_connect()
- * zwr�ci b��d, nie ma sensu pr�bowa� dalej. */
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), critical\n", errno, strerror(errno));
- goto fail_connecting;
- }
-
- /* je�li podano serwer i ��czmy si� przez proxy,
- * jest to bezpo�rednie po��czenie, inaczej jest
- * do huba. */
- sess->state = (sess->proxy_addr && sess->proxy_port && sess->server_addr) ? GG_STATE_CONNECTING_GG : GG_STATE_CONNECTING_HUB;
- sess->check = GG_CHECK_WRITE;
- sess->timeout = GG_DEFAULT_TIMEOUT;
-
- break;
- }
-
- case GG_STATE_CONNECTING_HUB:
- {
- char buf[1024], *client, *auth;
- int res = 0, res_size = sizeof(res);
- const char *host, *appmsg;
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTING_HUB\n");
-
- /* je�li asynchroniczne, sprawdzamy, czy nie wyst�pi�
- * przypadkiem jaki� b��d. */
- if (sess->async && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) {
- /* no tak, nie uda�o si� po��czy� z proxy. nawet
- * nie pr�bujemy dalej. */
- if (sess->proxy_addr && sess->proxy_port) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res));
- goto fail_connecting;
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to hub failed (errno=%d, %s), trying direct connection\n", res, strerror(res));
- close(sess->fd);
-
- if ((sess->fd = gg_connect(&sess->hub_addr, GG_DEFAULT_PORT, sess->async)) == -1) {
- /* przy asynchronicznych, gg_connect()
- * zwraca -1 przy b��dach socket(),
- * ioctl(), braku routingu itd. dlatego
- * nawet nie pr�bujemy dalej. */
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() direct connection failed (errno=%d, %s), critical\n", errno, strerror(errno));
- goto fail_connecting;
- }
-
- sess->state = GG_STATE_CONNECTING_GG;
- sess->check = GG_CHECK_WRITE;
- sess->timeout = GG_DEFAULT_TIMEOUT;
- break;
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connected to hub, sending query\n");
-
- if (!(client = gg_urlencode((sess->client_version) ? sess->client_version : GG_DEFAULT_CLIENT_VERSION))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() out of memory for client version\n");
- goto fail_connecting;
- }
-
- if (!gg_proxy_http_only && sess->proxy_addr && sess->proxy_port)
- host = "http://" GG_APPMSG_HOST;
- else
- host = "";
-
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
- if (sess->ssl)
- appmsg = "appmsg3.asp";
- else
-#endif
- appmsg = "appmsg2.asp";
-
- auth = gg_proxy_auth();
-
- snprintf(buf, sizeof(buf) - 1,
- "GET %s/appsvc/%s?fmnumber=%u&version=%s&lastmsg=%d HTTP/1.0\r\n"
- "Host: " GG_APPMSG_HOST "\r\n"
- "User-Agent: " GG_HTTP_USERAGENT "\r\n"
- "Pragma: no-cache\r\n"
- "%s"
- "\r\n", host, appmsg, sess->uin, client, sess->last_sysmsg, (auth) ? auth : "");
-
- if (auth)
- free(auth);
-
- free(client);
-
- /* zwolnij pami�� po wersji klienta. */
- if (sess->client_version) {
- free(sess->client_version);
- sess->client_version = NULL;
- }
-
- gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", buf);
-
- /* zapytanie jest kr�tkie, wi�c zawsze zmie�ci si�
- * do bufora gniazda. je�li write() zwr�ci mniej,
- * sta�o si� co� z�ego. */
- if (write(sess->fd, buf, strlen(buf)) < (signed)strlen(buf)) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() sending query failed\n");
-
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_WRITING;
- sess->state = GG_STATE_IDLE;
- close(sess->fd);
- sess->fd = -1;
- break;
- }
-
- sess->state = GG_STATE_READING_DATA;
- sess->check = GG_CHECK_READ;
- sess->timeout = GG_DEFAULT_TIMEOUT;
-
- break;
- }
-
- case GG_STATE_READING_DATA:
- {
- char buf[1024], *tmp, *host;
- int port = GG_DEFAULT_PORT;
- struct in_addr addr;
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_DATA\n");
-
- /* czytamy lini� z gniazda i obcinamy \r\n. */
- gg_read_line(sess->fd, buf, sizeof(buf) - 1);
- gg_chomp(buf);
- gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http header (%s)\n", buf);
-
- /* sprawdzamy, czy wszystko w porz�dku. */
- if (strncmp(buf, "HTTP/1.", 7) || strncmp(buf + 9, "200", 3)) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() that's not what we've expected, trying direct connection\n");
-
- close(sess->fd);
-
- /* je�li otrzymali�my jakie� dziwne informacje,
- * pr�bujemy si� ��czy� z pomini�ciem huba. */
- if (sess->proxy_addr && sess->proxy_port) {
- if ((sess->fd = gg_connect(&sess->proxy_addr, sess->proxy_port, sess->async)) == -1) {
- /* trudno. nie wysz�o. */
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail_connecting;
- }
-
- sess->state = GG_STATE_CONNECTING_GG;
- sess->check = GG_CHECK_WRITE;
- sess->timeout = GG_DEFAULT_TIMEOUT;
- break;
- }
-
- sess->port = GG_DEFAULT_PORT;
-
- /* ��czymy si� na port 8074 huba. */
- if ((sess->fd = gg_connect(&sess->hub_addr, sess->port, sess->async)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", errno, strerror(errno));
-
- sess->port = GG_HTTPS_PORT;
-
- /* ��czymy si� na port 443. */
- if ((sess->fd = gg_connect(&sess->hub_addr, sess->port, sess->async)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail_connecting;
- }
- }
-
- sess->state = GG_STATE_CONNECTING_GG;
- sess->check = GG_CHECK_WRITE;
- sess->timeout = GG_DEFAULT_TIMEOUT;
- break;
- }
-
- /* ignorujemy reszt� nag��wka. */
- while (strcmp(buf, "\r\n") && strcmp(buf, ""))
- gg_read_line(sess->fd, buf, sizeof(buf) - 1);
-
- /* czytamy pierwsz� lini� danych. */
- gg_read_line(sess->fd, buf, sizeof(buf) - 1);
- gg_chomp(buf);
-
- /* je�li pierwsza liczba w linii nie jest r�wna zeru,
- * oznacza to, �e mamy wiadomo�� systemow�. */
- if (atoi(buf)) {
- char tmp[1024], *foo, *sysmsg_buf = NULL;
- int len = 0;
-
- while (gg_read_line(sess->fd, tmp, sizeof(tmp) - 1)) {
- if (!(foo = realloc(sysmsg_buf, len + strlen(tmp) + 2))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() out of memory for system message, ignoring\n");
- break;
- }
-
- sysmsg_buf = foo;
-
- if (!len)
- strcpy(sysmsg_buf, tmp);
- else
- strcat(sysmsg_buf, tmp);
-
- len += strlen(tmp);
- }
-
- e->type = GG_EVENT_MSG;
- e->event.msg.msgclass = atoi(buf);
- e->event.msg.sender = 0;
- e->event.msg.message = sysmsg_buf;
- }
-
- close(sess->fd);
-
- gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http data (%s)\n", buf);
-
- /* analizujemy otrzymane dane. */
- tmp = buf;
-
- while (*tmp && *tmp != ' ')
- tmp++;
- while (*tmp && *tmp == ' ')
- tmp++;
- host = tmp;
- while (*tmp && *tmp != ' ')
- tmp++;
- *tmp = 0;
-
- if ((tmp = (char*)strchr(host, ':'))) {
- *tmp = 0;
- port = atoi(tmp + 1);
- }
-
- if (!strcmp(host, "notoperating")) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() service unavailable\n", errno, strerror(errno));
- sess->fd = -1;
- goto fail_unavailable;
- }
-
- addr.s_addr = inet_addr(host);
- sess->server_addr = addr.s_addr;
-
- if (!gg_proxy_http_only && sess->proxy_addr && sess->proxy_port) {
- /* je�li mamy proxy, ��czymy si� z nim. */
- if ((sess->fd = gg_connect(&sess->proxy_addr, sess->proxy_port, sess->async)) == -1) {
- /* nie wysz�o? trudno. */
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail_connecting;
- }
-
- sess->state = GG_STATE_CONNECTING_GG;
- sess->check = GG_CHECK_WRITE;
- sess->timeout = GG_DEFAULT_TIMEOUT;
- break;
- }
-
- sess->port = port;
-
- /* ��czymy si� z w�a�ciwym serwerem. */
- if ((sess->fd = gg_connect(&addr, sess->port, sess->async)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", errno, strerror(errno));
-
- sess->port = GG_HTTPS_PORT;
-
- /* nie wysz�o? pr�bujemy portu 443. */
- if ((sess->fd = gg_connect(&addr, GG_HTTPS_PORT, sess->async)) == -1) {
- /* ostatnia deska ratunku zawiod�a?
- * w takim razie zwijamy manatki. */
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail_connecting;
- }
- }
-
- sess->state = GG_STATE_CONNECTING_GG;
- sess->check = GG_CHECK_WRITE;
- sess->timeout = GG_DEFAULT_TIMEOUT;
-
- break;
- }
-
- case GG_STATE_CONNECTING_GG:
- {
- int res = 0, res_size = sizeof(res);
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTING_GG\n");
-
- /* je�li wyst�pi� b��d podczas ��czenia si�... */
- if (sess->async && (sess->timeout == 0 || getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) {
- /* je�li nie uda�o si� po��czenie z proxy,
- * nie mamy czego pr�bowa� wi�cej. */
- if (sess->proxy_addr && sess->proxy_port) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res));
- goto fail_connecting;
- }
-
- close(sess->fd);
- sess->fd = -1;
-
-#ifdef ETIMEDOUT
- if (sess->timeout == 0)
- errno = ETIMEDOUT;
-#endif
-
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
- /* je�li logujemy si� po TLS, nie pr�bujemy
- * si� ��czy� ju� z niczym innym w przypadku
- * b��du. nie do��, �e nie ma sensu, to i
- * trzeba by si� bawi� w tworzenie na nowo
- * SSL i SSL_CTX. */
-
- if (sess->ssl) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", res, strerror(res));
- goto fail_connecting;
- }
-#endif
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", res, strerror(res));
-
- sess->port = GG_HTTPS_PORT;
-
- /* pr�bujemy na port 443. */
- if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail_connecting;
- }
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connected\n");
-
- if (gg_proxy_http_only)
- sess->proxy_port = 0;
-
- /* je�li mamy proxy, wy�lijmy zapytanie. */
- if (sess->proxy_addr && sess->proxy_port) {
- char buf[100], *auth = gg_proxy_auth();
- struct in_addr addr;
-
- if (sess->server_addr)
- addr.s_addr = sess->server_addr;
- else
- addr.s_addr = sess->hub_addr;
-
- snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n", inet_ntoa(addr), sess->port);
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() proxy request:\n// %s", buf);
-
- /* wysy�amy zapytanie. jest ono na tyle kr�tkie,
- * �e musi si� zmie�ci� w buforze gniazda. je�li
- * write() zawiedzie, sta�o si� co� z�ego. */
- if (write(sess->fd, buf, strlen(buf)) < (signed)strlen(buf)) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
- if (auth)
- free(auth);
- goto fail_connecting;
- }
-
- if (auth) {
- gg_debug(GG_DEBUG_MISC, "// %s", auth);
- if (write(sess->fd, auth, strlen(auth)) < (signed)strlen(auth)) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
- free(auth);
- goto fail_connecting;
- }
-
- free(auth);
- }
-
- if (write(sess->fd, "\r\n", 2) < 2) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
- goto fail_connecting;
- }
- }
-
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
- if (sess->ssl) {
- SSL_set_fd(sess->ssl, sess->fd);
-
- sess->state = GG_STATE_TLS_NEGOTIATION;
- sess->check = GG_CHECK_WRITE;
- sess->timeout = GG_DEFAULT_TIMEOUT;
-
- break;
- }
-#endif
-
- sess->state = GG_STATE_READING_KEY;
- sess->check = GG_CHECK_READ;
- sess->timeout = GG_DEFAULT_TIMEOUT;
-
- break;
- }
-
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
- case GG_STATE_TLS_NEGOTIATION:
- {
- int res;
- X509 *peer;
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_TLS_NEGOTIATION\n");
-
- if ((res = SSL_connect(sess->ssl)) <= 0) {
- int err = SSL_get_error(sess->ssl, res);
-
- if (res == 0) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() disconnected during TLS negotiation\n");
-
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_TLS;
- sess->state = GG_STATE_IDLE;
- close(sess->fd);
- sess->fd = -1;
- break;
- }
-
- if (err == SSL_ERROR_WANT_READ) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to read\n");
-
- sess->state = GG_STATE_TLS_NEGOTIATION;
- sess->check = GG_CHECK_READ;
- sess->timeout = GG_DEFAULT_TIMEOUT;
-
- break;
- } else if (err == SSL_ERROR_WANT_WRITE) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to write\n");
-
- sess->state = GG_STATE_TLS_NEGOTIATION;
- sess->check = GG_CHECK_WRITE;
- sess->timeout = GG_DEFAULT_TIMEOUT;
-
- break;
- } else {
- char buf[1024];
-
- ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() bailed out: %s\n", buf);
-
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_TLS;
- sess->state = GG_STATE_IDLE;
- close(sess->fd);
- sess->fd = -1;
- break;
- }
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() TLS negotiation succeded:\n// cipher: %s\n", SSL_get_cipher_name(sess->ssl));
-
- peer = SSL_get_peer_certificate(sess->ssl);
-
- if (!peer)
- gg_debug(GG_DEBUG_MISC, "// WARNING! unable to get peer certificate!\n");
- else {
- char buf[1024];
-
- X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof(buf));
- gg_debug(GG_DEBUG_MISC, "// cert subject: %s\n", buf);
-
- X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof(buf));
- gg_debug(GG_DEBUG_MISC, "// cert issuer: %s\n", buf);
- }
-
- sess->state = GG_STATE_READING_KEY;
- sess->check = GG_CHECK_READ;
- sess->timeout = GG_DEFAULT_TIMEOUT;
-
- break;
- }
-#endif
-
- case GG_STATE_READING_KEY:
- {
- struct gg_header *h;
- struct gg_welcome *w;
- struct gg_login60 l;
- unsigned int hash;
- unsigned char *password = sess->password;
- int ret;
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_KEY\n");
-
- memset(&l, 0, sizeof(l));
- l.dunno2 = 0xbe;
-
- /* XXX bardzo, bardzo, bardzo g�upi pomys� na pozbycie
- * si� tekstu wrzucanego przez proxy. */
- if (sess->proxy_addr && sess->proxy_port) {
- char buf[100];
-
- strcpy(buf, "");
- gg_read_line(sess->fd, buf, sizeof(buf) - 1);
- gg_chomp(buf);
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() proxy response:\n// %s\n", buf);
-
- while (strcmp(buf, "")) {
- gg_read_line(sess->fd, buf, sizeof(buf) - 1);
- gg_chomp(buf);
- if (strcmp(buf, ""))
- gg_debug(GG_DEBUG_MISC, "// %s\n", buf);
- }
-
- /* XXX niech czeka jeszcze raz w tej samej
- * fazie. g�upio, ale dzia�a. */
- sess->proxy_port = 0;
-
- break;
- }
-
- /* czytaj pierwszy pakiet. */
- if (!(h = gg_recv_packet(sess))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() didn't receive packet (errno=%d, %s)\n", errno, strerror(errno));
-
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_READING;
- sess->state = GG_STATE_IDLE;
- errno2 = errno;
- close(sess->fd);
- errno = errno2;
- sess->fd = -1;
- break;
- }
-
- if (h->type != GG_WELCOME) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() invalid packet received\n");
- free(h);
- close(sess->fd);
- sess->fd = -1;
- errno = EINVAL;
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_INVALID;
- sess->state = GG_STATE_IDLE;
- break;
- }
-
- w = (struct gg_welcome*) ((char*) h + sizeof(struct gg_header));
- w->key = gg_fix32(w->key);
-
- hash = gg_login_hash(password, w->key);
-
- gg_debug(GG_DEBUG_DUMP, "// gg_watch_fd() challenge %.4x --> hash %.8x\n", w->key, hash);
-
- free(h);
-
- free(sess->password);
- sess->password = NULL;
-
- {
- struct in_addr dcc_ip;
- dcc_ip.s_addr = gg_dcc_ip;
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() gg_dcc_ip = %s\n", inet_ntoa(dcc_ip));
- }
-
- if (gg_dcc_ip == (unsigned long) inet_addr("255.255.255.255")) {
- struct sockaddr_in sin;
- int sin_len = sizeof(sin);
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() detecting address\n");
-
- if (!getsockname(sess->fd, (struct sockaddr*) &sin, &sin_len)) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr));
- l.local_ip = sin.sin_addr.s_addr;
- } else {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n");
- l.local_ip = 0;
- }
- } else
- l.local_ip = gg_dcc_ip;
-
- l.uin = gg_fix32(sess->uin);
- l.hash = gg_fix32(hash);
- l.status = gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL);
- l.version = gg_fix32(sess->protocol_version);
- l.local_port = gg_fix16(gg_dcc_port);
- l.image_size = sess->image_size;
-
- if (sess->external_addr && sess->external_port > 1023) {
- l.external_ip = sess->external_addr;
- l.external_port = gg_fix16(sess->external_port);
- }
-
- gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending GG_LOGIN60 packet\n");
- ret = gg_send_packet(sess, GG_LOGIN60, &l, sizeof(l), sess->initial_descr, (sess->initial_descr) ? strlen(sess->initial_descr) : 0, NULL);
-
- free(sess->initial_descr);
- sess->initial_descr = NULL;
-
- if (ret == -1) {
- gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno));
- errno2 = errno;
- close(sess->fd);
- errno = errno2;
- sess->fd = -1;
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_WRITING;
- sess->state = GG_STATE_IDLE;
- break;
- }
-
- sess->state = GG_STATE_READING_REPLY;
-
- break;
- }
-
- case GG_STATE_READING_REPLY:
- {
- struct gg_header *h;
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_REPLY\n");
-
- if (!(h = gg_recv_packet(sess))) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() didn't receive packet (errno=%d, %s)\n", errno, strerror(errno));
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_READING;
- sess->state = GG_STATE_IDLE;
- errno2 = errno;
- close(sess->fd);
- errno = errno2;
- sess->fd = -1;
- break;
- }
-
- if (h->type == GG_LOGIN_OK || h->type == GG_NEED_EMAIL) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n");
- e->type = GG_EVENT_CONN_SUCCESS;
- sess->state = GG_STATE_CONNECTED;
- sess->timeout = -1;
- sess->status = (sess->initial_status) ? sess->initial_status : GG_STATUS_AVAIL;
- free(h);
- break;
- }
-
- if (h->type == GG_LOGIN_FAILED) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() login failed\n");
- e->event.failure = GG_FAILURE_PASSWORD;
- errno = EACCES;
- } else if (h->type == GG_DISCONNECTING) {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() too many incorrect password attempts\n");
- e->event.failure = GG_FAILURE_INTRUDER;
- errno = EACCES;
- } else {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() invalid packet\n");
- e->event.failure = GG_FAILURE_INVALID;
- errno = EINVAL;
- }
-
- e->type = GG_EVENT_CONN_FAILED;
- sess->state = GG_STATE_IDLE;
- errno2 = errno;
- close(sess->fd);
- errno = errno2;
- sess->fd = -1;
- free(h);
-
- break;
- }
-
- case GG_STATE_CONNECTED:
- {
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTED\n");
-
- sess->last_event = time(NULL);
-
- if ((res = gg_watch_fd_connected(sess, e)) == -1) {
-
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() watch_fd_connected failed (errno=%d, %s)\n", errno, strerror(errno));
-
- if (errno == EAGAIN) {
- e->type = GG_EVENT_NONE;
- res = 0;
- } else
- res = -1;
- }
- break;
- }
- }
-
-done:
- if (res == -1) {
- free(e);
- e = NULL;
- }
-
- return e;
-
-fail_connecting:
- if (sess->fd != -1) {
- errno2 = errno;
- close(sess->fd);
- errno = errno2;
- sess->fd = -1;
- }
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_CONNECTING;
- sess->state = GG_STATE_IDLE;
- goto done;
-
-fail_resolving:
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_RESOLVING;
- sess->state = GG_STATE_IDLE;
- goto done;
-
-fail_unavailable:
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_UNAVAILABLE;
- sess->state = GG_STATE_IDLE;
- goto done;
-}
-
-/*
- * Local variables:
- * c-indentation-style: k&r
- * c-basic-offset: 8
- * indent-tabs-mode: notnil
- * End:
- *
- * vim: shiftwidth=8:
- */
diff --git a/kopete/protocols/gadu/libgadu/http.c b/kopete/protocols/gadu/libgadu/http.c
deleted file mode 100644
index 9f7369c5..00000000
--- a/kopete/protocols/gadu/libgadu/http.c
+++ /dev/null
@@ -1,522 +0,0 @@
-/* $Id$ */
-
-/*
- * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License Version
- * 2.1 as published by the Free Software Foundation.
- *
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "libgadu-config.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <netdb.h>
-#ifdef __GG_LIBGADU_HAVE_PTHREAD
-# include <pthread.h>
-#endif
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "compat.h"
-#include "libgadu.h"
-
-/*
- * gg_http_connect() // funkcja pomocnicza
- *
- * rozpoczyna po��czenie po http.
- *
- * - hostname - adres serwera
- * - port - port serwera
- * - async - asynchroniczne po��czenie
- * - method - metoda http (GET, POST, cokolwiek)
- * - path - �cie�ka do zasobu (musi by� poprzedzona ,,/'')
- * - header - nag��wek zapytania plus ewentualne dane dla POST
- *
- * zaalokowana struct gg_http, kt�r� po�niej nale�y
- * zwolni� funkcj� gg_http_free(), albo NULL je�li wyst�pi� b��d.
- */
-struct gg_http *gg_http_connect(const char *hostname, int port, int async, const char *method, const char *path, const char *header)
-{
- struct gg_http *h;
-
- if (!hostname || !port || !method || !path || !header) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() invalid arguments\n");
- errno = EFAULT;
- return NULL;
- }
-
- if (!(h = malloc(sizeof(*h))))
- return NULL;
- memset(h, 0, sizeof(*h));
-
- h->async = async;
- h->port = port;
- h->fd = -1;
- h->type = GG_SESSION_HTTP;
-
- if (gg_proxy_enabled) {
- char *auth = gg_proxy_auth();
-
- h->query = gg_saprintf("%s http://%s:%d%s HTTP/1.0\r\n%s%s",
- method, hostname, port, path, (auth) ? auth :
- "", header);
- hostname = gg_proxy_host;
- h->port = port = gg_proxy_port;
-
- if (auth)
- free(auth);
- } else {
- h->query = gg_saprintf("%s %s HTTP/1.0\r\n%s",
- method, path, header);
- }
-
- if (!h->query) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() not enough memory for query\n");
- free(h);
- errno = ENOMEM;
- return NULL;
- }
-
- gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", h->query);
-
- if (async) {
-#ifndef __GG_LIBGADU_HAVE_PTHREAD
- if (gg_resolve(&h->fd, &h->pid, hostname)) {
-#else
- if (gg_resolve_pthread(&h->fd, &h->resolver, hostname)) {
-#endif
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver failed\n");
- gg_http_free(h);
- errno = ENOENT;
- return NULL;
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver = %p\n", h->resolver);
-
- h->state = GG_STATE_RESOLVING;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
- } else {
- struct in_addr *hn, a;
-
- if (!(hn = gg_gethostbyname(hostname))) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() host not found\n");
- gg_http_free(h);
- errno = ENOENT;
- return NULL;
- } else {
- a.s_addr = hn->s_addr;
- free(hn);
- }
-
- if (!(h->fd = gg_connect(&a, port, 0)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno));
- gg_http_free(h);
- return NULL;
- }
-
- h->state = GG_STATE_CONNECTING;
-
- while (h->state != GG_STATE_ERROR && h->state != GG_STATE_PARSING) {
- if (gg_http_watch_fd(h) == -1)
- break;
- }
-
- if (h->state != GG_STATE_PARSING) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() some strange error\n");
- gg_http_free(h);
- return NULL;
- }
- }
-
- h->callback = gg_http_watch_fd;
- h->destroy = gg_http_free;
-
- return h;
-}
-
-#define gg_http_error(x) \
- close(h->fd); \
- h->fd = -1; \
- h->state = GG_STATE_ERROR; \
- h->error = x; \
- return 0;
-
-/*
- * gg_http_watch_fd()
- *
- * przy asynchronicznej obs�udze HTTP funkcj� t� nale�y wywo�a�, je�li
- * zmieni�o si� co� na obserwowanym deskryptorze.
- *
- * - h - struktura opisuj�ca po��czenie
- *
- * je�li wszystko posz�o dobrze to 0, inaczej -1. po��czenie b�dzie
- * zako�czone, je�li h->state == GG_STATE_PARSING. je�li wyst�pi jaki�
- * b��d, to b�dzie tam GG_STATE_ERROR i odpowiedni kod b��du w h->error.
- */
-int gg_http_watch_fd(struct gg_http *h)
-{
- gg_debug(GG_DEBUG_FUNCTION, "** gg_http_watch_fd(%p);\n", h);
-
- if (!h) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_watch_fd() invalid arguments\n");
- errno = EFAULT;
- return -1;
- }
-
- if (h->state == GG_STATE_RESOLVING) {
- struct in_addr a;
-
- gg_debug(GG_DEBUG_MISC, "=> http, resolving done\n");
-
- if (read(h->fd, &a, sizeof(a)) < (signed)sizeof(a) || a.s_addr == INADDR_NONE) {
- gg_debug(GG_DEBUG_MISC, "=> http, resolver thread failed\n");
- gg_http_error(GG_ERROR_RESOLVING);
- }
-
- close(h->fd);
- h->fd = -1;
-
-#ifndef __GG_LIBGADU_HAVE_PTHREAD
- waitpid(h->pid, NULL, 0);
-#else
- if (h->resolver) {
- pthread_cancel(*((pthread_t *) h->resolver));
- free(h->resolver);
- h->resolver = NULL;
- }
-#endif
-
- gg_debug(GG_DEBUG_MISC, "=> http, connecting to %s:%d\n", inet_ntoa(a), h->port);
-
- if ((h->fd = gg_connect(&a, h->port, h->async)) == -1) {
- gg_debug(GG_DEBUG_MISC, "=> http, connection failed (errno=%d, %s)\n", errno, strerror(errno));
- gg_http_error(GG_ERROR_CONNECTING);
- }
-
- h->state = GG_STATE_CONNECTING;
- h->check = GG_CHECK_WRITE;
- h->timeout = GG_DEFAULT_TIMEOUT;
-
- return 0;
- }
-
- if (h->state == GG_STATE_CONNECTING) {
- int res = 0;
- unsigned int res_size = sizeof(res);
-
- if (h->async && (getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) {
- gg_debug(GG_DEBUG_MISC, "=> http, async connection failed (errno=%d, %s)\n", (res) ? res : errno , strerror((res) ? res : errno));
- close(h->fd);
- h->fd = -1;
- h->state = GG_STATE_ERROR;
- h->error = GG_ERROR_CONNECTING;
- if (res)
- errno = res;
- return 0;
- }
-
- gg_debug(GG_DEBUG_MISC, "=> http, connected, sending request\n");
-
- h->state = GG_STATE_SENDING_QUERY;
- }
-
- if (h->state == GG_STATE_SENDING_QUERY) {
- int res;
-
- if ((res = write(h->fd, h->query, strlen(h->query))) < 1) {
- gg_debug(GG_DEBUG_MISC, "=> http, write() failed (len=%d, res=%d, errno=%d)\n", strlen(h->query), res, errno);
- gg_http_error(GG_ERROR_WRITING);
- }
-
- if (res < strlen(h->query)) {
- gg_debug(GG_DEBUG_MISC, "=> http, partial header sent (led=%d, sent=%d)\n", strlen(h->query), res);
-
- memmove(h->query, h->query + res, strlen(h->query) - res + 1);
- h->state = GG_STATE_SENDING_QUERY;
- h->check = GG_CHECK_WRITE;
- h->timeout = GG_DEFAULT_TIMEOUT;
- } else {
- gg_debug(GG_DEBUG_MISC, "=> http, request sent (len=%d)\n", strlen(h->query));
- free(h->query);
- h->query = NULL;
-
- h->state = GG_STATE_READING_HEADER;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
- }
-
- return 0;
- }
-
- if (h->state == GG_STATE_READING_HEADER) {
- char buf[1024], *tmp;
- int res;
-
- if ((res = read(h->fd, buf, sizeof(buf))) == -1) {
- gg_debug(GG_DEBUG_MISC, "=> http, reading header failed (errno=%d)\n", errno);
- if (h->header) {
- free(h->header);
- h->header = NULL;
- }
- gg_http_error(GG_ERROR_READING);
- }
-
- if (!res) {
- gg_debug(GG_DEBUG_MISC, "=> http, connection reset by peer\n");
- if (h->header) {
- free(h->header);
- h->header = NULL;
- }
- gg_http_error(GG_ERROR_READING);
- }
-
- gg_debug(GG_DEBUG_MISC, "=> http, read %d bytes of header\n", res);
-
- if (!(tmp = realloc(h->header, h->header_size + res + 1))) {
- gg_debug(GG_DEBUG_MISC, "=> http, not enough memory for header\n");
- free(h->header);
- h->header = NULL;
- gg_http_error(GG_ERROR_READING);
- }
-
- h->header = tmp;
-
- memcpy(h->header + h->header_size, buf, res);
- h->header_size += res;
-
- gg_debug(GG_DEBUG_MISC, "=> http, header_buf=%p, header_size=%d\n", h->header, h->header_size);
-
- h->header[h->header_size] = 0;
-
- if ((tmp = strstr(h->header, "\r\n\r\n")) || (tmp = strstr(h->header, "\n\n"))) {
- int sep_len = (*tmp == '\r') ? 4 : 2;
- unsigned int left;
- char *line;
-
- left = h->header_size - ((long)(tmp) - (long)(h->header) + sep_len);
-
- gg_debug(GG_DEBUG_MISC, "=> http, got all header (%d bytes, %d left)\n", h->header_size - left, left);
-
- /* HTTP/1.1 200 OK */
- if (strlen(h->header) < 16 || strncmp(h->header + 9, "200", 3)) {
- gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header);
-
- gg_debug(GG_DEBUG_MISC, "=> http, didn't get 200 OK -- no results\n");
- free(h->header);
- h->header = NULL;
- gg_http_error(GG_ERROR_CONNECTING);
- }
-
- h->body_size = 0;
- line = h->header;
- *tmp = 0;
-
- gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header);
-
- while (line) {
- if (!strncasecmp(line, "Content-length: ", 16)) {
- h->body_size = atoi(line + 16);
- }
- line = (char*)strchr(line, '\n');
- if (line)
- line++;
- }
-
- if (h->body_size <= 0) {
- gg_debug(GG_DEBUG_MISC, "=> http, content-length not found\n");
- h->body_size = left;
- }
-
- if (left > h->body_size) {
- gg_debug(GG_DEBUG_MISC, "=> http, oversized reply (%d bytes needed, %d bytes left)\n", h->body_size, left);
- h->body_size = left;
- }
-
- gg_debug(GG_DEBUG_MISC, "=> http, body_size=%d\n", h->body_size);
-
- if (!(h->body = malloc(h->body_size + 1))) {
- gg_debug(GG_DEBUG_MISC, "=> http, not enough memory (%d bytes for body_buf)\n", h->body_size + 1);
- free(h->header);
- h->header = NULL;
- gg_http_error(GG_ERROR_READING);
- }
-
- if (left) {
- memcpy(h->body, tmp + sep_len, left);
- h->body_done = left;
- }
-
- h->body[left] = 0;
-
- h->state = GG_STATE_READING_DATA;
- h->check = GG_CHECK_READ;
- h->timeout = GG_DEFAULT_TIMEOUT;
- }
-
- return 0;
- }
-
- if (h->state == GG_STATE_READING_DATA) {
- char buf[1024];
- int res;
-
- if ((res = read(h->fd, buf, sizeof(buf))) == -1) {
- gg_debug(GG_DEBUG_MISC, "=> http, reading body failed (errno=%d)\n", errno);
- if (h->body) {
- free(h->body);
- h->body = NULL;
- }
- gg_http_error(GG_ERROR_READING);
- }
-
- if (!res) {
- if (h->body_done >= h->body_size) {
- gg_debug(GG_DEBUG_MISC, "=> http, we're done, closing socket\n");
- h->state = GG_STATE_PARSING;
- close(h->fd);
- h->fd = -1;
- } else {
- gg_debug(GG_DEBUG_MISC, "=> http, connection closed while reading (have %d, need %d)\n", h->body_done, h->body_size);
- if (h->body) {
- free(h->body);
- h->body = NULL;
- }
- gg_http_error(GG_ERROR_READING);
- }
-
- return 0;
- }
-
- gg_debug(GG_DEBUG_MISC, "=> http, read %d bytes of body\n", res);
-
- if (h->body_done + res > h->body_size) {
- char *tmp;
-
- gg_debug(GG_DEBUG_MISC, "=> http, too much data (%d bytes, %d needed), enlarging buffer\n", h->body_done + res, h->body_size);
-
- if (!(tmp = realloc(h->body, h->body_done + res + 1))) {
- gg_debug(GG_DEBUG_MISC, "=> http, not enough memory for data (%d needed)\n", h->body_done + res + 1);
- free(h->body);
- h->body = NULL;
- gg_http_error(GG_ERROR_READING);
- }
-
- h->body = tmp;
- h->body_size = h->body_done + res;
- }
-
- h->body[h->body_done + res] = 0;
- memcpy(h->body + h->body_done, buf, res);
- h->body_done += res;
-
- gg_debug(GG_DEBUG_MISC, "=> body_done=%d, body_size=%d\n", h->body_done, h->body_size);
-
- return 0;
- }
-
- if (h->fd != -1)
- close(h->fd);
-
- h->fd = -1;
- h->state = GG_STATE_ERROR;
- h->error = 0;
-
- return -1;
-}
-
-#undef gg_http_error
-
-/*
- * gg_http_stop()
- *
- * je�li po��czenie jest w trakcie, przerywa je. nie zwalnia h->data.
- *
- * - h - struktura opisuj�ca po��czenie
- */
-void gg_http_stop(struct gg_http *h)
-{
- if (!h)
- return;
-
- if (h->state == GG_STATE_ERROR || h->state == GG_STATE_DONE)
- return;
-
- if (h->fd != -1)
- close(h->fd);
- h->fd = -1;
-}
-
-/*
- * gg_http_free_fields() // funkcja wewn�trzna
- *
- * zwalnia pola struct gg_http, ale nie zwalnia samej struktury.
- */
-void gg_http_free_fields(struct gg_http *h)
-{
- if (!h)
- return;
-
- if (h->body) {
- free(h->body);
- h->body = NULL;
- }
-
- if (h->query) {
- free(h->query);
- h->query = NULL;
- }
-
- if (h->header) {
- free(h->header);
- h->header = NULL;
- }
-}
-
-/*
- * gg_http_free()
- *
- * pr�buje zamkn�� po��czenie i zwalnia pami�� po nim.
- *
- * - h - struktura, kt�r� nale�y zlikwidowa�
- */
-void gg_http_free(struct gg_http *h)
-{
- if (!h)
- return;
-
- gg_http_stop(h);
- gg_http_free_fields(h);
- free(h);
-}
-
-/*
- * Local variables:
- * c-indentation-style: k&r
- * c-basic-offset: 8
- * indent-tabs-mode: notnil
- * End:
- *
- * vim: shiftwidth=8:
- */
diff --git a/kopete/protocols/gadu/libgadu/libgadu-config.h.in b/kopete/protocols/gadu/libgadu/libgadu-config.h.in
deleted file mode 100644
index dc4fb435..00000000
--- a/kopete/protocols/gadu/libgadu/libgadu-config.h.in
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Local libgadu configuration. */
-
-#ifndef __GG_LIBGADU_CONFIG_H
-#define __GG_LIBGADU_CONFIG_H
-
-/* Defined if libgadu was compiled for bigendian machine. */
-#undef __GG_LIBGADU_BIGENDIAN
-
-/* Defined if libgadu was compiled and linked with pthread support. */
-#define __GG_LIBGADU_HAVE_PTHREAD
-
-/* Defined if this machine has C99-compiliant vsnprintf(). */
-#undef __GG_LIBGADU_HAVE_C99_VSNPRINTF
-
-/* Defined if this machine has va_copy(). */
-#undef __GG_LIBGADU_HAVE_VA_COPY
-
-/* Defined if this machine has __va_copy(). */
-#undef __GG_LIBGADU_HAVE___VA_COPY
-
-/* Defined if this machine supports long long. */
-#undef __GG_LIBGADU_HAVE_LONG_LONG
-
-/* Defined if libgadu was compiled and linked with TLS support. */
-#undef __GG_LIBGADU_HAVE_OPENSSL
-
-/* Include file containing uintXX_t declarations. */
-#include <inttypes.h>
-
-#endif /* __GG_LIBGADU_CONFIG_H */
diff --git a/kopete/protocols/gadu/libgadu/libgadu.c b/kopete/protocols/gadu/libgadu/libgadu.c
deleted file mode 100644
index 79f0a170..00000000
--- a/kopete/protocols/gadu/libgadu/libgadu.c
+++ /dev/null
@@ -1,1818 +0,0 @@
-/* $Id$ */
-
-/*
- * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl>
- * Robert J. Wo¼ny <speedy@ziew.org>
- * Arkadiusz Mi¶kiewicz <arekm@pld-linux.org>
- * Tomasz Chiliñski <chilek@chilan.com>
- * Adam Wysocki <gophi@ekg.chmurka.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License Version
- * 2.1 as published by the Free Software Foundation.
- *
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifdef sun
-# include <sys/filio.h>
-#endif
-
-#include "libgadu-config.h"
-
-#include <errno.h>
-#include <netdb.h>
-#ifdef __GG_LIBGADU_HAVE_PTHREAD
-# include <pthread.h>
-#endif
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <unistd.h>
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
-# include <openssl/err.h>
-# include <openssl/rand.h>
-#endif
-
-#include "compat.h"
-#include "libgadu.h"
-
-int gg_debug_level = 0;
-void (*gg_debug_handler)(int level, const char *format, va_list ap) = NULL;
-
-int gg_dcc_port = 0;
-unsigned long gg_dcc_ip = 0;
-
-unsigned long gg_local_ip = 0;
-/*
- * zmienne opisuj±ce parametry proxy http.
- */
-char *gg_proxy_host = NULL;
-int gg_proxy_port = 0;
-int gg_proxy_enabled = 0;
-int gg_proxy_http_only = 0;
-char *gg_proxy_username = NULL;
-char *gg_proxy_password = NULL;
-
-#ifndef lint
-static char rcsid[]
-#ifdef __GNUC__
-__attribute__ ((unused))
-#endif
-= "$Id$";
-#endif
-
-/*
- * gg_libgadu_version()
- *
- * zwraca wersjê libgadu.
- *
- * - brak
- *
- * wersja libgadu.
- */
-const char *gg_libgadu_version()
-{
- return GG_LIBGADU_VERSION;
-}
-
-/*
- * gg_fix32()
- *
- * zamienia kolejno¶æ bajtów w liczbie 32-bitowej tak, by odpowiada³a
- * kolejno¶ci bajtów w protokole GG. ze wzglêdu na LE-owo¶æ serwera,
- * zamienia tylko na maszynach BE-wych.
- *
- * - x - liczba do zamiany
- *
- * liczba z odpowiedni± kolejno¶ci± bajtów.
- */
-uint32_t gg_fix32(uint32_t x)
-{
-#ifndef __GG_LIBGADU_BIGENDIAN
- return x;
-#else
- return (uint32_t)
- (((x & (uint32_t) 0x000000ffU) << 24) |
- ((x & (uint32_t) 0x0000ff00U) << 8) |
- ((x & (uint32_t) 0x00ff0000U) >> 8) |
- ((x & (uint32_t) 0xff000000U) >> 24));
-#endif
-}
-
-/*
- * gg_fix16()
- *
- * zamienia kolejno¶æ bajtów w liczbie 16-bitowej tak, by odpowiada³a
- * kolejno¶ci bajtów w protokole GG. ze wzglêdu na LE-owo¶æ serwera,
- * zamienia tylko na maszynach BE-wych.
- *
- * - x - liczba do zamiany
- *
- * liczba z odpowiedni± kolejno¶ci± bajtów.
- */
-uint16_t gg_fix16(uint16_t x)
-{
-#ifndef __GG_LIBGADU_BIGENDIAN
- return x;
-#else
- return (uint16_t)
- (((x & (uint16_t) 0x00ffU) << 8) |
- ((x & (uint16_t) 0xff00U) >> 8));
-#endif
-}
-
-/*
- * gg_login_hash() // funkcja wewnêtrzna
- *
- * liczy hash z has³a i danego seeda.
- *
- * - password - has³o do hashowania
- * - seed - warto¶æ podana przez serwer
- *
- * hash.
- */
-unsigned int gg_login_hash(const unsigned char *password, unsigned int seed)
-{
- unsigned int x, y, z;
-
- y = seed;
-
- for (x = 0; *password; password++) {
- x = (x & 0xffffff00) | *password;
- y ^= x;
- y += x;
- x <<= 8;
- y ^= x;
- x <<= 8;
- y -= x;
- x <<= 8;
- y ^= x;
-
- z = y & 0x1F;
- y = (y << z) | (y >> (32 - z));
- }
-
- return y;
-}
-
-/*
- * gg_resolve() // funkcja wewnêtrzna
- *
- * tworzy potok, forkuje siê i w drugim procesie zaczyna resolvowaæ
- * podanego hosta. zapisuje w sesji deskryptor potoku. je¶li co¶ tam
- * bêdzie gotowego, znaczy, ¿e mo¿na wczytaæ struct in_addr. je¶li
- * nie znajdzie, zwraca INADDR_NONE.
- *
- * - fd - wska¼nik gdzie wrzuciæ deskryptor
- * - pid - gdzie wrzuciæ pid procesu potomnego
- * - hostname - nazwa hosta do zresolvowania
- *
- * 0, -1.
- */
-int gg_resolve(int *fd, int *pid, const char *hostname)
-{
- int pipes[2], res;
- struct in_addr a;
- int errno2;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve(%p, %p, \"%s\");\n", fd, pid, hostname);
-
- if (!fd || !pid) {
- errno = EFAULT;
- return -1;
- }
-
- if (pipe(pipes) == -1)
- return -1;
-
- if ((res = fork()) == -1) {
- errno2 = errno;
- close(pipes[0]);
- close(pipes[1]);
- errno = errno2;
- return -1;
- }
-
- if (!res) {
- close(pipes[0]);
-
- if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) {
- struct in_addr *hn;
-
- if (!(hn = gg_gethostbyname(hostname)))
- a.s_addr = INADDR_NONE;
- else {
- a.s_addr = hn->s_addr;
- free(hn);
- }
- }
-
- write(pipes[1], &a, sizeof(a));
-
- exit(0);
- }
-
- close(pipes[1]);
-
- *fd = pipes[0];
- *pid = res;
-
- return 0;
-}
-
-#ifdef __GG_LIBGADU_HAVE_PTHREAD
-
-struct gg_resolve_pthread_data {
- char *hostname;
- int fd;
-};
-
-static void *gg_resolve_pthread_thread(void *arg)
-{
- struct gg_resolve_pthread_data *d = arg;
- struct in_addr a;
-
- pthread_detach(pthread_self());
-
- if ((a.s_addr = inet_addr(d->hostname)) == INADDR_NONE) {
- struct in_addr *hn;
-
- if (!(hn = gg_gethostbyname(d->hostname)))
- a.s_addr = INADDR_NONE;
- else {
- a.s_addr = hn->s_addr;
- free(hn);
- }
- }
-
- write(d->fd, &a, sizeof(a));
- close(d->fd);
-
- free(d->hostname);
- d->hostname = NULL;
-
- free(d);
-
- pthread_exit(NULL);
-
- return NULL; /* ¿eby kompilator nie marudzi³ */
-}
-
-/*
- * gg_resolve_pthread() // funkcja wewnêtrzna
- *
- * tworzy potok, nowy w±tek i w nim zaczyna resolvowaæ podanego hosta.
- * zapisuje w sesji deskryptor potoku. je¶li co¶ tam bêdzie gotowego,
- * znaczy, ¿e mo¿na wczytaæ struct in_addr. je¶li nie znajdzie, zwraca
- * INADDR_NONE.
- *
- * - fd - wska¼nik do zmiennej przechowuj±cej desktyptor resolvera
- * - resolver - wska¼nik do wska¼nika resolvera
- * - hostname - nazwa hosta do zresolvowania
- *
- * 0, -1.
- */
-int gg_resolve_pthread(int *fd, void **resolver, const char *hostname)
-{
- struct gg_resolve_pthread_data *d = NULL;
- pthread_t *tmp;
- int pipes[2], new_errno;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve_pthread(%p, %p, \"%s\");\n", fd, resolver, hostname);
-
- if (!resolver || !fd || !hostname) {
- gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() invalid arguments\n");
- errno = EFAULT;
- return -1;
- }
-
- if (!(tmp = malloc(sizeof(pthread_t)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory for pthread id\n");
- return -1;
- }
-
- if (pipe(pipes) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno));
- free(tmp);
- return -1;
- }
-
- if (!(d = malloc(sizeof(*d)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n");
- new_errno = errno;
- goto cleanup;
- }
-
- d->hostname = NULL;
-
- if (!(d->hostname = strdup(hostname))) {
- gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n");
- new_errno = errno;
- goto cleanup;
- }
-
- d->fd = pipes[1];
-
- if (pthread_create(tmp, NULL, gg_resolve_pthread_thread, d)) {
- gg_debug(GG_DEBUG_MISC, "// gg_resolve_phread() unable to create thread\n");
- new_errno = errno;
- goto cleanup;
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() %p\n", tmp);
-
- *resolver = tmp;
-
- *fd = pipes[0];
-
- return 0;
-
-cleanup:
- if (d) {
- free(d->hostname);
- free(d);
- }
-
- close(pipes[0]);
- close(pipes[1]);
-
- free(tmp);
-
- errno = new_errno;
-
- return -1;
-}
-
-#endif
-
-/*
- * gg_read() // funkcja pomocnicza
- *
- * czyta z gniazda okre¶lon± ilo¶æ bajtów. bierze pod uwagê, czy mamy
- * po³±czenie zwyk³e czy TLS.
- *
- * - sess - sesja,
- * - buf - bufor,
- * - length - ilo¶æ bajtów,
- *
- * takie same warto¶ci jak read().
- */
-int gg_read(struct gg_session *sess, char *buf, int length)
-{
- int res;
-
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
- if (sess->ssl) {
- int err;
-
- res = SSL_read(sess->ssl, buf, length);
-
- if (res < 0) {
- err = SSL_get_error(sess->ssl, res);
-
- if (err == SSL_ERROR_WANT_READ)
- errno = EAGAIN;
-
- return -1;
- }
- } else
-#endif
- res = read(sess->fd, buf, length);
-
- return res;
-}
-
-/*
- * gg_write() // funkcja pomocnicza
- *
- * zapisuje do gniazda okre¶lon± ilo¶æ bajtów. bierze pod uwagê, czy mamy
- * po³±czenie zwyk³e czy TLS.
- *
- * - sess - sesja,
- * - buf - bufor,
- * - length - ilo¶æ bajtów,
- *
- * takie same warto¶ci jak write().
- */
-int gg_write(struct gg_session *sess, const char *buf, int length)
-{
- int res = 0;
-
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
- if (sess->ssl) {
- int err;
-
- res = SSL_write(sess->ssl, buf, length);
-
- if (res < 0) {
- err = SSL_get_error(sess->ssl, res);
-
- if (err == SSL_ERROR_WANT_WRITE)
- errno = EAGAIN;
-
- return -1;
- }
- } else
-#endif
- {
- int written = 0;
-
- while (written < length) {
- res = write(sess->fd, buf + written, length - written);
-
- if (res == -1) {
- if (errno == EAGAIN)
- continue;
- else
- break;
- } else {
- written += res;
- res = written;
- }
- }
- }
-
- return res;
-}
-
-/*
- * gg_recv_packet() // funkcja wewnêtrzna
- *
- * odbiera jeden pakiet i zwraca wska¼nik do niego. pamiêæ po nim
- * nale¿y zwolniæ za pomoc± free().
- *
- * - sess - opis sesji
- *
- * w przypadku b³êdu NULL, kod b³êdu w errno. nale¿y zwróciæ uwagê, ¿e gdy
- * po³±czenie jest nieblokuj±ce, a kod b³êdu wynosi EAGAIN, nie uda³o siê
- * odczytaæ ca³ego pakietu i nie nale¿y tego traktowaæ jako b³±d.
- */
-void *gg_recv_packet(struct gg_session *sess)
-{
- struct gg_header h;
- char *buf = NULL;
- int ret = 0;
- unsigned int offset, size = 0;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess);
-
- if (!sess) {
- errno = EFAULT;
- return NULL;
- }
-
- if (sess->recv_left < 1) {
- if (sess->header_buf) {
- memcpy(&h, sess->header_buf, sess->header_done);
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv: resuming last read (%d bytes left)\n", sizeof(h) - sess->header_done);
- free(sess->header_buf);
- sess->header_buf = NULL;
- } else
- sess->header_done = 0;
-
- while (sess->header_done < sizeof(h)) {
- ret = gg_read(sess, (char*) &h + sess->header_done, sizeof(h) - sess->header_done);
-
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv(%d,%p,%d) = %d\n", sess->fd, &h + sess->header_done, sizeof(h) - sess->header_done, ret);
-
- if (!ret) {
- errno = ECONNRESET;
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n");
- return NULL;
- }
-
- if (ret == -1) {
- if (errno == EINTR) {
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() interrupted system call, resuming\n");
- continue;
- }
-
- if (errno == EAGAIN) {
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() incomplete header received\n");
-
- if (!(sess->header_buf = malloc(sess->header_done))) {
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() not enough memory\n");
- return NULL;
- }
-
- memcpy(sess->header_buf, &h, sess->header_done);
-
- return NULL;
- }
-
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: errno=%d, %s\n", errno, strerror(errno));
-
- return NULL;
- }
-
- sess->header_done += ret;
-
- }
-
- h.type = gg_fix32(h.type);
- h.length = gg_fix32(h.length);
- } else
- memcpy(&h, sess->recv_buf, sizeof(h));
-
- /* jakie¶ sensowne limity na rozmiar pakietu */
- if (h.length > 65535) {
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() invalid packet length (%d)\n", h.length);
- errno = ERANGE;
- return NULL;
- }
-
- if (sess->recv_left > 0) {
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() resuming last gg_recv_packet()\n");
- size = sess->recv_left;
- offset = sess->recv_done;
- buf = sess->recv_buf;
- } else {
- if (!(buf = malloc(sizeof(h) + h.length + 1))) {
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() not enough memory for packet data\n");
- return NULL;
- }
-
- memcpy(buf, &h, sizeof(h));
-
- offset = 0;
- size = h.length;
- }
-
- while (size > 0) {
- ret = gg_read(sess, buf + sizeof(h) + offset, size);
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret);
- if (!ret) {
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n");
- errno = ECONNRESET;
- return NULL;
- }
- if (ret > -1 && ret <= size) {
- offset += ret;
- size -= ret;
- } else if (ret == -1) {
- int errno2 = errno;
-
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno));
- errno = errno2;
-
- if (errno == EAGAIN) {
- gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size);
- sess->recv_buf = buf;
- sess->recv_left = size;
- sess->recv_done = offset;
- return NULL;
- }
- if (errno != EINTR) {
- free(buf);
- return NULL;
- }
- }
- }
-
- sess->recv_left = 0;
-
- if ((gg_debug_level & GG_DEBUG_DUMP)) {
- unsigned int i;
-
- gg_debug(GG_DEBUG_DUMP, "// gg_recv_packet(%.2x)", h.type);
- for (i = 0; i < sizeof(h) + h.length; i++)
- gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) buf[i]);
- gg_debug(GG_DEBUG_DUMP, "\n");
- }
-
- return buf;
-}
-
-/*
- * gg_send_packet() // funkcja wewnêtrzna
- *
- * konstruuje pakiet i wysy³a go do serwera.
- *
- * - sock - deskryptor gniazda
- * - type - typ pakietu
- * - payload_1 - pierwsza czê¶æ pakietu
- * - payload_length_1 - d³ugo¶æ pierwszej czê¶ci
- * - payload_2 - druga czê¶æ pakietu
- * - payload_length_2 - d³ugo¶æ drugiej czê¶ci
- * - ... - kolejne czê¶ci pakietu i ich d³ugo¶ci
- * - NULL - koñcowym parametr (konieczny!)
- *
- * je¶li siê powiod³o, zwraca 0, w przypadku b³êdu -1. je¶li errno == ENOMEM,
- * zabrak³o pamiêci. inaczej by³ b³±d przy wysy³aniu pakietu. dla errno == 0
- * nie wys³ano ca³ego pakietu.
- */
-int gg_send_packet(struct gg_session *sess, int type, ...)
-{
- struct gg_header *h;
- char *tmp;
- unsigned int tmp_length;
- void *payload;
- unsigned int payload_length;
- va_list ap;
- int res;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_send_packet(%p, 0x%.2x, ...)\n", sess, type);
-
- tmp_length = sizeof(struct gg_header);
-
- if (!(tmp = malloc(tmp_length))) {
- gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for packet header\n");
- return -1;
- }
-
- va_start(ap, type);
-
- payload = va_arg(ap, void *);
-
- while (payload) {
- char *tmp2;
-
- payload_length = va_arg(ap, unsigned int);
-
- if (!(tmp2 = realloc(tmp, tmp_length + payload_length))) {
- gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for payload\n");
- free(tmp);
- va_end(ap);
- return -1;
- }
-
- tmp = tmp2;
-
- memcpy(tmp + tmp_length, payload, payload_length);
- tmp_length += payload_length;
-
- payload = va_arg(ap, void *);
- }
-
- va_end(ap);
-
- h = (struct gg_header*) tmp;
- h->type = gg_fix32(type);
- h->length = gg_fix32(tmp_length - sizeof(struct gg_header));
-
- if ((gg_debug_level & GG_DEBUG_DUMP)) {
- unsigned int i;
-
- gg_debug(GG_DEBUG_DUMP, "// gg_send_packet(0x%.2x)", gg_fix32(h->type));
- for (i = 0; i < tmp_length; ++i)
- gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) tmp[i]);
- gg_debug(GG_DEBUG_DUMP, "\n");
- }
-
- if ((res = gg_write(sess, tmp, tmp_length)) < tmp_length) {
- gg_debug(GG_DEBUG_MISC, "// gg_send_packet() write() failed. res = %d, errno = %d (%s)\n", res, errno, strerror(errno));
- free(tmp);
- return -1;
- }
-
- free(tmp);
- return 0;
-}
-
-/*
- * gg_session_callback() // funkcja wewnêtrzna
- *
- * wywo³ywany z gg_session->callback, wykonuje gg_watch_fd() i pakuje
- * do gg_session->event jego wynik.
- */
-static int gg_session_callback(struct gg_session *s)
-{
- if (!s) {
- errno = EFAULT;
- return -1;
- }
-
- return ((s->event = gg_watch_fd(s)) != NULL) ? 0 : -1;
-}
-
-/*
- * gg_login()
- *
- * rozpoczyna procedurê ³±czenia siê z serwerem. resztê obs³uguje siê przez
- * gg_watch_fd().
- *
- * UWAGA! program musi obs³u¿yæ SIGCHLD, je¶li ³±czy siê asynchronicznie,
- * ¿eby poprawnie zamkn±æ proces resolvera.
- *
- * - p - struktura opisuj±ca pocz±tkowy stan. wymagane pola: uin,
- * password
- *
- * w przypadku b³êdu NULL, je¶li idzie dobrze (async) albo posz³o
- * dobrze (sync), zwróci wska¼nik do zaalokowanej struct gg_session.
- */
-struct gg_session *gg_login(const struct gg_login_params *p)
-{
- struct gg_session *sess = NULL;
- char *hostname;
- int port;
-
- if (!p) {
- gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%p);\n", p);
- errno = EFAULT;
- return NULL;
- }
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%p: [uin=%u, async=%d, ...]);\n", p, p->uin, p->async);
-
- if (!(sess = malloc(sizeof(struct gg_session)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for session data\n");
- goto fail;
- }
-
- memset(sess, 0, sizeof(struct gg_session));
-
- if (!p->password || !p->uin) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. uin and password needed\n");
- errno = EFAULT;
- goto fail;
- }
-
- if (!(sess->password = strdup(p->password))) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for password\n");
- goto fail;
- }
-
- if (p->status_descr && !(sess->initial_descr = strdup(p->status_descr))) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n");
- goto fail;
- }
-
- sess->uin = p->uin;
- sess->state = GG_STATE_RESOLVING;
- sess->check = GG_CHECK_READ;
- sess->timeout = GG_DEFAULT_TIMEOUT;
- sess->async = p->async;
- sess->type = GG_SESSION_GG;
- sess->initial_status = p->status;
- sess->callback = gg_session_callback;
- sess->destroy = gg_free_session;
- sess->port = (p->server_port) ? p->server_port : ((gg_proxy_enabled) ? GG_HTTPS_PORT : GG_DEFAULT_PORT);
- sess->server_addr = p->server_addr;
- sess->external_port = p->external_port;
- sess->external_addr = p->external_addr;
- sess->protocol_version = (p->protocol_version) ? p->protocol_version : GG_DEFAULT_PROTOCOL_VERSION;
- if (p->era_omnix)
- sess->protocol_version |= GG_ERA_OMNIX_MASK;
- if (p->has_audio)
- sess->protocol_version |= GG_HAS_AUDIO_MASK;
- sess->client_version = (p->client_version) ? strdup(p->client_version) : NULL;
- sess->last_sysmsg = p->last_sysmsg;
- sess->image_size = p->image_size;
- sess->pid = -1;
-
- if (p->tls == 1) {
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
- char buf[1024];
-
- OpenSSL_add_ssl_algorithms();
-
- if (!RAND_status()) {
- char rdata[1024];
- struct {
- time_t time;
- void *ptr;
- } rstruct;
-
- time(&rstruct.time);
- rstruct.ptr = (void *) &rstruct;
-
- RAND_seed((void *) rdata, sizeof(rdata));
- RAND_seed((void *) &rstruct, sizeof(rstruct));
- }
-
- sess->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
-
- if (!sess->ssl_ctx) {
- ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
- gg_debug(GG_DEBUG_MISC, "// gg_login() SSL_CTX_new() failed: %s\n", buf);
- goto fail;
- }
-
- SSL_CTX_set_verify(sess->ssl_ctx, SSL_VERIFY_NONE, NULL);
-
- sess->ssl = SSL_new(sess->ssl_ctx);
-
- if (!sess->ssl) {
- ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
- gg_debug(GG_DEBUG_MISC, "// gg_login() SSL_new() failed: %s\n", buf);
- goto fail;
- }
-#else
- gg_debug(GG_DEBUG_MISC, "// gg_login() client requested TLS but no support compiled in\n");
-#endif
- }
-
- if (gg_proxy_enabled) {
- hostname = gg_proxy_host;
- sess->proxy_port = port = gg_proxy_port;
- } else {
- hostname = GG_APPMSG_HOST;
- port = GG_APPMSG_PORT;
- }
-
- if (!p->async) {
- struct in_addr a;
-
- if (!p->server_addr || !p->server_port) {
- if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) {
- struct in_addr *hn;
-
- if (!(hn = gg_gethostbyname(hostname))) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() host \"%s\" not found\n", hostname);
- goto fail;
- } else {
- a.s_addr = hn->s_addr;
- free(hn);
- }
- }
- } else {
- a.s_addr = p->server_addr;
- port = p->server_port;
- }
-
- sess->hub_addr = a.s_addr;
-
- if (gg_proxy_enabled)
- sess->proxy_addr = a.s_addr;
-
- if ((sess->fd = gg_connect(&a, port, 0)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() connection failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail;
- }
-
- if (p->server_addr && p->server_port)
- sess->state = GG_STATE_CONNECTING_GG;
- else
- sess->state = GG_STATE_CONNECTING_HUB;
-
- while (sess->state != GG_STATE_CONNECTED) {
- struct gg_event *e;
-
- if (!(e = gg_watch_fd(sess))) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() critical error in gg_watch_fd()\n");
- goto fail;
- }
-
- if (e->type == GG_EVENT_CONN_FAILED) {
- errno = EACCES;
- gg_debug(GG_DEBUG_MISC, "// gg_login() could not login\n");
- gg_event_free(e);
- goto fail;
- }
-
- gg_event_free(e);
- }
-
- return sess;
- }
-
- if (!sess->server_addr || gg_proxy_enabled) {
-#ifndef __GG_LIBGADU_HAVE_PTHREAD
- if (gg_resolve(&sess->fd, &sess->pid, hostname)) {
-#else
- if (gg_resolve_pthread(&sess->fd, &sess->resolver, hostname)) {
-#endif
- gg_debug(GG_DEBUG_MISC, "// gg_login() resolving failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail;
- }
- } else {
- if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_login() direct connection failed (errno=%d, %s)\n", errno, strerror(errno));
- goto fail;
- }
- sess->state = GG_STATE_CONNECTING_GG;
- sess->check = GG_CHECK_WRITE;
- }
-
- return sess;
-
-fail:
- if (sess) {
- if (sess->password)
- free(sess->password);
- if (sess->initial_descr)
- free(sess->initial_descr);
- free(sess);
- }
-
- return NULL;
-}
-
-/*
- * gg_free_session()
- *
- * próbuje zamkn±æ po³±czenia i zwalnia pamiêæ zajmowan± przez sesjê.
- *
- * - sess - opis sesji
- */
-void gg_free_session(struct gg_session *sess)
-{
- if (!sess)
- return;
-
- /* XXX dopisaæ zwalnianie i zamykanie wszystkiego, co mog³o zostaæ */
-
- if (sess->password)
- free(sess->password);
-
- if (sess->initial_descr)
- free(sess->initial_descr);
-
- if (sess->client_version)
- free(sess->client_version);
-
- if (sess->header_buf)
- free(sess->header_buf);
-
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
- if (sess->ssl)
- SSL_free(sess->ssl);
-
- if (sess->ssl_ctx)
- SSL_CTX_free(sess->ssl_ctx);
-#endif
-
-#ifdef __GG_LIBGADU_HAVE_PTHREAD
- if (sess->resolver) {
- pthread_cancel(*((pthread_t*) sess->resolver));
- free(sess->resolver);
- sess->resolver = NULL;
- }
-#else
- if (sess->pid != -1) {
- kill(sess->pid, SIGTERM);
- waitpid(sess->pid, NULL, WNOHANG);
- }
-#endif
-
- if (sess->fd != -1)
- close(sess->fd);
-
- while (sess->images)
- gg_image_queue_remove(sess, sess->images, 1);
-
- free(sess);
-}
-
-/*
- * gg_change_status()
- *
- * zmienia status u¿ytkownika. przydatne do /away i /busy oraz /quit.
- *
- * - sess - opis sesji
- * - status - nowy status u¿ytkownika
- *
- * 0, -1.
- */
-int gg_change_status(struct gg_session *sess, int status)
-{
- struct gg_new_status p;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status(%p, %d);\n", sess, status);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- p.status = gg_fix32(status);
-
- sess->status = status;
-
- return gg_send_packet(sess, GG_NEW_STATUS, &p, sizeof(p), NULL);
-}
-
-/*
- * gg_change_status_descr()
- *
- * zmienia status u¿ytkownika na opisowy.
- *
- * - sess - opis sesji
- * - status - nowy status u¿ytkownika
- * - descr - opis statusu
- *
- * 0, -1.
- */
-int gg_change_status_descr(struct gg_session *sess, int status, const char *descr)
-{
- struct gg_new_status p;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status_descr(%p, %d, \"%s\");\n", sess, status, descr);
-
- if (!sess || !descr) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- p.status = gg_fix32(status);
-
- sess->status = status;
-
- return gg_send_packet(sess, GG_NEW_STATUS, &p, sizeof(p), descr, (strlen(descr) > GG_STATUS_DESCR_MAXSIZE) ? GG_STATUS_DESCR_MAXSIZE : strlen(descr), NULL);
-}
-
-/*
- * gg_change_status_descr_time()
- *
- * zmienia status u¿ytkownika na opisowy z godzin± powrotu.
- *
- * - sess - opis sesji
- * - status - nowy status u¿ytkownika
- * - descr - opis statusu
- * - time - czas w formacie uniksowym
- *
- * 0, -1.
- */
-int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int time)
-{
- struct gg_new_status p;
- uint32_t newtime;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", sess, status, descr, time);
-
- if (!sess || !descr || !time) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- p.status = gg_fix32(status);
-
- sess->status = status;
-
- newtime = gg_fix32(time);
-
- return gg_send_packet(sess, GG_NEW_STATUS, &p, sizeof(p), descr, (strlen(descr) > GG_STATUS_DESCR_MAXSIZE) ? GG_STATUS_DESCR_MAXSIZE : strlen(descr), &newtime, sizeof(newtime), NULL);
-}
-
-/*
- * gg_logoff()
- *
- * wylogowuje u¿ytkownika i zamyka po³±czenie, ale nie zwalnia pamiêci.
- *
- * - sess - opis sesji
- */
-void gg_logoff(struct gg_session *sess)
-{
- if (!sess)
- return;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_logoff(%p);\n", sess);
-
- if (GG_S_NA(sess->status & ~GG_STATUS_FRIENDS_MASK))
- gg_change_status(sess, GG_STATUS_NOT_AVAIL);
-
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
- if (sess->ssl)
- SSL_shutdown(sess->ssl);
-#endif
-
-#ifdef __GG_LIBGADU_HAVE_PTHREAD
- if (sess->resolver) {
- pthread_cancel(*((pthread_t*) sess->resolver));
- free(sess->resolver);
- sess->resolver = NULL;
- }
-#else
- if (sess->pid != -1) {
- kill(sess->pid, SIGTERM);
- waitpid(sess->pid, NULL, WNOHANG);
- sess->pid = -1;
- }
-#endif
-
- if (sess->fd != -1) {
- shutdown(sess->fd, SHUT_RDWR);
- close(sess->fd);
- sess->fd = -1;
- }
-}
-
-/*
- * gg_image_request()
- *
- * wysy³a ¿±danie wys³ania obrazka o podanych parametrach.
- *
- * - sess - opis sesji
- * - recipient - numer adresata
- * - size - rozmiar obrazka
- * - crc32 - suma kontrolna obrazka
- *
- * 0/-1
- */
-int gg_image_request(struct gg_session *sess, uin_t recipient, int size, uint32_t crc32)
-{
- struct gg_send_msg s;
- struct gg_msg_image_request r;
- char dummy = 0;
- int res;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_image_request(%p, %d, %u, 0x%.4x);\n", sess, recipient, size, crc32);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- if (size < 0) {
- errno = EINVAL;
- return -1;
- }
-
- s.recipient = gg_fix32(recipient);
- s.seq = gg_fix32(0);
- s.msgclass = gg_fix32(GG_CLASS_MSG);
-
- r.flag = 0x04;
- r.size = gg_fix32(size);
- r.crc32 = gg_fix32(crc32);
-
- res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), &dummy, 1, &r, sizeof(r), NULL);
-
- if (!res) {
- struct gg_image_queue *q = malloc(sizeof(*q));
- char *buf;
-
- if (!q) {
- gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image queue\n");
- return -1;
- }
-
- buf = malloc(size);
- if (size && !buf)
- {
- gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image\n");
- free(q);
- return -1;
- }
-
- memset(q, 0, sizeof(*q));
-
- q->sender = recipient;
- q->size = size;
- q->crc32 = crc32;
- q->image = buf;
-
- if (!sess->images)
- sess->images = q;
- else {
- struct gg_image_queue *qq;
-
- for (qq = sess->images; qq->next; qq = qq->next)
- ;
-
- qq->next = q;
- }
- }
-
- return res;
-}
-
-/*
- * gg_image_reply()
- *
- * wysy³a ¿±dany obrazek.
- *
- * - sess - opis sesji
- * - recipient - numer adresata
- * - filename - nazwa pliku
- * - image - bufor z obrazkiem
- * - size - rozmiar obrazka
- *
- * 0/-1
- */
-int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const char *image, int size)
-{
- struct gg_msg_image_reply *r;
- struct gg_send_msg s;
- const char *tmp;
- char buf[1910];
- int res = -1;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_image_reply(%p, %d, \"%s\", %p, %d);\n", sess, recipient, filename, image, size);
-
- if (!sess || !filename || !image) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- if (size < 0) {
- errno = EINVAL;
- return -1;
- }
-
- /* wytnij ¶cie¿ki, zostaw tylko nazwê pliku */
- while ((tmp = strrchr(filename, '/')) || (tmp = strrchr(filename, '\\')))
- filename = tmp + 1;
-
- if (strlen(filename) < 1 || strlen(filename) > 1024) {
- errno = EINVAL;
- return -1;
- }
-
- s.recipient = gg_fix32(recipient);
- s.seq = gg_fix32(0);
- s.msgclass = gg_fix32(GG_CLASS_MSG);
-
- buf[0] = 0;
- r = (void*) &buf[1];
-
- r->flag = 0x05;
- r->size = gg_fix32(size);
- r->crc32 = gg_fix32(gg_crc32(0, image, size));
-
- while (size > 0) {
- int buflen, chunklen;
-
- /* \0 + struct gg_msg_image_reply */
- buflen = sizeof(struct gg_msg_image_reply) + 1;
-
- /* w pierwszym kawa³ku jest nazwa pliku */
- if (r->flag == 0x05) {
- strcpy(buf + buflen, filename);
- buflen += strlen(filename) + 1;
- }
-
- chunklen = (size >= sizeof(buf) - buflen) ? (sizeof(buf) - buflen) : size;
-
- memcpy(buf + buflen, image, chunklen);
- size -= chunklen;
- image += chunklen;
-
- res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), buf, buflen + chunklen, NULL);
-
- if (res == -1)
- break;
-
- r->flag = 0x06;
- }
-
- return res;
-}
-
-/*
- * gg_send_message_ctcp()
- *
- * wysy³a wiadomo¶æ do innego u¿ytkownika. zwraca losowy numer
- * sekwencyjny, który mo¿na zignorowaæ albo wykorzystaæ do potwierdzenia.
- *
- * - sess - opis sesji
- * - msgclass - rodzaj wiadomo¶ci
- * - recipient - numer adresata
- * - message - tre¶æ wiadomo¶ci
- * - message_len - d³ugo¶æ
- *
- * numer sekwencyjny wiadomo¶ci lub -1 w przypadku b³êdu.
- */
-int gg_send_message_ctcp(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, int message_len)
-{
- struct gg_send_msg s;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_ctcp(%p, %d, %u, ...);\n", sess, msgclass, recipient);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- s.recipient = gg_fix32(recipient);
- s.seq = gg_fix32(0);
- s.msgclass = gg_fix32(msgclass);
-
- return gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, message_len, NULL);
-}
-
-/*
- * gg_send_message()
- *
- * wysy³a wiadomo¶æ do innego u¿ytkownika. zwraca losowy numer
- * sekwencyjny, który mo¿na zignorowaæ albo wykorzystaæ do potwierdzenia.
- *
- * - sess - opis sesji
- * - msgclass - rodzaj wiadomo¶ci
- * - recipient - numer adresata
- * - message - tre¶æ wiadomo¶ci
- *
- * numer sekwencyjny wiadomo¶ci lub -1 w przypadku b³êdu.
- */
-int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message)
-{
- gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message(%p, %d, %u, %p)\n", sess, msgclass, recipient, message);
-
- return gg_send_message_richtext(sess, msgclass, recipient, message, NULL, 0);
-}
-
-/*
- * gg_send_message_richtext()
- *
- * wysy³a kolorow± wiadomo¶æ do innego u¿ytkownika. zwraca losowy numer
- * sekwencyjny, który mo¿na zignorowaæ albo wykorzystaæ do potwierdzenia.
- *
- * - sess - opis sesji
- * - msgclass - rodzaj wiadomo¶ci
- * - recipient - numer adresata
- * - message - tre¶æ wiadomo¶ci
- * - format - informacje o formatowaniu
- * - formatlen - d³ugo¶æ informacji o formatowaniu
- *
- * numer sekwencyjny wiadomo¶ci lub -1 w przypadku b³êdu.
- */
-int gg_send_message_richtext(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, const unsigned char *format, int formatlen)
-{
- struct gg_send_msg s;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_richtext(%p, %d, %u, %p, %p, %d);\n", sess, msgclass, recipient, message, format, formatlen);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- if (!message) {
- errno = EFAULT;
- return -1;
- }
-
- s.recipient = gg_fix32(recipient);
- if (!sess->seq)
- sess->seq = 0x01740000 | (rand() & 0xffff);
- s.seq = gg_fix32(sess->seq);
- s.msgclass = gg_fix32(msgclass);
- sess->seq += (rand() % 0x300) + 0x300;
-
- if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, strlen(message) + 1, format, formatlen, NULL) == -1)
- return -1;
-
- return gg_fix32(s.seq);
-}
-
-/*
- * gg_send_message_confer()
- *
- * wysy³a wiadomo¶æ do kilku u¿ytkownikow (konferencja). zwraca losowy numer
- * sekwencyjny, który mo¿na zignorowaæ albo wykorzystaæ do potwierdzenia.
- *
- * - sess - opis sesji
- * - msgclass - rodzaj wiadomo¶ci
- * - recipients_count - ilo¶æ adresatów
- * - recipients - numerki adresatów
- * - message - tre¶æ wiadomo¶ci
- *
- * numer sekwencyjny wiadomo¶ci lub -1 w przypadku b³êdu.
- */
-int gg_send_message_confer(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message)
-{
- gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_confer(%p, %d, %d, %p, %p);\n", sess, msgclass, recipients_count, recipients, message);
-
- return gg_send_message_confer_richtext(sess, msgclass, recipients_count, recipients, message, NULL, 0);
-}
-
-/*
- * gg_send_message_confer_richtext()
- *
- * wysy³a kolorow± wiadomo¶æ do kilku u¿ytkownikow (konferencja). zwraca
- * losowy numer sekwencyjny, który mo¿na zignorowaæ albo wykorzystaæ do
- * potwierdzenia.
- *
- * - sess - opis sesji
- * - msgclass - rodzaj wiadomo¶ci
- * - recipients_count - ilo¶æ adresatów
- * - recipients - numerki adresatów
- * - message - tre¶æ wiadomo¶ci
- * - format - informacje o formatowaniu
- * - formatlen - d³ugo¶æ informacji o formatowaniu
- *
- * numer sekwencyjny wiadomo¶ci lub -1 w przypadku b³êdu.
- */
-int gg_send_message_confer_richtext(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message, const unsigned char *format, int formatlen)
-{
- struct gg_send_msg s;
- struct gg_msg_recipients r;
- int i, j, k;
- uin_t *recps;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_confer_richtext(%p, %d, %d, %p, %p, %p, %d);\n", sess, msgclass, recipients_count, recipients, message, format, formatlen);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- if (!message || recipients_count <= 0 || recipients_count > 0xffff || !recipients) {
- errno = EINVAL;
- return -1;
- }
-
- r.flag = 0x01;
- r.count = gg_fix32(recipients_count - 1);
-
- if (!sess->seq)
- sess->seq = 0x01740000 | (rand() & 0xffff);
- s.seq = gg_fix32(sess->seq);
- s.msgclass = gg_fix32(msgclass);
-
- recps = malloc(sizeof(uin_t) * recipients_count);
- if (!recps)
- return -1;
-
- for (i = 0; i < recipients_count; i++) {
-
- s.recipient = gg_fix32(recipients[i]);
-
- for (j = 0, k = 0; j < recipients_count; j++)
- if (recipients[j] != recipients[i]) {
- recps[k] = gg_fix32(recipients[j]);
- k++;
- }
-
- if (!i)
- sess->seq += (rand() % 0x300) + 0x300;
-
- if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, strlen(message) + 1, &r, sizeof(r), recps, (recipients_count - 1) * sizeof(uin_t), format, formatlen, NULL) == -1) {
- free(recps);
- return -1;
- }
- }
-
- free(recps);
-
- return gg_fix32(s.seq);
-}
-
-/*
- * gg_ping()
- *
- * wysy³a do serwera pakiet ping.
- *
- * - sess - opis sesji
- *
- * 0, -1.
- */
-int gg_ping(struct gg_session *sess)
-{
- gg_debug(GG_DEBUG_FUNCTION, "** gg_ping(%p);\n", sess);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- return gg_send_packet(sess, GG_PING, NULL);
-}
-
-/*
- * gg_notify_ex()
- *
- * wysy³a serwerowi listê kontaktów (wraz z odpowiadaj±cymi im typami userów),
- * dziêki czemu wie, czyj stan nas interesuje.
- *
- * - sess - opis sesji
- * - userlist - wska¼nik do tablicy numerów
- * - types - wska¼nik do tablicy typów u¿ytkowników
- * - count - ilo¶æ numerków
- *
- * 0, -1.
- */
-int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count)
-{
- struct gg_notify *n;
- uin_t *u;
- char *t;
- int i, res = 0;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_notify_ex(%p, %p, %p, %d);\n", sess, userlist, types, count);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- if (!userlist || !count)
- return gg_send_packet(sess, GG_LIST_EMPTY, NULL);
-
- while (count > 0) {
- int part_count, packet_type;
-
- if (count > 400) {
- part_count = 400;
- packet_type = GG_NOTIFY_FIRST;
- } else {
- part_count = count;
- packet_type = GG_NOTIFY_LAST;
- }
-
- if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count)))
- return -1;
-
- for (u = userlist, t = types, i = 0; i < part_count; u++, t++, i++) {
- n[i].uin = gg_fix32(*u);
- n[i].dunno1 = *t;
- }
-
- if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) {
- free(n);
- res = -1;
- break;
- }
-
- count -= part_count;
- userlist += part_count;
- types += part_count;
-
- free(n);
- }
-
- return res;
-}
-
-/*
- * gg_notify()
- *
- * wysy³a serwerowi listê kontaktów, dziêki czemu wie, czyj stan nas
- * interesuje.
- *
- * - sess - opis sesji
- * - userlist - wska¼nik do tablicy numerów
- * - count - ilo¶æ numerków
- *
- * 0, -1.
- */
-int gg_notify(struct gg_session *sess, uin_t *userlist, int count)
-{
- struct gg_notify *n;
- uin_t *u;
- int i, res = 0;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- if (!userlist || !count)
- return gg_send_packet(sess, GG_LIST_EMPTY, NULL);
-
- while (count > 0) {
- int part_count, packet_type;
-
- if (count > 400) {
- part_count = 400;
- packet_type = GG_NOTIFY_FIRST;
- } else {
- part_count = count;
- packet_type = GG_NOTIFY_LAST;
- }
-
- if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count)))
- return -1;
-
- for (u = userlist, i = 0; i < part_count; u++, i++) {
- n[i].uin = gg_fix32(*u);
- n[i].dunno1 = GG_USER_NORMAL;
- }
-
- if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) {
- res = -1;
- free(n);
- break;
- }
-
- free(n);
-
- userlist += part_count;
- count -= part_count;
- }
-
- return res;
-}
-
-/*
- * gg_add_notify_ex()
- *
- * dodaje do listy kontaktów dany numer w trakcie po³±czenia.
- * dodawanemu u¿ytkownikowi okre¶lamy jego typ (patrz protocol.html)
- *
- * - sess - opis sesji
- * - uin - numer
- * - type - typ
- *
- * 0, -1.
- */
-int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type)
-{
- struct gg_add_remove a;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_add_notify_ex(%p, %u, %d);\n", sess, uin, type);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- a.uin = gg_fix32(uin);
- a.dunno1 = type;
-
- return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL);
-}
-
-/*
- * gg_add_notify()
- *
- * dodaje do listy kontaktów dany numer w trakcie po³±czenia.
- *
- * - sess - opis sesji
- * - uin - numer
- *
- * 0, -1.
- */
-int gg_add_notify(struct gg_session *sess, uin_t uin)
-{
- return gg_add_notify_ex(sess, uin, GG_USER_NORMAL);
-}
-
-/*
- * gg_remove_notify_ex()
- *
- * usuwa z listy kontaktów w trakcie po³±czenia.
- * usuwanemu u¿ytkownikowi okre¶lamy jego typ (patrz protocol.html)
- *
- * - sess - opis sesji
- * - uin - numer
- * - type - typ
- *
- * 0, -1.
- */
-int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type)
-{
- struct gg_add_remove a;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_remove_notify_ex(%p, %u, %d);\n", sess, uin, type);
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- a.uin = gg_fix32(uin);
- a.dunno1 = type;
-
- return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL);
-}
-
-/*
- * gg_remove_notify()
- *
- * usuwa z listy kontaktów w trakcie po³±czenia.
- *
- * - sess - opis sesji
- * - uin - numer
- *
- * 0, -1.
- */
-int gg_remove_notify(struct gg_session *sess, uin_t uin)
-{
- return gg_remove_notify_ex(sess, uin, GG_USER_NORMAL);
-}
-
-/*
- * gg_userlist_request()
- *
- * wysy³a ¿±danie/zapytanie listy kontaktów na serwerze.
- *
- * - sess - opis sesji
- * - type - rodzaj zapytania/¿±dania
- * - request - tre¶æ zapytania/¿±dania (mo¿e byæ NULL)
- *
- * 0, -1
- */
-int gg_userlist_request(struct gg_session *sess, char type, const char *request)
-{
- int len;
-
- if (!sess) {
- errno = EFAULT;
- return -1;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
- if (!request) {
- sess->userlist_blocks = 1;
- return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), NULL);
- }
-
- len = strlen(request);
-
- sess->userlist_blocks = 0;
-
- while (len > 2047) {
- sess->userlist_blocks++;
-
- if (gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, 2047, NULL) == -1)
- return -1;
-
- if (type == GG_USERLIST_PUT)
- type = GG_USERLIST_PUT_MORE;
-
- request += 2047;
- len -= 2047;
- }
-
- sess->userlist_blocks++;
-
- return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, len, NULL);
-}
-
-/*
- * Local variables:
- * c-indentation-style: k&r
- * c-basic-offset: 8
- * indent-tabs-mode: notnil
- * End:
- *
- * vim: shiftwidth=8:
- */
diff --git a/kopete/protocols/gadu/libgadu/libgadu.h b/kopete/protocols/gadu/libgadu/libgadu.h
deleted file mode 100644
index 85c54953..00000000
--- a/kopete/protocols/gadu/libgadu/libgadu.h
+++ /dev/null
@@ -1,1310 +0,0 @@
-/* $Id$ */
-
-/*
- * (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka@irc.pl>
- * Robert J. Wo¼ny <speedy@ziew.org>
- * Arkadiusz Mi¶kiewicz <arekm@pld-linux.org>
- * Tomasz Chiliñski <chilek@chilan.com>
- * Piotr Wysocki <wysek@linux.bydg.org>
- * Dawid Jarosz <dawjar@poczta.onet.pl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License Version
- * 2.1 as published by the Free Software Foundation.
- *
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#ifndef __GG_LIBGADU_H
-#define __GG_LIBGADU_H
-
-#ifdef __cplusplus
-#ifdef _WIN32
-#pragma pack(push, 1)
-#endif
-extern "C" {
-#endif
-
-#include <libgadu-config.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
-#include <openssl/ssl.h>
-#endif
-
-/*
- * typedef uin_t
- *
- * typ reprezentuj±cy numer osoby.
- */
-typedef uint32_t uin_t;
-
-/*
- * ogólna struktura opisuj±ca ró¿ne sesje. przydatna w klientach.
- */
-#define gg_common_head(x) \
- int fd; /* podgl±dany deskryptor */ \
- int check; /* sprawdzamy zapis czy odczyt */ \
- int state; /* aktualny stan maszynki */ \
- int error; /* kod b³êdu dla GG_STATE_ERROR */ \
- int type; /* rodzaj sesji */ \
- int id; /* identyfikator */ \
- int timeout; /* sugerowany timeout w sekundach */ \
- int (*callback)(x*); /* callback przy zmianach */ \
- void (*destroy)(x*); /* funkcja niszczenia */
-
-struct gg_common {
- gg_common_head(struct gg_common)
-};
-
-struct gg_image_queue;
-
-/*
- * struct gg_session
- *
- * struktura opisuj±ca dan± sesjê. tworzona przez gg_login(), zwalniana
- * przez gg_free_session().
- */
-struct gg_session {
- gg_common_head(struct gg_session)
-
- int async; /* czy po³±czenie jest asynchroniczne */
- int pid; /* pid procesu resolvera */
- int port; /* port, z którym siê ³±czymy */
- int seq; /* numer sekwencyjny ostatniej wiadomo¶ci */
- int last_pong; /* czas otrzymania ostatniego ping/pong */
- int last_event; /* czas otrzymania ostatniego pakietu */
-
- struct gg_event *event; /* zdarzenie po ->callback() */
-
- uint32_t proxy_addr; /* adres proxy, keszowany */
- uint16_t proxy_port; /* port proxy */
-
- uint32_t hub_addr; /* adres huba po resolvniêciu */
- uint32_t server_addr; /* adres serwera, od huba */
-
- uint32_t client_addr; /* adres klienta */
- uint16_t client_port; /* port, na którym klient s³ucha */
-
- uint32_t external_addr; /* adres zewnetrzny klienta */
- uint16_t external_port; /* port zewnetrzny klienta */
-
- uin_t uin; /* numerek klienta */
- char *password; /* i jego has³o. zwalniane automagicznie */
-
- int initial_status; /* pocz±tkowy stan klienta */
- int status; /* aktualny stan klienta */
-
- char *recv_buf; /* bufor na otrzymywane pakiety */
- int recv_done; /* ile ju¿ wczytano do bufora */
- int recv_left; /* i ile jeszcze trzeba wczytaæ */
-
- int protocol_version; /* wersja u¿ywanego protoko³u */
- char *client_version; /* wersja u¿ywanego klienta */
- int last_sysmsg; /* ostatnia wiadomo¶æ systemowa */
-
- char *initial_descr; /* pocz±tkowy opis stanu klienta */
-
- void *resolver; /* wska¼nik na informacje resolvera */
-
- char *header_buf; /* bufor na pocz±tek nag³ówka */
- unsigned int header_done;/* ile ju¿ mamy */
-
-#ifdef __GG_LIBGADU_HAVE_OPENSSL
- SSL *ssl; /* sesja TLS */
- SSL_CTX *ssl_ctx; /* kontekst sesji? */
-#else
- void *ssl; /* zachowujemy ABI */
- void *ssl_ctx;
-#endif
-
- int image_size; /* maksymalny rozmiar obrazków w KiB */
-
- char *userlist_reply; /* fragment odpowiedzi listy kontaktów */
-
- int userlist_blocks; /* na ile kawa³ków podzielono listê kontaktów */
-
- struct gg_image_queue *images; /* aktualnie wczytywane obrazki */
-};
-
-/*
- * struct gg_http
- *
- * ogólna struktura opisuj±ca stan wszystkich operacji HTTP. tworzona
- * przez gg_http_connect(), zwalniana przez gg_http_free().
- */
-struct gg_http {
- gg_common_head(struct gg_http)
-
- int async; /* czy po³±czenie asynchroniczne */
- int pid; /* pid procesu resolvera */
- int port; /* port, z którym siê ³±czymy */
-
- char *query; /* bufor zapytania http */
- char *header; /* bufor nag³ówka */
- int header_size; /* rozmiar wczytanego nag³ówka */
- char *body; /* bufor otrzymanych informacji */
- unsigned int body_size; /* oczekiwana ilo¶æ informacji */
-
- void *data; /* dane danej operacji http */
-
- char *user_data; /* dane u¿ytkownika, nie s± zwalniane przez gg_http_free() */
-
- void *resolver; /* wska¼nik na informacje resolvera */
-
- unsigned int body_done; /* ile ju¿ tre¶ci odebrano? */
-};
-
-#ifdef __GNUC__
-#define GG_PACKED __attribute__ ((packed))
-#else
-#define GG_PACKED
-#endif
-
-#define GG_MAX_PATH 276
-
-/*
- * struct gg_file_info
- *
- * odpowiednik windowsowej struktury WIN32_FIND_DATA niezbêdnej przy
- * wysy³aniu plików.
- */
-struct gg_file_info {
- uint32_t mode; /* dwFileAttributes */
- uint32_t ctime[2]; /* ftCreationTime */
- uint32_t atime[2]; /* ftLastAccessTime */
- uint32_t mtime[2]; /* ftLastWriteTime */
- uint32_t size_hi; /* nFileSizeHigh */
- uint32_t size; /* nFileSizeLow */
- uint32_t reserved0; /* dwReserved0 */
- uint32_t reserved1; /* dwReserved1 */
- unsigned char filename[GG_MAX_PATH - 14]; /* cFileName */
- unsigned char short_filename[14]; /* cAlternateFileName */
-} GG_PACKED;
-
-/*
- * struct gg_dcc
- *
- * struktura opisuj±ca nas³uchuj±ce gniazdo po³±czeñ miêdzy klientami.
- * tworzona przez gg_dcc_socket_create(), zwalniana przez gg_dcc_free().
- */
-struct gg_dcc {
- gg_common_head(struct gg_dcc)
-
- struct gg_event *event; /* opis zdarzenia */
-
- int active; /* czy to my siê ³±czymy? */
- int port; /* port, na którym siedzi */
- uin_t uin; /* uin klienta */
- uin_t peer_uin; /* uin drugiej strony */
- int file_fd; /* deskryptor pliku */
- unsigned int offset; /* offset w pliku */
- unsigned int chunk_size;/* rozmiar kawa³ka */
- unsigned int chunk_offset;/* offset w aktualnym kawa³ku */
- struct gg_file_info file_info;
- /* informacje o pliku */
- int established; /* po³±czenie ustanowione */
- char *voice_buf; /* bufor na pakiet po³±czenia g³osowego */
- int incoming; /* po³±czenie przychodz±ce */
- char *chunk_buf; /* bufor na kawa³ek danych */
- uint32_t remote_addr; /* adres drugiej strony */
- uint16_t remote_port; /* port drugiej strony */
-};
-
-/*
- * enum gg_session_t
- *
- * rodzaje sesji.
- */
-enum gg_session_t {
- GG_SESSION_GG = 1, /* po³±czenie z serwerem gg */
- GG_SESSION_HTTP, /* ogólna sesja http */
- GG_SESSION_SEARCH, /* szukanie */
- GG_SESSION_REGISTER, /* rejestrowanie */
- GG_SESSION_REMIND, /* przypominanie has³a */
- GG_SESSION_PASSWD, /* zmiana has³a */
- GG_SESSION_CHANGE, /* zmiana informacji o sobie */
- GG_SESSION_DCC, /* ogólne po³±czenie DCC */
- GG_SESSION_DCC_SOCKET, /* nas³uchuj±cy socket */
- GG_SESSION_DCC_SEND, /* wysy³anie pliku */
- GG_SESSION_DCC_GET, /* odbieranie pliku */
- GG_SESSION_DCC_VOICE, /* rozmowa g³osowa */
- GG_SESSION_USERLIST_GET, /* pobieranie userlisty */
- GG_SESSION_USERLIST_PUT, /* wysy³anie userlisty */
- GG_SESSION_UNREGISTER, /* usuwanie konta */
- GG_SESSION_USERLIST_REMOVE, /* usuwanie userlisty */
- GG_SESSION_TOKEN, /* pobieranie tokenu */
-
- GG_SESSION_USER0 = 256, /* zdefiniowana dla u¿ytkownika */
- GG_SESSION_USER1, /* j.w. */
- GG_SESSION_USER2, /* j.w. */
- GG_SESSION_USER3, /* j.w. */
- GG_SESSION_USER4, /* j.w. */
- GG_SESSION_USER5, /* j.w. */
- GG_SESSION_USER6, /* j.w. */
- GG_SESSION_USER7 /* j.w. */
-};
-
-/*
- * enum gg_state_t
- *
- * opisuje stan asynchronicznej maszyny.
- */
-enum gg_state_t {
- /* wspólne */
- GG_STATE_IDLE = 0, /* nie powinno wyst±piæ. */
- GG_STATE_RESOLVING, /* wywo³a³ gethostbyname() */
- GG_STATE_CONNECTING, /* wywo³a³ connect() */
- GG_STATE_READING_DATA, /* czeka na dane http */
- GG_STATE_ERROR, /* wyst±pi³ b³±d. kod w x->error */
-
- /* gg_session */
- GG_STATE_CONNECTING_HUB, /* wywo³a³ connect() na huba */
- GG_STATE_CONNECTING_GG, /* wywo³a³ connect() na serwer */
- GG_STATE_READING_KEY, /* czeka na klucz */
- GG_STATE_READING_REPLY, /* czeka na odpowied¼ */
- GG_STATE_CONNECTED, /* po³±czy³ siê */
-
- /* gg_http */
- GG_STATE_SENDING_QUERY, /* wysy³a zapytanie http */
- GG_STATE_READING_HEADER, /* czeka na nag³ówek http */
- GG_STATE_PARSING, /* przetwarza dane */
- GG_STATE_DONE, /* skoñczy³ */
-
- /* gg_dcc */
- GG_STATE_LISTENING, /* czeka na po³±czenia */
- GG_STATE_READING_UIN_1, /* czeka na uin peera */
- GG_STATE_READING_UIN_2, /* czeka na swój uin */
- GG_STATE_SENDING_ACK, /* wysy³a potwierdzenie dcc */
- GG_STATE_READING_ACK, /* czeka na potwierdzenie dcc */
- GG_STATE_READING_REQUEST, /* czeka na komendê */
- GG_STATE_SENDING_REQUEST, /* wysy³a komendê */
- GG_STATE_SENDING_FILE_INFO, /* wysy³a informacje o pliku */
- GG_STATE_READING_PRE_FILE_INFO, /* czeka na pakiet przed file_info */
- GG_STATE_READING_FILE_INFO, /* czeka na informacje o pliku */
- GG_STATE_SENDING_FILE_ACK, /* wysy³a potwierdzenie pliku */
- GG_STATE_READING_FILE_ACK, /* czeka na potwierdzenie pliku */
- GG_STATE_SENDING_FILE_HEADER, /* wysy³a nag³ówek pliku */
- GG_STATE_READING_FILE_HEADER, /* czeka na nag³ówek */
- GG_STATE_GETTING_FILE, /* odbiera plik */
- GG_STATE_SENDING_FILE, /* wysy³a plik */
- GG_STATE_READING_VOICE_ACK, /* czeka na potwierdzenie voip */
- GG_STATE_READING_VOICE_HEADER, /* czeka na rodzaj bloku voip */
- GG_STATE_READING_VOICE_SIZE, /* czeka na rozmiar bloku voip */
- GG_STATE_READING_VOICE_DATA, /* czeka na dane voip */
- GG_STATE_SENDING_VOICE_ACK, /* wysy³a potwierdzenie voip */
- GG_STATE_SENDING_VOICE_REQUEST, /* wysy³a ¿±danie voip */
- GG_STATE_READING_TYPE, /* czeka na typ po³±czenia */
-
- /* nowe. bez sensu jest to API. */
- GG_STATE_TLS_NEGOTIATION /* negocjuje po³±czenie TLS */
-};
-
-/*
- * enum gg_check_t
- *
- * informuje, co proces klienta powinien sprawdziæ na deskryptorze danego
- * po³±czenia.
- */
-enum gg_check_t {
- GG_CHECK_NONE = 0, /* nic. nie powinno wyst±piæ */
- GG_CHECK_WRITE = 1, /* sprawdzamy mo¿liwo¶æ zapisu */
- GG_CHECK_READ = 2 /* sprawdzamy mo¿liwo¶æ odczytu */
-};
-
-/*
- * struct gg_login_params
- *
- * parametry gg_login(). przeniesiono do struktury, ¿eby unikn±æ problemów
- * z ci±g³ymi zmianami API, gdy dodano co¶ nowego do protoko³u.
- */
-struct gg_login_params {
- uin_t uin; /* numerek */
- char *password; /* has³o */
- int async; /* asynchroniczne sockety? */
- int status; /* pocz±tkowy status klienta */
- char *status_descr; /* opis statusu */
- uint32_t server_addr; /* adres serwera gg */
- uint16_t server_port; /* port serwera gg */
- uint32_t client_addr; /* adres dcc klienta */
- uint16_t client_port; /* port dcc klienta */
- int protocol_version; /* wersja protoko³u */
- char *client_version; /* wersja klienta */
- int has_audio; /* czy ma d¼wiêk? */
- int last_sysmsg; /* ostatnia wiadomo¶æ systemowa */
- uint32_t external_addr; /* adres widziany na zewnatrz */
- uint16_t external_port; /* port widziany na zewnatrz */
- int tls; /* czy ³±czymy po TLS? */
- int image_size; /* maksymalny rozmiar obrazka w KiB */
- int era_omnix; /* czy udawaæ klienta era omnix? */
-
- char dummy[6 * sizeof(int)]; /* miejsce na kolejnych 6 zmiennych,
- * ¿eby z dodaniem parametru nie
- * zmienia³ siê rozmiar struktury */
-};
-
-struct gg_session *gg_login(const struct gg_login_params *p);
-void gg_free_session(struct gg_session *sess);
-void gg_logoff(struct gg_session *sess);
-int gg_change_status(struct gg_session *sess, int status);
-int gg_change_status_descr(struct gg_session *sess, int status, const char *descr);
-int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int time);
-int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message);
-int gg_send_message_richtext(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, const unsigned char *format, int formatlen);
-int gg_send_message_confer(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message);
-int gg_send_message_confer_richtext(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message, const unsigned char *format, int formatlen);
-int gg_send_message_ctcp(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, int message_len);
-int gg_ping(struct gg_session *sess);
-int gg_userlist_request(struct gg_session *sess, char type, const char *request);
-int gg_image_request(struct gg_session *sess, uin_t recipient, int size, uint32_t crc32);
-int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const char *image, int size);
-
-uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len);
-
-struct gg_image_queue {
- uin_t sender; /* nadawca obrazka */
- uint32_t size; /* rozmiar */
- uint32_t crc32; /* suma kontrolna */
- char *filename; /* nazwa pliku */
- char *image; /* bufor z obrazem */
- uint32_t done; /* ile ju¿ wczytano */
-
- struct gg_image_queue *next; /* nastêpny na li¶cie */
-};
-
-/*
- * enum gg_event_t
- *
- * rodzaje zdarzeñ.
- */
-enum gg_event_t {
- GG_EVENT_NONE = 0, /* nic siê nie wydarzy³o */
- GG_EVENT_MSG, /* otrzymano wiadomo¶æ */
- GG_EVENT_NOTIFY, /* kto¶ siê pojawi³ */
- GG_EVENT_NOTIFY_DESCR, /* kto¶ siê pojawi³ z opisem */
- GG_EVENT_STATUS, /* kto¶ zmieni³ stan */
- GG_EVENT_ACK, /* potwierdzenie wys³ania wiadomo¶ci */
- GG_EVENT_PONG, /* pakiet pong */
- GG_EVENT_CONN_FAILED, /* po³±czenie siê nie uda³o */
- GG_EVENT_CONN_SUCCESS, /* po³±czenie siê powiod³o */
- GG_EVENT_DISCONNECT, /* serwer zrywa po³±czenie */
-
- GG_EVENT_DCC_NEW, /* nowe po³±czenie miêdzy klientami */
- GG_EVENT_DCC_ERROR, /* b³±d po³±czenia miêdzy klientami */
- GG_EVENT_DCC_DONE, /* zakoñczono po³±czenie */
- GG_EVENT_DCC_CLIENT_ACCEPT, /* moment akceptacji klienta */
- GG_EVENT_DCC_CALLBACK, /* klient siê po³±czy³ na ¿±danie */
- GG_EVENT_DCC_NEED_FILE_INFO, /* nale¿y wype³niæ file_info */
- GG_EVENT_DCC_NEED_FILE_ACK, /* czeka na potwierdzenie pliku */
- GG_EVENT_DCC_NEED_VOICE_ACK, /* czeka na potwierdzenie rozmowy */
- GG_EVENT_DCC_VOICE_DATA, /* ramka danych rozmowy g³osowej */
-
- GG_EVENT_PUBDIR50_SEARCH_REPLY, /* odpowiedz wyszukiwania */
- GG_EVENT_PUBDIR50_READ, /* odczytano w³asne dane z katalogu */
- GG_EVENT_PUBDIR50_WRITE, /* wpisano w³asne dane do katalogu */
-
- GG_EVENT_STATUS60, /* kto¶ zmieni³ stan w GG 6.0 */
- GG_EVENT_NOTIFY60, /* kto¶ siê pojawi³ w GG 6.0 */
- GG_EVENT_USERLIST, /* odpowied¼ listy kontaktów w GG 6.0 */
- GG_EVENT_IMAGE_REQUEST, /* pro¶ba o wys³anie obrazka GG 6.0 */
- GG_EVENT_IMAGE_REPLY, /* podes³any obrazek GG 6.0 */
- GG_EVENT_DCC_ACK /* potwierdzenie transmisji */
-};
-
-#define GG_EVENT_SEARCH50_REPLY GG_EVENT_PUBDIR50_SEARCH_REPLY
-
-/*
- * enum gg_failure_t
- *
- * okre¶la powód nieudanego po³±czenia.
- */
-enum gg_failure_t {
- GG_FAILURE_RESOLVING = 1, /* nie znaleziono serwera */
- GG_FAILURE_CONNECTING, /* nie mo¿na siê po³±czyæ */
- GG_FAILURE_INVALID, /* serwer zwróci³ nieprawid³owe dane */
- GG_FAILURE_READING, /* zerwano po³±czenie podczas odczytu */
- GG_FAILURE_WRITING, /* zerwano po³±czenie podczas zapisu */
- GG_FAILURE_PASSWORD, /* nieprawid³owe has³o */
- GG_FAILURE_404, /* XXX nieu¿ywane */
- GG_FAILURE_TLS, /* b³±d negocjacji TLS */
- GG_FAILURE_NEED_EMAIL, /* serwer roz³±czy³ nas z pro¶b± o zmianê emaila */
- GG_FAILURE_INTRUDER, /* za du¿o prób po³±czenia siê z nieprawid³owym has³em */
- GG_FAILURE_UNAVAILABLE /* serwery s± wy³±czone */
-};
-
-/*
- * enum gg_error_t
- *
- * okre¶la rodzaj b³êdu wywo³anego przez dan± operacjê. nie zawiera
- * przesadnie szczegó³owych informacji o powodzie b³êdu, by nie komplikowaæ
- * obs³ugi b³êdów. je¶li wymagana jest wiêksza dok³adno¶æ, nale¿y sprawdziæ
- * zawarto¶æ zmiennej errno.
- */
-enum gg_error_t {
- GG_ERROR_RESOLVING = 1, /* b³±d znajdowania hosta */
- GG_ERROR_CONNECTING, /* b³±d ³aczenia siê */
- GG_ERROR_READING, /* b³±d odczytu */
- GG_ERROR_WRITING, /* b³±d wysy³ania */
-
- GG_ERROR_DCC_HANDSHAKE, /* b³±d negocjacji */
- GG_ERROR_DCC_FILE, /* b³±d odczytu/zapisu pliku */
- GG_ERROR_DCC_EOF, /* plik siê skoñczy³? */
- GG_ERROR_DCC_NET, /* b³±d wysy³ania/odbierania */
- GG_ERROR_DCC_REFUSED /* po³±czenie odrzucone przez usera */
-};
-
-/*
- * struktury dotycz±ce wyszukiwania w GG 5.0. NIE NALE¯Y SIÊ DO NICH
- * ODWO£YWAÆ BEZPO¦REDNIO! do dostêpu do nich s³u¿± funkcje gg_pubdir50_*()
- */
-struct gg_pubdir50_entry {
- int num;
- char *field;
- char *value;
-};
-
-struct gg_pubdir50_s {
- int count;
- uin_t next;
- int type;
- uint32_t seq;
- struct gg_pubdir50_entry *entries;
- int entries_count;
-};
-
-/*
- * typedef gg_pubdir_50_t
- *
- * typ opisuj±cy zapytanie lub wynik zapytania katalogu publicznego
- * z protoko³u GG 5.0. nie nale¿y siê odwo³ywaæ bezpo¶rednio do jego
- * pól -- s³u¿± do tego funkcje gg_pubdir50_*()
- */
-typedef struct gg_pubdir50_s *gg_pubdir50_t;
-
-/*
- * struct gg_event
- *
- * struktura opisuj±ca rodzaj zdarzenia. wychodzi z gg_watch_fd() lub
- * z gg_dcc_watch_fd()
- */
-struct gg_event {
- int type; /* rodzaj zdarzenia -- gg_event_t */
- union { /* @event */
- struct gg_notify_reply *notify; /* informacje o li¶cie kontaktów -- GG_EVENT_NOTIFY */
-
- enum gg_failure_t failure; /* b³±d po³±czenia -- GG_EVENT_FAILURE */
-
- struct gg_dcc *dcc_new; /* nowe po³±czenie bezpo¶rednie -- GG_EVENT_DCC_NEW */
-
- int dcc_error; /* b³±d po³±czenia bezpo¶redniego -- GG_EVENT_DCC_ERROR */
-
- gg_pubdir50_t pubdir50; /* wynik operacji zwi±zanej z katalogiem publicznym -- GG_EVENT_PUBDIR50_* */
-
- struct { /* @msg odebrano wiadomo¶æ -- GG_EVENT_MSG */
- uin_t sender; /* numer nadawcy */
- int msgclass; /* klasa wiadomo¶ci */
- time_t time; /* czas nadania */
- unsigned char *message; /* tre¶æ wiadomo¶ci */
-
- int recipients_count; /* ilo¶æ odbiorców konferencji */
- uin_t *recipients; /* odbiorcy konferencji */
-
- int formats_length; /* d³ugo¶æ informacji o formatowaniu tekstu */
- void *formats; /* informacje o formatowaniu tekstu */
- } msg;
-
- struct { /* @notify_descr informacje o li¶cie kontaktów z opisami stanu -- GG_EVENT_NOTIFY_DESCR */
- struct gg_notify_reply *notify; /* informacje o li¶cie kontaktów */
- char *descr; /* opis stanu */
- } notify_descr;
-
- struct { /* @status zmiana stanu -- GG_EVENT_STATUS */
- uin_t uin; /* numer */
- uint32_t status; /* nowy stan */
- char *descr; /* opis stanu */
- } status;
-
- struct { /* @status60 zmiana stanu -- GG_EVENT_STATUS60 */
- uin_t uin; /* numer */
- int status; /* nowy stan */
- uint32_t remote_ip; /* adres ip */
- uint16_t remote_port; /* port */
- int version; /* wersja klienta */
- int image_size; /* maksymalny rozmiar grafiki w KiB */
- char *descr; /* opis stanu */
- time_t time; /* czas powrotu */
- } status60;
-
- struct { /* @notify60 informacja o li¶cie kontaktów -- GG_EVENT_NOTIFY60 */
- uin_t uin; /* numer */
- int status; /* stan */
- uint32_t remote_ip; /* adres ip */
- uint16_t remote_port; /* port */
- int version; /* wersja klienta */
- int image_size; /* maksymalny rozmiar grafiki w KiB */
- char *descr; /* opis stanu */
- time_t time; /* czas powrotu */
- } *notify60;
-
- struct { /* @ack potwierdzenie wiadomo¶ci -- GG_EVENT_ACK */
- uin_t recipient; /* numer odbiorcy */
- int status; /* stan dorêczenia wiadomo¶ci */
- int seq; /* numer sekwencyjny wiadomo¶ci */
- } ack;
-
- struct { /* @dcc_voice_data otrzymano dane d¼wiêkowe -- GG_EVENT_DCC_VOICE_DATA */
- uint8_t *data; /* dane d¼wiêkowe */
- int length; /* ilo¶æ danych d¼wiêkowych */
- } dcc_voice_data;
-
- struct { /* @userlist odpowied¼ listy kontaktów serwera */
- char type; /* rodzaj odpowiedzi */
- char *reply; /* tre¶æ odpowiedzi */
- } userlist;
-
- struct { /* @image_request pro¶ba o obrazek */
- uin_t sender; /* nadawca pro¶by */
- uint32_t size; /* rozmiar obrazka */
- uint32_t crc32; /* suma kontrolna */
- } image_request;
-
- struct { /* @image_reply odpowied¼ z obrazkiem */
- uin_t sender; /* nadawca odpowiedzi */
- uint32_t size; /* rozmiar obrazka */
- uint32_t crc32; /* suma kontrolna */
- char *filename; /* nazwa pliku */
- char *image; /* bufor z obrazkiem */
- } image_reply;
- } event;
-};
-
-struct gg_event *gg_watch_fd(struct gg_session *sess);
-void gg_event_free(struct gg_event *e);
-#define gg_free_event gg_event_free
-
-/*
- * funkcje obs³ugi listy kontaktów.
- */
-int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count);
-int gg_notify(struct gg_session *sess, uin_t *userlist, int count);
-int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type);
-int gg_add_notify(struct gg_session *sess, uin_t uin);
-int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type);
-int gg_remove_notify(struct gg_session *sess, uin_t uin);
-
-/*
- * funkcje obs³ugi http.
- */
-struct gg_http *gg_http_connect(const char *hostname, int port, int async, const char *method, const char *path, const char *header);
-int gg_http_watch_fd(struct gg_http *h);
-void gg_http_stop(struct gg_http *h);
-void gg_http_free(struct gg_http *h);
-void gg_http_free_fields(struct gg_http *h);
-#define gg_free_http gg_http_free
-
-/*
- * struktury opisuj±ca kryteria wyszukiwania dla gg_search(). nieaktualne,
- * zast±pione przez gg_pubdir50_t. pozostawiono je dla zachowania ABI.
- */
-struct gg_search_request {
- int active;
- unsigned int start;
- char *nickname;
- char *first_name;
- char *last_name;
- char *city;
- int gender;
- int min_birth;
- int max_birth;
- char *email;
- char *phone;
- uin_t uin;
-};
-
-struct gg_search {
- int count;
- struct gg_search_result *results;
-};
-
-struct gg_search_result {
- uin_t uin;
- char *first_name;
- char *last_name;
- char *nickname;
- int born;
- int gender;
- char *city;
- int active;
-};
-
-#define GG_GENDER_NONE 0
-#define GG_GENDER_FEMALE 1
-#define GG_GENDER_MALE 2
-
-/*
- * funkcje wyszukiwania.
- */
-struct gg_http *gg_search(const struct gg_search_request *r, int async);
-int gg_search_watch_fd(struct gg_http *f);
-void gg_free_search(struct gg_http *f);
-#define gg_search_free gg_free_search
-
-const struct gg_search_request *gg_search_request_mode_0(char *nickname, char *first_name, char *last_name, char *city, int gender, int min_birth, int max_birth, int active, int start);
-const struct gg_search_request *gg_search_request_mode_1(char *email, int active, int start);
-const struct gg_search_request *gg_search_request_mode_2(char *phone, int active, int start);
-const struct gg_search_request *gg_search_request_mode_3(uin_t uin, int active, int start);
-void gg_search_request_free(struct gg_search_request *r);
-
-/*
- * funkcje obs³ugi katalogu publicznego zgodne z GG 5.0. tym razem funkcje
- * zachowuj± pewien poziom abstrakcji, ¿eby unikn±æ zmian ABI przy zmianach
- * w protokole.
- *
- * NIE NALE¯Y SIÊ ODWO£YWAÆ DO PÓL gg_pubdir50_t BEZPO¦REDNIO!
- */
-uint32_t gg_pubdir50(struct gg_session *sess, gg_pubdir50_t req);
-gg_pubdir50_t gg_pubdir50_new(int type);
-int gg_pubdir50_add(gg_pubdir50_t req, const char *field, const char *value);
-int gg_pubdir50_seq_set(gg_pubdir50_t req, uint32_t seq);
-const char *gg_pubdir50_get(gg_pubdir50_t res, int num, const char *field);
-int gg_pubdir50_type(gg_pubdir50_t res);
-int gg_pubdir50_count(gg_pubdir50_t res);
-uin_t gg_pubdir50_next(gg_pubdir50_t res);
-uint32_t gg_pubdir50_seq(gg_pubdir50_t res);
-void gg_pubdir50_free(gg_pubdir50_t res);
-
-#define GG_PUBDIR50_UIN "FmNumber"
-#define GG_PUBDIR50_STATUS "FmStatus"
-#define GG_PUBDIR50_FIRSTNAME "firstname"
-#define GG_PUBDIR50_LASTNAME "lastname"
-#define GG_PUBDIR50_NICKNAME "nickname"
-#define GG_PUBDIR50_BIRTHYEAR "birthyear"
-#define GG_PUBDIR50_CITY "city"
-#define GG_PUBDIR50_GENDER "gender"
-#define GG_PUBDIR50_GENDER_FEMALE "1"
-#define GG_PUBDIR50_GENDER_MALE "2"
-#define GG_PUBDIR50_GENDER_SET_FEMALE "2"
-#define GG_PUBDIR50_GENDER_SET_MALE "1"
-#define GG_PUBDIR50_ACTIVE "ActiveOnly"
-#define GG_PUBDIR50_ACTIVE_TRUE "1"
-#define GG_PUBDIR50_START "fmstart"
-#define GG_PUBDIR50_FAMILYNAME "familyname"
-#define GG_PUBDIR50_FAMILYCITY "familycity"
-
-int gg_pubdir50_handle_reply(struct gg_event *e, const char *packet, int length);
-
-/*
- * struct gg_pubdir
- *
- * operacje na katalogu publicznym.
- */
-struct gg_pubdir {
- int success; /* czy siê uda³o */
- uin_t uin; /* otrzymany numerek. 0 je¶li b³±d */
-};
-
-/* ogólne funkcje, nie powinny byæ u¿ywane */
-int gg_pubdir_watch_fd(struct gg_http *f);
-void gg_pubdir_free(struct gg_http *f);
-#define gg_free_pubdir gg_pubdir_free
-
-struct gg_token {
- int width; /* szeroko¶æ obrazka */
- int height; /* wysoko¶æ obrazka */
- int length; /* ilo¶æ znaków w tokenie */
- char *tokenid; /* id tokenu */
-};
-
-/* funkcje dotycz±ce tokenów */
-struct gg_http *gg_token(int async);
-int gg_token_watch_fd(struct gg_http *h);
-void gg_token_free(struct gg_http *h);
-
-/* rejestracja nowego numerka */
-struct gg_http *gg_register(const char *email, const char *password, int async);
-struct gg_http *gg_register2(const char *email, const char *password, const char *qa, int async);
-struct gg_http *gg_register3(const char *email, const char *password, const char *tokenid, const char *tokenval, int async);
-#define gg_register_watch_fd gg_pubdir_watch_fd
-#define gg_register_free gg_pubdir_free
-#define gg_free_register gg_pubdir_free
-
-struct gg_http *gg_unregister(uin_t uin, const char *password, const char *email, int async);
-struct gg_http *gg_unregister2(uin_t uin, const char *password, const char *qa, int async);
-struct gg_http *gg_unregister3(uin_t uin, const char *password, const char *tokenid, const char *tokenval, int async);
-#define gg_unregister_watch_fd gg_pubdir_watch_fd
-#define gg_unregister_free gg_pubdir_free
-
-/* przypomnienie has³a e-mailem */
-struct gg_http *gg_remind_passwd(uin_t uin, int async);
-struct gg_http *gg_remind_passwd2(uin_t uin, const char *tokenid, const char *tokenval, int async);
-struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async);
-#define gg_remind_passwd_watch_fd gg_pubdir_watch_fd
-#define gg_remind_passwd_free gg_pubdir_free
-#define gg_free_remind_passwd gg_pubdir_free
-
-/* zmiana has³a */
-struct gg_http *gg_change_passwd(uin_t uin, const char *passwd, const char *newpasswd, const char *newemail, int async);
-struct gg_http *gg_change_passwd2(uin_t uin, const char *passwd, const char *newpasswd, const char *email, const char *newemail, int async);
-struct gg_http *gg_change_passwd3(uin_t uin, const char *passwd, const char *newpasswd, const char *qa, int async);
-struct gg_http *gg_change_passwd4(uin_t uin, const char *email, const char *passwd, const char *newpasswd, const char *tokenid, const char *tokenval, int async);
-#define gg_change_passwd_free gg_pubdir_free
-#define gg_free_change_passwd gg_pubdir_free
-
-/*
- * struct gg_change_info_request
- *
- * opis ¿±dania zmiany informacji w katalogu publicznym.
- */
-struct gg_change_info_request {
- char *first_name; /* imiê */
- char *last_name; /* nazwisko */
- char *nickname; /* pseudonim */
- char *email; /* email */
- int born; /* rok urodzenia */
- int gender; /* p³eæ */
- char *city; /* miasto */
-};
-
-struct gg_change_info_request *gg_change_info_request_new(const char *first_name, const char *last_name, const char *nickname, const char *email, int born, int gender, const char *city);
-void gg_change_info_request_free(struct gg_change_info_request *r);
-
-struct gg_http *gg_change_info(uin_t uin, const char *passwd, const struct gg_change_info_request *request, int async);
-#define gg_change_pubdir_watch_fd gg_pubdir_watch_fd
-#define gg_change_pubdir_free gg_pubdir_free
-#define gg_free_change_pubdir gg_pubdir_free
-
-/*
- * funkcje dotycz±ce listy kontaktów na serwerze.
- */
-struct gg_http *gg_userlist_get(uin_t uin, const char *password, int async);
-int gg_userlist_get_watch_fd(struct gg_http *f);
-void gg_userlist_get_free(struct gg_http *f);
-
-struct gg_http *gg_userlist_put(uin_t uin, const char *password, const char *contacts, int async);
-int gg_userlist_put_watch_fd(struct gg_http *f);
-void gg_userlist_put_free(struct gg_http *f);
-
-struct gg_http *gg_userlist_remove(uin_t uin, const char *password, int async);
-int gg_userlist_remove_watch_fd(struct gg_http *f);
-void gg_userlist_remove_free(struct gg_http *f);
-
-
-
-/*
- * funkcje dotycz±ce komunikacji miêdzy klientami.
- */
-extern int gg_dcc_port; /* port, na którym nas³uchuje klient */
-extern unsigned long gg_dcc_ip; /* adres, na którym nas³uchuje klient */
-
-int gg_dcc_request(struct gg_session *sess, uin_t uin);
-
-struct gg_dcc *gg_dcc_send_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin);
-struct gg_dcc *gg_dcc_get_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin);
-struct gg_dcc *gg_dcc_voice_chat(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin);
-void gg_dcc_set_type(struct gg_dcc *d, int type);
-int gg_dcc_fill_file_info(struct gg_dcc *d, const char *filename);
-int gg_dcc_fill_file_info2(struct gg_dcc *d, const char *filename, const char *local_filename);
-int gg_dcc_voice_send(struct gg_dcc *d, char *buf, int length);
-
-#define GG_DCC_VOICE_FRAME_LENGTH 195
-#define GG_DCC_VOICE_FRAME_LENGTH_505 326
-
-struct gg_dcc *gg_dcc_socket_create(uin_t uin, uint16_t port);
-#define gg_dcc_socket_free gg_free_dcc
-#define gg_dcc_socket_watch_fd gg_dcc_watch_fd
-
-struct gg_event *gg_dcc_watch_fd(struct gg_dcc *d);
-
-void gg_dcc_free(struct gg_dcc *c);
-#define gg_free_dcc gg_dcc_free
-
-/*
- * je¶li chcemy sobie podebugowaæ, wystarczy ustawiæ `gg_debug_level'.
- * niestety w miarê przybywania wpisów `gg_debug(...)' nie chcia³o mi
- * siê ustawiaæ odpowiednich leveli, wiêc wiêkszo¶æ sz³a do _MISC.
- */
-extern int gg_debug_level; /* poziom debugowania. mapa bitowa sta³ych GG_DEBUG_* */
-
-/*
- * mo¿na podaæ wska¼nik do funkcji obs³uguj±cej wywo³ania gg_debug().
- * nieoficjalne, nieudokumentowane, mo¿e siê zmieniæ. je¶li kto¶ jest
- * zainteresowany, niech da znaæ na ekg-devel.
- */
-extern void (*gg_debug_handler)(int level, const char *format, va_list ap);
-
-/*
- * mo¿na podaæ plik, do którego bêd± zapisywane teksty z gg_debug().
- */
-extern FILE *gg_debug_file;
-
-#define GG_DEBUG_NET 1
-#define GG_DEBUG_TRAFFIC 2
-#define GG_DEBUG_DUMP 4
-#define GG_DEBUG_FUNCTION 8
-#define GG_DEBUG_MISC 16
-
-#ifdef GG_DEBUG_DISABLE
-#define gg_debug(x, y...) do { } while(0)
-#else
-void gg_debug(int level, const char *format, ...);
-#endif
-
-const char *gg_libgadu_version(void);
-
-/*
- * konfiguracja http proxy.
- */
-extern int gg_proxy_enabled; /* w³±cza obs³ugê proxy */
-extern char *gg_proxy_host; /* okre¶la adres serwera proxy */
-extern int gg_proxy_port; /* okre¶la port serwera proxy */
-extern char *gg_proxy_username; /* okre¶la nazwê u¿ytkownika przy autoryzacji serwera proxy */
-extern char *gg_proxy_password; /* okre¶la has³o u¿ytkownika przy autoryzacji serwera proxy */
-extern int gg_proxy_http_only; /* w³±cza obs³ugê proxy wy³±cznie dla us³ug HTTP */
-
-
-/*
- * adres, z którego ¶lemy pakiety (np ³±czymy siê z serwerem)
- * u¿ywany przy gg_connect()
- */
-extern unsigned long gg_local_ip;
-/*
- * -------------------------------------------------------------------------
- * poni¿ej znajduj± siê wewnêtrzne sprawy biblioteki. zwyk³y klient nie
- * powinien ich w ogóle ruszaæ, bo i nie ma po co. wszystko mo¿na za³atwiæ
- * procedurami wy¿szego poziomu, których definicje znajduj± siê na pocz±tku
- * tego pliku.
- * -------------------------------------------------------------------------
- */
-
-#ifdef __GG_LIBGADU_HAVE_PTHREAD
-int gg_resolve_pthread(int *fd, void **resolver, const char *hostname);
-#endif
-
-#ifdef _WIN32
-int gg_thread_socket(int thread_id, int socket);
-#endif
-
-int gg_resolve(int *fd, int *pid, const char *hostname);
-
-#ifdef __GNUC__
-char *gg_saprintf(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
-#else
-char *gg_saprintf(const char *format, ...);
-#endif
-
-char *gg_vsaprintf(const char *format, va_list ap);
-
-#define gg_alloc_sprintf gg_saprintf
-
-char *gg_get_line(char **ptr);
-
-int gg_connect(void *addr, int port, int async);
-struct in_addr *gg_gethostbyname(const char *hostname);
-char *gg_read_line(int sock, char *buf, int length);
-void gg_chomp(char *line);
-char *gg_urlencode(const char *str);
-int gg_http_hash(const char *format, ...);
-int gg_read(struct gg_session *sess, char *buf, int length);
-int gg_write(struct gg_session *sess, const char *buf, int length);
-void *gg_recv_packet(struct gg_session *sess);
-int gg_send_packet(struct gg_session *sess, int type, ...);
-unsigned int gg_login_hash(const unsigned char *password, unsigned int seed);
-uint32_t gg_fix32(uint32_t x);
-uint16_t gg_fix16(uint16_t x);
-#define fix16 gg_fix16
-#define fix32 gg_fix32
-char *gg_proxy_auth(void);
-char *gg_base64_encode(const char *buf);
-char *gg_base64_decode(const char *buf);
-int gg_image_queue_remove(struct gg_session *s, struct gg_image_queue *q, int freeq);
-
-#define GG_APPMSG_HOST "appmsg.gadu-gadu.pl"
-#define GG_APPMSG_PORT 80
-#define GG_PUBDIR_HOST "pubdir.gadu-gadu.pl"
-#define GG_PUBDIR_PORT 80
-#define GG_REGISTER_HOST "register.gadu-gadu.pl"
-#define GG_REGISTER_PORT 80
-#define GG_REMIND_HOST "retr.gadu-gadu.pl"
-#define GG_REMIND_PORT 80
-
-#define GG_DEFAULT_PORT 8074
-#define GG_HTTPS_PORT 443
-#define GG_HTTP_USERAGENT "Mozilla/4.7 [en] (Win98; I)"
-
-#define GG_DEFAULT_CLIENT_VERSION "6, 1, 0, 158"
-#define GG_DEFAULT_PROTOCOL_VERSION 0x24
-#define GG_DEFAULT_TIMEOUT 30
-#define GG_HAS_AUDIO_MASK 0x40000000
-#define GG_ERA_OMNIX_MASK 0x04000000
-#define GG_LIBGADU_VERSION "CVS"
-
-#define GG_DEFAULT_DCC_PORT 1550
-
-struct gg_header {
- uint32_t type; /* typ pakietu */
- uint32_t length; /* d³ugo¶æ reszty pakietu */
-} GG_PACKED;
-
-#define GG_WELCOME 0x0001
-#define GG_NEED_EMAIL 0x0014
-
-struct gg_welcome {
- uint32_t key; /* klucz szyfrowania has³a */
-} GG_PACKED;
-
-#define GG_LOGIN 0x000c
-
-struct gg_login {
- uint32_t uin; /* mój numerek */
- uint32_t hash; /* hash has³a */
- uint32_t status; /* status na dzieñ dobry */
- uint32_t version; /* moja wersja klienta */
- uint32_t local_ip; /* mój adres ip */
- uint16_t local_port; /* port, na którym s³ucham */
-} GG_PACKED;
-
-#define GG_LOGIN_EXT 0x0013
-
-struct gg_login_ext {
- uint32_t uin; /* mój numerek */
- uint32_t hash; /* hash has³a */
- uint32_t status; /* status na dzieñ dobry */
- uint32_t version; /* moja wersja klienta */
- uint32_t local_ip; /* mój adres ip */
- uint16_t local_port; /* port, na którym s³ucham */
- uint32_t external_ip; /* zewnêtrzny adres ip */
- uint16_t external_port; /* zewnêtrzny port */
-} GG_PACKED;
-
-#define GG_LOGIN60 0x0015
-
-struct gg_login60 {
- uint32_t uin; /* mój numerek */
- uint32_t hash; /* hash has³a */
- uint32_t status; /* status na dzieñ dobry */
- uint32_t version; /* moja wersja klienta */
- uint8_t dunno1; /* 0x00 */
- uint32_t local_ip; /* mój adres ip */
- uint16_t local_port; /* port, na którym s³ucham */
- uint32_t external_ip; /* zewnêtrzny adres ip */
- uint16_t external_port; /* zewnêtrzny port */
- uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */
- uint8_t dunno2; /* 0xbe */
-} GG_PACKED;
-
-#define GG_LOGIN_OK 0x0003
-
-#define GG_LOGIN_FAILED 0x0009
-
-#define GG_PUBDIR50_REQUEST 0x0014
-
-#define GG_PUBDIR50_WRITE 0x01
-#define GG_PUBDIR50_READ 0x02
-#define GG_PUBDIR50_SEARCH 0x03
-#define GG_PUBDIR50_SEARCH_REQUEST GG_PUBDIR50_SEARCH
-#define GG_PUBDIR50_SEARCH_REPLY 0x05
-
-struct gg_pubdir50_request {
- uint8_t type; /* GG_PUBDIR50_* */
- uint32_t seq; /* czas wys³ania zapytania */
-} GG_PACKED;
-
-#define GG_PUBDIR50_REPLY 0x000e
-
-struct gg_pubdir50_reply {
- uint8_t type; /* GG_PUBDIR50_* */
- uint32_t seq; /* czas wys³ania zapytania */
-} GG_PACKED;
-
-#define GG_NEW_STATUS 0x0002
-
-#define GG_STATUS_NOT_AVAIL 0x0001 /* niedostêpny */
-#define GG_STATUS_NOT_AVAIL_DESCR 0x0015 /* niedostêpny z opisem (4.8) */
-#define GG_STATUS_AVAIL 0x0002 /* dostêpny */
-#define GG_STATUS_AVAIL_DESCR 0x0004 /* dostêpny z opisem (4.9) */
-#define GG_STATUS_BUSY 0x0003 /* zajêty */
-#define GG_STATUS_BUSY_DESCR 0x0005 /* zajêty z opisem (4.8) */
-#define GG_STATUS_INVISIBLE 0x0014 /* niewidoczny (4.6) */
-#define GG_STATUS_INVISIBLE_DESCR 0x0016 /* niewidoczny z opisem (4.9) */
-#define GG_STATUS_BLOCKED 0x0006 /* zablokowany */
-
-#define GG_STATUS_FRIENDS_MASK 0x8000 /* tylko dla znajomych (4.6) */
-
-#define GG_STATUS_DESCR_MAXSIZE 70
-
-/*
- * makra do ³atwego i szybkiego sprawdzania stanu.
- */
-
-/* GG_S_F() tryb tylko dla znajomych */
-#define GG_S_F(x) (((x) & GG_STATUS_FRIENDS_MASK) != 0)
-
-/* GG_S() stan bez uwzglêdnienia trybu tylko dla znajomych */
-#define GG_S(x) ((x) & ~GG_STATUS_FRIENDS_MASK)
-
-/* GG_S_A() dostêpny */
-#define GG_S_A(x) (GG_S(x) == GG_STATUS_AVAIL || GG_S(x) == GG_STATUS_AVAIL_DESCR)
-
-/* GG_S_NA() niedostêpny */
-#define GG_S_NA(x) (GG_S(x) == GG_STATUS_NOT_AVAIL || GG_S(x) == GG_STATUS_NOT_AVAIL_DESCR)
-
-/* GG_S_B() zajêty */
-#define GG_S_B(x) (GG_S(x) == GG_STATUS_BUSY || GG_S(x) == GG_STATUS_BUSY_DESCR)
-
-/* GG_S_I() niewidoczny */
-#define GG_S_I(x) (GG_S(x) == GG_STATUS_INVISIBLE || GG_S(x) == GG_STATUS_INVISIBLE_DESCR)
-
-/* GG_S_D() stan opisowy */
-#define GG_S_D(x) (GG_S(x) == GG_STATUS_NOT_AVAIL_DESCR || GG_S(x) == GG_STATUS_AVAIL_DESCR || GG_S(x) == GG_STATUS_BUSY_DESCR || GG_S(x) == GG_STATUS_INVISIBLE_DESCR)
-
-/* GG_S_BL() blokowany lub blokuj±cy */
-#define GG_S_BL(x) (GG_S(x) == GG_STATUS_BLOCKED)
-
-struct gg_new_status {
- uint32_t status; /* na jaki zmieniæ? */
-} GG_PACKED;
-
-#define GG_NOTIFY_FIRST 0x000f
-#define GG_NOTIFY_LAST 0x0010
-
-#define GG_NOTIFY 0x0010
-
-struct gg_notify {
- uint32_t uin; /* numerek danej osoby */
- uint8_t dunno1; /* rodzaj wpisu w li¶cie */
-} GG_PACKED;
-
-#define GG_USER_OFFLINE 0x01 /* bêdziemy niewidoczni dla u¿ytkownika */
-#define GG_USER_NORMAL 0x03 /* zwyk³y u¿ytkownik */
-#define GG_USER_BLOCKED 0x04 /* zablokowany u¿ytkownik */
-
-#define GG_LIST_EMPTY 0x0012
-
-#define GG_NOTIFY_REPLY 0x000c /* tak, to samo co GG_LOGIN */
-
-struct gg_notify_reply {
- uint32_t uin; /* numerek */
- uint32_t status; /* status danej osoby */
- uint32_t remote_ip; /* adres ip delikwenta */
- uint16_t remote_port; /* port, na którym s³ucha klient */
- uint32_t version; /* wersja klienta */
- uint16_t dunno2; /* znowu port? */
-} GG_PACKED;
-
-#define GG_NOTIFY_REPLY60 0x0011
-
-struct gg_notify_reply60 {
- uint32_t uin; /* numerek plus flagi w MSB */
- uint8_t status; /* status danej osoby */
- uint32_t remote_ip; /* adres ip delikwenta */
- uint16_t remote_port; /* port, na którym s³ucha klient */
- uint8_t version; /* wersja klienta */
- uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */
- uint8_t dunno1; /* 0x00 */
-} GG_PACKED;
-
-#define GG_STATUS60 0x000f
-
-struct gg_status60 {
- uint32_t uin; /* numerek plus flagi w MSB */
- uint8_t status; /* status danej osoby */
- uint32_t remote_ip; /* adres ip delikwenta */
- uint16_t remote_port; /* port, na którym s³ucha klient */
- uint8_t version; /* wersja klienta */
- uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */
- uint8_t dunno1; /* 0x00 */
-} GG_PACKED;
-
-#define GG_ADD_NOTIFY 0x000d
-#define GG_REMOVE_NOTIFY 0x000e
-
-struct gg_add_remove {
- uint32_t uin; /* numerek */
- uint8_t dunno1; /* bitmapa */
-} GG_PACKED;
-
-#define GG_STATUS 0x0002
-
-struct gg_status {
- uint32_t uin; /* numerek */
- uint32_t status; /* nowy stan */
-} GG_PACKED;
-
-#define GG_SEND_MSG 0x000b
-
-#define GG_CLASS_QUEUED 0x0001
-#define GG_CLASS_OFFLINE GG_CLASS_QUEUED
-#define GG_CLASS_MSG 0x0004
-#define GG_CLASS_CHAT 0x0008
-#define GG_CLASS_CTCP 0x0010
-#define GG_CLASS_ACK 0x0020
-#define GG_CLASS_EXT GG_CLASS_ACK /* kompatybilno¶æ wstecz */
-
-#define GG_MSG_MAXSIZE 2000
-
-struct gg_send_msg {
- uint32_t recipient;
- uint32_t seq;
- uint32_t msgclass;
-} GG_PACKED;
-
-struct gg_msg_richtext {
- uint8_t flag;
- uint16_t length;
-} GG_PACKED;
-
-struct gg_msg_richtext_format {
- uint16_t position;
- uint8_t font;
-} GG_PACKED;
-
-struct gg_msg_richtext_image {
- uint16_t unknown1;
- uint32_t size;
- uint32_t crc32;
-} GG_PACKED;
-
-#define GG_FONT_BOLD 0x01
-#define GG_FONT_ITALIC 0x02
-#define GG_FONT_UNDERLINE 0x04
-#define GG_FONT_COLOR 0x08
-#define GG_FONT_IMAGE 0x80
-
-struct gg_msg_richtext_color {
- uint8_t red;
- uint8_t green;
- uint8_t blue;
-} GG_PACKED;
-
-struct gg_msg_recipients {
- uint8_t flag;
- uint32_t count;
-} GG_PACKED;
-
-struct gg_msg_image_request {
- uint8_t flag;
- uint32_t size;
- uint32_t crc32;
-} GG_PACKED;
-
-struct gg_msg_image_reply {
- uint8_t flag;
- uint32_t size;
- uint32_t crc32;
- /* char filename[]; */
- /* char image[]; */
-} GG_PACKED;
-
-#define GG_SEND_MSG_ACK 0x0005
-
-#define GG_ACK_BLOCKED 0x0001
-#define GG_ACK_DELIVERED 0x0002
-#define GG_ACK_QUEUED 0x0003
-#define GG_ACK_MBOXFULL 0x0004
-#define GG_ACK_NOT_DELIVERED 0x0006
-
-struct gg_send_msg_ack {
- uint32_t status;
- uint32_t recipient;
- uint32_t seq;
-} GG_PACKED;
-
-#define GG_RECV_MSG 0x000a
-
-struct gg_recv_msg {
- uint32_t sender;
- uint32_t seq;
- uint32_t time;
- uint32_t msgclass;
-} GG_PACKED;
-
-#define GG_PING 0x0008
-
-#define GG_PONG 0x0007
-
-#define GG_DISCONNECTING 0x000b
-
-#define GG_USERLIST_REQUEST 0x0016
-
-#define GG_USERLIST_PUT 0x00
-#define GG_USERLIST_PUT_MORE 0x01
-#define GG_USERLIST_GET 0x02
-
-struct gg_userlist_request {
- uint8_t type;
-} GG_PACKED;
-
-#define GG_USERLIST_REPLY 0x0010
-
-#define GG_USERLIST_PUT_REPLY 0x00
-#define GG_USERLIST_PUT_MORE_REPLY 0x02
-#define GG_USERLIST_GET_REPLY 0x06
-#define GG_USERLIST_GET_MORE_REPLY 0x04
-
-struct gg_userlist_reply {
- uint8_t type;
-} GG_PACKED;
-
-/*
- * pakiety, sta³e, struktury dla DCC
- */
-
-struct gg_dcc_tiny_packet {
- uint8_t type; /* rodzaj pakietu */
-} GG_PACKED;
-
-struct gg_dcc_small_packet {
- uint32_t type; /* rodzaj pakietu */
-} GG_PACKED;
-
-struct gg_dcc_big_packet {
- uint32_t type; /* rodzaj pakietu */
- uint32_t dunno1; /* niewiadoma */
- uint32_t dunno2; /* niewiadoma */
-} GG_PACKED;
-
-/*
- * póki co, nie znamy dok³adnie protoko³u. nie wiemy, co czemu odpowiada.
- * nazwy s± niepowa¿ne i tymczasowe.
- */
-#define GG_DCC_WANT_FILE 0x0003 /* peer chce plik */
-#define GG_DCC_HAVE_FILE 0x0001 /* wiêc mu damy */
-#define GG_DCC_HAVE_FILEINFO 0x0003 /* niech ma informacje o pliku */
-#define GG_DCC_GIMME_FILE 0x0006 /* peer jest pewny */
-#define GG_DCC_CATCH_FILE 0x0002 /* wysy³amy plik */
-
-#define GG_DCC_FILEATTR_READONLY 0x0020
-
-#define GG_DCC_TIMEOUT_SEND 1800 /* 30 minut */
-#define GG_DCC_TIMEOUT_GET 1800 /* 30 minut */
-#define GG_DCC_TIMEOUT_FILE_ACK 300 /* 5 minut */
-#define GG_DCC_TIMEOUT_VOICE_ACK 300 /* 5 minut */
-
-#ifdef __cplusplus
-}
-#ifdef _WIN32
-#pragma pack(pop)
-#endif
-#endif
-
-#endif /* __GG_LIBGADU_H */
-
-/*
- * Local variables:
- * c-indentation-style: k&r
- * c-basic-offset: 8
- * indent-tabs-mode: notnil
- * End:
- *
- * vim: shiftwidth=8:
- */
diff --git a/kopete/protocols/gadu/libgadu/pubdir.c b/kopete/protocols/gadu/libgadu/pubdir.c
deleted file mode 100644
index 2741ea4b..00000000
--- a/kopete/protocols/gadu/libgadu/pubdir.c
+++ /dev/null
@@ -1,689 +0,0 @@
-/* $Id$ */
-
-/*
- * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl>
- * Dawid Jarosz <dawjar@poczta.onet.pl>
- * Adam Wysocki <gophi@ekg.chmurka.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License Version
- * 2.1 as published by the Free Software Foundation.
- *
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "libgadu.h"
-
-/*
- * gg_register3()
- *
- * rozpoczyna rejestracj� u�ytkownika protoko�em GG 6.0. wymaga wcze�niejszego
- * pobrania tokenu za pomoc� funkcji gg_token().
- *
- * - email - adres e-mail klienta
- * - password - has�o klienta
- * - tokenid - identyfikator tokenu
- * - tokenval - warto�� tokenu
- * - async - po��czenie asynchroniczne
- *
- * zaalokowana struct gg_http, kt�r� po�niej nale�y zwolni�
- * funkcj� gg_register_free(), albo NULL je�li wyst�pi� b��d.
- */
-struct gg_http *gg_register3(const char *email, const char *password, const char *tokenid, const char *tokenval, int async)
-{
- struct gg_http *h;
- char *__pwd, *__email, *__tokenid, *__tokenval, *form, *query;
-
- if (!email || !password || !tokenid || !tokenval) {
- gg_debug(GG_DEBUG_MISC, "=> register, NULL parameter\n");
- errno = EFAULT;
- return NULL;
- }
-
- __pwd = gg_urlencode(password);
- __email = gg_urlencode(email);
- __tokenid = gg_urlencode(tokenid);
- __tokenval = gg_urlencode(tokenval);
-
- if (!__pwd || !__email || !__tokenid || !__tokenval) {
- gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for form fields\n");
- free(__pwd);
- free(__email);
- free(__tokenid);
- free(__tokenval);
- return NULL;
- }
-
- form = gg_saprintf("pwd=%s&email=%s&tokenid=%s&tokenval=%s&code=%u",
- __pwd, __email, __tokenid, __tokenval,
- gg_http_hash("ss", email, password));
-
- free(__pwd);
- free(__email);
- free(__tokenid);
- free(__tokenval);
-
- if (!form) {
- gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for form query\n");
- return NULL;
- }
-
- gg_debug(GG_DEBUG_MISC, "=> register, %s\n", form);
-
- query = gg_saprintf(
- "Host: " GG_REGISTER_HOST "\r\n"
- "Content-Type: application/x-www-form-urlencoded\r\n"
- "User-Agent: " GG_HTTP_USERAGENT "\r\n"
- "Content-Length: %d\r\n"
- "Pragma: no-cache\r\n"
- "\r\n"
- "%s",
- (int) strlen(form), form);
-
- free(form);
-
- if (!query) {
- gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for query\n");
- return NULL;
- }
-
- if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
- gg_debug(GG_DEBUG_MISC, "=> register, gg_http_connect() failed mysteriously\n");
- free(query);
- return NULL;
- }
-
- h->type = GG_SESSION_REGISTER;
-
- free(query);
-
- h->callback = gg_pubdir_watch_fd;
- h->destroy = gg_pubdir_free;
-
- if (!async)
- gg_pubdir_watch_fd(h);
-
- return h;
-}
-
-/*
- * gg_unregister3()
- *
- * usuwa konto u�ytkownika z serwera protoko�em GG 6.0
- *
- * - uin - numerek GG
- * - password - has�o klienta
- * - tokenid - identyfikator tokenu
- * - tokenval - warto�� tokenu
- * - async - po��czenie asynchroniczne
- *
- * zaalokowana struct gg_http, kt�r� po�niej nale�y zwolni�
- * funkcj� gg_unregister_free(), albo NULL je�li wyst�pi� b��d.
- */
-struct gg_http *gg_unregister3(uin_t uin, const char *password, const char *tokenid, const char *tokenval, int async)
-{
- struct gg_http *h;
- char *__fmpwd, *__pwd, *__tokenid, *__tokenval, *form, *query;
-
- if (!password || !tokenid || !tokenval) {
- gg_debug(GG_DEBUG_MISC, "=> unregister, NULL parameter\n");
- errno = EFAULT;
- return NULL;
- }
-
- __pwd = gg_saprintf("%ld", random());
- __fmpwd = gg_urlencode(password);
- __tokenid = gg_urlencode(tokenid);
- __tokenval = gg_urlencode(tokenval);
-
- if (!__fmpwd || !__pwd || !__tokenid || !__tokenval) {
- gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for form fields\n");
- free(__pwd);
- free(__fmpwd);
- free(__tokenid);
- free(__tokenval);
- return NULL;
- }
-
- form = gg_saprintf("fmnumber=%d&fmpwd=%s&delete=1&pwd=%s&email=deletedaccount@gadu-gadu.pl&tokenid=%s&tokenval=%s&code=%u", uin, __fmpwd, __pwd, __tokenid, __tokenval, gg_http_hash("ss", "deletedaccount@gadu-gadu.pl", __pwd));
-
- free(__fmpwd);
- free(__pwd);
- free(__tokenid);
- free(__tokenval);
-
- if (!form) {
- gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for form query\n");
- return NULL;
- }
-
- gg_debug(GG_DEBUG_MISC, "=> unregister, %s\n", form);
-
- query = gg_saprintf(
- "Host: " GG_REGISTER_HOST "\r\n"
- "Content-Type: application/x-www-form-urlencoded\r\n"
- "User-Agent: " GG_HTTP_USERAGENT "\r\n"
- "Content-Length: %d\r\n"
- "Pragma: no-cache\r\n"
- "\r\n"
- "%s",
- (int) strlen(form), form);
-
- free(form);
-
- if (!query) {
- gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for query\n");
- return NULL;
- }
-
- if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
- gg_debug(GG_DEBUG_MISC, "=> unregister, gg_http_connect() failed mysteriously\n");
- free(query);
- return NULL;
- }
-
- h->type = GG_SESSION_UNREGISTER;
-
- free(query);
-
- h->callback = gg_pubdir_watch_fd;
- h->destroy = gg_pubdir_free;
-
- if (!async)
- gg_pubdir_watch_fd(h);
-
- return h;
-}
-
-/*
- * gg_change_passwd4()
- *
- * wysy�a ��danie zmiany has�a zgodnie z protoko�em GG 6.0. wymaga
- * wcze�niejszego pobrania tokenu za pomoc� funkcji gg_token().
- *
- * - uin - numer
- * - email - adres e-mail
- * - passwd - stare has�o
- * - newpasswd - nowe has�o
- * - tokenid - identyfikator tokenu
- * - tokenval - warto�� tokenu
- * - async - po��czenie asynchroniczne
- *
- * zaalokowana struct gg_http, kt�r� po�niej nale�y zwolni�
- * funkcj� gg_change_passwd_free(), albo NULL je�li wyst�pi� b��d.
- */
-struct gg_http *gg_change_passwd4(uin_t uin, const char *email, const char *passwd, const char *newpasswd, const char *tokenid, const char *tokenval, int async)
-{
- struct gg_http *h;
- char *form, *query, *__email, *__fmpwd, *__pwd, *__tokenid, *__tokenval;
-
- if (!uin || !email || !passwd || !newpasswd || !tokenid || !tokenval) {
- gg_debug(GG_DEBUG_MISC, "=> change, NULL parameter\n");
- errno = EFAULT;
- return NULL;
- }
-
- __fmpwd = gg_urlencode(passwd);
- __pwd = gg_urlencode(newpasswd);
- __email = gg_urlencode(email);
- __tokenid = gg_urlencode(tokenid);
- __tokenval = gg_urlencode(tokenval);
-
- if (!__fmpwd || !__pwd || !__email || !__tokenid || !__tokenval) {
- gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n");
- free(__fmpwd);
- free(__pwd);
- free(__email);
- free(__tokenid);
- free(__tokenval);
- return NULL;
- }
-
- if (!(form = gg_saprintf("fmnumber=%d&fmpwd=%s&pwd=%s&email=%s&tokenid=%s&tokenval=%s&code=%u", uin, __fmpwd, __pwd, __email, __tokenid, __tokenval, gg_http_hash("ss", email, newpasswd)))) {
- gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n");
- free(__fmpwd);
- free(__pwd);
- free(__email);
- free(__tokenid);
- free(__tokenval);
-
- return NULL;
- }
-
- free(__fmpwd);
- free(__pwd);
- free(__email);
- free(__tokenid);
- free(__tokenval);
-
- gg_debug(GG_DEBUG_MISC, "=> change, %s\n", form);
-
- query = gg_saprintf(
- "Host: " GG_REGISTER_HOST "\r\n"
- "Content-Type: application/x-www-form-urlencoded\r\n"
- "User-Agent: " GG_HTTP_USERAGENT "\r\n"
- "Content-Length: %d\r\n"
- "Pragma: no-cache\r\n"
- "\r\n"
- "%s",
- (int) strlen(form), form);
-
- free(form);
-
- if (!query) {
- gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for query\n");
- return NULL;
- }
-
- if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
- gg_debug(GG_DEBUG_MISC, "=> change, gg_http_connect() failed mysteriously\n");
- free(query);
- return NULL;
- }
-
- h->type = GG_SESSION_PASSWD;
-
- free(query);
-
- h->callback = gg_pubdir_watch_fd;
- h->destroy = gg_pubdir_free;
-
- if (!async)
- gg_pubdir_watch_fd(h);
-
- return h;
-}
-
-/*
- * gg_remind_passwd3()
- *
- * wysy�a ��danie przypomnienia has�a e-mailem.
- *
- * - uin - numer
- * - email - adres e-mail taki, jak ten zapisany na serwerze
- * - async - po��czenie asynchroniczne
- * - tokenid - identyfikator tokenu
- * - tokenval - warto�� tokenu
- *
- * zaalokowana struct gg_http, kt�r� po�niej nale�y zwolni�
- * funkcj� gg_remind_passwd_free(), albo NULL je�li wyst�pi� b��d.
- */
-struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async)
-{
- struct gg_http *h;
- char *form, *query, *__tokenid, *__tokenval, *__email;
-
- if (!tokenid || !tokenval || !email) {
- gg_debug(GG_DEBUG_MISC, "=> remind, NULL parameter\n");
- errno = EFAULT;
- return NULL;
- }
-
- __tokenid = gg_urlencode(tokenid);
- __tokenval = gg_urlencode(tokenval);
- __email = gg_urlencode(email);
-
- if (!__tokenid || !__tokenval || !__email) {
- gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n");
- free(__tokenid);
- free(__tokenval);
- free(__email);
- return NULL;
- }
-
- if (!(form = gg_saprintf("userid=%d&code=%u&tokenid=%s&tokenval=%s&email=%s", uin, gg_http_hash("u", uin), __tokenid, __tokenval, __email))) {
- gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n");
- free(__tokenid);
- free(__tokenval);
- free(__email);
- return NULL;
- }
-
- free(__tokenid);
- free(__tokenval);
- free(__email);
-
- gg_debug(GG_DEBUG_MISC, "=> remind, %s\n", form);
-
- query = gg_saprintf(
- "Host: " GG_REMIND_HOST "\r\n"
- "Content-Type: application/x-www-form-urlencoded\r\n"
- "User-Agent: " GG_HTTP_USERAGENT "\r\n"
- "Content-Length: %d\r\n"
- "Pragma: no-cache\r\n"
- "\r\n"
- "%s",
- (int) strlen(form), form);
-
- free(form);
-
- if (!query) {
- gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for query\n");
- return NULL;
- }
-
- if (!(h = gg_http_connect(GG_REMIND_HOST, GG_REMIND_PORT, async, "POST", "/appsvc/fmsendpwd3.asp", query))) {
- gg_debug(GG_DEBUG_MISC, "=> remind, gg_http_connect() failed mysteriously\n");
- free(query);
- return NULL;
- }
-
- h->type = GG_SESSION_REMIND;
-
- free(query);
-
- h->callback = gg_pubdir_watch_fd;
- h->destroy = gg_pubdir_free;
-
- if (!async)
- gg_pubdir_watch_fd(h);
-
- return h;
-}
-
-/*
- * gg_pubdir_watch_fd()
- *
- * przy asynchronicznych operacjach na katalogu publicznym nale�y wywo�ywa�
- * t� funkcj� przy zmianach na obserwowanym deskryptorze.
- *
- * - h - struktura opisuj�ca po��czenie
- *
- * je�li wszystko posz�o dobrze to 0, inaczej -1. operacja b�dzie
- * zako�czona, je�li h->state == GG_STATE_DONE. je�li wyst�pi jaki�
- * b��d, to b�dzie tam GG_STATE_ERROR i odpowiedni kod b��du w h->error.
- */
-int gg_pubdir_watch_fd(struct gg_http *h)
-{
- struct gg_pubdir *p;
- char *tmp;
-
- if (!h) {
- errno = EFAULT;
- return -1;
- }
-
- if (h->state == GG_STATE_ERROR) {
- gg_debug(GG_DEBUG_MISC, "=> pubdir, watch_fd issued on failed session\n");
- errno = EINVAL;
- return -1;
- }
-
- if (h->state != GG_STATE_PARSING) {
- if (gg_http_watch_fd(h) == -1) {
- gg_debug(GG_DEBUG_MISC, "=> pubdir, http failure\n");
- errno = EINVAL;
- return -1;
- }
- }
-
- if (h->state != GG_STATE_PARSING)
- return 0;
-
- h->state = GG_STATE_DONE;
-
- if (!(h->data = p = malloc(sizeof(struct gg_pubdir)))) {
- gg_debug(GG_DEBUG_MISC, "=> pubdir, not enough memory for results\n");
- return -1;
- }
-
- p->success = 0;
- p->uin = 0;
-
- gg_debug(GG_DEBUG_MISC, "=> pubdir, let's parse \"%s\"\n", h->body);
-
- if ((tmp = strstr(h->body, "Tokens okregisterreply_packet.reg.dwUserId="))) {
- p->success = 1;
- p->uin = strtol(tmp + sizeof("Tokens okregisterreply_packet.reg.dwUserId=") - 1, NULL, 0);
- gg_debug(GG_DEBUG_MISC, "=> pubdir, success (okregisterreply, uin=%d)\n", p->uin);
- } else if ((tmp = strstr(h->body, "success")) || (tmp = strstr(h->body, "results"))) {
- p->success = 1;
- if (tmp[7] == ':')
- p->uin = strtol(tmp + 8, NULL, 0);
- gg_debug(GG_DEBUG_MISC, "=> pubdir, success (uin=%d)\n", p->uin);
- } else
- gg_debug(GG_DEBUG_MISC, "=> pubdir, error.\n");
-
- return 0;
-}
-
-/*
- * gg_pubdir_free()
- *
- * zwalnia pami�� po efektach operacji na katalogu publicznym.
- *
- * - h - zwalniana struktura
- */
-void gg_pubdir_free(struct gg_http *h)
-{
- if (!h)
- return;
-
- free(h->data);
- gg_http_free(h);
-}
-
-/*
- * gg_token()
- *
- * pobiera z serwera token do autoryzacji zak�adania konta, usuwania
- * konta i zmiany has�a.
- *
- * zaalokowana struct gg_http, kt�r� po�niej nale�y zwolni�
- * funkcj� gg_token_free(), albo NULL je�li wyst�pi� b��d.
- */
-struct gg_http *gg_token(int async)
-{
- struct gg_http *h;
- const char *query;
-
- query = "Host: " GG_REGISTER_HOST "\r\n"
- "Content-Type: application/x-www-form-urlencoded\r\n"
- "User-Agent: " GG_HTTP_USERAGENT "\r\n"
- "Content-Length: 0\r\n"
- "Pragma: no-cache\r\n"
- "\r\n";
-
- if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/regtoken.asp", query))) {
- gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n");
- return NULL;
- }
-
- h->type = GG_SESSION_TOKEN;
-
- h->callback = gg_token_watch_fd;
- h->destroy = gg_token_free;
-
- if (!async)
- gg_token_watch_fd(h);
-
- return h;
-}
-
-/*
- * gg_token_watch_fd()
- *
- * przy asynchronicznych operacjach zwi�zanych z tokenem nale�y wywo�ywa�
- * t� funkcj� przy zmianach na obserwowanym deskryptorze.
- *
- * - h - struktura opisuj�ca po��czenie
- *
- * je�li wszystko posz�o dobrze to 0, inaczej -1. operacja b�dzie
- * zako�czona, je�li h->state == GG_STATE_DONE. je�li wyst�pi jaki�
- * b��d, to b�dzie tam GG_STATE_ERROR i odpowiedni kod b��du w h->error.
- */
-int gg_token_watch_fd(struct gg_http *h)
-{
- if (!h) {
- errno = EFAULT;
- return -1;
- }
-
- if (h->state == GG_STATE_ERROR) {
- gg_debug(GG_DEBUG_MISC, "=> token, watch_fd issued on failed session\n");
- errno = EINVAL;
- return -1;
- }
-
- if (h->state != GG_STATE_PARSING) {
- if (gg_http_watch_fd(h) == -1) {
- gg_debug(GG_DEBUG_MISC, "=> token, http failure\n");
- errno = EINVAL;
- return -1;
- }
- }
-
- if (h->state != GG_STATE_PARSING)
- return 0;
-
- /* je�li h->data jest puste, to �ci�gali�my tokenid i url do niego,
- * ale je�li co� tam jest, to znaczy, �e mamy drugi etap polegaj�cy
- * na pobieraniu tokenu. */
- if (!h->data) {
- int width, height, length;
- char *url = NULL, *tokenid = NULL, *path, *headers;
- const char *host;
- struct gg_http *h2;
- struct gg_token *t;
-
- gg_debug(GG_DEBUG_MISC, "=> token body \"%s\"\n", h->body);
-
- if (h->body && (!(url = malloc(strlen(h->body))) || !(tokenid = malloc(strlen(h->body))))) {
- gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for results\n");
- free(url);
- return -1;
- }
-
- if (!h->body || sscanf(h->body, "%d %d %d\r\n%s\r\n%s", &width, &height, &length, tokenid, url) != 5) {
- gg_debug(GG_DEBUG_MISC, "=> token, parsing failed\n");
- free(url);
- free(tokenid);
- errno = EINVAL;
- return -1;
- }
-
- /* dostali�my tokenid i wszystkie niezb�dne informacje,
- * wi�c pobierzmy obrazek z tokenem */
-
- if (strncmp(url, "http://", 7)) {
- path = gg_saprintf("%s?tokenid=%s", url, tokenid);
- host = GG_REGISTER_HOST;
- } else {
- char *slash = (char*)strchr(url + 7, '/');
-
- if (slash) {
- path = gg_saprintf("%s?tokenid=%s", slash, tokenid);
- *slash = 0;
- host = url + 7;
- } else {
- gg_debug(GG_DEBUG_MISC, "=> token, url parsing failed\n");
- free(url);
- free(tokenid);
- errno = EINVAL;
- return -1;
- }
- }
-
- if (!path) {
- gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n");
- free(url);
- free(tokenid);
- return -1;
- }
-
- if (!(headers = gg_saprintf("Host: %s\r\nUser-Agent: " GG_HTTP_USERAGENT "\r\n\r\n", host))) {
- gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n");
- free(path);
- free(url);
- free(tokenid);
- return -1;
- }
-
- if (!(h2 = gg_http_connect(host, GG_REGISTER_PORT, h->async, "GET", path, headers))) {
- gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n");
- free(headers);
- free(url);
- free(path);
- free(tokenid);
- return -1;
- }
-
- free(headers);
- free(path);
- free(url);
-
- memcpy(h, h2, sizeof(struct gg_http));
- free(h2);
-
- h->type = GG_SESSION_TOKEN;
-
- h->callback = gg_token_watch_fd;
- h->destroy = gg_token_free;
-
- if (!h->async)
- gg_token_watch_fd(h);
-
- if (!(h->data = t = malloc(sizeof(struct gg_token)))) {
- gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token data\n");
- free(tokenid);
- return -1;
- }
-
- t->width = width;
- t->height = height;
- t->length = length;
- t->tokenid = tokenid;
- } else {
- /* obrazek mamy w h->body */
- h->state = GG_STATE_DONE;
- }
-
- return 0;
-}
-
-/*
- * gg_token_free()
- *
- * zwalnia pami�� po efektach pobierania tokenu.
- *
- * - h - zwalniana struktura
- */
-void gg_token_free(struct gg_http *h)
-{
- struct gg_token *t;
-
- if (!h)
- return;
-
- if ((t = h->data))
- free(t->tokenid);
-
- free(h->data);
- gg_http_free(h);
-}
-
-/*
- * Local variables:
- * c-indentation-style: k&r
- * c-basic-offset: 8
- * indent-tabs-mode: notnil
- * End:
- *
- * vim: shiftwidth=8:
- */
diff --git a/kopete/protocols/gadu/libgadu/pubdir50.c b/kopete/protocols/gadu/libgadu/pubdir50.c
deleted file mode 100644
index 877ab83e..00000000
--- a/kopete/protocols/gadu/libgadu/pubdir50.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/* $Id$ */
-
-/*
- * (C) Copyright 2003 Wojtek Kaniewski <wojtekka@irc.pl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License Version
- * 2.1 as published by the Free Software Foundation.
- *
- * 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include "libgadu.h"
-
-/*
- * gg_pubdir50_new()
- *
- * tworzy now± zmienn± typu gg_pubdir50_t.
- *
- * zaalokowana zmienna lub NULL w przypadku braku pamiêci.
- */
-gg_pubdir50_t gg_pubdir50_new(int type)
-{
- gg_pubdir50_t res = malloc(sizeof(struct gg_pubdir50_s));
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_new(%d);\n", type);
-
- if (!res) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_new() out of memory\n");
- return NULL;
- }
-
- memset(res, 0, sizeof(struct gg_pubdir50_s));
-
- res->type = type;
-
- return res;
-}
-
-/*
- * gg_pubdir50_add_n() // funkcja wewnêtrzna
- *
- * funkcja dodaje lub zastêpuje istniej±ce pole do zapytania lub odpowiedzi.
- *
- * - req - wska¼nik opisu zapytania,
- * - num - numer wyniku (0 dla zapytania),
- * - field - nazwa pola,
- * - value - warto¶æ pola,
- *
- * 0/-1
- */
-static int gg_pubdir50_add_n(gg_pubdir50_t req, int num, const char *field, const char *value)
-{
- struct gg_pubdir50_entry *tmp = NULL, *entry;
- char *dupfield, *dupvalue;
- int i;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_add_n(%p, %d, \"%s\", \"%s\");\n", req, num, field, value);
-
- if (!(dupvalue = strdup(value))) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n");
- return -1;
- }
-
- for (i = 0; i < req->entries_count; i++) {
- if (req->entries[i].num != num || strcmp(req->entries[i].field, field))
- continue;
-
- free(req->entries[i].value);
- req->entries[i].value = dupvalue;
-
- return 0;
- }
-
- if (!(dupfield = strdup(field))) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n");
- free(dupvalue);
- return -1;
- }
-
- if (!(tmp = realloc(req->entries, sizeof(struct gg_pubdir50_entry) * (req->entries_count + 1)))) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n");
- free(dupfield);
- free(dupvalue);
- return -1;
- }
-
- req->entries = tmp;
-
- entry = &req->entries[req->entries_count];
- entry->num = num;
- entry->field = dupfield;
- entry->value = dupvalue;
-
- req->entries_count++;
-
- return 0;
-}
-
-/*
- * gg_pubdir50_add()
- *
- * funkcja dodaje pole do zapytania.
- *
- * - req - wska¼nik opisu zapytania,
- * - field - nazwa pola,
- * - value - warto¶æ pola,
- *
- * 0/-1
- */
-int gg_pubdir50_add(gg_pubdir50_t req, const char *field, const char *value)
-{
- return gg_pubdir50_add_n(req, 0, field, value);
-}
-
-/*
- * gg_pubdir50_seq_set()
- *
- * ustawia numer sekwencyjny zapytania.
- *
- * - req - zapytanie,
- * - seq - nowy numer sekwencyjny.
- *
- * 0/-1.
- */
-int gg_pubdir50_seq_set(gg_pubdir50_t req, uint32_t seq)
-{
- gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_seq_set(%p, %d);\n", req, seq);
-
- if (!req) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_seq_set() invalid arguments\n");
- errno = EFAULT;
- return -1;
- }
-
- req->seq = seq;
-
- return 0;
-}
-
-/*
- * gg_pubdir50_free()
- *
- * zwalnia pamiêæ po zapytaniu lub rezultacie szukania u¿ytkownika.
- *
- * - s - zwalniana zmienna,
- */
-void gg_pubdir50_free(gg_pubdir50_t s)
-{
- int i;
-
- if (!s)
- return;
-
- for (i = 0; i < s->entries_count; i++) {
- free(s->entries[i].field);
- free(s->entries[i].value);
- }
-
- free(s->entries);
- free(s);
-}
-
-/*
- * gg_pubdir50()
- *
- * wysy³a zapytanie katalogu publicznego do serwera.
- *
- * - sess - sesja,
- * - req - zapytanie.
- *
- * numer sekwencyjny wyszukiwania lub 0 w przypadku b³êdu.
- */
-uint32_t gg_pubdir50(struct gg_session *sess, gg_pubdir50_t req)
-{
- int i, size = 5;
- uint32_t res;
- char *buf, *p;
- struct gg_pubdir50_request *r;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50(%p, %p);\n", sess, req);
-
- if (!sess || !req) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() invalid arguments\n");
- errno = EFAULT;
- return 0;
- }
-
- if (sess->state != GG_STATE_CONNECTED) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() not connected\n");
- errno = ENOTCONN;
- return 0;
- }
-
- for (i = 0; i < req->entries_count; i++) {
- /* wyszukiwanie bierze tylko pierwszy wpis */
- if (req->entries[i].num)
- continue;
-
- size += strlen(req->entries[i].field) + 1;
- size += strlen(req->entries[i].value) + 1;
- }
-
- if (!(buf = malloc(size))) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() out of memory (%d bytes)\n", size);
- return 0;
- }
-
- r = (struct gg_pubdir50_request*) buf;
- res = time(NULL);
- r->type = req->type;
- r->seq = (req->seq) ? gg_fix32(req->seq) : gg_fix32(time(NULL));
- req->seq = gg_fix32(r->seq);
-
- for (i = 0, p = buf + 5; i < req->entries_count; i++) {
- if (req->entries[i].num)
- continue;
-
- strcpy(p, req->entries[i].field);
- p += strlen(p) + 1;
-
- strcpy(p, req->entries[i].value);
- p += strlen(p) + 1;
- }
-
- if (gg_send_packet(sess, GG_PUBDIR50_REQUEST, buf, size, NULL, 0) == -1)
- res = 0;
-
- free(buf);
-
- return res;
-}
-
-/*
- * gg_pubdir50_handle_reply() // funkcja wewnêtrzna
- *
- * analizuje przychodz±cy pakiet odpowiedzi i zapisuje wynik w struct gg_event.
- *
- * - e - opis zdarzenia
- * - packet - zawarto¶æ pakietu odpowiedzi
- * - length - d³ugo¶æ pakietu odpowiedzi
- *
- * 0/-1
- */
-int gg_pubdir50_handle_reply(struct gg_event *e, const char *packet, int length)
-{
- const char *end = packet + length, *p;
- struct gg_pubdir50_reply *r = (struct gg_pubdir50_reply*) packet;
- gg_pubdir50_t res;
- int num = 0;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_handle_reply(%p, %p, %d);\n", e, packet, length);
-
- if (!e || !packet) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() invalid arguments\n");
- errno = EFAULT;
- return -1;
- }
-
- if (length < 5) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() packet too short\n");
- errno = EINVAL;
- return -1;
- }
-
- if (!(res = gg_pubdir50_new(r->type))) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() unable to allocate reply\n");
- return -1;
- }
-
- e->event.pubdir50 = res;
-
- res->seq = gg_fix32(r->seq);
-
- switch (res->type) {
- case GG_PUBDIR50_READ:
- e->type = GG_EVENT_PUBDIR50_READ;
- break;
-
- case GG_PUBDIR50_WRITE:
- e->type = GG_EVENT_PUBDIR50_WRITE;
- break;
-
- default:
- e->type = GG_EVENT_PUBDIR50_SEARCH_REPLY;
- break;
- }
-
- /* brak wyników? */
- if (length == 5)
- return 0;
-
- /* pomiñ pocz±tek odpowiedzi */
- p = packet + 5;
-
- while (p < end) {
- const char *field, *value;
-
- field = p;
-
- /* sprawd¼, czy nie mamy podzia³u na kolejne pole */
- if (!*field) {
- num++;
- field++;
- }
-
- value = NULL;
-
- for (p = field; p < end; p++) {
- /* je¶li mamy koniec tekstu... */
- if (!*p) {
- /* ...i jeszcze nie mieli¶my warto¶ci pola to
- * wiemy, ¿e po tym zerze jest warto¶æ... */
- if (!value)
- value = p + 1;
- else
- /* ...w przeciwym wypadku koniec
- * warto¶ci i mo¿emy wychodziæ
- * grzecznie z pêtli */
- break;
- }
- }
-
- /* sprawd¼my, czy pole nie wychodzi poza pakiet, ¿eby nie
- * mieæ segfaultów, je¶li serwer przestanie zakañczaæ pakietów
- * przez \0 */
-
- if (p == end) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() premature end of packet\n");
- goto failure;
- }
-
- p++;
-
- /* je¶li dostali¶my namier na nastêpne wyniki, to znaczy ¿e
- * mamy koniec wyników i nie jest to kolejna osoba. */
- if (!strcasecmp(field, "nextstart")) {
- res->next = atoi(value);
- num--;
- } else {
- if (gg_pubdir50_add_n(res, num, field, value) == -1)
- goto failure;
- }
- }
-
- res->count = num + 1;
-
- return 0;
-
-failure:
- gg_pubdir50_free(res);
- return -1;
-}
-
-/*
- * gg_pubdir50_get()
- *
- * pobiera informacjê z rezultatu wyszukiwania.
- *
- * - res - rezultat wyszukiwania,
- * - num - numer odpowiedzi,
- * - field - nazwa pola (wielko¶æ liter nie ma znaczenia).
- *
- * warto¶æ pola lub NULL, je¶li nie znaleziono.
- */
-const char *gg_pubdir50_get(gg_pubdir50_t res, int num, const char *field)
-{
- char *value = NULL;
- int i;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_get(%p, %d, \"%s\");\n", res, num, field);
-
- if (!res || num < 0 || !field) {
- gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_get() invalid arguments\n");
- errno = EINVAL;
- return NULL;
- }
-
- for (i = 0; i < res->entries_count; i++) {
- if (res->entries[i].num == num && !strcasecmp(res->entries[i].field, field)) {
- value = res->entries[i].value;
- break;
- }
- }
-
- return value;
-}
-
-/*
- * gg_pubdir50_count()
- *
- * zwraca ilo¶æ wyników danego zapytania.
- *
- * - res - odpowied¼
- *
- * ilo¶æ lub -1 w przypadku b³êdu.
- */
-int gg_pubdir50_count(gg_pubdir50_t res)
-{
- return (!res) ? -1 : res->count;
-}
-
-/*
- * gg_pubdir50_type()
- *
- * zwraca rodzaj zapytania lub odpowiedzi.
- *
- * - res - zapytanie lub odpowied¼
- *
- * ilo¶æ lub -1 w przypadku b³êdu.
- */
-int gg_pubdir50_type(gg_pubdir50_t res)
-{
- return (!res) ? -1 : res->type;
-}
-
-/*
- * gg_pubdir50_next()
- *
- * zwraca numer, od którego nale¿y rozpocz±æ kolejne wyszukiwanie, je¶li
- * zale¿y nam na kolejnych wynikach.
- *
- * - res - odpowied¼
- *
- * numer lub -1 w przypadku b³êdu.
- */
-uin_t gg_pubdir50_next(gg_pubdir50_t res)
-{
- return (!res) ? (unsigned) -1 : res->next;
-}
-
-/*
- * gg_pubdir50_seq()
- *
- * zwraca numer sekwencyjny zapytania lub odpowiedzi.
- *
- * - res - zapytanie lub odpowied¼
- *
- * numer lub -1 w przypadku b³êdu.
- */
-uint32_t gg_pubdir50_seq(gg_pubdir50_t res)
-{
- return (!res) ? (unsigned) -1 : res->seq;
-}
-
-/*
- * Local variables:
- * c-indentation-style: k&r
- * c-basic-offset: 8
- * indent-tabs-mode: notnil
- * End:
- *
- * vim: shiftwidth=8:
- */
diff --git a/kopete/protocols/gadu/ui/CMakeLists.txt b/kopete/protocols/gadu/ui/CMakeLists.txt
new file mode 100644
index 00000000..10b5b07d
--- /dev/null
+++ b/kopete/protocols/gadu/ui/CMakeLists.txt
@@ -0,0 +1,28 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### gaduui (static) ###########################
+
+tde_add_library( gaduui STATIC_PIC AUTOMOC
+ SOURCES
+ gaduadd.ui gadusearch.ui gadueditaccountui.ui gaduawayui.ui
+ gaduregisteraccountui.ui empty.cpp
+)
diff --git a/kopete/protocols/groupwise/CMakeLists.txt b/kopete/protocols/groupwise/CMakeLists.txt
new file mode 100644
index 00000000..c6df3323
--- /dev/null
+++ b/kopete/protocols/groupwise/CMakeLists.txt
@@ -0,0 +1,50 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( icons )
+add_subdirectory( libgroupwise )
+add_subdirectory( ui )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}/libgroupwise
+ ${CMAKE_CURRENT_SOURCE_DIR}/libgroupwise/tasks
+ ${CMAKE_CURRENT_SOURCE_DIR}/libgroupwise/qca/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_groupwise.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES gwchatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_groupwise )
+
+
+##### kopete_groupwise (module) #################
+
+tde_add_kpart( kopete_groupwise AUTOMOC
+ SOURCES
+ gwprotocol.cpp gwcontact.cpp gwaccount.cpp gwbytestream.cpp
+ gwconnector.cpp gwmessagemanager.cpp gwcontactlist.cpp
+ LINK
+ kopetegroupwiseui-static groupwise-static groupwise_tasks-static
+ groupwise_qca-static kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/groupwise/icons/CMakeLists.txt b/kopete/protocols/groupwise/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/protocols/groupwise/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/protocols/groupwise/libgroupwise/CMakeLists.txt b/kopete/protocols/groupwise/libgroupwise/CMakeLists.txt
new file mode 100644
index 00000000..ef158cd9
--- /dev/null
+++ b/kopete/protocols/groupwise/libgroupwise/CMakeLists.txt
@@ -0,0 +1,53 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( qca )
+add_subdirectory( tasks )
+
+# add_definitions(
+# -DUSE_TLSHANDLER
+# )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/qca/src
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### groupwise (static) ########################
+
+tde_add_library( groupwise STATIC_PIC AUTOMOC
+ SOURCES
+ bytestream.cpp chatroommanager.cpp client.cpp connector.cpp
+ coreprotocol.cpp eventprotocol.cpp eventtransfer.cpp
+ gwclientstream.cpp gwerror.cpp gwfield.cpp gwglobal.cpp
+ inputprotocolbase.cpp privacymanager.cpp qcatlshandler.cpp
+ request.cpp requestfactory.cpp response.cpp responseprotocol.cpp
+ rtf.cc safedelete.cpp securestream.cpp stream.cpp task.cpp
+ tlshandler.cpp transfer.cpp transferbase.cpp userdetailsmanager.cpp
+ usertransfer.cpp
+)
+
+
+##### gwtest (static) ###########################
+
+tde_add_library( gwtest STATIC_PIC AUTOMOC
+ SOURCES
+ coreprotocol.cpp eventtransfer.cpp gwfield.cpp request.cpp
+ requestfactory.cpp transfer.cpp usertransfer.cpp client.cpp task.cpp
+ safedelete.cpp gwclientstream.cpp qcatlshandler.cpp stream.cpp
+ tlshandler.cpp response.cpp connector.cpp securestream.cpp
+ bytestream.cpp
+)
diff --git a/kopete/protocols/groupwise/libgroupwise/qca/CMakeLists.txt b/kopete/protocols/groupwise/libgroupwise/qca/CMakeLists.txt
new file mode 100644
index 00000000..7356f221
--- /dev/null
+++ b/kopete/protocols/groupwise/libgroupwise/qca/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( src )
diff --git a/kopete/protocols/groupwise/libgroupwise/qca/src/CMakeLists.txt b/kopete/protocols/groupwise/libgroupwise/qca/src/CMakeLists.txt
new file mode 100644
index 00000000..9c74e339
--- /dev/null
+++ b/kopete/protocols/groupwise/libgroupwise/qca/src/CMakeLists.txt
@@ -0,0 +1,22 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### groupwise_qca (static) ####################
+
+tde_add_library( groupwise_qca STATIC_PIC AUTOMOC
+ SOURCES qca.cpp
+)
diff --git a/kopete/protocols/groupwise/libgroupwise/tasks/CMakeLists.txt b/kopete/protocols/groupwise/libgroupwise/tasks/CMakeLists.txt
new file mode 100644
index 00000000..1fc4a60a
--- /dev/null
+++ b/kopete/protocols/groupwise/libgroupwise/tasks/CMakeLists.txt
@@ -0,0 +1,38 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../qca/src
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### groupwise_tasks (static) ##################
+
+tde_add_library( groupwise_tasks STATIC_PIC AUTOMOC
+ SOURCES
+ requesttask.cpp eventtask.cpp logintask.cpp setstatustask.cpp
+ statustask.cpp conferencetask.cpp createconferencetask.cpp
+ sendmessagetask.cpp getdetailstask.cpp getstatustask.cpp
+ typingtask.cpp connectiontask.cpp sendinvitetask.cpp
+ joinconferencetask.cpp leaveconferencetask.cpp rejectinvitetask.cpp
+ keepalivetask.cpp createcontacttask.cpp modifycontactlisttask.cpp
+ createfoldertask.cpp movecontacttask.cpp updateitemtask.cpp
+ createcontactinstancetask.cpp deleteitemtask.cpp updatefoldertask.cpp
+ updatecontacttask.cpp pollsearchresultstask.cpp privacyitemtask.cpp
+ needfoldertask.cpp searchchattask.cpp searchusertask.cpp
+ searchusertask.h getchatsearchresultstask.cpp chatcountstask.cpp
+ chatpropertiestask.cpp joinchattask.cpp
+)
diff --git a/kopete/protocols/groupwise/ui/CMakeLists.txt b/kopete/protocols/groupwise/ui/CMakeLists.txt
new file mode 100644
index 00000000..2045bef7
--- /dev/null
+++ b/kopete/protocols/groupwise/ui/CMakeLists.txt
@@ -0,0 +1,35 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libgroupwise
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libgroupwise/qca/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopetegroupwiseui (static) ################
+
+tde_add_library( kopetegroupwiseui STATIC_PIC AUTOMOC
+ SOURCES
+ gwaccountpreferences.ui gwaddcontactpage.cpp gwaddui.ui
+ gweditaccountwidget.cpp gwreceiveinvitationdialog.cpp
+ gwshowinvitation.ui gwcontactpropswidget.ui gwcontactproperties.cpp
+ gwprivacy.ui gwprivacydialog.cpp gwsearch.cpp gwcustomstatuswidget.ui
+ gwcustomstatusedit.ui gwcontactsearch.ui gwchatsearchwidget.ui
+ gwchatsearchdialog.cpp gwchatpropswidget.ui gwchatpropsdialog.cpp
+)
diff --git a/kopete/protocols/irc/CMakeLists.txt b/kopete/protocols/irc/CMakeLists.txt
new file mode 100644
index 00000000..6c795704
--- /dev/null
+++ b/kopete/protocols/irc/CMakeLists.txt
@@ -0,0 +1,54 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( icons )
+add_subdirectory( libkirc )
+add_subdirectory( ui )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}/libkirc
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES
+ kopete_irc.desktop irc.protocol
+ DESTINATION ${SERVICES_INSTALL_DIR} )
+
+install( FILES
+ ircnetworks.xml ircchatui.rc
+ DESTINATION ${DATA_INSTALL_DIR}/kopete )
+
+
+##### kopete_irc (module) #######################
+
+tde_add_kpart( kopete_irc AUTOMOC
+ SOURCES
+ ircaccount.cpp ircaddcontactpage.cpp ircchannelcontact.cpp
+ irccontact.cpp ircguiclient.cpp ircprotocol.cpp ircservercontact.cpp
+ ircsignalhandler.cpp irctransferhandler.cpp ircusercontact.cpp
+ irccontactmanager.cpp kcodecaction.cpp ksparser.cpp
+ LINK
+ kopeteircui-static kirc-static kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/irc/icons/CMakeLists.txt b/kopete/protocols/irc/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/protocols/irc/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/protocols/irc/libkirc/CMakeLists.txt b/kopete/protocols/irc/libkirc/CMakeLists.txt
new file mode 100644
index 00000000..d2b298c2
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/CMakeLists.txt
@@ -0,0 +1,30 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kirc (static) #############################
+
+tde_add_library( kirc STATIC_PIC AUTOMOC
+ SOURCES
+ kircengine.cpp kircengine_commands.cpp kircengine_ctcp.cpp
+ kircengine_numericreplies.cpp kircentity.cpp kircmessage.cpp
+ kircmessageredirector.cpp kirctransfer.cpp kirctransferhandler.cpp
+ kirctransferserver.cpp ksslsocket.cpp
+)
diff --git a/kopete/protocols/irc/libkirc/kircentity.h b/kopete/protocols/irc/libkirc/kircentity.h
index d802d8f4..1878a406 100644
--- a/kopete/protocols/irc/libkirc/kircentity.h
+++ b/kopete/protocols/irc/libkirc/kircentity.h
@@ -39,7 +39,7 @@ class Entity
Q_OBJECT
public:
- typedef enum Type
+ enum Type
{
Unknown,
Server,
diff --git a/kopete/protocols/irc/ui/CMakeLists.txt b/kopete/protocols/irc/ui/CMakeLists.txt
new file mode 100644
index 00000000..7d77d5b8
--- /dev/null
+++ b/kopete/protocols/irc/ui/CMakeLists.txt
@@ -0,0 +1,30 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libkirc
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopeteircui (static) ######################
+
+tde_add_library( kopeteircui STATIC_PIC AUTOMOC
+ SOURCES
+ ircadd.ui empty.cpp irceditaccountwidget.cpp irceditaccount.ui
+ channellist.cpp channellistdialog.cpp networkconfig.ui
+)
diff --git a/kopete/protocols/jabber/CMakeLists.txt b/kopete/protocols/jabber/CMakeLists.txt
new file mode 100644
index 00000000..d3fb6d79
--- /dev/null
+++ b/kopete/protocols/jabber/CMakeLists.txt
@@ -0,0 +1,85 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( ui )
+add_subdirectory( icons )
+add_subdirectory( libiris )
+add_subdirectory( kioslave )
+
+if( WITH_JINGLE )
+ add_subdirectory( jingle )
+ set( SUPPORT_JINGLE 1 CACHE INTERNAL "" FORCE )
+ set( JINGLE_LIBRARIES
+ kopetejabberjingle-static cricketsessionphone-static cricketxmllite-static
+ cricketp2pclient-static cricketxmpp-static cricketp2pbase-static cricketbase-static
+ mediastreamer-static ortp-static
+ ${GLIB2_LIBRARIES} ${GTHREAD2_LIBRARIES} ${GMODULE2_LIBRARIES}
+ ${EXPAT_LIBRARY} ${SPEEX_LIBRARIES} pthread
+ )
+endif( )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_CURRENT_BINARY_DIR}/jingle
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/libiris/iris/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/libiris/iris/jabber
+ ${CMAKE_CURRENT_SOURCE_DIR}/libiris/iris/xmpp-im
+ ${CMAKE_CURRENT_SOURCE_DIR}/libiris/qca/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/libiris/cutestuff/util
+ ${CMAKE_CURRENT_SOURCE_DIR}/libiris/cutestuff/network
+ ${CMAKE_CURRENT_SOURCE_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}/jingle
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../libkopete
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../libkopete/ui
+ ${CMAKE_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_jabber.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES jabberchatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_jabber )
+
+
+##### jabberclient (static) #####################
+
+tde_add_library( jabberclient STATIC_PIC AUTOMOC
+ SOURCES
+ jabberclient.cpp jabberconnector.cpp jabberbytestream.cpp
+)
+
+
+##### kopete_jabber (module) ####################
+
+tde_add_kpart( kopete_jabber AUTOMOC
+ SOURCES
+ jabberprotocol.cpp jabberaccount.cpp jabberresource.cpp
+ jabberresourcepool.cpp jabberbasecontact.cpp jabbercontact.cpp
+ jabbergroupcontact.cpp jabbergroupmembercontact.cpp
+ jabbercontactpool.cpp jabberformtranslator.cpp jabberformlineedit.cpp
+ jabberchatsession.cpp jabbergroupchatmanager.cpp
+ jabberfiletransfer.cpp jabbercapabilitiesmanager.cpp
+ jabbertransport.cpp jabberbookmarks.cpp
+ LINK
+ jabberclient-static kopetejabberui-static
+ iris_jabber-static iris_xmpp_core-static iris_xmpp_im-static iris-static
+ qca-static cutestuff_network-static cutestuff_util-static ${JINGLE_LIBRARIES}
+ kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/jabber/icons/CMakeLists.txt b/kopete/protocols/jabber/icons/CMakeLists.txt
new file mode 100644
index 00000000..37a5c370
--- /dev/null
+++ b/kopete/protocols/jabber/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( )
diff --git a/kopete/protocols/jabber/jingle/CMakeLists.txt b/kopete/protocols/jabber/jingle/CMakeLists.txt
new file mode 100644
index 00000000..18bbf758
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/CMakeLists.txt
@@ -0,0 +1,38 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( libjingle )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/libjingle
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/iris/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/iris/xmpp-im
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/iris/jabber
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/cutestuff/util
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopetejabberjingle (static) ###############
+
+tde_moc( MOCS voicecaller.h )
+
+tde_add_library( kopetejabberjingle STATIC_PIC AUTOMOC
+ SOURCES
+ jinglevoicecaller.cpp jinglevoicesessiondialogbase.ui
+ jinglevoicesessiondialog.cpp ${MOCS}
+)
diff --git a/kopete/protocols/jabber/jingle/jinglevoicecaller.cpp b/kopete/protocols/jabber/jingle/jinglevoicecaller.cpp
index dd809cea..12e4b93d 100644
--- a/kopete/protocols/jabber/jingle/jinglevoicecaller.cpp
+++ b/kopete/protocols/jabber/jingle/jinglevoicecaller.cpp
@@ -374,3 +374,5 @@ cricket::Thread* JingleVoiceCaller::thread_ = NULL;
cricket::NetworkManager* JingleVoiceCaller::network_manager_ = NULL;
cricket::BasicPortAllocator* JingleVoiceCaller::port_allocator_ = NULL;
cricket::SocketAddress* JingleVoiceCaller::stun_addr_ = NULL;
+
+#include "jinglevoicecaller.moc"
diff --git a/kopete/protocols/jabber/jingle/libjingle/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/CMakeLists.txt
new file mode 100644
index 00000000..0aa34648
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( talk )
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/CMakeLists.txt
new file mode 100644
index 00000000..1a1d0416
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/CMakeLists.txt
@@ -0,0 +1,19 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include( ConfigureChecks.cmake )
+
+add_subdirectory( base )
+add_subdirectory( p2p )
+add_subdirectory( xmllite )
+add_subdirectory( xmpp )
+add_subdirectory( session )
+add_subdirectory( third_party )
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/ConfigureChecks.cmake b/kopete/protocols/jabber/jingle/libjingle/talk/ConfigureChecks.cmake
new file mode 100644
index 00000000..396efa92
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/ConfigureChecks.cmake
@@ -0,0 +1,48 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+# gthread-2.0
+pkg_search_module( GTHREAD2 gthread-2.0 )
+if( NOT GTHREAD2_FOUND )
+ tde_message_fatal( "gthread-2.0 is required, but was not found on your system" )
+endif( )
+
+
+# gmodule-2.0
+pkg_search_module( GMODULE2 gmodule-2.0 )
+if( NOT GMODULE2_FOUND )
+ tde_message_fatal( "gmodule-2.0 are required, but not found on your system" )
+endif( )
+
+
+# speex
+if( WITH_SPEEX )
+ pkg_search_module( SPEEX speex )
+ if( SPEEX_FOUND )
+ set( HAVE_SPEEX 1 CACHE INTERNAL "" FORCE )
+ if( NOT SPEEX_INCLUDE_DIRS )
+ set( SPEEX_INCLUDE_DIRS "/usr/include/speex" )
+ endif( )
+ else( )
+ tde_message_fatal( "speex is required, but was not found on your system" )
+ endif( )
+endif( )
+
+# expat
+check_include_file( expat.h HAVE_EXPAT_H )
+if( HAVE_EXPAT_H )
+ check_library_exists( expat XML_ParserCreate "" HAVE_EXPAT )
+endif( )
+if( HAVE_EXPAT_H AND HAVE_EXPAT )
+ set( EXPAT_LIBRARY expat CACHE INTERNAL "" FORCE )
+else( )
+ tde_message_fatal( "expat is required, but was not found on your system" )
+endif( )
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/base/CMakeLists.txt
new file mode 100644
index 00000000..8f037a9a
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/CMakeLists.txt
@@ -0,0 +1,32 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions(
+ -DPOSIX
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../..
+ ${CMAKE_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### cricketbase (static) ######################
+
+tde_add_library( cricketbase STATIC_PIC
+ SOURCES
+ socketaddress.cc jtime.cc asyncudpsocket.cc messagequeue.cc
+ thread.cc physicalsocketserver.cc bytebuffer.cc asyncpacketsocket.cc
+ network.cc asynctcpsocket.cc socketadapters.cc md5c.c base64.cc
+ task.cc taskrunner.cc host.cc socketaddresspair.cc
+)
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc
index 6d4697a6..8bf66a38 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc
@@ -32,6 +32,7 @@
#include "talk/base/byteorder.h"
#include "talk/base/common.h"
#include "talk/base/logging.h"
+#include <cstring>
#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std {
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc
index 067f50ed..e3af08b7 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc
@@ -30,6 +30,7 @@
#include "talk/base/byteorder.h"
#include <algorithm>
#include <cassert>
+#include <cstring>
#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std {
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc
index 7b7490d9..f604050f 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc
@@ -30,6 +30,8 @@
#include "talk/base/network.h"
#include "talk/base/socket.h"
#include <string>
+#include <cstring>
+#include <cstdlib>
#include <iostream>
#include <cassert>
#include <errno.h>
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h
index 2a9cbed6..9b35b9af 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h
@@ -32,6 +32,7 @@
#include "talk/base/criticalsection.h"
#include "talk/base/socketserver.h"
#include "talk/base/jtime.h"
+#include <string.h>
#include <vector>
#include <queue>
#include <algorithm>
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc
index 91d2daad..37836302 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc
@@ -30,6 +30,7 @@
#endif
#include <cassert>
+#include <algorithm>
#ifdef POSIX
extern "C" {
@@ -37,6 +38,7 @@ extern "C" {
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
+#include <string.h>
}
#endif
@@ -59,9 +61,6 @@ extern "C" {
#include <windows.h>
#undef SetPort
-#include <algorithm>
-#include <iostream>
-
class WinsockInitializer {
public:
WinsockInitializer() {
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc
index 049e923c..f57043e3 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc
@@ -42,6 +42,7 @@
#endif
#include <cassert>
+#include <cstring>
#include "talk/base/base64.h"
#include "talk/base/basicdefs.h"
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/CMakeLists.txt
new file mode 100644
index 00000000..1708f179
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/CMakeLists.txt
@@ -0,0 +1,13 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( base )
+add_subdirectory( client )
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/CMakeLists.txt
new file mode 100644
index 00000000..ba05a061
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/CMakeLists.txt
@@ -0,0 +1,52 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions(
+ -DPOSIX
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../..
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### cricketp2pbase (static) ###################
+
+tde_add_library( cricketp2pbase STATIC_PIC
+ SOURCES
+ stun.cc port.cc udpport.cc tcpport.cc helpers.cc sessionmanager.cc
+ session.cc p2psocket.cc relayport.cc stunrequest.cc stunport.cc
+ socketmanager.cc
+)
+
+
+##### relayserver (executable) ##################
+
+tde_add_executable( relayserver
+ SOURCES
+ relayserver.cc relayserver_main.cc
+ LINK
+ cricketbase-static cricketp2pbase-static pthread
+ DESTINATION ${BIN_INSTALL_DIR}
+)
+
+
+##### stunserver (executable) ###################
+
+tde_add_executable( stunserver
+ SOURCES
+ stunserver.cc stunserver_main.cc
+ LINK
+ cricketbase-static cricketp2pbase-static pthread
+ DESTINATION ${BIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver_main.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver_main.cc
index 5f624f37..4dfae42c 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver_main.cc
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/relayserver_main.cc
@@ -30,6 +30,7 @@
#include "talk/p2p/base/relayserver.h"
#include <iostream>
#include <assert.h>
+#include <cstring>
#ifdef POSIX
extern "C" {
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.cc
index 6a22b238..2d6aa67c 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.cc
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stun.cc
@@ -29,6 +29,7 @@
#include "talk/p2p/base/stun.h"
#include <iostream>
#include <cassert>
+#include <cstring>
#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std {
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.cc
index 6e4f6b66..c6d9f9f8 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.cc
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver.cc
@@ -28,6 +28,7 @@
#include "talk/base/bytebuffer.h"
#include "talk/p2p/base/stunserver.h"
#include <iostream>
+#include <cstring>
#ifdef POSIX
extern "C" {
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver_main.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver_main.cc
index bd8a96e5..bac3e35f 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver_main.cc
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunserver_main.cc
@@ -29,6 +29,7 @@
#include "talk/base/thread.h"
#include "talk/p2p/base/stunserver.h"
#include <iostream>
+#include <cstring>
#ifdef POSIX
extern "C" {
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/CMakeLists.txt
new file mode 100644
index 00000000..7ede9820
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/CMakeLists.txt
@@ -0,0 +1,30 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions(
+ -DLINUX
+ -DPOSIX
+ -DINTERNAL_BUILD
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../..
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### cricketp2pclient (static) #################
+
+tde_add_library( cricketp2pclient STATIC_PIC
+ SOURCES
+ sessionclient.cc basicportallocator.cc socketmonitor.cc
+)
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/session/CMakeLists.txt
new file mode 100644
index 00000000..0b78949f
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( phone )
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/CMakeLists.txt
new file mode 100644
index 00000000..3f22e535
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/CMakeLists.txt
@@ -0,0 +1,34 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions(
+ -DPOSIX
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../third_party/ortp
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../third_party/mediastreamer
+ ${CMAKE_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+ ${GLIB2_INCLUDE_DIRS}
+ ${SPEEX_INCLUDE_DIRS}
+)
+
+
+##### cricketsessionphone (static) ##############
+
+tde_add_library( cricketsessionphone STATIC_PIC
+ SOURCES
+ audiomonitor.cc channelmanager.cc voicechannel.cc call.cc
+ phonesessionclient.cc linphonemediaengine.cc
+)
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc
index e363392c..f3244c54 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc
@@ -27,7 +27,7 @@ extern "C" {
#include "talk/third_party/mediastreamer/msspeexdec.h"
#endif
}
-#include <ortp/ortp.h>
+#include <ortp.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc
index d8a31df2..7f2ff11f 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc
@@ -25,6 +25,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <stdio.h>
+
#include "talk/base/logging.h"
#include "talk/session/receiver.h"
#include "talk/session/phone/phonesessionclient.h"
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/CMakeLists.txt
new file mode 100644
index 00000000..da1647c0
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/CMakeLists.txt
@@ -0,0 +1,13 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( mediastreamer )
+add_subdirectory( ortp )
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/CMakeLists.txt
new file mode 100644
index 00000000..8c5a923b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/CMakeLists.txt
@@ -0,0 +1,36 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions(
+ -DG_LOG_DOMAIN="MediaStreamer"
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../ortp
+ ${CMAKE_BINARY_DIR}
+ ${GLIB2_INCLUDE_DIRS}
+ ${SPEEX_INCLUDE_DIRS}
+)
+
+
+##### mediastreamer (static) ####################
+
+tde_add_library( mediastreamer STATIC_PIC
+ SOURCES
+ msfilter.c mscodec.c mssoundread.c mssoundwrite.c msbuffer.c
+ msqueue.c msfifo.c ms.c mssync.c msnosync.c msread.c mswrite.c
+ mscopy.c msosswrite.c msossread.c msringplayer.c msrtprecv.c
+ msrtpsend.c msAlawenc.c msAlawdec.c msMUlawenc.c msMUlawdec.c
+ mstimer.c msqdispatcher.c msfdispatcher.c sndcard.c osscard.c
+ hpuxsndcard.c alsacard.c jackcard.c audiostream.c msspeexenc.c
+ msspeexdec.c msilbcdec.c msilbcenc.c
+)
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.h
index 5c8b616c..0f36c379 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.h
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtprecv.h
@@ -28,7 +28,7 @@
/* because of a conflict between config.h from oRTP and config.h from linphone:*/
#undef PACKAGE
#undef VERSION
-#include <ortp/ortp.h>
+#include <ortp.h>
/*this is the class that implements a copy filter*/
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.c
index b13dfe28..645a19cd 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.c
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.c
@@ -19,7 +19,7 @@
*/
#include "msrtpsend.h"
-#include <ortp/telephonyevents.h>
+#include <telephonyevents.h>
#include "mssync.h"
#include "mscodec.h"
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.h
index 746e436d..96889964 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.h
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/mediastreamer/msrtpsend.h
@@ -27,7 +27,7 @@
#undef PACKAGE
#undef VERSION
-#include <ortp/ortp.h>
+#include <ortp.h>
/*this is the class that implements a sending through rtp filter*/
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/CMakeLists.txt
new file mode 100644
index 00000000..92a73a36
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/CMakeLists.txt
@@ -0,0 +1,32 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions(
+ -D_ORTP_SOURCE
+ -DG_LOG_DOMAIN="oRTP"
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${GLIB2_INCLUDE_DIRS}
+)
+
+
+##### ortp (static) #############################
+
+tde_add_library( ortp STATIC_PIC
+ SOURCES
+ port_fct.c rtpmod.c rtpparse.c rtpsession.c jitterctl.c
+ rtpsignaltable.c rtptimer.c posixtimer.c ortp.c scheduler.c
+ avprofile.c sessionset.c telephonyevents.c payloadtype.c rtcp.c
+ utils.c rtcpparse.c str_utils.c
+)
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/avprofile.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/avprofile.c
new file mode 100644
index 00000000..8917e21b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/avprofile.c
@@ -0,0 +1,281 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include <payloadtype.h>
+
+char offset127=127;
+char offset0xD5=0xD5;
+char offset0=0;
+
+/* IMPORTANT */
+/* some compiler don't support the "field:" syntax. Those macros are there to trap the problem
+This means that if you want to keep portability, payload types must be defined with their fields
+in the right order. */
+
+#if !defined(__hpux) && !defined(WIN32)
+
+#define TYPE(val) type: (val)
+#define CLOCK_RATE(val) clock_rate: (val)
+#define BITS_PER_SAMPLE(val) bits_per_sample: (val)
+#define ZERO_PATTERN(val) zero_pattern: (val)
+#define PATTERN_LENGTH(val) pattern_length: (val)
+#define NORMAL_BITRATE(val) normal_bitrate: (val)
+#define MIME_TYPE(val) mime_type: (val)
+#define FMTP(val) FMTP : (val)
+
+#else
+
+#define TYPE(val) (val)
+#define CLOCK_RATE(val) (val)
+#define BITS_PER_SAMPLE(val) (val)
+#define ZERO_PATTERN(val) (val)
+#define PATTERN_LENGTH(val) (val)
+#define NORMAL_BITRATE(val) (val)
+#define MIME_TYPE(val) (val)
+#define FMTP(val) (val)
+
+#endif
+
+PayloadType pcmu8000={
+ TYPE( PAYLOAD_AUDIO_CONTINUOUS),
+ CLOCK_RATE( 8000),
+ BITS_PER_SAMPLE(8),
+ ZERO_PATTERN( &offset127),
+ PATTERN_LENGTH( 1),
+ NORMAL_BITRATE( 64000),
+ MIME_TYPE ("PCMU")
+};
+
+PayloadType pcma8000={
+ TYPE( PAYLOAD_AUDIO_CONTINUOUS),
+ CLOCK_RATE(8000),
+ BITS_PER_SAMPLE(8),
+ ZERO_PATTERN( &offset0xD5),
+ PATTERN_LENGTH( 1),
+ NORMAL_BITRATE( 64000),
+ MIME_TYPE ("PCMA")
+};
+
+PayloadType pcm8000={
+ TYPE( PAYLOAD_AUDIO_CONTINUOUS),
+ CLOCK_RATE(8000),
+ BITS_PER_SAMPLE(16),
+ ZERO_PATTERN( &offset0),
+ PATTERN_LENGTH(1),
+ NORMAL_BITRATE( 128000),
+ MIME_TYPE ("PCM")
+};
+
+PayloadType lpc1016={
+ TYPE( PAYLOAD_AUDIO_PACKETIZED),
+ CLOCK_RATE(8000),
+ BITS_PER_SAMPLE( 0),
+ ZERO_PATTERN( NULL),
+ PATTERN_LENGTH( 0),
+ NORMAL_BITRATE( 2400),
+ MIME_TYPE ("1016")
+};
+
+
+PayloadType gsm=
+{
+ TYPE( PAYLOAD_AUDIO_PACKETIZED),
+ CLOCK_RATE(8000),
+ BITS_PER_SAMPLE( 0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH( 0),
+ NORMAL_BITRATE( 13500),
+ MIME_TYPE ("GSM")
+};
+
+PayloadType payload_type_g7231=
+{
+ TYPE( PAYLOAD_AUDIO_PACKETIZED),
+ CLOCK_RATE(8000),
+ BITS_PER_SAMPLE( 0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH( 0),
+ NORMAL_BITRATE( 6300),
+ MIME_TYPE ("G723")
+};
+
+PayloadType payload_type_g729={
+ TYPE( PAYLOAD_AUDIO_PACKETIZED),
+ CLOCK_RATE(8000),
+ BITS_PER_SAMPLE( 0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH( 0),
+ NORMAL_BITRATE( 8000),
+ MIME_TYPE ("G729")
+};
+
+PayloadType mpv=
+{
+ TYPE( PAYLOAD_VIDEO),
+ CLOCK_RATE(90000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE( 256000),
+ MIME_TYPE ("MPV")
+};
+
+
+PayloadType h261={
+ TYPE( PAYLOAD_VIDEO),
+ CLOCK_RATE(90000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE(0),
+ MIME_TYPE ("H261")
+};
+
+PayloadType h263={
+ TYPE( PAYLOAD_VIDEO),
+ CLOCK_RATE(90000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE(256000),
+ MIME_TYPE ("H263")
+};
+
+PayloadType truespeech=
+{
+ TYPE( PAYLOAD_AUDIO_PACKETIZED),
+ CLOCK_RATE(8000),
+ BITS_PER_SAMPLE( 0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH( 0),
+ NORMAL_BITRATE(8536),
+ MIME_TYPE ("TSP0")
+};
+
+
+RtpProfile av_profile;
+
+
+void av_profile_init(RtpProfile *profile)
+{
+ rtp_profile_clear_all(profile);
+ rtp_profile_set_name(profile,"AV profile");
+ rtp_profile_set_payload(profile,0,&pcmu8000);
+ rtp_profile_set_payload(profile,1,&lpc1016);
+ rtp_profile_set_payload(profile,3,&gsm);
+ rtp_profile_set_payload(profile,4,&payload_type_g7231);
+ rtp_profile_set_payload(profile,8,&pcma8000);
+ rtp_profile_set_payload(profile,18,&payload_type_g729);
+ rtp_profile_set_payload(profile,31,&h261);
+ rtp_profile_set_payload(profile,32,&mpv);
+ rtp_profile_set_payload(profile,34,&h263);
+}
+
+/* these are extra payload types that can be used dynamically */
+PayloadType lpc1015={
+ TYPE( PAYLOAD_AUDIO_PACKETIZED),
+ CLOCK_RATE(8000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE(2400),
+ MIME_TYPE ("1015")
+};
+
+PayloadType speex_nb={
+ TYPE( PAYLOAD_AUDIO_PACKETIZED),
+ CLOCK_RATE(8000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE(8000), /*not true: 8000 is the minimum*/
+ MIME_TYPE ("speex")
+};
+
+PayloadType speex_wb={
+ TYPE( PAYLOAD_AUDIO_PACKETIZED),
+ CLOCK_RATE(16000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE(28000),
+ MIME_TYPE ("speex")
+};
+
+PayloadType payload_type_ilbc={
+ TYPE( PAYLOAD_AUDIO_PACKETIZED),
+ CLOCK_RATE(8000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE(13300), /* the minimum, with 30ms frames */
+ MIME_TYPE ("iLBC"),
+};
+
+PayloadType amr={
+ TYPE(PAYLOAD_AUDIO_PACKETIZED),
+ CLOCK_RATE(8000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE(0),
+ MIME_TYPE ("AMR")
+};
+
+PayloadType amrwb={
+ TYPE(PAYLOAD_AUDIO_PACKETIZED),
+ CLOCK_RATE(16000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE(0),
+ MIME_TYPE ("AMR-WB")
+};
+
+PayloadType mp4v={
+ TYPE( PAYLOAD_VIDEO),
+ CLOCK_RATE(90000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE(0),
+ MIME_TYPE ("MP4V-ES")
+};
+
+
+PayloadType h263_1998={
+ TYPE( PAYLOAD_VIDEO),
+ CLOCK_RATE(90000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE(0),
+ MIME_TYPE ("H263-1998")
+};
+
+PayloadType h263_2000={
+ TYPE( PAYLOAD_VIDEO),
+ CLOCK_RATE(90000),
+ BITS_PER_SAMPLE(0),
+ ZERO_PATTERN(NULL),
+ PATTERN_LENGTH(0),
+ NORMAL_BITRATE(0),
+ MIME_TYPE ("H263-2000")
+};
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/export.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/export.c
new file mode 100644
index 00000000..0f061c36
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/export.c
@@ -0,0 +1,25 @@
+/*
+ * file : export.c
+ *
+ * this file is used when building the oRTP stack as a dynamic loadable library
+ * on win32 OS. Indeed, structures cannot been exported 'as is' using the .def
+ * file. Since we want to use the av_profile and telephone_event instances as defined
+ * in the original source code, We have to implement those 2 functions to retrieve
+ * pointers on them.
+ *
+ */
+
+
+#include "export.h"
+
+
+RtpProfile * get_av_profile( void )
+{
+ return &av_profile;
+}
+
+PayloadType * get_telephone_event( void )
+{
+ return &telephone_event;
+}
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/export.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/export.h
new file mode 100644
index 00000000..0f5a3992
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/export.h
@@ -0,0 +1,38 @@
+/*
+ * file : export.h
+ *
+ * this file is used when building the oRTP stack as a dynamic loadable library
+ * on win32 OS. Indeed, structures cannot been exported 'as is' using the .def
+ * file. Since we want to use the av_profile and telephone_event instances as defined
+ * in the original source code, We have to implement those 2 functions to retrieve
+ * pointers on them.
+ *
+ */
+
+
+
+#ifndef EXPORT_H
+#define EXPORT_H
+
+
+#if defined __cplusplus
+extern "C"
+{
+#endif
+
+
+#include "payloadtype.h"
+#include "telephonyevents.h"
+
+
+ RtpProfile * get_av_profile( void );
+ PayloadType * get_telephone_event( void );
+
+
+
+#if defined __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/jitterctl.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/jitterctl.c
new file mode 100644
index 00000000..5f236f71
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/jitterctl.c
@@ -0,0 +1,141 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+/***************************************************************************
+ * jitterctl.c
+ *
+ * Mon Nov 8 11:53:21 2004
+ * Copyright 2004 Simon MORLAT
+ * Email simon.morlat@linphone.org
+ ****************************************************************************/
+
+#include <rtpsession.h>
+#include <payloadtype.h>
+#include <math.h>
+#include <stdlib.h>
+
+#define JC_BETA 0.03 /*allows a clock slide around 3% */
+#define JC_GAMMA (JC_BETA)
+
+#include "jitterctl.h"
+
+void jitter_control_init(JitterControl *ctl, int base_jiitt_time, PayloadType *payload){
+ ctl->count=0;
+ ctl->slide=0;
+ ctl->jitter=0;
+ ctl->inter_jitter=0;
+ ctl->slide=0;
+ if (base_jiitt_time!=-1) ctl->jitt_comp = base_jiitt_time;
+ /* convert in timestamp unit: */
+ if (payload!=NULL){
+ jitter_control_set_payload(ctl,payload);
+ }
+ ctl->adapt_jitt_comp_ts=ctl->jitt_comp_ts;
+ ctl->corrective_slide=0;
+}
+
+void jitter_control_enable_adaptive(JitterControl *ctl, gboolean val){
+ ctl->adaptive=val;
+}
+
+void jitter_control_set_payload(JitterControl *ctl, PayloadType *pt){
+ ctl->jitt_comp_ts =
+ (gint) (((double) ctl->jitt_comp / 1000.0) * (pt->clock_rate));
+ ctl->corrective_step=(160 * 8000 )/pt->clock_rate; /* This formula got to me after some beers */
+ ctl->adapt_jitt_comp_ts=ctl->jitt_comp_ts;
+}
+
+
+void jitter_control_dump_stats(JitterControl *ctl){
+ g_log("oRTP-stats",G_LOG_LEVEL_MESSAGE,"JitterControl:\n\tslide=%g,jitter=%g,count=%i",
+ ctl->slide,ctl->jitter, ctl->count);
+}
+
+
+/*
+ The algorithm computes two values:
+ slide: an average of difference between the expected and the socket-received timestamp
+ jitter: an average of the absolute value of the difference between socket-received timestamp and slide.
+ slide is used to make clock-slide detection and correction.
+ jitter is added to the initial jitt_comp_time value. It compensates bursty packets arrival (packets
+ not arriving at regular interval ).
+*/
+void jitter_control_new_packet(JitterControl *ctl, guint32 packet_ts, guint32 cur_str_ts, gint32 * slide, gint32 *safe_delay){
+ int diff=packet_ts - cur_str_ts;
+ float gap;
+ int d;
+ //printf("diff=%g\n",diff);
+
+ ctl->count++;
+ ctl->slide= (ctl->slide*(1-JC_BETA)) + ((float)diff*JC_BETA);
+ gap=fabs((float)diff - ctl->slide);
+ ctl->jitter=(ctl->jitter*(1-JC_GAMMA)) + (gap*JC_GAMMA);
+ d=diff-ctl->olddiff;
+ ctl->inter_jitter=ctl->inter_jitter+ (( (float)abs(d) - ctl->inter_jitter)*(1/16.0));
+ ctl->olddiff=diff;
+ if (ctl->adaptive){
+ int tmp;
+ if (ctl->count%50==0) {
+ /*jitter_control_dump_stats(ctl);*/
+ }
+ tmp=(int)(ctl->slide)-ctl->corrective_slide;
+ if (tmp>ctl->corrective_step) ctl->corrective_slide+=ctl->corrective_step;
+ else if (tmp<-ctl->corrective_step) ctl->corrective_slide-=ctl->corrective_step;
+ /* the following is nearly equivalent, but maybe it consumes more CPU: ?*/
+ /*ctl->corrective_slide=(((gint)ctl->slide)/ctl->corrective_step)*ctl->corrective_step;*/
+
+ ctl->adapt_jitt_comp_ts=MAX(ctl->jitt_comp_ts,ctl->jitter);
+
+ *slide=(gint32)ctl->slide;
+ *safe_delay=(gint32)ctl->adapt_jitt_comp_ts;
+ }else {
+ *slide=0;
+ *safe_delay=(gint32)ctl->jitt_comp_ts;
+ }
+ return ;
+}
+
+
+/**
+ *rtp_session_set_jitter_compensation:
+ *@session: a RtpSession
+ *@milisec: the time interval in milisec to be jitter compensed.
+ *
+ * Sets the time interval for which packet are buffered instead of being delivered to the
+ * application.
+ **/
+void
+rtp_session_set_jitter_compensation (RtpSession * session, gint milisec)
+{
+ PayloadType *payload = rtp_profile_get_payload (session->profile,
+ session->
+ payload_type);
+ if (payload==NULL){
+ g_warning("rtp_session_set_jitter_compensation: cannot set because the payload type is unknown");
+ return;
+ }
+ jitter_control_init(&session->rtp.jittctl,milisec,payload);
+}
+
+void rtp_session_enable_adaptive_jitter_compensation(RtpSession *session, gboolean val){
+ jitter_control_enable_adaptive(&session->rtp.jittctl,val);
+}
+
+gboolean rtp_session_adaptive_jitter_compensation_enabled(RtpSession *session){
+ return session->rtp.jittctl.adaptive;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/jitterctl.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/jitterctl.h
new file mode 100644
index 00000000..8e6986a9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/jitterctl.h
@@ -0,0 +1,38 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+/***************************************************************************
+ * jitterctl.c
+ *
+ * Mon Nov 8 11:53:21 2004
+ * Copyright 2004 Simon MORLAT
+ * Email simon.morlat@linphone.org
+ ****************************************************************************/
+
+#ifndef JITTERCTL_H
+#define JITTERCTL_H
+
+
+void jitter_control_init(JitterControl *ctl, int base_jiitt_time, PayloadType *pt);
+void jitter_control_enable_adaptive(JitterControl *ctl, gboolean val);
+void jitter_control_new_packet(JitterControl *ctl, guint32 packet_ts, guint32 cur_str_ts,
+ gint32 * slide, gint32 *safe_delay);
+#define jitter_control_adaptive_enabled(ctl) ((ctl)->adaptive)
+void jitter_control_set_payload(JitterControl *ctl, PayloadType *pt);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp-config.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp-config.h
new file mode 100644
index 00000000..049a76d8
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp-config.h
@@ -0,0 +1,9 @@
+#include <config.h>
+
+#define ORTP_MAJOR_VERSION 0
+#define ORTP_MINOR_VERSION 7
+#define ORTP_MICRO_VERSION 1
+#define ORTP_EXTRA_VERSION
+#define ORTP_VERSION "0.7.1"
+
+#define POSIXTIMER_INTERVAL 10000
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp.c
new file mode 100644
index 00000000..80e07682
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp.c
@@ -0,0 +1,258 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <ortp.h>
+#include "scheduler.h"
+#include <stdlib.h>
+
+rtp_stats_t ortp_global_stats;
+
+#ifdef ENABLE_MEMCHECK
+gint ortp_allocations=0;
+#endif
+
+
+RtpScheduler *__ortp_scheduler;
+
+
+void dummy_log(const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data)
+{
+ return;
+}
+
+extern void av_profile_init(RtpProfile *profile);
+
+static void init_random_number_generator(){
+ struct timeval t;
+ gettimeofday(&t,NULL);
+ srandom(t.tv_usec+t.tv_sec);
+}
+
+/**
+ *ortp_init:
+ *
+ * Initialize the oRTP library. You should call this function first before using
+ * oRTP API.
+**/
+
+void ortp_init()
+{
+ static gboolean initialized=FALSE;
+ if (initialized) return;
+ initialized=TRUE;
+
+#ifdef _WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD( 1, 0 );
+
+ if (WSAStartup(wVersionRequested,&wsaData)!=0)
+ {
+ g_error("Fail to initialise socket api");
+ }
+#endif
+
+#ifdef HAVE_GLIB
+ if (!g_thread_supported()) g_thread_init (NULL);
+#endif
+ av_profile_init(&av_profile);
+ ortp_global_stats_reset();
+ init_random_number_generator();
+ g_message("oRTP-" ORTP_VERSION "initialized.");
+}
+
+
+/**
+ *ortp_scheduler_init:
+ *
+ * Initialize the oRTP scheduler. You only have to do that if you intend to use the
+ * scheduled mode of the #RtpSession in your application.
+ *
+**/
+void ortp_scheduler_init()
+{
+ static gboolean initialized=FALSE;
+ if (initialized) return;
+ initialized=TRUE;
+#ifdef __hpux
+ /* on hpux, we must block sigalrm on the main process, because signal delivery
+ is ?random?, well, sometimes the SIGALRM goes to both the main thread and the
+ scheduler thread */
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set,SIGALRM);
+ sigprocmask(SIG_BLOCK,&set,NULL);
+#endif /* __hpux */
+ if (!g_thread_supported()) g_thread_init(NULL);
+ __ortp_scheduler=rtp_scheduler_new();
+ rtp_scheduler_start(__ortp_scheduler);
+ //sleep(1);
+}
+
+
+/**
+ *ortp_exit:
+ *
+ * Gracefully uninitialize the library, including shutdowning the scheduler if it was started.
+ *
+**/
+void ortp_exit()
+{
+ if (__ortp_scheduler!=NULL)
+ {
+ rtp_scheduler_destroy(__ortp_scheduler);
+ __ortp_scheduler=NULL;
+ }
+}
+
+/**
+ *ortp_get_scheduler:
+ *
+ * Returns a pointer to the scheduler, NULL if it was not running.
+ * The application developer should have to call this function.
+ *
+ *Returns: a pointer to the scheduler.
+**/
+RtpScheduler * ortp_get_scheduler()
+{
+ if (__ortp_scheduler==NULL) g_error("Cannot use the scheduled mode: the scheduler is not "
+ "started. Call ortp_scheduler_init() at the begginning of the application.");
+ return __ortp_scheduler;
+}
+
+
+void ortp_log(const gchar *log_domain,GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data)
+{
+ gchar *lev;
+ switch(log_level){
+ case G_LOG_LEVEL_MESSAGE:
+ lev="message";
+ break;
+ case G_LOG_LEVEL_WARNING:
+ lev="warning";
+ break;
+ case G_LOG_LEVEL_ERROR:
+ lev="error";
+ default:
+ lev="(unknown log type)";
+ }
+ if (user_data==NULL){
+ user_data=stdout;
+ }
+ fprintf((FILE*)user_data,"%s-%s:%s\n",log_domain,lev,message);
+}
+
+
+/**
+ *ortp_set_debug_file:
+ *@domain: one of "oRTP" or "oRTP-stats" logging domain.
+ *@file: a FILE pointer where to output the messages from the domain.
+ *
+ * Warning: domain is ignored when not compiling with glib support.
+**/
+void ortp_set_debug_file(gchar *domain,FILE *file)
+{
+ if (file!=NULL)
+ g_log_set_handler (domain, G_LOG_LEVEL_MASK, ortp_log, (gpointer)file);
+ else g_log_set_handler (domain, G_LOG_LEVEL_MASK, dummy_log, NULL);
+}
+/**
+ *ortp_set_log_handler:
+ *@domain: one of the "oRTP" or "oRTP-stats" logging domain.
+ *@func: your logging function, compatible with the GLogFunc prototype.
+ *
+ * Warning: domain is ignored when not compiling with glib support.
+**/
+void ortp_set_log_handler(const gchar *domain, GLogFunc func, gpointer userdata){
+ g_log_set_handler(domain,G_LOG_LEVEL_MASK,func,userdata);
+}
+
+
+
+void ortp_global_stats_display()
+{
+ rtp_stats_display(&ortp_global_stats,"Global statistics");
+#ifdef ENABLE_MEMCHECK
+ printf("Unfreed allocations: %i\n",ortp_allocations);
+#endif
+}
+
+
+void rtp_stats_display(rtp_stats_t *stats, char *header)
+{
+
+ g_log("oRTP-stats",G_LOG_LEVEL_MESSAGE,
+ "\n %s :\n"
+ " number of rtp packet sent=%lld\n"
+ " number of rtp bytes sent=%lld bytes\n"
+ " number of rtp packet received=%lld\n"
+ " number of rtp bytes received=%lld bytes\n"
+ " number of incoming rtp bytes successfully delivered to the application=%lld \n"
+ " number of times the application queried a packet that didn't exist=%lld \n"
+ " number of rtp packets received too late=%lld\n"
+ " number of rtp packets skipped=%lld\n"
+ " number of bad formatted rtp packets=%lld\n"
+ " number of packet discarded because of queue overflow=%lld\n",
+ header,
+ (long long)stats->packet_sent,
+ (long long)stats->sent,
+ (long long)stats->packet_recv,
+ (long long)stats->hw_recv,
+ (long long)stats->recv,
+ (long long)stats->unavaillable,
+ (long long)stats->outoftime,
+ (long long)stats->skipped,
+ (long long)stats->bad,
+ (long long)stats->discarded);
+}
+
+void ortp_global_stats_reset(){
+ memset(&ortp_global_stats,0,sizeof(rtp_stats_t));
+}
+
+rtp_stats_t *ortp_get_global_stats(){
+ return &ortp_global_stats;
+}
+
+void rtp_stats_reset(rtp_stats_t *stats){
+ memset((void*)stats,0,sizeof(rtp_stats_t));
+}
+
+
+/**
+ *ortp_min_version_required:
+ *@major:
+ *@minor:
+ *@micro:
+ *
+ * This function give the opportunity to programs to check if the libortp they link to
+ * has the minimum version number they need.
+ *
+ * Returns: true if ortp has a version number greater or equal than the required one.
+**/
+gboolean ortp_min_version_required(int major, int minor, int micro){
+ return ((major*1000000) + (minor*1000) + micro) <=
+ ((ORTP_MAJOR_VERSION*1000000) + (ORTP_MINOR_VERSION*1000) + ORTP_MICRO_VERSION);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp.h
new file mode 100644
index 00000000..a3c8b01c
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/ortp.h
@@ -0,0 +1,54 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef ORTP_H
+#define ORTP_H
+
+#include <rtpsession.h>
+#include <sessionset.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+gboolean ortp_min_version_required(int major, int minor, int micro);
+void ortp_init();
+void ortp_scheduler_init();
+void ortp_exit();
+
+
+void ortp_set_debug_file(gchar *domain, FILE *file);
+/* domain is ignored when not compiling with glib support */
+void ortp_set_log_handler(const gchar *domain, GLogFunc func, gpointer ud);
+
+extern rtp_stats_t ortp_global_stats;
+
+void ortp_global_stats_reset();
+rtp_stats_t *ortp_get_global_stats();
+
+void ortp_global_stats_display();
+void rtp_stats_display(rtp_stats_t *stats, char *header);
+void rtp_stats_reset(rtp_stats_t *stats);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/payloadtype.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/payloadtype.c
new file mode 100644
index 00000000..c4886208
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/payloadtype.c
@@ -0,0 +1,268 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <payloadtype.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef WIN32
+#define snprintf _snprintf
+#define strcasecmp stricmp
+#endif
+
+/**
+ *rtp_profile_clear_all:
+ *@profile: an RTP profile (#RtpProfile object)
+ *
+ * Initialize the profile to the empty profile (all payload type are unassigned).
+ *
+**/
+
+/**
+ *rtp_profile_set_name:
+ *@profile: a rtp profile object (#RtpProfile)
+ *@nm: a string
+ *
+ * Set a name to the rtp profile. (This is not required)
+ *
+**/
+
+/**
+ *rtp_profile_get_name:
+ *@profile: a rtp profile object (#RtpProfile)
+ *
+ *Returns: the name of the rtp profile. May be NULL.
+**/
+
+/**
+ *rtp_profile_set_payload:
+ *@profile: an RTP profile (a #RtpProfile object)
+ *@index: the payload type number
+ *@pt: the payload type description (a #PayloadType object )
+ *
+ * Assign payload type number @index to payload type desribed in @pt for the RTP profile
+ * @profile.
+ *
+**/
+
+/**
+ *rtp_profile_get_payload:
+ *@profile: an RTP profile (a #RtpProfile object)
+ *@index: the payload type number
+ *
+ * Gets the payload description of the payload type @index in the profile @profile.
+ *
+ *Returns: the payload description (a #PayloadType object)
+**/
+
+/**
+ *rtp_profile_clear_payload:
+ *@profile: an RTP profile (a #RtpProfile object)
+ *@index: the payload type number
+ *
+ * Set payload type number @index unassigned in profile @profile.
+ *
+**/
+
+char *payload_type_get_rtpmap(PayloadType *pt)
+{
+ int len=strlen(pt->mime_type)+15;
+ char *rtpmap=g_malloc(len);
+ snprintf(rtpmap,len,"%s/%i/1",pt->mime_type,pt->clock_rate);
+ return rtpmap;
+}
+
+PayloadType *payload_type_new()
+{
+ PayloadType *newpayload=g_new0(PayloadType,1);
+ newpayload->flags|=PAYLOAD_TYPE_ALLOCATED;
+ return newpayload;
+}
+
+
+PayloadType *payload_type_clone(PayloadType *payload)
+{
+ PayloadType *newpayload=g_new0(PayloadType,1);
+ memcpy(newpayload,payload,sizeof(PayloadType));
+ newpayload->mime_type=g_strdup(payload->mime_type);
+ if (payload->fmtp!=NULL) newpayload->fmtp=g_strdup(payload->fmtp);
+ newpayload->flags|=PAYLOAD_TYPE_ALLOCATED;
+ return newpayload;
+}
+
+void payload_type_destroy(PayloadType *pt)
+{
+ g_free(pt->mime_type);
+ g_free(pt->fmtp);
+ g_free(pt);
+}
+
+gint rtp_profile_get_payload_number_from_mime(RtpProfile *profile,const char *mime)
+{
+ PayloadType *pt;
+ gint i;
+ for (i=0;i<RTP_PROFILE_MAX_PAYLOADS;i++)
+ {
+ pt=rtp_profile_get_payload(profile,i);
+ if (pt!=NULL)
+ {
+ if (strcasecmp(pt->mime_type,mime)==0){
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+gint rtp_profile_find_payload_number(RtpProfile*profile,const gchar *mime,int rate)
+{
+ int i;
+ PayloadType *pt;
+ for (i=0;i<RTP_PROFILE_MAX_PAYLOADS;i++)
+ {
+ pt=rtp_profile_get_payload(profile,i);
+ if (pt!=NULL)
+ {
+ if (strcasecmp(pt->mime_type,mime)==0 && pt->clock_rate==rate){
+
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+gint rtp_profile_get_payload_number_from_rtpmap(RtpProfile *profile,const char *rtpmap)
+{
+ gint clock_rate,ret;
+ char *p,*mime,*tmp,*c;
+
+ /* parse the rtpmap */
+ tmp=g_strdup(rtpmap);
+ p=strchr(tmp,'/');
+ if (p!=NULL){
+ mime=tmp;
+ *p='\0';
+ c=p+1;
+ p=strchr(c,'/');
+ if (p!=NULL) *p='\0';
+ clock_rate=atoi(c);
+ }else return -1;
+
+ //printf("Searching for payload %s at freq %i",mime,clock_rate);
+ ret=rtp_profile_find_payload_number(profile,mime,clock_rate);
+ g_free(tmp);
+ return ret;
+}
+
+PayloadType * rtp_profile_find_payload(RtpProfile *prof,const gchar *mime,int rate)
+{
+ int i;
+ i=rtp_profile_find_payload_number(prof,mime,rate);
+ if (i>=0) return rtp_profile_get_payload(prof,i);
+ return NULL;
+}
+
+
+PayloadType * rtp_profile_get_payload_from_mime(RtpProfile *profile,const char *mime)
+{
+ int pt;
+ pt=rtp_profile_get_payload_number_from_mime(profile,mime);
+ if (pt==-1) return NULL;
+ else return rtp_profile_get_payload(profile,pt);
+}
+
+
+PayloadType * rtp_profile_get_payload_from_rtpmap(RtpProfile *profile, const char *rtpmap)
+{
+ int pt;
+ pt=rtp_profile_get_payload_number_from_rtpmap(profile,rtpmap);
+ if (pt==-1) return NULL;
+ else return rtp_profile_get_payload(profile,pt);
+}
+
+int rtp_profile_move_payload(RtpProfile *prof,int oldpos,int newpos){
+ prof->payload[newpos]=prof->payload[oldpos];
+ prof->payload[oldpos]=NULL;
+ return 0;
+}
+
+RtpProfile * rtp_profile_new(const char *name)
+{
+ RtpProfile *prof=g_new0(RtpProfile,1);
+ rtp_profile_set_name(prof,name);
+ rtp_profile_clear_all(prof);
+ return prof;
+}
+
+void rtp_profile_set_name(RtpProfile *obj, const char *name){
+ if (obj->name!=NULL) g_free(obj->name);
+ obj->name=g_strdup(name);
+}
+
+/* ! payload are not cloned*/
+RtpProfile * rtp_profile_clone(RtpProfile *prof)
+{
+ int i;
+ PayloadType *pt;
+ RtpProfile *newprof=rtp_profile_new(prof->name);
+ rtp_profile_clear_all(newprof);
+ for (i=0;i<128;i++){
+ pt=rtp_profile_get_payload(prof,i);
+ if (pt!=NULL){
+ rtp_profile_set_payload(newprof,i,pt);
+ }
+ }
+ return newprof;
+}
+
+void rtp_profile_copy(const RtpProfile *orig, RtpProfile *dest){
+ memcpy(dest,orig,sizeof(RtpProfile));
+}
+
+
+/*clone a profile and its payloads */
+RtpProfile * rtp_profile_clone_full(RtpProfile *prof)
+{
+ int i;
+ PayloadType *pt;
+ RtpProfile *newprof=rtp_profile_new(prof->name);
+ rtp_profile_clear_all(newprof);
+ for (i=0;i<RTP_PROFILE_MAX_PAYLOADS;i++){
+ pt=rtp_profile_get_payload(prof,i);
+ if (pt!=NULL){
+ rtp_profile_set_payload(newprof,i,payload_type_clone(pt));
+ }
+ }
+ return newprof;
+}
+
+void rtp_profile_destroy(RtpProfile *prof)
+{
+ int i;
+ PayloadType *payload;
+ for (i=0;i<RTP_PROFILE_MAX_PAYLOADS;i++)
+ {
+ payload=rtp_profile_get_payload(prof,i);
+ if (payload!=NULL && (payload->flags & PAYLOAD_TYPE_ALLOCATED))
+ payload_type_destroy(payload);
+ }
+ g_free(prof);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/payloadtype.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/payloadtype.h
new file mode 100644
index 00000000..e5efa797
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/payloadtype.h
@@ -0,0 +1,136 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef PAYLOADTYPE_H
+#define PAYLOADTYPE_H
+#include <rtpport.h>
+
+typedef enum{
+ PAYLOAD_TYPE_ALLOCATED = 1
+}PayloadTypeFlags;
+
+struct _PayloadType
+{
+ gint type;
+ #define PAYLOAD_AUDIO_CONTINUOUS 0
+ #define PAYLOAD_AUDIO_PACKETIZED 1
+ #define PAYLOAD_VIDEO 2
+ #define PAYLOAD_OTHER 3 /* ?? */
+ gint clock_rate;
+ char bits_per_sample; /* in case of continuous audio data */
+ char *zero_pattern;
+ gint pattern_length;
+ /* other usefull information */
+ gint normal_bitrate; /*in bit/s */
+ char *mime_type;
+ char *fmtp; /*various parameters, as a string */
+ PayloadTypeFlags flags;
+ void *user_data;
+};
+
+#ifndef PayloadType_defined
+#define PayloadType_defined
+typedef struct _PayloadType PayloadType;
+#endif
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+PayloadType *payload_type_new();
+PayloadType *payload_type_clone(PayloadType *payload);
+void payload_type_destroy(PayloadType *pt);
+#ifdef __cplusplus
+}
+#endif
+
+#define payload_type_set_flag(pt,flag) (pt)->flags|=(flag)
+#define payload_type_unset_flag(pt,flag) (pt)->flags&=(~flag)
+
+#define RTP_PROFILE_MAX_PAYLOADS 128
+
+struct _RtpProfile
+{
+ char *name;
+ PayloadType *payload[RTP_PROFILE_MAX_PAYLOADS];
+};
+
+
+typedef struct _RtpProfile RtpProfile;
+
+
+extern RtpProfile av_profile;
+
+#define payload_type_set_user_data(pt,p) (pt)->user_data=(p)
+#define payload_type_get_user_data(pt) ((pt)->user_data)
+
+
+
+#define rtp_profile_get_name(profile) (const char*)((profile)->name)
+#define rtp_profile_set_payload(profile,index,pt) (profile)->payload[(index)]=(pt)
+#define rtp_profile_clear_payload(profile,index) (profile)->payload[(index)]=NULL
+#define rtp_profile_clear_all(profile) memset((void*)(profile),0,sizeof(RtpProfile))
+#define rtp_profile_get_payload(profile,index) ((profile)->payload[(index)])
+#ifdef __cplusplus
+extern "C"{
+#endif
+void rtp_profile_set_name(RtpProfile *prof, const char *name);
+PayloadType * rtp_profile_get_payload_from_mime(RtpProfile *profile,const char *mime);
+PayloadType * rtp_profile_get_payload_from_rtpmap(RtpProfile *profile, const char *rtpmap);
+gint rtp_profile_get_payload_number_from_mime(RtpProfile *profile,const char *mime);
+gint rtp_profile_get_payload_number_from_rtpmap(RtpProfile *profile, const char *rtpmap);
+gint rtp_profile_find_payload_number(RtpProfile *prof,const gchar *mime,int rate);
+PayloadType * rtp_profile_find_payload(RtpProfile *prof,const gchar *mime,int rate);
+gint rtp_profile_move_payload(RtpProfile *prof,int oldpos,int newpos);
+
+RtpProfile * rtp_profile_new(const char *name);
+/* clone a profile, payload are not cloned */
+RtpProfile * rtp_profile_clone(RtpProfile *prof);
+/* copy a profile into another one; payload are not cloned */
+void rtp_profile_copy(const RtpProfile *orig, RtpProfile *dest);
+
+/*clone a profile and its payloads (ie payload type are newly allocated, not reusing payload types of the reference profile) */
+RtpProfile * rtp_profile_clone_full(RtpProfile *prof);
+/* frees the profile and all its PayloadTypes*/
+void rtp_profile_destroy(RtpProfile *prof);
+#ifdef __cplusplus
+}
+#endif
+
+/* some payload types */
+/* audio */
+extern PayloadType pcmu8000;
+extern PayloadType pcma8000;
+extern PayloadType pcm8000;
+extern PayloadType lpc1016;
+extern PayloadType gsm;
+extern PayloadType lpc1015;
+extern PayloadType speex_nb;
+extern PayloadType speex_wb;
+extern PayloadType payload_type_ilbc;
+extern PayloadType truespeech;
+
+/* video */
+extern PayloadType mpv;
+extern PayloadType h261;
+extern PayloadType h263;
+
+
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/port_fct.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/port_fct.c
new file mode 100644
index 00000000..2ad6b4dc
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/port_fct.c
@@ -0,0 +1,183 @@
+
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* port_fct.h. define methods to help for portability between unix and win32 */
+
+#include <unistd.h>
+
+#include <rtpport.h>
+#include "port_fct.h"
+
+
+
+/*
+ * this method is an utility method that calls fnctl() on UNIX or
+ * ioctlsocket on Win32.
+ * int retrun the result of the system method
+ */
+int set_non_blocking_socket (gint sock)
+{
+
+
+#ifndef _WIN32
+ return fcntl (sock, F_SETFL, O_NONBLOCK);
+#else
+ unsigned long nonBlock = 1;
+ return ioctlsocket(sock, FIONBIO , &nonBlock);
+#endif
+}
+
+
+/*
+ * this method is an utility method that calls close() on UNIX or
+ * closesocket on Win32.
+ * int retrun the result of the system method
+ */
+#ifndef _WIN32
+ int close_socket(gint sock)
+ {
+ return close (sock);
+ }
+#else
+ int close_socket(SOCKET sock)
+ {
+ return closesocket(sock);
+ }
+#endif
+
+
+
+/*
+ * getSocketError() return a string describing the error
+ */
+#ifdef _WIN32
+char *getSocketError()
+{
+ int error = WSAGetLastError ();
+ static char buf[80];
+
+ switch (error)
+ {
+ case WSANOTINITIALISED: return "Windows sockets not initialized : call WSAStartup";
+ case WSAEADDRINUSE: return "Local Address already in use";
+ case WSAEADDRNOTAVAIL: return "The specified address is not a valid address for this machine";
+// case WSAEFAULT: return "";
+// case WSAEINPROGRESS: return "";
+ case WSAEINVAL: return "The socket is already bound to an address.";
+ case WSAENOBUFS: return "Not enough buffers available, too many connections.";
+ case WSAENOTSOCK: return "The descriptor is not a socket.";
+ case WSAECONNRESET: return "Connection reset by peer";
+/*
+
+ case : return "";
+ case : return "";
+ case : return "";
+ case : return "";
+ case : return "";
+ case : return "";
+*/
+ default :
+ sprintf (buf,"Error code : %d", error);
+ return buf;
+ break;
+ }
+
+ return buf;
+
+}
+#endif
+
+#ifndef _WIN32
+ /* Use UNIX inet_aton method */
+#else
+ int inet_aton (const char * cp, struct in_addr * addr)
+ {
+ unsigned long retval;
+
+ retval = inet_addr (cp);
+
+ if (retval == INADDR_NONE)
+ {
+ return -1;
+ }
+ else
+ {
+ addr->S_un.S_addr = retval;
+ return 1;
+ }
+ }
+#endif
+
+#ifndef HAVE_GLIB
+
+char * g_strdup_vprintf(const char *fmt, va_list ap)
+{
+ /* Guess we need no more than 100 bytes. */
+ int n, size = 100;
+ char *p;
+ if ((p = g_malloc (size)) == NULL)
+ return NULL;
+ while (1)
+ {
+ /* Try to print in the allocated space. */
+ n = vsnprintf (p, size, fmt, ap);
+ /* If that worked, return the string. */
+ if (n > -1 && n < size)
+ return p;
+ //printf("Reallocing space.\n");
+ /* Else try again with more space. */
+ if (n > -1) /* glibc 2.1 */
+ size = n + 1; /* precisely what is needed */
+ else /* glibc 2.0 */
+ size *= 2; /* twice the old size */
+ if ((p = g_realloc (p, size)) == NULL)
+ return NULL;
+ }
+}
+
+
+
+extern void ortp_log(const gchar *log_domain,GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data);
+
+static GLogFunc __log_func=ortp_log;
+static gpointer __log_user_data=(gpointer)NULL;
+
+void g_log(const gchar *log_domain,GLogLevelFlags log_level,const gchar *format,...){
+ va_list args;
+ va_start(args,format);
+ g_logv(log_domain,log_level,format,args);
+ va_end(args);
+}
+
+void g_logv(const gchar *log_domain,GLogLevelFlags log_level,const gchar *format,va_list args){
+ gchar *msg;
+ msg=g_strdup_vprintf(format,args);
+ __log_func(log_domain,log_level,msg,__log_user_data);
+ g_free(msg);
+}
+
+void g_log_set_handler(const gchar *log_domain,GLogLevelFlags log_levels, GLogFunc log_func, gpointer user_data){
+ __log_func=log_func;
+ __log_user_data=user_data;
+}
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/port_fct.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/port_fct.h
new file mode 100644
index 00000000..3b3abe31
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/port_fct.h
@@ -0,0 +1,48 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* fct-win32.h. define unix methods that are not defined in win32 env */
+
+#ifndef PORT_FCT_H
+#define PORT_FCT_H
+
+#ifdef _WIN32
+#include <Winsock2.h>
+#else
+#include <fcntl.h>
+#endif
+
+#include <rtpport.h>
+
+#ifndef _WIN32
+/* use unix pthread_t... */
+ extern int close_socket(gint sock);
+#else
+ #define pthread_t HANDLE
+ extern int pthread_create(pthread_t *thread,const void *attr,void *(__cdecl *start)(void *),void* arg);
+ extern int pthread_join(pthread_t thread,void **);
+
+ extern int close_socket(SOCKET sock);
+ extern int inet_aton (const char * cp, struct in_addr * addr);
+#endif
+
+extern int set_non_blocking_socket (int sock);
+extern int set_thread_priority();
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/posixtimer.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/posixtimer.c
new file mode 100644
index 00000000..9e20ead4
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/posixtimer.c
@@ -0,0 +1,167 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <rtpport.h>
+#include "rtptimer.h"
+
+
+#ifndef _WIN32
+
+#ifdef __linux__
+#include <sys/select.h>
+#endif
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+static struct timeval orig,cur;
+static guint32 posix_timer_time=0; /*in milisecond */
+
+void posix_timer_init()
+{
+ posix_timer.state=RTP_TIMER_RUNNING;
+ gettimeofday(&orig,NULL);
+ posix_timer_time=0;
+}
+
+
+
+
+void posix_timer_do()
+{
+ gint32 diff,time;
+ struct timeval tv;
+
+ gettimeofday(&cur,NULL);
+ time=((cur.tv_usec-orig.tv_usec)/1000 ) + ((cur.tv_sec-orig.tv_sec)*1000 );
+ if ( (diff=time-posix_timer_time)>50){
+ g_warning("Must catchup %i miliseconds.",diff);
+ }
+ while((diff = posix_timer_time-time) > 0)
+ {
+ tv.tv_sec = diff/1000;
+ tv.tv_usec = (diff%1000)*1000;
+ select(0,NULL,NULL,NULL,&tv);
+ gettimeofday(&cur,NULL);
+ time=((cur.tv_usec-orig.tv_usec)/1000 ) + ((cur.tv_sec-orig.tv_sec)*1000 );
+ }
+ posix_timer_time+=POSIXTIMER_INTERVAL/1000;
+
+}
+
+void posix_timer_uninit()
+{
+ posix_timer.state=RTP_TIMER_STOPPED;
+}
+
+RtpTimer posix_timer={ 0,
+ posix_timer_init,
+ posix_timer_do,
+ posix_timer_uninit,
+ {0,POSIXTIMER_INTERVAL}};
+
+
+#else //WIN32
+
+#include <windows.h>
+#include <mmsystem.h>
+
+
+MMRESULT timerId;
+HANDLE TimeEvent;
+int late_ticks;
+
+
+static DWORD posix_timer_time;
+static DWORD offset_time;
+
+
+#define TIME_INTERVAL 50
+#define TIME_RESOLUTION 10
+#define TIME_TIMEOUT 100
+
+
+
+void CALLBACK timerCb(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+ // Check timerId
+ if (timerId == uID)
+ {
+ SetEvent(TimeEvent);
+ posix_timer_time += TIME_INTERVAL;
+ }
+}
+
+
+void win_timer_init(void)
+{
+ timerId = timeSetEvent(TIME_INTERVAL,10,timerCb,0,TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
+ TimeEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
+
+ late_ticks = 0;
+
+ offset_time = GetTickCount();
+ posix_timer_time=0;
+}
+
+
+void win_timer_do(void)
+{
+ DWORD diff;
+
+ // If timer have expired while we where out of this method
+ // Try to run after lost time.
+ if (late_ticks > 0)
+ {
+ late_ticks--;
+ posix_timer_time+=TIME_INTERVAL;
+ return;
+ }
+
+
+ diff = GetTickCount() - posix_timer_time - offset_time;
+ if( diff>TIME_INTERVAL && (diff<(1<<31)))
+ {
+ late_ticks = diff/TIME_INTERVAL;
+ g_warning("we must catchup %i ticks.",late_ticks);
+ return;
+ }
+
+ WaitForSingleObject(TimeEvent,TIME_TIMEOUT);
+ return;
+}
+
+
+void win_timer_close(void)
+{
+ timeKillEvent(timerId);
+}
+
+RtpTimer toto;
+
+RtpTimer posix_timer={ 0,
+ win_timer_init,
+ win_timer_do,
+ win_timer_close,
+ {0,TIME_INTERVAL * 1000}};
+
+
+#endif // _WIN32
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcp.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcp.c
new file mode 100644
index 00000000..78599ae5
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcp.c
@@ -0,0 +1,294 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/***************************************************************************
+ * rtcp.c
+ *
+ * Wed Dec 1 11:45:30 2004
+ * Copyright 2004 Simon Morlat
+ * Email simon dot morlat at linphone dot org
+ ****************************************************************************/
+
+#include <rtpsession.h>
+#include <rtcp.h>
+
+extern gint ortp_rtcp_send (RtpSession * session, mblk_t * m);
+
+
+void rtcp_common_header_init(rtcp_common_header_t *ch, RtpSession *s,int type, int rc, int bytes_len){
+ rtcp_common_header_set_version(ch,2);
+ rtcp_common_header_set_padbit(ch,0);
+ rtcp_common_header_set_packet_type(ch,type);
+ rtcp_common_header_set_rc(ch,rc); /* as we don't yet support multi source receiving */
+ rtcp_common_header_set_length(ch,(bytes_len/4)-1);
+}
+
+mblk_t *sdes_chunk_new(guint32 ssrc){
+ mblk_t *m=allocb(RTCP_SDES_CHUNK_DEFAULT_SIZE,0);
+ sdes_chunk_t *sc=(sdes_chunk_t*)m->b_rptr;
+ sc->csrc=htonl(ssrc);
+ m->b_wptr+=sizeof(sc->csrc);
+ return m;
+}
+
+
+mblk_t * sdes_chunk_append_item(mblk_t *m, rtcp_sdes_type_t sdes_type, const gchar *content)
+{
+ if ( content )
+ {
+ sdes_item_t si;
+ si.item_type=sdes_type;
+ si.len=MIN(strlen(content),RTCP_SDES_MAX_STRING_SIZE);
+ m=appendb(m,(char*)&si,RTCP_SDES_ITEM_HEADER_SIZE,FALSE);
+ m=appendb(m,content,si.len,FALSE);
+ }
+ return m;
+}
+
+void sdes_chunk_set_ssrc(mblk_t *m, guint32 ssrc){
+ sdes_chunk_t *sc=(sdes_chunk_t*)m->b_rptr;
+ sc->csrc=htonl(ssrc);
+}
+
+#define sdes_chunk_get_ssrc(m) ntohl(((sdes_chunk_t*)((m)->b_rptr))->csrc)
+
+mblk_t * sdes_chunk_pad(mblk_t *m){
+ return appendb(m,NULL,0,TRUE);
+}
+
+void rtp_session_set_source_description(RtpSession *session,
+ const gchar *cname, const gchar *name, const gchar *email, const gchar *phone,
+ const gchar *loc, const gchar *tool, const gchar *note){
+ mblk_t *chunk = sdes_chunk_new(session->send_ssrc);
+ mblk_t *m=chunk;
+ const gchar *_cname=cname;
+ if (_cname==NULL)
+ {
+ _cname="Unknown";
+ }
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_CNAME, _cname);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NAME, name);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_EMAIL, email);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_PHONE, phone);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_LOC, loc);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_TOOL, tool);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NOTE, note);
+ chunk=sdes_chunk_pad(chunk);
+ rtp_session_lock(session);
+ if (session->sd!=NULL) freemsg(session->sd);
+ session->sd=m;
+ rtp_session_unlock(session);
+}
+
+void
+rtp_session_add_contributing_source(RtpSession *session, guint32 csrc,
+ const gchar *cname, const gchar *name, const gchar *email, const gchar *phone,
+ const gchar *loc, const gchar *tool, const gchar *note)
+{
+ mblk_t *chunk = sdes_chunk_new(csrc);
+ mblk_t *m=chunk;
+ gchar *_cname=(gchar*)cname;
+ if (_cname==NULL)
+ {
+ _cname="toto";
+ }
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_CNAME, cname);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NAME, name);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_EMAIL, email);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_PHONE, phone);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_LOC, loc);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_TOOL, tool);
+ chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NOTE, note);
+ chunk=sdes_chunk_pad(chunk);
+ rtp_session_lock(session);
+ putq(&session->contributing_sources,m);
+ rtp_session_unlock(session);
+}
+
+
+
+mblk_t* rtp_session_create_rtcp_sdes_packet(RtpSession *session)
+{
+ mblk_t *mp=allocb(sizeof(rtcp_common_header_t),0);
+ rtcp_common_header_t *rtcp;
+ mblk_t *tmp,*m=mp;
+ queue_t *q;
+ int rc=0;
+ rtcp = (rtcp_common_header_t*)mp->b_wptr;
+ mp->b_wptr+=sizeof(rtcp_common_header_t);
+
+ /* concatenate all sdes chunks */
+ sdes_chunk_set_ssrc(session->sd,session->send_ssrc);
+ m=concatb(m,dupmsg(session->sd));
+ rc++;
+
+ q=&session->contributing_sources;
+ for (tmp=qbegin(q); !qend(q,tmp); tmp=qnext(q,mp)){
+ m=concatb(m,dupmsg(tmp));
+ rc++;
+ }
+ rtcp_common_header_init(rtcp,session,RTCP_SDES,rc,msgdsize(mp));
+ return mp;
+}
+
+
+mblk_t *rtcp_create_simple_bye_packet(guint32 ssrc, const gchar *reason)
+{
+ gint strsize=0;
+ gint packet_size;
+ mblk_t *mp;
+ rtcp_bye_t *rtcp;
+ packet_size = RTCP_BYE_HEADER_SIZE + 1 + strsize;
+ if (reason!=NULL)
+ strsize=MIN(strlen(reason),RTCP_BYE_REASON_MAX_STRING_SIZE);
+ mp = allocb(packet_size, 0);
+
+ rtcp = (rtcp_bye_t*)mp->b_rptr;
+
+ rtcp_common_header_init(&rtcp->ch,NULL,RTCP_BYE,1,packet_size);
+ rtcp->ssrc[0] = htonl(ssrc);
+ mp->b_wptr += packet_size;
+ /* append the reason if any*/
+ if (reason!=NULL)
+ appendb(mp,reason,strsize,FALSE);
+ return mp;
+}
+
+void rtp_session_remove_contributing_sources(RtpSession *session, guint32 ssrc)
+{
+ queue_t *q=&session->contributing_sources;
+ mblk_t *tmp;
+ for (tmp=qbegin(q); !qend(q,tmp); tmp=qnext(q,tmp)){
+ guint32 csrc=sdes_chunk_get_ssrc(tmp);
+ if (csrc==ssrc) {
+ remq(q,tmp);
+ break;
+ }
+ }
+ tmp=rtcp_create_simple_bye_packet(ssrc, NULL);
+ ortp_rtcp_send(session,tmp);
+}
+
+void sender_info_init(sender_info_t *info, RtpSession *session){
+ struct timeval tv;
+ guint32 tmp;
+ gettimeofday(&tv,NULL);
+ info->ntp_timestamp_msw=htonl(tv.tv_sec);
+ tmp=(guint32)((double)tv.tv_usec*(double)(1LL<<32)*1.0e-6);
+ info->ntp_timestamp_lsw=htonl(tmp);
+ info->rtp_timestamp=htonl(session->rtp.snd_last_ts);
+ info->senders_packet_count=htonl(session->rtp.stats.packet_sent);
+ info->senders_octet_count=htonl(session->rtp.stats.sent);
+}
+
+
+
+void report_block_init(report_block_t *b, RtpSession *session){
+ guint packet_loss=0;
+ guint8 loss_fraction=0;
+ RtpStream *stream=&session->rtp;
+ guint32 delay_snc_last_sr=0;
+
+ /* compute the statistics */
+ /*printf("hwrcv_extseq.one=%u, hwrcv_seq_at_last_SR=%u hwrcv_since_last_SR=%u\n",
+ stream->hwrcv_extseq.one,
+ stream->hwrcv_seq_at_last_SR,
+ stream->hwrcv_since_last_SR
+ );*/
+ if (stream->hwrcv_seq_at_last_SR!=0){
+ packet_loss=(stream->hwrcv_extseq.one - stream->hwrcv_seq_at_last_SR) - stream->hwrcv_since_last_SR;
+ stream->stats.cum_packet_loss+=packet_loss;
+ loss_fraction=(int)(256.0*(float)packet_loss/(float)stream->hwrcv_since_last_SR);
+ }
+ /* reset them */
+ stream->hwrcv_since_last_SR=0;
+ stream->hwrcv_seq_at_last_SR=stream->hwrcv_extseq.one;
+
+ if (stream->last_rcv_SR_time.tv_sec!=0){
+ struct timeval now;
+ gfloat delay;
+ gettimeofday(&now,NULL);
+ delay=((now.tv_sec-stream->last_rcv_SR_time.tv_sec)*1e6 ) + (now.tv_usec-stream->last_rcv_SR_time.tv_usec);
+ delay=delay*65536*1e-6;
+ delay_snc_last_sr=(guint32) delay;
+ }
+
+ b->ssrc=htonl(session->recv_ssrc);
+ b->fraction_lost=loss_fraction;
+ b->cum_num_packet_lost=hton24(stream->stats.cum_packet_loss);
+ b->interarrival_jitter=htonl((guint32) stream->jittctl.inter_jitter);
+ b->ext_high_seq_num_rec=htonl(stream->hwrcv_extseq.one);
+ b->lsr=htonl(stream->last_rcv_SR_ts);
+ b->delay_snc_last_sr=htonl(delay_snc_last_sr);
+}
+
+
+
+int rtcp_sr_init(RtpSession *session, char *buf, int size){
+ rtcp_sr_t *sr=(rtcp_sr_t*)buf;
+ if (size<sizeof(rtcp_sr_t)) return -1;
+ rtcp_common_header_init(&sr->ch,session,RTCP_SR,1,sizeof(rtcp_sr_t));
+ sr->ssrc=htonl(session->send_ssrc);
+ sender_info_init(&sr->si,session);
+ report_block_init(&sr->rb[0],session);
+ return sizeof(rtcp_sr_t);
+}
+
+int rtcp_rr_init(RtpSession *session, char *buf, int size){
+ rtcp_rr_t *rr=(rtcp_rr_t*)buf;
+ if (size<sizeof(rtcp_rr_t)) return -1;
+ rtcp_common_header_init(&rr->ch,session,RTCP_RR,1,sizeof(rtcp_sr_t));
+ rr->ssrc=htonl(session->send_ssrc);
+ report_block_init(&rr->rb[0],session);
+ return sizeof(rtcp_sr_t);
+}
+
+
+void __rtp_session_rtcp_process(RtpSession *session){
+ mblk_t *cm=NULL;
+ mblk_t *sdes=NULL;
+ if (session->mode==RTP_SESSION_SENDONLY || session->mode==RTP_SESSION_SENDRECV){
+ /* first make a SR packet */
+ cm=allocb(sizeof(rtcp_sr_t),0);
+ cm->b_wptr+=rtcp_sr_init(session,cm->b_wptr,sizeof(rtcp_sr_t));
+ /* make a SDES packet */
+ sdes=rtp_session_create_rtcp_sdes_packet(session);
+ /* link them */
+ cm->b_cont=sdes;
+ }else{
+ /* make a RR packet */
+ cm=allocb(sizeof(rtcp_rr_t),0);
+ cm->b_wptr+=rtcp_rr_init(session,cm->b_wptr,sizeof(rtcp_rr_t));
+ /* if we are recv-only do we need to add SDES packet ? I don't think so
+ as we are not a source */
+ }
+ /* send the compound packet */
+ ortp_rtcp_send(session,cm);
+ ortp_debug("Rtcp compound message sent.");
+}
+
+void rtp_session_rtcp_process(RtpSession *session){
+ RtpStream *st=&session->rtp;
+ if (st->rcv_last_app_ts - st->last_rtcp_report_snt_r > st->rtcp_report_snt_interval
+ || st->snd_last_ts - st->last_rtcp_report_snt_s > st->rtcp_report_snt_interval){
+ st->last_rtcp_report_snt_r=st->rcv_last_app_ts;
+ st->last_rtcp_report_snt_s=st->snd_last_ts;
+ __rtp_session_rtcp_process(session);
+ }
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcp.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcp.h
new file mode 100644
index 00000000..574bcf91
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcp.h
@@ -0,0 +1,167 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef RTCP_H
+#define RTCP_H
+
+#include <rtpport.h>
+
+#define RTCP_MAX_RECV_BUFSIZE 1024
+
+#define RTCP_SENDER_INFO_SIZE 20
+#define RTCP_REPORT_BLOCK_SIZE 24
+#define RTCP_COMMON_HEADER_SIZE 4
+#define RTCP_SSRC_FIELD_SIZE 4
+
+
+/* RTCP common header */
+
+typedef enum {
+ RTCP_SR = 200,
+ RTCP_RR = 201,
+ RTCP_SDES = 202,
+ RTCP_BYE = 203,
+ RTCP_APP = 204
+} rtcp_type_t;
+
+
+typedef struct rtcp_common_header
+{
+#ifdef WORDS_BIGENDIAN
+ guint16 version:2;
+ guint16 padbit:1;
+ guint16 rc:5;
+ guint16 packet_type:8;
+#else
+ guint16 rc:5;
+ guint16 padbit:1;
+ guint16 version:2;
+ guint16 packet_type:8;
+#endif
+ guint16 length:16;
+} rtcp_common_header_t;
+
+#define rtcp_common_header_set_version(ch,v) (ch)->version=v
+#define rtcp_common_header_set_padbit(ch,p) (ch)->padbit=p
+#define rtcp_common_header_set_rc(ch,rc) (ch)->rc=rc
+#define rtcp_common_header_set_packet_type(ch,pt) (ch)->packet_type=pt
+#define rtcp_common_header_set_length(ch,l) (ch)->length=htons(l)
+
+#define rtcp_common_header_get_version(ch,v) ((ch)->version)
+#define rtcp_common_header_get padbit(ch,p) ((ch)->padbit)
+#define rtcp_common_header_get_rc(ch,rc) ((ch)->rc)
+#define rtcp_common_header_get_packet_type(ch,pt) ((ch)->packet_type)
+#define rtcp_common_header_get_length(ch,l) ntohs((ch)->length)
+
+
+/* SR or RR packets */
+
+typedef struct sender_info
+{
+ guint32 ntp_timestamp_msw;
+ guint32 ntp_timestamp_lsw;
+ guint32 rtp_timestamp;
+ guint32 senders_packet_count;
+ guint32 senders_octet_count;
+} sender_info_t;
+
+typedef struct report_block
+{
+ guint32 ssrc;
+ guint32 fraction_lost:8;
+ guint32 cum_num_packet_lost:24; /*cumulative number of packet lost*/
+ guint32 ext_high_seq_num_rec; /*extended highest sequence number received */
+ guint32 interarrival_jitter;
+ guint32 lsr; /*last SR */
+ guint32 delay_snc_last_sr; /*delay since last sr*/
+} report_block_t;
+
+
+/* SDES packets */
+
+typedef enum {
+ RTCP_SDES_END = 0,
+ RTCP_SDES_CNAME = 1,
+ RTCP_SDES_NAME = 2,
+ RTCP_SDES_EMAIL = 3,
+ RTCP_SDES_PHONE = 4,
+ RTCP_SDES_LOC = 5,
+ RTCP_SDES_TOOL = 6,
+ RTCP_SDES_NOTE = 7,
+ RTCP_SDES_PRIV = 8,
+ RTCP_SDES_MAX = 9
+} rtcp_sdes_type_t;
+
+typedef struct sdes_chunk
+{
+ guint32 csrc;
+} sdes_chunk_t;
+
+typedef struct sdes_item
+{
+ guint8 item_type;
+ guint8 len;
+ gchar content[1];
+} sdes_item_t;
+
+#define RTCP_SDES_MAX_STRING_SIZE 255
+#define RTCP_SDES_ITEM_HEADER_SIZE 2
+#define RTCP_SDES_CHUNK_DEFAULT_SIZE 1024
+#define RTCP_SDES_CHUNK_HEADER_SIZE (sizeof(sdes_chunk_t))
+
+/* RTCP bye packet */
+
+typedef struct rtcp_bye_reason
+{
+ guint8 len;
+ gchar content[1];
+} rtcp_bye_reason_t;
+
+typedef struct rtcp_bye
+{
+ rtcp_common_header_t ch;
+ guint32 ssrc[1]; /* the bye may contain several ssrc/csrc */
+} rtcp_bye_t;
+#define RTCP_BYE_HEADER_SIZE sizeof(rtcp_bye_t)
+#define RTCP_BYE_REASON_MAX_STRING_SIZE 255
+
+#define rtcp_bye_set_ssrc(b,pos,ssrc) (b)->ssrc[pos]=htonl(ssrc)
+#define rtcp_bye_get_ssrc(b,pos) ntohl((b)->ssrc[pos])
+
+
+typedef struct rtcp_sr{
+ rtcp_common_header_t ch;
+ guint32 ssrc;
+ sender_info_t si;
+ report_block_t rb[1];
+} rtcp_sr_t;
+
+typedef struct rtcp_rr{
+ rtcp_common_header_t ch;
+ guint32 ssrc;
+ report_block_t rb[1];
+} rtcp_rr_t;
+
+struct _RtpSession;
+void rtp_session_rtcp_process(struct _RtpSession *s);
+
+#define RTCP_DEFAULT_REPORT_INTERVAL 5
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcpparse.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcpparse.c
new file mode 100644
index 00000000..77e38245
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtcpparse.c
@@ -0,0 +1,218 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This source code file was written by Nicola Baldo as an extension of
+ the oRTP library. Copyright (C) 2005 Nicola Baldo nicola@baldo.biz
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include <ortp.h>
+
+
+
+void report_block_parse(RtpSession *session, report_block_t *rb, struct timeval rcv_time_tv)
+{
+ rb->ssrc = ntohl(rb->ssrc);
+
+ if ( rb->ssrc != session->send_ssrc )
+
+ {
+ ortp_debug("Received rtcp report block related to unknown ssrc (not from us)... discarded");
+ return;
+ }
+
+ else
+
+ {
+ guint32 rcv_time_msw;
+ guint32 rcv_time_lsw;
+ guint32 rcv_time;
+ double rtt;
+
+ rcv_time_msw = rcv_time_tv.tv_sec;
+ rcv_time_lsw = (guint32) ((double)rcv_time_tv.tv_usec*(double)(1LL<<32)*1.0e-6);
+ rcv_time = (rcv_time_msw<<16) | (rcv_time_lsw >> 16);
+
+ rb->cum_num_packet_lost = ntoh24(rb->cum_num_packet_lost);
+ rb->ext_high_seq_num_rec = ntohl(rb->ext_high_seq_num_rec);
+ rb->interarrival_jitter = ntohl(rb->interarrival_jitter);
+ rb->lsr = ntohl(rb->lsr);
+ rb->delay_snc_last_sr = ntohl(rb->delay_snc_last_sr);
+
+
+ /* calculating Round Trip Time*/
+ if (rb->lsr != 0)
+ {
+ rtt = (double) (rcv_time - rb->delay_snc_last_sr - rb->lsr);
+ rtt = rtt/65536;
+ //printf("RTT = %f s\n",rtt);
+ }
+
+ }
+
+}
+
+
+void rtcp_parse(RtpSession *session, mblk_t *mp)
+{
+ rtcp_common_header_t *rtcp;
+ int msgsize;
+ int rtcp_pk_size;
+ RtpStream *rtpstream=&session->rtp;
+ struct timeval rcv_time_tv;
+
+
+ gettimeofday(&rcv_time_tv,NULL);
+
+ g_return_if_fail(mp!=NULL);
+
+ msgsize=mp->b_wptr-mp->b_rptr;
+
+
+
+ if (msgsize < RTCP_COMMON_HEADER_SIZE)
+ {
+ ortp_debug("Receiving too short rtcp packet... discarded");
+ return;
+ }
+
+ rtcp=(rtcp_common_header_t *)mp->b_rptr;
+
+
+ /* compound rtcp packet can be composed by more than one rtcp message */
+ while (msgsize >= RTCP_COMMON_HEADER_SIZE)
+
+ {
+
+ if (rtcp->version!=2)
+ {
+ ortp_debug("Receiving rtcp packet with version number !=2...discarded");
+ return;
+ }
+
+ /* convert header data from network order to host order */
+ rtcp->length = ntohs(rtcp->length);
+
+
+ switch (rtcp->packet_type)
+
+ {
+
+ case RTCP_SR:
+
+ {
+ rtcp_sr_t *sr = (rtcp_sr_t *) rtcp;
+ report_block_t *rb;
+ int i;
+
+ if ( ntohl(sr->ssrc) != session->recv_ssrc )
+ {
+ ortp_debug("Receiving rtcp sr packet from unknown ssrc.. discarded");
+ return;
+ }
+
+ if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + RTCP_SENDER_INFO_SIZE + (RTCP_REPORT_BLOCK_SIZE*sr->ch.rc))
+ {
+ ortp_debug("Receiving too short rtcp sr packet... discarded");
+ return;
+ }
+
+ /* parsing RTCP Sender Info */
+ sr->si.ntp_timestamp_msw = ntohl(sr->si.ntp_timestamp_msw);
+ sr->si.ntp_timestamp_lsw = ntohl(sr->si.ntp_timestamp_lsw);
+ sr->si.rtp_timestamp = ntohl(sr->si.rtp_timestamp);
+ sr->si.senders_packet_count = ntohl(sr->si.senders_packet_count);
+ sr->si.senders_octet_count = ntohl(sr->si.senders_octet_count);
+
+ /* saving data to fill LSR and DLSR field in next RTCP report to be transmitted */
+ rtpstream->last_rcv_SR_ts = (sr->si.ntp_timestamp_msw << 16) | (sr->si.ntp_timestamp_lsw >> 16);
+ rtpstream->last_rcv_SR_time.tv_usec = rcv_time_tv.tv_usec;
+ rtpstream->last_rcv_SR_time.tv_sec = rcv_time_tv.tv_sec;
+
+
+ /* parsing all RTCP report blocks */
+ for (i=0; i<sr->ch.rc; i++)
+ {
+ rb = &(sr->rb[i]);
+ report_block_parse(session, rb, rcv_time_tv);
+ }
+
+ }
+ break;
+
+
+
+ case RTCP_RR:
+
+ {
+ rtcp_rr_t *rr = (rtcp_rr_t *) rtcp;
+ report_block_t *rb;
+ int i;
+
+ if ( ntohl(rr->ssrc) != session->recv_ssrc )
+ {
+ ortp_debug("Receiving rtcp rr packet from unknown ssrc.. discarded");
+ return;
+ }
+
+ if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + (RTCP_REPORT_BLOCK_SIZE*rr->ch.rc))
+ {
+ ortp_debug("Receiving too short rtcp sr packet... discarded");
+ return;
+ }
+
+ /* parsing all RTCP report blocks */
+ for (i=0; i<rr->ch.rc; i++)
+ {
+ rb = &(rr->rb[i]);
+ report_block_parse(session, rb, rcv_time_tv);
+ }
+
+ }
+ break;
+
+
+ case RTCP_SDES:
+ /* to be implemented */
+ break;
+
+
+ case RTCP_BYE:
+ /* to be implemented */
+ break;
+
+
+ case RTCP_APP:
+ /* to be implemented */
+ break;
+
+
+ default:
+
+ ortp_debug("Receiving unknown rtcp packet type... discarded");
+ return;
+
+ }
+
+
+ rtcp_pk_size = ((rtcp->length)+1)*4; /* current RTCP packet size, in octets */
+ msgsize -= rtcp_pk_size; /* size of unparsed portion of UDP packet, in octets */
+ rtcp = (rtcp_common_header_t *) (rtcp_pk_size + (char *) rtcp); /* pointer to next RTCP packet in current UDP packet */
+
+ }
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtp.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtp.h
new file mode 100644
index 00000000..625d2111
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtp.h
@@ -0,0 +1,90 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef RTP_H
+#define RTP_H
+
+#include <rtpport.h>
+
+
+
+
+#define RTP_MAX_RQ_SIZE 100 /* max number of packet allowed to be enqueued */
+
+#define IPMAXLEN 20
+#define UDP_MAX_SIZE 65536
+#define RTP_FIXED_HEADER_SIZE 12
+#define RTP_DEFAULT_JITTER_TIME 80 /*miliseconds*/
+
+
+
+typedef struct rtp_header
+{
+#ifdef WORDS_BIGENDIAN
+ guint16 version:2;
+ guint16 padbit:1;
+ guint16 extbit:1;
+ guint16 cc:4;
+ guint16 markbit:1;
+ guint16 paytype:7;
+#else
+ guint16 cc:4;
+ guint16 extbit:1;
+ guint16 padbit:1;
+ guint16 version:2;
+ guint16 paytype:7;
+ guint16 markbit:1;
+#endif
+ guint16 seq_number;
+ guint32 timestamp;
+ guint32 ssrc;
+ guint32 csrc[16];
+} rtp_header_t;
+
+
+
+
+typedef struct rtp_stats
+{
+ guint64 packet_sent;
+ guint64 sent; /* bytes sent */
+ guint64 recv; /* bytes received and delivered in time to the application */
+ guint64 hw_recv; /* bytes of udp packets received */
+ guint64 packet_recv; /* number of packets received */
+ guint64 unavaillable; /* packets not availlable when they were queried */
+ guint64 outoftime; /* number of packets that were received too late */
+ guint64 skipped; /* number of packets skipped (that the application never queried
+ or that need to be skipped in order to compensate a clock slide (see adaptive jitter control)) */
+ guint64 cum_packet_loss; /* cumulative number of packet lost */
+ guint64 bad; /* packets that did not appear to be RTP */
+ guint64 discarded; /* incoming packets discarded because the queue exceeds its max size */
+} rtp_stats_t;
+
+#define RTP_TIMESTAMP_IS_NEWER_THAN(ts1,ts2) \
+ ((guint32)((guint32)(ts1) - (guint32)(ts2))< (guint32)(1<<31))
+
+#define RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(ts1,ts2) \
+ ( ((guint32)((guint32)(ts1) - (guint32)(ts2))< (guint32)(1<<31)) && (ts1)!=(ts2) )
+
+#define TIME_IS_NEWER_THAN(t1,t2) RTP_TIMESTAMP_IS_NEWER_THAN(t1,t2)
+
+#define TIME_IS_STRICTLY_NEWER_THAN(t1,t2) RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(t1,t2)
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpmod.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpmod.c
new file mode 100644
index 00000000..50aeef10
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpmod.c
@@ -0,0 +1,122 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+
+
+#include <rtp.h>
+#include "rtpmod.h"
+
+#define RTP_SEQ_IS_GREATER(seq1,seq2)\
+ ((guint16)((guint16)(seq1) - (guint16)(seq2))< (guint16)(1<<15))
+
+/* put an rtp packet in queue. It is called by rtp_parse()*/
+void rtp_putq(queue_t *q, mblk_t *mp)
+{
+ mblk_t *tmp;
+ rtp_header_t *rtp=(rtp_header_t*)mp->b_rptr,*tmprtp;
+ /* insert message block by increasing time stamp order : the last (at the bottom)
+ message of the queue is the newest*/
+ ortp_debug("rtp_putq(): Enqueuing packet with ts=%i and seq=%i",rtp->timestamp,rtp->seq_number);
+
+ if (qempty(q)) {
+ putq(q,mp);
+ return;
+ }
+ tmp=qlast(q);
+ /* we look at the queue from bottom to top, because enqueued packets have a better chance
+ to be enqueued at the bottom, since there are surely newer */
+ while (!qend(q,tmp))
+ {
+ tmprtp=(rtp_header_t*)tmp->b_rptr;
+ ortp_debug("rtp_putq(): Seeing packet with seq=%i",tmprtp->seq_number);
+
+ if (rtp->seq_number == tmprtp->seq_number)
+ {
+ /* this is a duplicated packet. Don't queue it */
+ ortp_debug("rtp_putq: duplicated message.");
+ freemsg(mp);
+ return;
+ }else if (RTP_SEQ_IS_GREATER(rtp->seq_number,tmprtp->seq_number)){
+
+ insq(q,tmp->b_next,mp);
+ return;
+ }
+ tmp=tmp->b_prev;
+ }
+ /* this packet is the oldest, it has to be
+ placed on top of the queue */
+ insq(q,qfirst(q),mp);
+
+}
+
+
+
+mblk_t *rtp_getq(queue_t *q,guint32 timestamp, int *rejected)
+{
+ mblk_t *tmp,*ret=NULL,*old;
+ rtp_header_t *tmprtp;
+ guint32 oldest;
+ guint32 ts_found=0;
+
+ *rejected=0;
+ ortp_debug("rtp_getq(): Timestamp %i wanted.",timestamp);
+
+ if (qempty(q))
+ {
+ /*ortp_debug("rtp_getq: q is empty.");*/
+ return NULL;
+ }
+ /* prevent somebody to ask for a timestamp that is older than the oldest of the queue */
+ oldest=((rtp_header_t*) qfirst(q)->b_rptr)->timestamp;
+ if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(oldest,timestamp))
+ {
+ ortp_debug("rtp_getq(): asking for too old packet ! oldest=%i",oldest);
+ return NULL;
+ }
+ ret=NULL;
+ old=NULL;
+ /* return the packet with ts just equal or older than the asked timestamp */
+ while ((tmp=qfirst(q))!=NULL)
+ {
+ tmprtp=(rtp_header_t*)tmp->b_rptr;
+ ortp_debug("rtp_getq: Seeing packet with ts=%i",tmprtp->timestamp);
+ if ( RTP_TIMESTAMP_IS_NEWER_THAN(timestamp,tmprtp->timestamp) )
+ {
+ if (ret!=NULL && tmprtp->timestamp==ts_found) {
+ /* we've found two packets with same timestamp. return the first one */
+ break;
+ }
+ if (old!=NULL) {
+ ortp_debug("rtp_getq: discarding too old packet with ts=%i",ts_found);
+ (*rejected)++;
+ freemsg(old);
+ }
+ ret=getq(q); /* dequeue the packet, since it has an interesting timestamp*/
+ ts_found=tmprtp->timestamp;
+ ortp_debug("rtp_getq: Found packet with ts=%i",tmprtp->timestamp);
+ old=ret;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return ret;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpmod.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpmod.h
new file mode 100644
index 00000000..e675394d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpmod.h
@@ -0,0 +1,31 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef RTPMOD_H
+#define RTPMOD_H
+
+#include <rtpport.h>
+#include <str_utils.h>
+#include <rtp.h>
+
+void rtp_putq(queue_t *q, mblk_t *mp);
+mblk_t *rtp_getq(queue_t *q,guint32 timestamp, int *rejected);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpparse.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpparse.c
new file mode 100644
index 00000000..50ecba97
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpparse.c
@@ -0,0 +1,159 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include <ortp.h>
+#include "rtpmod.h"
+#include "jitterctl.h"
+
+
+void split_and_queue(queue_t *q, int maxrqsz, mblk_t *mp, rtp_header_t *rtp, int *discarded)
+{
+ mblk_t *mdata,*tmp;
+ int header_size;
+ *discarded=0;
+ header_size=RTP_FIXED_HEADER_SIZE+ (4*rtp->cc);
+ if ((mp->b_wptr - mp->b_rptr)==header_size){
+ ortp_debug("Rtp packet contains no data.");
+ (*discarded)++;
+ freemsg(mp);
+ return;
+ }
+ /* creates a new mblk_t to be linked with the rtp header*/
+ mdata=dupb(mp);
+
+ mp->b_wptr=mp->b_rptr+header_size;
+ mdata->b_rptr+=header_size;
+ /* link proto with data */
+ mp->b_cont=mdata;
+ /* and then add the packet to the queue */
+
+ rtp_putq(q,mp);
+ /* make some checks: q size must not exceed RtpStream::max_rq_size */
+ while (q->q_mcount > maxrqsz)
+ {
+ /* remove the oldest mblk_t */
+ tmp=getq(q);
+ if (mp!=NULL)
+ {
+ ortp_debug("rtp_putq: Queue is full. Discarding message with ts=%i",((rtp_header_t*)mp->b_rptr)->timestamp);
+ freemsg(tmp);
+ (*discarded)++;
+ }
+ }
+}
+
+void rtp_parse(RtpSession *session, mblk_t *mp, guint32 local_str_ts)
+{
+ gint i;
+ rtp_header_t *rtp;
+ int msgsize;
+ RtpStream *rtpstream=&session->rtp;
+ rtp_stats_t *stats=&rtpstream->stats;
+
+ g_return_if_fail(mp!=NULL);
+
+ msgsize=msgdsize(mp);
+ ortp_global_stats.hw_recv+=msgsize;
+ stats->hw_recv+=msgsize;
+ ortp_global_stats.packet_recv++;
+ stats->packet_recv++;
+
+ session->rtp.hwrcv_since_last_SR++;
+
+ rtp=(rtp_header_t*)mp->b_rptr;
+ if (rtp->version!=2)
+ {
+ ortp_debug("Receiving rtp packet with version number !=2...discarded");
+ stats->bad++;
+ ortp_global_stats.bad++;
+ freemsg(mp);
+ return;
+ }
+
+ /* convert all header data from network order to host order */
+ rtp->seq_number=ntohs(rtp->seq_number);
+ rtp->timestamp=ntohl(rtp->timestamp);
+ rtp->ssrc=ntohl(rtp->ssrc);
+ /* convert csrc if necessary */
+ if (rtp->cc*sizeof(guint32) > (msgsize-RTP_FIXED_HEADER_SIZE)){
+ ortp_debug("Receiving too short rtp packet.");
+ stats->bad++;
+ ortp_global_stats.bad++;
+ freemsg(mp);
+ return;
+ }
+ for (i=0;i<rtp->cc;i++)
+ rtp->csrc[i]=ntohl(rtp->csrc[i]);
+ if (session->recv_ssrc!=0)
+ {
+ /*the ssrc is set, so we must check it */
+ if (session->recv_ssrc!=rtp->ssrc){
+ /*ortp_debug("rtp_parse: bad ssrc - %i",rtp->ssrc);*/
+ session->recv_ssrc=rtp->ssrc;
+ rtp_signal_table_emit(&session->on_ssrc_changed);
+ }
+ }else session->recv_ssrc=rtp->ssrc;
+
+ /* update some statistics */
+ if (rtp->seq_number>rtpstream->hwrcv_extseq.split.lo){
+ rtpstream->hwrcv_extseq.split.lo=rtp->seq_number;
+ }else if (rtp->seq_number<200 && rtpstream->hwrcv_extseq.split.lo>((1<<16) - 200)){
+ /* this is a check for sequence number looping */
+ rtpstream->hwrcv_extseq.split.lo=rtp->seq_number;
+ rtpstream->hwrcv_extseq.split.hi++;
+ }
+
+
+ /* check for possible telephone events */
+ if (rtp->paytype==session->telephone_events_pt){
+ split_and_queue(&session->rtp.tev_rq,session->rtp.max_rq_size,mp,rtp,&i);
+ stats->discarded+=i;
+ ortp_global_stats.discarded+=i;
+ return;
+ }
+
+ if (!(session->flags & RTP_SESSION_RECV_SYNC)){
+ gint32 slide=0;
+ gint32 safe_delay=0;
+ jitter_control_new_packet(&session->rtp.jittctl,rtp->timestamp,local_str_ts,&slide,&safe_delay);
+
+ session->rtp.rcv_diff_ts=session->rtp.hwrcv_diff_ts + slide - safe_delay;
+ ortp_debug(" rcv_diff_ts=%i", session->rtp.rcv_diff_ts);
+
+ /* detect timestamp important jumps in the future, to workaround stupid rtp senders */
+ if (RTP_TIMESTAMP_IS_NEWER_THAN(rtp->timestamp,session->rtp.rcv_last_ts+session->rtp.ts_jump)){
+ ortp_debug("rtp_parse: timestamp jump ?");
+ rtp_signal_table_emit2(&session->on_timestamp_jump,&rtp->timestamp);
+ }
+ else if (RTP_TIMESTAMP_IS_NEWER_THAN(session->rtp.rcv_last_ts,rtp->timestamp)){
+ /* avoid very old packet to enqueued, because the user is no more supposed to get them */
+ ortp_debug("rtp_parse: silently discarding very old packet (ts=%i)",rtp->timestamp);
+ freemsg(mp);
+ stats->outoftime++;
+ ortp_global_stats.outoftime++;
+ return;
+ }
+
+ }
+
+ split_and_queue(&session->rtp.rq,session->rtp.max_rq_size,mp,rtp,&i);
+ stats->discarded+=i;
+ ortp_global_stats.discarded+=i;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpport.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpport.h
new file mode 100644
index 00000000..65e48530
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpport.h
@@ -0,0 +1,308 @@
+/*
+ The oRTP LinPhone RTP library intends to provide basics for a RTP stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+/* this file is responsible of the portability of the stack */
+
+#ifndef RTPPORT_H
+#define RTPPORT_H
+
+#ifdef UGLIB_H
+#define HAVE_GLIB
+#endif
+
+#ifndef _WIN32 /* do not include ortp-config.h when we are on win32 */
+# ifdef _ORTP_SOURCE
+# include <ortp-config.h>
+# else
+# include <ortp-config.h>
+# endif
+#else
+ #include "ortp-config-win32.h"
+#endif
+
+#define INT_TO_POINTER(truc) ((gpointer)(long)(truc))
+#define POINTER_TO_INT(truc) ((int)(long)(truc))
+
+/* defines things that should be defined when we have not glib */
+#ifndef HAVE_GLIB
+
+#include <errno.h>
+#include <sys/types.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+/* integer types */
+typedef uint64_t guint64;
+typedef uint16_t guint16;
+typedef uint32_t guint32;
+typedef signed short gint16;
+typedef int32_t gint32;
+typedef unsigned int guint;
+typedef int gint;
+typedef char gchar;
+typedef unsigned char guchar;
+typedef unsigned char guint8;
+typedef void* gpointer;
+typedef int gboolean;
+typedef double gdouble;
+typedef float gfloat;
+
+#define TRUE 1
+#define FALSE 0
+
+
+/*misc*/
+#define g_return_if_fail(expr) if (!(expr)) {printf("%s:%i- assertion" #expr "failed\n",__FILE__,__LINE__); return;}
+#define g_return_val_if_fail(expr,ret) if (!(expr)) {printf("%s:%i- assertion" #expr "failed\n",__FILE__,__LINE__); return (ret);}
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+typedef enum {
+ /* GLib log levels */
+ G_LOG_LEVEL_ERROR = 1 << 2, /* always fatal */
+ G_LOG_LEVEL_CRITICAL = 1 << 3,
+ G_LOG_LEVEL_WARNING = 1 << 4,
+ G_LOG_LEVEL_MESSAGE = 1 << 5,
+ G_LOG_LEVEL_MASK = ~0
+
+} GLogLevelFlags;
+
+#ifndef G_LOG_DOMAIN
+#define G_LOG_DOMAIN ((const gchar*)"")
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void g_log(const gchar *log_domain,GLogLevelFlags log_level,const gchar *format,...);
+void g_logv(const gchar *log_domain,GLogLevelFlags log_level,const gchar *format,va_list args);
+typedef void (*GLogFunc) (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data);
+static inline void g_warning(const gchar *fmt,...)
+{
+ va_list args;
+ va_start (args, fmt);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, fmt, args);
+ va_end (args);
+}
+static inline void g_error(const gchar *fmt,...)
+{
+ va_list args;
+ va_start (args, fmt);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, fmt, args);
+ va_end (args);
+}
+static inline void g_message(const gchar *fmt,...)
+{
+ va_list args;
+ va_start (args, fmt);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, args);
+ va_end (args);
+}
+/* in order to simplify, domain is ignored when using the folowing function, ie all logs will go through your handler
+whatever the domain is */
+void g_log_set_handler(const gchar *domain, GLogLevelFlags levels, GLogFunc func, gpointer ud);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAVE_GLIB */
+
+
+#if defined(TIME_WITH_SYS_TIME)
+#include <time.h>
+#include <sys/time.h>
+#elif defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#endif
+
+
+#ifdef HAVE_GLIB
+
+#ifndef UGLIB_H
+#include <glib.h>
+#endif
+#include <string.h>
+
+
+#else /* not HAVE_GLIB */
+/* things that in glib, but should only be defined when we are not in the HPUX kernel. */
+#include <stdlib.h>
+#include <pthread.h>
+#include <sched.h>
+#include <string.h>
+
+#ifdef ENABLE_MEMCHECK
+extern gint ortp_allocations;
+#endif
+
+/* memory allocation functions */
+static inline void * g_malloc(int sz)
+{
+ void *p=malloc(sz);
+ if (p==NULL) {
+ printf("g_malloc: Failed to allocate %i bytes: %s.\n",sz,strerror(errno));
+ abort();
+ }
+#ifdef ENABLE_MEMCHECK
+ ortp_allocations++;
+#endif
+ return p;
+}
+
+static inline void * g_malloc0(int sz)
+{
+ void *p=malloc(sz);
+ if (p==NULL) {
+ printf("g_malloc: Failed to allocate %i bytes: %s.\n",sz,strerror(errno));
+ abort();
+ }
+ memset(p,0,sz);
+#ifdef ENABLE_MEMCHECK
+ ortp_allocations++;
+#endif
+ return p;
+}
+
+#define g_new(type,count) (type *)g_malloc(sizeof(type)*(count))
+#define g_new0(type, count) (type *)g_malloc0(sizeof(type)*(count))
+#define g_realloc(p,sz) realloc((p),(sz))
+static inline void g_free(void *p)
+{
+#ifdef ENABLE_MEMCHECK
+ ortp_allocations--;
+#endif
+ free(p);
+}
+
+#define g_strdup(machin) strdup(machin)
+
+typedef pthread_mutex_t GMutex;
+static inline GMutex * g_mutex_new()
+{
+ pthread_mutex_t *mutex=g_new(pthread_mutex_t,1);
+ pthread_mutex_init(mutex,NULL);
+ return mutex;
+}
+typedef enum
+{
+ G_THREAD_PRIORITY_LOW,
+ G_THREAD_PRIORITY_NORMAL,
+ G_THREAD_PRIORITY_HIGH,
+ G_THREAD_PRIORITY_URGENT
+} GThreadPriority;
+typedef pthread_t GThread;
+typedef gpointer (*GThreadFunc)(gpointer data);
+static inline GThread *g_thread_create(GThreadFunc func, gpointer data, gboolean joinable, void **error){
+ GThread *thread=g_new(GThread,1);
+ pthread_create(thread,NULL,func,data);
+ return thread;
+}
+
+static inline void g_thread_join(GThread *thread){
+ pthread_join(*thread,NULL);
+ g_free(thread);
+}
+
+static inline void g_thread_set_priority(GThread *thread,GThreadPriority prio){
+ if (prio>G_THREAD_PRIORITY_NORMAL){
+ /* this is unsupported on HPUX */
+ /*
+ struct sched_param param;
+ param.sched_priority=1;
+ sched_setscheduler(*thread,SCHED_RR,&param);
+ */
+ }
+}
+
+#define g_mutex_lock(mutex) pthread_mutex_lock((mutex))
+#define g_mutex_unlock(mutex) pthread_mutex_unlock((mutex))
+#define g_mutex_free(mutex) pthread_mutex_destroy((mutex));g_free((mutex))
+
+typedef pthread_cond_t GCond;
+static inline GCond * g_cond_new()
+{
+ pthread_cond_t *cond=g_new(pthread_cond_t,1);
+ pthread_cond_init(cond,NULL);
+ return cond;
+}
+#define g_cond_wait(cond,mutex) pthread_cond_wait((cond),(mutex))
+#define g_cond_signal(cond) pthread_cond_signal((cond))
+#define g_cond_broadcast(cond) pthread_cond_broadcast((cond))
+#define g_cond_free(cond) pthread_cond_destroy((cond)); g_free((cond))
+
+#define g_thread_init(vtable)
+#define g_thread_supported() (1)
+
+#endif /* HAVE_GLIB */
+
+
+#ifndef RTP_DEBUG
+#define ortp_debug(...)
+#else
+#define ortp_debug g_message
+#endif
+
+#ifdef _WIN32
+extern char *getSocketError();
+#define getSocketErrorCode() WSAGetLastError ()
+#else
+#define getSocketError() strerror(errno)
+#define getSocketErrorCode() (errno)
+#endif
+
+#ifdef UGLIB_H
+#undef HAVE_GLIB
+#endif
+
+#undef MIN
+#define MIN(a,b) (((a)>(b)) ? (b) : (a))
+#undef MAX
+#define MAX(a,b) (((a)>(b)) ? (a) : (b))
+
+typedef struct _dwsplit_t{
+#ifdef WORDS_BIGENDIAN
+ guint16 hi;
+ guint16 lo;
+#else
+ guint16 lo;
+ guint16 hi;
+#endif
+} dwsplit_t;
+
+typedef union{
+ dwsplit_t split;
+ guint32 one;
+} poly32_t;
+
+#ifdef WORDS_BIGENDIAN
+#define hton24(x) (x)
+#else
+#define hton24(x) ((( (x) & 0x00ff0000) >>16) | (( (x) & 0x000000ff) <<16) | ( (x) & 0x0000ff00) )
+#endif
+#define ntoh24(x) hton24(x)
+
+#endif /*RTPPORT_H*/
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsession.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsession.c
new file mode 100644
index 00000000..de6b2e7d
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsession.c
@@ -0,0 +1,1954 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include <ortp.h>
+#include <telephonyevents.h>
+#include "rtpmod.h"
+#include "jitterctl.h"
+#include "scheduler.h"
+#include "port_fct.h"
+#include "utils.h"
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef _WIN32
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# ifdef INET6
+# include <netdb.h>
+# endif
+#else
+# include <winsock2.h>
+# include "errno-win32.h"
+#endif
+
+
+#if defined(HAVE_POLL_H)
+#include <poll.h>
+#elif defined(HAVE_SYS_POLL_H)
+#include <sys/poll.h>
+#endif
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#define USE_SENDMSG 1
+#endif
+
+
+
+void wait_point_init(WaitPoint *wp){
+ wp->lock=g_mutex_new();
+ wp->cond=g_cond_new();
+ wp->time=0;
+ wp->wakeup=FALSE;
+}
+void wait_point_uninit(WaitPoint *wp){
+ g_cond_free(wp->cond);
+ g_mutex_free(wp->lock);
+}
+
+#define wait_point_lock(wp) g_mutex_lock((wp)->lock)
+#define wait_point_unlock(wp) g_mutex_unlock((wp)->lock)
+
+void wait_point_wakeup_at(WaitPoint *wp, guint32 t, gboolean dosleep){
+ wp->time=t;
+ wp->wakeup=TRUE;
+ if (dosleep) g_cond_wait(wp->cond,wp->lock);
+}
+
+
+gboolean wait_point_check(WaitPoint *wp, guint32 t){
+ gboolean ok=FALSE;
+
+ if (wp->wakeup){
+ if (TIME_IS_NEWER_THAN(t,wp->time)){
+ wp->wakeup=FALSE;
+ ok=TRUE;
+
+ }
+ }
+ return ok;
+}
+#define wait_point_wakeup(wp) g_cond_signal((wp)->cond);
+
+extern void rtp_parse(RtpSession *session, mblk_t *mp, guint32 local_str_ts);
+
+
+static guint32 guint32_random(){
+ return random();
+}
+
+void
+rtp_session_init (RtpSession * session, gint mode)
+{
+ memset (session, 0, sizeof (RtpSession));
+ session->lock = g_mutex_new ();
+ session->rtp.max_rq_size = RTP_MAX_RQ_SIZE;
+ session->mode = mode;
+ if ((mode == RTP_SESSION_RECVONLY) || (mode == RTP_SESSION_SENDRECV))
+ {
+ rtp_session_set_flag (session, RTP_SESSION_RECV_SYNC);
+ rtp_session_set_flag (session, RTP_SESSION_RECV_NOT_STARTED);
+
+ }
+ if ((mode == RTP_SESSION_SENDONLY) || (mode == RTP_SESSION_SENDRECV))
+ {
+ rtp_session_set_flag (session, RTP_SESSION_SEND_NOT_STARTED);
+ rtp_session_set_flag (session, RTP_SESSION_SEND_SYNC);
+ session->send_ssrc=guint32_random();
+ /* set default source description */
+ rtp_session_set_source_description(session,"unknown@unknown",NULL,NULL,
+ NULL,NULL,"oRTP-" ORTP_VERSION,"This is free sofware (LGPL) !");
+ }
+ session->telephone_events_pt=-1; /* not defined a priori */
+ rtp_session_set_profile (session, &av_profile); /*the default profile to work with */
+ session->payload_type=0;/* default to something */
+ qinit(&session->rtp.rq);
+ qinit(&session->rtp.tev_rq);
+ qinit(&session->contributing_sources);
+ /* init signal tables */
+ rtp_signal_table_init (&session->on_ssrc_changed, session,"ssrc_changed");
+ rtp_signal_table_init (&session->on_payload_type_changed, session,"payload_type_changed");
+ rtp_signal_table_init (&session->on_telephone_event, session,"telephone-event");
+ rtp_signal_table_init (&session->on_telephone_event_packet, session,"telephone-event_packet");
+ rtp_signal_table_init (&session->on_timestamp_jump,session,"timestamp_jump");
+ rtp_signal_table_init (&session->on_network_error,session,"network_error");
+ wait_point_init(&session->send_wp);
+ wait_point_init(&session->recv_wp);
+ rtp_session_set_jitter_compensation(session,RTP_DEFAULT_JITTER_TIME);
+ rtp_session_enable_adaptive_jitter_compensation(session,FALSE);
+ rtp_session_set_time_jump_limit(session,5000);
+ session->max_buf_size = UDP_MAX_SIZE;
+}
+
+/**
+ *rtp_session_new:
+ *@mode: One of the #RtpSessionMode flags.
+ *
+ * Creates a new rtp session.
+ * If the session is able to send data (RTP_SESSION_SENDONLY or RTP_SESSION_SENDRECV), then a
+ * random SSRC number is choosed for the outgoing stream.
+ *
+ *Returns: the newly created rtp session.
+**/
+
+RtpSession *
+rtp_session_new (gint mode)
+{
+ RtpSession *session;
+ session = g_malloc (sizeof (RtpSession));
+ rtp_session_init (session, mode);
+ return session;
+}
+
+/**
+ *rtp_session_set_scheduling_mode:
+ *@session: a rtp session.
+ *@yesno: a boolean to indicate the scheduling mode.
+ *
+ * Sets the scheduling mode of the rtp session. If @yesno is TRUE, the rtp session is in
+ * the scheduled mode, that means that you can use session_set_select() to block until it's time
+ * to receive or send on this session according to the timestamp passed to the respective functions.
+ * You can also use blocking mode (see rtp_session_set_blocking_mode() ), to simply block within
+ * the receive and send functions.
+ * If @yesno is FALSE, the ortp scheduler will not manage those sessions, meaning that blocking mode
+ * and the use of session_set_select() for this session are disabled.
+ *
+**/
+
+void
+rtp_session_set_scheduling_mode (RtpSession * session, gint yesno)
+{
+ if (yesno)
+ {
+ RtpScheduler *sched;
+ sched = ortp_get_scheduler ();
+ if (sched != NULL)
+ {
+ rtp_session_set_flag (session, RTP_SESSION_SCHEDULED);
+ session->sched = sched;
+ rtp_scheduler_add_session (sched, session);
+ }
+ else
+ g_warning
+ ("rtp_session_set_scheduling_mode: Cannot use scheduled mode because the "
+ "scheduler is not started. Use ortp_scheduler_init() before.");
+ }
+ else
+ rtp_session_unset_flag (session, RTP_SESSION_SCHEDULED);
+}
+
+
+/**
+ *rtp_session_set_blocking_mode:
+ *@session: a rtp session
+ *@yesno: a boolean
+ *
+ * Using this function implies that you previously enabled scheduled mode on the session
+ * (see rtp_session_set_scheduling_mode() ).
+ * rtp_session_set_blocking_mode() defines the behaviour of the rtp_session_recv_with_ts() and
+ * rtp_session_send_with_ts() functions. If @yesno is TRUE, rtp_session_recv_with_ts()
+ * will block until it is time for the packet to be received, according to the timestamp
+ * passed to the function. After this time, the function returns.
+ * For rtp_session_send_with_ts(), it will block until it is time for the packet to be sent.
+ * If @yesno is FALSE, then the two functions will return immediately.
+ *
+**/
+void
+rtp_session_set_blocking_mode (RtpSession * session, gint yesno)
+{
+ if (yesno)
+ rtp_session_set_flag (session, RTP_SESSION_BLOCKING_MODE);
+ else
+ rtp_session_unset_flag (session, RTP_SESSION_BLOCKING_MODE);
+}
+
+/**
+ *rtp_session_set_profile:
+ *@session: a rtp session
+ *@profile: a rtp profile
+ *
+ * Set the RTP profile to be used for the session. By default, all session are created by
+ * rtp_session_new() are initialized with the AV profile, as defined in RFC 1890. The application
+ * can set any other profile instead using that function.
+ *
+ *
+**/
+
+void
+rtp_session_set_profile (RtpSession * session, RtpProfile * profile)
+{
+ session->profile = profile;
+ rtp_session_telephone_events_supported(session);
+}
+
+
+/**
+ *rtp_session_signal_connect:
+ *@session: a rtp session
+ *@signal: the name of a signal
+ *@cb: a #RtpCallback
+ *@user_data: a pointer to any data to be passed when invoking the callback.
+ *
+ * This function provides the way for an application to be informed of various events that
+ * may occur during a rtp session. @signal is a string identifying the event, and @cb is
+ * a user supplied function in charge of processing it. The application can register
+ * several callbacks for the same signal, in the limit of #RTP_CALLBACK_TABLE_MAX_ENTRIES.
+ * Here are name and meaning of supported signals types:
+ *
+ * "ssrc_changed" : the SSRC of the incoming stream has changed.
+ *
+ * "payload_type_changed" : the payload type of the incoming stream has changed.
+ *
+ * "telephone-event_packet" : a telephone-event rtp packet (RFC2833) is received.
+ *
+ * "telephone-event" : a telephone event has occured. This is a high-level shortcut for "telephone-event_packet".
+ *
+ * "network_error" : a network error happened on a socket. Arguments of the callback functions are
+ * a const char * explaining the error, an int errno error code and the user_data as usual.
+ *
+ * "timestamp_jump" : we have received a packet with timestamp in far future compared to last timestamp received.
+ * The farness of far future is set by rtp_sesssion_set_time_jump_limit()
+ *
+ * Returns: 0 on success, -EOPNOTSUPP if the signal does not exists, -1 if no more callbacks
+ * can be assigned to the signal type.
+**/
+int
+rtp_session_signal_connect (RtpSession * session, const char *signal,
+ RtpCallback cb, gpointer user_data)
+{
+ OList *elem;
+ for (elem=session->signal_tables;elem!=NULL;elem=o_list_next(elem)){
+ RtpSignalTable *s=(RtpSignalTable*) elem->data;
+ if (strcmp(signal,s->signal_name)==0){
+ return rtp_signal_table_add(s,cb,user_data);
+ }
+ }
+ g_warning ("rtp_session_signal_connect: inexistant signal %s",signal);
+ return -1;
+}
+
+
+/**
+ *rtp_session_signal_disconnect_by_callback:
+ *@session: a rtp session
+ *@signal: a signal name
+ *@cb: a callback function.
+ *
+ * Removes callback function @cb to the list of callbacks for signal @signal.
+ *
+ *Returns: 0 on success, -ENOENT if the callbacks was not found.
+**/
+
+int
+rtp_session_signal_disconnect_by_callback (RtpSession * session, const gchar *signal,
+ RtpCallback cb)
+{
+ OList *elem;
+ for (elem=session->signal_tables;elem!=NULL;elem=o_list_next(elem)){
+ RtpSignalTable *s=(RtpSignalTable*) elem->data;
+ if (strcmp(signal,s->signal_name)==0){
+ return rtp_signal_table_remove_by_callback(s,cb);
+ }
+ }
+ g_warning ("rtp_session_signal_connect: inexistant signal %s",signal);
+ return -1;
+}
+
+/**
+ *rtp_session_set_local_addr:
+ *@session: a rtp session freshly created.
+ *@addr: a local IP address in the xxx.xxx.xxx.xxx form.
+ *@port: a local port.
+ *
+ * Specify the local addr to be use to listen for rtp packets or to send rtp packet from.
+ * In case where the rtp session is send-only, then it is not required to call this function:
+ * when calling rtp_session_set_remote_addr(), if no local address has been set, then the
+ * default INADRR_ANY (0.0.0.0) IP address with a random port will be used. Calling
+ * rtp_sesession_set_local_addr() is mandatory when the session is recv-only or duplex.
+ *
+ * Returns: 0 on success.
+**/
+
+gint
+rtp_session_set_local_addr (RtpSession * session, const gchar * addr, gint port)
+{
+ gint err;
+ gint optval = 1;
+#ifdef INET6
+ char num[8];
+ struct addrinfo hints, *res0, *res;
+#endif
+
+ if (session->rtp.socket>0) {
+ /* dont try to rebind, close socket before */
+ close_socket(session->rtp.socket);
+ close_socket(session->rtcp.socket);
+ session->rtp.socket=0;
+ session->rtcp.socket=0;
+ }
+
+#ifdef INET6
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ snprintf(num, sizeof(num), "%d",port);
+ err = getaddrinfo(addr,num, &hints, &res0);
+ if (err!=0) {
+ g_warning ("Error: %s", gai_strerror(err));
+ return err;
+ }
+
+ for (res = res0; res; res = res->ai_next) {
+ session->rtp.socket = socket(res->ai_family, res->ai_socktype, 0);
+ if (session->rtp.socket < 0)
+ continue;
+
+ err = setsockopt (session->rtp.socket, SOL_SOCKET, SO_REUSEADDR,
+ (void*)&optval, sizeof (optval));
+ if (err < 0)
+ {
+ g_warning ("Fail to set rtp address reusable: %s.", getSocketError());
+ }
+
+ session->rtp.socktype=res->ai_family;
+ memcpy(&session->rtp.loc_addr, res->ai_addr, res->ai_addrlen);
+ err = bind (session->rtp.socket, res->ai_addr, res->ai_addrlen);
+ if (err != 0)
+ {
+ g_warning ("Fail to bind rtp socket to port %i: %s.", port, getSocketError());
+ close_socket (session->rtp.socket);
+ continue;
+ }
+#ifndef __hpux
+ switch (res->ai_family)
+ {
+ case AF_INET:
+ if (IN_MULTICAST(ntohl(((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr)))
+ {
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = INADDR_ANY;
+ err = setsockopt(session->rtp.socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+ if (err < 0)
+ {
+ g_warning ("Fail to join address group: %s.", getSocketError());
+ close_socket (session->rtp.socket);
+ continue;
+ }
+ }
+ break;
+ case AF_INET6:
+ if (IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr)))
+ {
+ struct ipv6_mreq mreq;
+ mreq.ipv6mr_multiaddr = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
+ mreq.ipv6mr_interface = 0;
+ err = setsockopt(session->rtp.socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
+ if (err < 0)
+ {
+ g_warning ("Fail to join address group: %s.", getSocketError());
+ close_socket (session->rtp.socket);
+ continue;
+ }
+ }
+ break;
+ }
+#endif
+ break;
+ }
+ freeaddrinfo(res0);
+ if (session->rtp.socket < 0){
+ if (session->mode==RTP_SESSION_RECVONLY) g_warning("Could not create rtp socket with address %s: %s",addr,getSocketError());
+ return -1;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ snprintf(num, sizeof(num), "%d", (port + 1));
+
+ err = getaddrinfo(addr, num, &hints, &res0);
+ if (err!=0) {
+ g_warning ("Error: %s", gai_strerror(err));
+ return err;
+ }
+
+ for (res = res0; res; res = res->ai_next) {
+ session->rtcp.socket = socket(res->ai_family, res->ai_socktype, 0);
+
+ if (session->rtcp.socket < 0)
+ continue;
+
+ err = setsockopt (session->rtcp.socket, SOL_SOCKET, SO_REUSEADDR,
+ (void*)&optval, sizeof (optval));
+ if (err < 0)
+ {
+ g_warning ("Fail to set rtcp address reusable: %s.",getSocketError());
+ }
+ session->rtcp.socktype=res->ai_family;
+ memcpy( &session->rtcp.loc_addr, res->ai_addr, res->ai_addrlen);
+ err = bind (session->rtcp.socket, res->ai_addr, res->ai_addrlen);
+ if (err != 0)
+ {
+ g_warning ("Fail to bind rtp socket to port %i: %s.", port, getSocketError());
+ close_socket (session->rtp.socket);
+ close_socket (session->rtcp.socket);
+ continue;
+ }
+#ifndef __hpux
+ switch (res->ai_family)
+ {
+ case AF_INET:
+ if (IN_MULTICAST(ntohl(((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr)))
+ {
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = INADDR_ANY;
+ err = setsockopt(session->rtcp.socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+ if (err < 0)
+ {
+ g_warning ("Fail to join address group: %s.", getSocketError());
+ close_socket (session->rtp.socket);
+ close_socket (session->rtcp.socket);
+ continue;
+ }
+ }
+ break;
+ case AF_INET6:
+ if (IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr)))
+ {
+ struct ipv6_mreq mreq;
+ mreq.ipv6mr_multiaddr = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
+ mreq.ipv6mr_interface = 0;
+ err = setsockopt(session->rtcp.socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
+ if (err < 0)
+ {
+ g_warning ("Fail to join address group: %s.", getSocketError());
+ close_socket (session->rtp.socket);
+ close_socket (session->rtcp.socket);
+ continue;
+ }
+ }
+ break;
+ }
+#endif
+
+ break;
+ }
+ freeaddrinfo(res0);
+ if (session->rtp.socket < 0){
+ g_warning("Could not create rtcp socket with address %s: %s",addr,getSocketError());
+ return -1;
+ }
+#else
+ session->rtp.loc_addr.sin_family = AF_INET;
+
+ err = inet_aton (addr, &session->rtp.loc_addr.sin_addr);
+
+ if (err < 0)
+ {
+ g_warning ("Error in socket address:%s.", getSocketError());
+ return err;
+ }
+ session->rtp.loc_addr.sin_port = htons (port);
+
+ session->rtp.socket = socket (PF_INET, SOCK_DGRAM, 0);
+ g_return_val_if_fail (session->rtp.socket > 0, -1);
+
+ err = setsockopt (session->rtp.socket, SOL_SOCKET, SO_REUSEADDR,
+ (void*)&optval, sizeof (optval));
+ if (err < 0)
+ {
+ g_warning ("Fail to set rtp address reusable: %s.",getSocketError());
+ }
+
+ err = bind (session->rtp.socket,
+ (struct sockaddr *) &session->rtp.loc_addr,
+ sizeof (struct sockaddr_in));
+
+ if (err != 0)
+ {
+ g_warning ("Fail to bind rtp socket to port %i: %s.", port, getSocketError());
+ close_socket (session->rtp.socket);
+ return -1;
+ }
+ memcpy (&session->rtcp.loc_addr, &session->rtp.loc_addr,
+ sizeof (struct sockaddr_in));
+ session->rtcp.loc_addr.sin_port = htons (port + 1);
+ session->rtcp.socket = socket (PF_INET, SOCK_DGRAM, 0);
+ g_return_val_if_fail (session->rtcp.socket > 0, -1);
+
+ err = setsockopt (session->rtcp.socket, SOL_SOCKET, SO_REUSEADDR,
+ (void*)&optval, sizeof (optval));
+ if (err < 0)
+ {
+ g_warning ("Fail to set rtcp address reusable: %s.",getSocketError());
+ }
+
+ err = bind (session->rtcp.socket,
+ (struct sockaddr *) &session->rtcp.loc_addr,
+ sizeof (struct sockaddr_in));
+ if (err != 0)
+ {
+ g_warning ("Fail to bind rtcp socket to port %i: %s.", port + 1, getSocketError());
+ close_socket (session->rtp.socket);
+ close_socket (session->rtcp.socket);
+ return -1;
+ }
+#ifndef __hpux
+ if (IN_MULTICAST(ntohl(session->rtp.loc_addr.sin_addr.s_addr)))
+ {
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = session->rtp.loc_addr.sin_addr.s_addr;
+ mreq.imr_interface.s_addr = INADDR_ANY;
+ err = setsockopt(session->rtp.socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+ if (err == 0)
+ err = setsockopt(session->rtcp.socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+ if (err < 0)
+ {
+ g_warning ("Fail to join address group: %s.", getSocketError());
+ close_socket (session->rtp.socket);
+ close_socket (session->rtcp.socket);
+ return -1;
+ }
+ }
+#endif
+#endif
+ /* set RTP socket options */
+ set_non_blocking_socket (session->rtp.socket);
+ /* set RTCP socket options */
+ set_non_blocking_socket (session->rtcp.socket);
+ return 0;
+}
+
+
+/**
+ *rtp_session_set_remote_addr:
+ *@session: a rtp session freshly created.
+ *@addr: a local IP address in the xxx.xxx.xxx.xxx form.
+ *@port: a local port.
+ *
+ * Sets the remote address of the rtp session, ie the destination address where rtp packet
+ * are sent. If the session is recv-only or duplex, it also sets the origin of incoming RTP
+ * packets. Rtp packets that don't come from addr:port are discarded.
+ *
+ * Returns: 0 on success.
+**/
+
+gint
+rtp_session_set_remote_addr (RtpSession * session, const gchar * addr, gint port)
+{
+ gint err;
+#ifdef INET6
+ struct addrinfo hints, *res0, *res;
+ char num[8];
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ snprintf(num, sizeof(num), "%d", port);
+ err = getaddrinfo(addr, num, &hints, &res0);
+ if (err) {
+ g_warning ("Error in socket address: %s", gai_strerror(err));
+ return err;
+ }
+#endif
+
+ if (session->rtp.socket == 0)
+ {
+ int retry;
+ /* the session has not its socket bound, do it */
+ g_message ("Setting random local addresses.");
+ for (retry=0;retry<10;retry++)
+ {
+ int localport;
+ do
+ {
+ localport = (rand () + 5000) & 0xfffe;
+ }
+ while ((localport < 5000) || (localport > 0xffff));
+#ifdef INET6
+ /* bind to an address type that matches the destination address */
+ if (res0->ai_addr->sa_family==AF_INET6)
+ err = rtp_session_set_local_addr (session, "::", localport);
+ else err=rtp_session_set_local_addr (session, "0.0.0.0", localport);
+#else
+ err = rtp_session_set_local_addr (session, "0.0.0.0", localport);
+#endif
+
+ if (err == 0)
+ break;
+ }
+ if (retry == 10){
+ g_warning("rtp_session_set_remote_addr: Could not find a random local address for socket !");
+ return -1;
+ }
+ }
+
+
+#ifdef INET6
+ err=1;
+ for (res = res0; res; res = res->ai_next) {
+ /* set a destination address that has the same type as the local address */
+ if (res->ai_family==session->rtp.socktype ) {
+ memcpy( &session->rtp.rem_addr, res->ai_addr, res->ai_addrlen);
+ session->rtp.addrlen=res->ai_addrlen;
+ err=0;
+ break;
+ }
+ }
+ freeaddrinfo(res0);
+ if (err) {
+ g_warning("Could not set destination for RTP socket to %s:%i.",addr,port);
+ return -1;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ snprintf(num, sizeof(num), "%d", (port + 1));
+ err = getaddrinfo(addr, num, &hints, &res0);
+ if (err) {
+ g_warning ("Error: %s", gai_strerror(err));
+ return err;
+ }
+ err=1;
+ for (res = res0; res; res = res->ai_next) {
+ /* set a destination address that has the same type as the local address */
+ if (res->ai_family==session->rtp.socktype ) {
+ err=0;
+ memcpy( &session->rtcp.rem_addr, res->ai_addr, res->ai_addrlen);
+ session->rtcp.addrlen=res->ai_addrlen;
+ break;
+ }
+ }
+ freeaddrinfo(res0);
+ if (err) {
+ g_warning("Could not set destination for RCTP socket to %s:%i.",addr,port+1);
+ return -1;
+ }
+#else
+ session->rtp.addrlen=sizeof(session->rtp.rem_addr);
+ session->rtp.rem_addr.sin_family = AF_INET;
+
+ err = inet_aton (addr, &session->rtp.rem_addr.sin_addr);
+ if (err < 0)
+ {
+ g_warning ("Error in socket address:%s.", getSocketError());
+ return err;
+ }
+ session->rtp.rem_addr.sin_port = htons (port);
+
+ memcpy (&session->rtcp.rem_addr, &session->rtp.rem_addr,
+ sizeof (struct sockaddr_in));
+ session->rtcp.rem_addr.sin_port = htons (port + 1);
+ session->rtcp.addrlen=sizeof(session->rtp.rem_addr);
+#endif
+#ifndef NOCONNECT
+ if (session->mode == RTP_SESSION_SENDONLY)
+ {
+ err = connect (session->rtp.socket,
+ (struct sockaddr *) &session->rtp.rem_addr,
+#ifdef INET6
+ session->rtp.addrlen);
+#else
+ sizeof (struct sockaddr_in));
+#endif
+ if (err != 0)
+ {
+ g_message ("Can't connect rtp socket: %s.",getSocketError());
+ return err;
+ }
+ err = connect (session->rtcp.socket,
+ (struct sockaddr *) &session->rtcp.rem_addr,
+#ifdef INET6
+ session->rtcp.addrlen);
+#else
+ sizeof (struct sockaddr_in));
+#endif
+ if (err != 0)
+ {
+ g_message ("Can't connect rtp socket: %s.",getSocketError());
+ return err;
+ }
+ }
+#endif
+ return 0;
+}
+
+void rtp_session_set_sockets(RtpSession *session, gint rtpfd, gint rtcpfd)
+{
+ if (rtpfd>0) set_non_blocking_socket(rtpfd);
+ if (rtcpfd>0) set_non_blocking_socket(rtcpfd);
+ session->rtp.socket=rtpfd;
+ session->rtcp.socket=rtcpfd;
+ session->flags|=RTP_SESSION_USING_EXT_SOCKETS;
+}
+
+/**
+ *rtp_session_flush_sockets:
+ *@session: a rtp session
+ *
+ * Flushes the sockets for all pending incoming packets.
+ * This can be usefull if you did not listen to the stream for a while
+ * and wishes to start to receive again. During the time no receive is made
+ * packets get bufferised into the internal kernel socket structure.
+ *
+**/
+void rtp_session_flush_sockets(RtpSession *session){
+ char trash[4096];
+#ifdef INET6
+ struct sockaddr_storage from;
+#else
+ struct sockaddr from;
+#endif
+ socklen_t fromlen=sizeof(from);
+ if (session->rtp.socket>0){
+ while (recvfrom(session->rtp.socket,(void*)trash,sizeof(trash),0,(struct sockaddr *)&from,&fromlen)>0){};
+ }
+ if (session->rtcp.socket>0){
+ while (recvfrom(session->rtcp.socket,(void*)trash,sizeof(trash),0,(struct sockaddr*)&from,&fromlen)>0){};
+ }
+}
+
+/**
+ *rtp_session_set_seq_number:
+ *@session: a rtp session freshly created.
+ *@addr: a 16 bit unsigned number.
+ *
+ * sets the initial sequence number of a sending session.
+ *
+**/
+void rtp_session_set_seq_number(RtpSession *session, guint16 seq){
+ session->rtp.snd_seq=seq;
+}
+
+
+guint16 rtp_session_get_seq_number(RtpSession *session){
+ return session->rtp.snd_seq;
+}
+
+
+#ifdef USE_SENDMSG
+#define MAX_IOV 10
+static gint rtp_sendmsg(int sock,mblk_t *m, struct sockaddr *rem_addr, int addr_len){
+ int error;
+ struct msghdr msg;
+ struct iovec iov[MAX_IOV];
+ int iovlen;
+ for(iovlen=0; iovlen<MAX_IOV && m!=NULL; m=m->b_cont,iovlen++){
+ iov[iovlen].iov_base=m->b_rptr;
+ iov[iovlen].iov_len=m->b_wptr-m->b_rptr;
+ }
+ msg.msg_name=(void*)rem_addr;
+ msg.msg_namelen=addr_len;
+ msg.msg_iov=&iov[0];
+ msg.msg_iovlen=iovlen;
+ msg.msg_control=NULL;
+ msg.msg_controllen=0;
+ msg.msg_flags=0;
+
+ error=sendmsg(sock,&msg,0);
+ return error;
+}
+#endif
+
+static gint
+ortp_rtp_send (RtpSession * session, mblk_t * m)
+{
+ gint error;
+ int i;
+ rtp_header_t *hdr;
+
+ hdr = (rtp_header_t *) m->b_rptr;
+ /* perform host to network conversions */
+ hdr->ssrc = htonl (hdr->ssrc);
+ hdr->timestamp = htonl (hdr->timestamp);
+ hdr->seq_number = htons (hdr->seq_number);
+ for (i = 0; i < hdr->cc; i++)
+ hdr->csrc[i] = htonl (hdr->csrc[i]);
+
+#ifdef USE_SENDMSG
+ if (session->flags & RTP_SESSION_USING_EXT_SOCKETS){
+ error=rtp_sendmsg(session->rtp.socket,m,(struct sockaddr *)NULL,0);
+ }else {
+ error=rtp_sendmsg(session->rtp.socket,m,(struct sockaddr *) &session->rtp.rem_addr,
+ session->rtp.addrlen);
+ }
+#else
+ if (m->b_cont!=NULL){
+ mblk_t *newm=msgpullup(m,-1);
+ freemsg(m);
+ m=newm;
+ }
+ if (session->flags & RTP_SESSION_USING_EXT_SOCKETS){
+ error=send(session->rtp.socket, m->b_rptr, (m->b_wptr - m->b_rptr),0);
+ }else error = sendto (session->rtp.socket, m->b_rptr,
+ (m->b_wptr - m->b_rptr), 0,
+ (struct sockaddr *) &session->rtp.rem_addr,
+ session->rtp.addrlen);
+#endif
+ if (error < 0){
+ if (session->on_network_error.count>0){
+ rtp_signal_table_emit3(&session->on_network_error,(gpointer)"Error sending RTP packet",INT_TO_POINTER(getSocketErrorCode()));
+ }else g_warning ("Error sending rtp packet: %s ; socket=%i", getSocketError(), session->rtp.socket);
+ }
+ freemsg (m);
+ return error;
+}
+
+gint
+ortp_rtcp_send (RtpSession * session, mblk_t * m)
+{
+ gint error=0;
+ gboolean using_ext_socket=(session->flags & RTP_SESSION_USING_EXT_SOCKETS)!=0;
+ if ( (using_ext_socket && session->rtcp.socket>0 ) || session->rtcp.addrlen>0){
+
+#ifndef USE_SENDMSG
+ if (m->b_cont!=NULL){
+ mblk_t *newm=msgpullup(m,-1);
+ freemsg(m);
+ m=newm;
+ }
+#endif
+ if (using_ext_socket && session->rtcp.socket>0 ){
+#ifdef USE_SENDMSG
+ error=rtp_sendmsg(session->rtcp.socket,m,(struct sockaddr *)NULL,0);
+#else
+ error=send(session->rtcp.socket, m->b_rptr, (m->b_wptr - m->b_rptr),0);
+#endif
+ }else {
+#ifdef USE_SENDMSG
+ error=rtp_sendmsg(session->rtcp.socket,m,(struct sockaddr *) &session->rtcp.rem_addr,
+ session->rtcp.addrlen);
+#else
+ error = sendto (session->rtcp.socket, m->b_rptr,
+ (m->b_wptr - m->b_rptr), 0,
+ (struct sockaddr *) &session->rtcp.rem_addr,
+ session->rtcp.addrlen);
+#endif
+ }
+
+ if (error < 0){
+ if (session->on_network_error.count>0){
+ rtp_signal_table_emit3(&session->on_network_error,(gpointer)"Error sending RTCP packet",INT_TO_POINTER(getSocketErrorCode()));
+ }else g_warning ("Error sending rtcp packet: %s ; socket=%i", getSocketError(), session->rtcp.socket);
+ }
+ }else g_warning("Cannot send rtcp report because I don't know the remote address.");
+ freemsg (m);
+ return error;
+}
+
+
+/**
+ *rtp_session_set_ssrc:
+ *@session: a rtp session.
+ *@ssrc: an unsigned 32bit integer representing the synchronisation source identifier (SSRC).
+ *
+ * Sets the SSRC for the outgoing stream.
+ * If not done, a random ssrc is used.
+ *
+**/
+void
+rtp_session_set_ssrc (RtpSession * session, guint32 ssrc)
+{
+ session->send_ssrc = ssrc;
+}
+
+/* this function initialize all session parameter's that depend on the payload type */
+static void payload_type_changed(RtpSession *session, PayloadType *pt){
+ jitter_control_set_payload(&session->rtp.jittctl,pt);
+ session->rtp.rtcp_report_snt_interval=RTCP_DEFAULT_REPORT_INTERVAL*pt->clock_rate;
+ rtp_session_set_time_jump_limit(session,session->rtp.time_jump);
+}
+
+/**
+ *rtp_session_set_payload_type:
+ *@session: a rtp session
+ *@paytype: the payload type
+ *
+ * Sets the payload type of the rtp session. It decides of the payload types written in the
+ * of the rtp header for the outgoing stream, if the session is SENDRECV or SENDONLY.
+ * For the incoming stream, it sets the waited payload type. If that value does not match
+ * at any time this waited value, then the application can be informed by registering
+ * for the "payload_type_changed" signal, so that it can make the necessary changes
+ * on the downstream decoder that deals with the payload of the packets.
+ *
+ *Returns: 0 on success, -1 if the payload is not defined.
+**/
+
+int
+rtp_session_set_payload_type (RtpSession * session, int paytype)
+{
+ PayloadType *pt;
+ session->payload_type = paytype;
+ pt=rtp_profile_get_payload(session->profile,paytype);
+ if (pt!=NULL){
+ payload_type_changed(session,pt);
+ }
+ return 0;
+}
+
+int rtp_session_get_payload_type(RtpSession *session){
+ return session->payload_type;
+}
+
+
+/**
+ *rtp_session_set_payload_type_with_string:
+ *@session: a rtp session
+ *@paytype: the payload type
+ *
+ * Sets the payload type of the rtp session. It decides of the payload types written in the
+ * of the rtp header for the outgoing stream, if the session is SENDRECV or SENDONLY.
+ * Unlike #rtp_session_set_payload_type(), it takes as argument a string referencing the
+ * payload type (mime type).
+ * For the incoming stream, it sets the waited payload type. If that value does not match
+ * at any time this waited value, then the application can be informed by registering
+ * for the "payload_type_changed" signal, so that it can make the necessary changes
+ * on the downstream decoder that deals with the payload of the packets.
+ *
+ *Returns: 0 on success, -1 if the payload is not defined.
+**/
+
+int
+rtp_session_set_payload_type_with_string (RtpSession * session, const char * mime)
+{
+ int pt;
+ pt=rtp_profile_get_payload_number_from_mime(session->profile,mime);
+ if (pt<0) {
+ g_warning("%s is not a know mime string within the rtpsession's profile.",mime);
+ return -1;
+ }
+ rtp_session_set_payload_type(session,pt);
+ return 0;
+}
+
+
+/**
+ *rtp_session_create_packet:
+ *@session: a rtp session.
+ *@header_size: the rtp header size. For standart size (without extensions), it is #RTP_FIXED_HEADER_SIZE
+ *@payload :data to be copied into the rtp packet.
+ *@payload_size : size of data carried by the rtp packet.
+ *
+ * Allocates a new rtp packet. In the header, ssrc and payload_type according to the session's
+ * context. Timestamp and seq number are not set, there will be set when the packet is going to be
+ * sent with rtp_session_sendm_with_ts().
+ *
+ *Returns: a rtp packet in a mblk_t (message block) structure.
+**/
+mblk_t * rtp_session_create_packet(RtpSession *session,gint header_size, const char *payload, gint payload_size)
+{
+ mblk_t *mp;
+ gint msglen=header_size+payload_size;
+ rtp_header_t *rtp;
+
+ mp=allocb(msglen,BPRI_MED);
+ rtp=(rtp_header_t*)mp->b_rptr;
+ rtp->version = 2;
+ rtp->padbit = 0;
+ rtp->extbit = 0;
+ rtp->markbit= 0;
+ rtp->cc = 0;
+ rtp->paytype = session->payload_type;
+ rtp->ssrc = session->send_ssrc;
+ rtp->timestamp = 0; /* set later, when packet is sended */
+ rtp->seq_number = 0; /*set later, when packet is sended */
+ /*copy the payload */
+ mp->b_wptr+=header_size;
+ memcpy(mp->b_wptr,payload,payload_size);
+ mp->b_wptr+=payload_size;
+ return mp;
+}
+
+/**
+ *rtp_session_create_packet_with_data:
+ *@session: a rtp session.
+ *@payload : the data to be sent with this packet
+ *@payload_size : size of data
+ *@freefn : a function that will be called when the payload buffer is no more needed.
+ *
+ * Creates a new rtp packet using the given payload buffer (no copy). The header will be allocated separetely.
+ * In the header, ssrc and payload_type according to the session's
+ * context. Timestamp and seq number are not set, there will be set when the packet is going to be
+ * sent with rtp_session_sendm_with_ts().
+ * oRTP will send this packet using libc's sendmsg() (if this function is availlable!) so that there will be no
+ * packet concatenation involving copies to be done in user-space.
+ * @freefn can be NULL, in that case payload will be kept untouched.
+ *
+ *Returns: a rtp packet in a mblk_t (message block) structure.
+**/
+
+mblk_t * rtp_session_create_packet_with_data(RtpSession *session, char *payload, gint payload_size, void (*freefn)(void*))
+{
+ mblk_t *mp,*mpayload;
+ gint header_size=RTP_FIXED_HEADER_SIZE; /* revisit when support for csrc is done */
+ rtp_header_t *rtp;
+
+ mp=allocb(header_size,BPRI_MED);
+ rtp=(rtp_header_t*)mp->b_rptr;
+ rtp->version = 2;
+ rtp->padbit = 0;
+ rtp->extbit = 0;
+ rtp->markbit= 0;
+ rtp->cc = 0;
+ rtp->paytype = session->payload_type;
+ rtp->ssrc = session->send_ssrc;
+ rtp->timestamp = 0; /* set later, when packet is sended */
+ rtp->seq_number = 0; /*set later, when packet is sended */
+ mp->b_wptr+=header_size;
+ /* create a mblk_t around the user supplied payload buffer */
+ mpayload=allocb_with_buf(payload,payload_size,BPRI_MED,freefn);
+ mpayload->b_wptr+=payload_size;
+ /* link it with the header */
+ mp->b_cont=mpayload;
+ return mp;
+}
+
+
+/**
+ *rtp_session_create_packet_in_place:
+ *@session: a rtp session.
+ *@buffer: a buffer that contains first just enough place to write a RTP header, then the data to send.
+ *@size : the size of the buffer
+ *@freefn : a function that will be called once the buffer is no more needed (the data has been sent).
+ *
+ * Creates a new rtp packet using the buffer given in arguments (no copy).
+ * In the header, ssrc and payload_type according to the session's
+ * context. Timestamp and seq number are not set, there will be set when the packet is going to be
+ * sent with rtp_session_sendm_with_ts().
+ * @freefn can be NULL, in that case payload will be kept untouched.
+ *
+ *Returns: a rtp packet in a mblk_t (message block) structure.
+**/
+mblk_t * rtp_session_create_packet_in_place(RtpSession *session,char *buffer, gint size, void (*freefn)(void*) )
+{
+ mblk_t *mp;
+ rtp_header_t *rtp;
+
+ mp=allocb_with_buf(buffer,size,BPRI_MED,freefn);
+
+ rtp=(rtp_header_t*)mp->b_rptr;
+ rtp->version = 2;
+ rtp->padbit = 0;
+ rtp->extbit = 0;
+ rtp->markbit= 0;
+ rtp->cc = 0;
+ rtp->paytype = session->payload_type;
+ rtp->ssrc = session->send_ssrc;
+ rtp->timestamp = 0; /* set later, when packet is sended */
+ rtp->seq_number = 0; /*set later, when packet is sended */
+ return mp;
+}
+
+
+/**
+ *rtp_session_sendm_with_ts:
+ *@session : a rtp session.
+ *@mp : a rtp packet presented as a mblk_t.
+ *@timestamp: the timestamp of the data to be sent. Refer to the rfc to know what it is.
+ *
+ * Send the rtp datagram @mp to the destination set by rtp_session_set_remote_addr()
+ * with timestamp @timestamp. For audio data, the timestamp is the number
+ * of the first sample resulting of the data transmitted. See rfc1889 for details.
+ * The packet (@mp) is freed once it is sended.
+ *
+ *Returns: the number of bytes sent over the network.
+**/
+gint
+rtp_session_sendm_with_ts (RtpSession * session, mblk_t *mp, guint32 timestamp)
+{
+ rtp_header_t *rtp;
+ guint32 packet_time;
+ gint error = 0;
+ gint payloadsize;
+ RtpScheduler *sched=session->sched;
+ RtpStream *stream=&session->rtp;
+
+ if (session->flags & RTP_SESSION_SEND_NOT_STARTED)
+ {
+ session->rtp.snd_ts_offset = timestamp;
+ if (session->flags & RTP_SESSION_SCHEDULED)
+ {
+ session->rtp.snd_time_offset = sched->time_;
+ }
+ rtp_session_unset_flag (session,RTP_SESSION_SEND_NOT_STARTED);
+ }
+ /* if we are in blocking mode, then suspend the process until the scheduler it's time to send the
+ * next packet */
+ /* if the timestamp of the packet queued is older than current time, then you we must
+ * not block */
+ if (session->flags & RTP_SESSION_SCHEDULED)
+ {
+ packet_time =
+ rtp_session_ts_to_time (session,
+ timestamp -
+ session->rtp.snd_ts_offset) +
+ session->rtp.snd_time_offset;
+ /*g_message("rtp_session_send_with_ts: packet_time=%i time=%i",packet_time,sched->time_);*/
+ wait_point_lock(&session->send_wp);
+ if (TIME_IS_STRICTLY_NEWER_THAN (packet_time, sched->time_))
+ {
+ wait_point_wakeup_at(&session->send_wp,packet_time,(session->flags & RTP_SESSION_BLOCKING_MODE)!=0);
+ session_set_clr(&sched->w_sessions,session); /* the session has written */
+ }
+ else session_set_set(&sched->w_sessions,session); /*to indicate select to return immediately */
+ wait_point_unlock(&session->send_wp);
+ }
+
+
+ rtp=(rtp_header_t*)mp->b_rptr;
+
+ payloadsize = msgdsize(mp) - RTP_FIXED_HEADER_SIZE - (rtp->cc*sizeof(guint32));
+ rtp_session_lock (session);
+
+ /* set a seq number */
+ rtp->seq_number=session->rtp.snd_seq;
+ rtp->timestamp=timestamp;
+ session->rtp.snd_seq++;
+ session->rtp.snd_last_ts = timestamp;
+
+
+ ortp_global_stats.sent += payloadsize;
+ stream->stats.sent += payloadsize;
+ ortp_global_stats.packet_sent++;
+ stream->stats.packet_sent++;
+
+ error = ortp_rtp_send (session, mp);
+ rtp_session_rtcp_process(session);
+ rtp_session_unlock (session);
+
+ return error;
+}
+
+
+/**
+ *rtp_session_send_with_ts:
+ *@session: a rtp session.
+ *@buffer: a buffer containing the data to be sent in a rtp packet.
+ *@len: the length of the data buffer, in bytes.
+ *@userts: the timestamp of the data to be sent. Refer to the rfc to know what it is.
+ *
+ * Send a rtp datagram to the destination set by rtp_session_set_remote_addr() containing
+ * the data from @buffer with timestamp @userts. This is a high level function that uses
+ * rtp_session_create_packet() and rtp_session_sendm_with_ts() to send the data.
+ *
+ *
+ *Returns: the number of bytes sent over the network.
+**/
+gint
+rtp_session_send_with_ts (RtpSession * session, const gchar * buffer, gint len,
+ guint32 userts)
+{
+ mblk_t *m;
+ int err;
+#ifdef USE_SENDMSG
+ m=rtp_session_create_packet_with_data(session,(gchar*)buffer,len,NULL);
+#else
+ m = rtp_session_create_packet(session,RTP_FIXED_HEADER_SIZE,(gchar*)buffer,len);
+#endif
+ err=rtp_session_sendm_with_ts(session,m,userts);
+ return err;
+}
+
+
+static gint
+rtp_recv (RtpSession * session, guint32 user_ts)
+{
+ gint error;
+ struct sockaddr remaddr;
+ socklen_t addrlen = sizeof (remaddr);
+ char *p;
+ mblk_t *mp;
+ RtpStream *stream=&session->rtp;
+
+ if (session->rtp.socket<1) return -1; /*session has no sockets for the moment*/
+
+
+ while (1)
+ {
+ if (session->rtp.cached_mp==NULL)
+ session->rtp.cached_mp = allocb (session->max_buf_size, 0);
+ mp=session->rtp.cached_mp;
+ if (session->flags & RTP_SESSION_USING_EXT_SOCKETS){
+ error=recv(session->rtp.socket,mp->b_wptr,session->max_buf_size,0);
+ }else error = recvfrom (session->rtp.socket, mp->b_wptr,
+ session->max_buf_size, 0,
+ (struct sockaddr *) &remaddr,
+ &addrlen);
+ if (error > 0)
+ {
+ if (error<RTP_FIXED_HEADER_SIZE){
+ g_warning("Packet too small to be a rtp packet (%i)!",error);
+ stream->stats.bad++;
+ ortp_global_stats.bad++;
+ /* don't free, it will be reused next time */
+ }else{
+ /* resize the memory allocated to fit the udp message */
+
+ p = g_realloc (mp->b_wptr, error);
+ if (p != mp->b_wptr)
+ ortp_debug("The recv area has moved during reallocation.");
+ mp->b_datap->db_base = mp->b_rptr =
+ mp->b_wptr = p;
+ mp->b_wptr += error;
+ mp->b_datap->db_lim = mp->b_wptr;
+ /* then parse the message and put on queue */
+ rtp_parse (session, mp, user_ts + session->rtp.hwrcv_diff_ts);
+ session->rtp.cached_mp=NULL;
+ }
+ }
+ else
+ {
+ if (error == 0)
+ {
+ g_warning
+ ("rtp_recv: strange... recv() returned zero.");
+ }
+ else if (errno!=EWOULDBLOCK && errno!=EAGAIN)
+ {
+ if (session->on_network_error.count>0){
+ rtp_signal_table_emit3(&session->on_network_error,(gpointer)"Error receiving RTP packet",INT_TO_POINTER(getSocketErrorCode()));
+ }else g_warning("Error receiving RTP packet: %s.",getSocketError());
+ }
+ /* don't free the cached_mp, it will be reused next time */
+ return -1; /* avoids an infinite loop ! */
+ }
+ }
+ return error;
+}
+
+extern void rtcp_parse(RtpSession *session, mblk_t *mp);
+
+static gint
+rtcp_recv (RtpSession * session)
+{
+ gint error;
+ struct sockaddr remaddr;
+ socklen_t addrlen=0;
+ char *p;
+ mblk_t *mp;
+
+
+ if (session->rtcp.socket<1) return -1; /*session has no rtcp sockets for the moment*/
+
+
+ while (1)
+ {
+ if (session->rtcp.cached_mp==NULL)
+ session->rtcp.cached_mp = allocb (RTCP_MAX_RECV_BUFSIZE, 0);
+
+ mp=session->rtcp.cached_mp;
+ if (session->flags & RTP_SESSION_USING_EXT_SOCKETS){
+ error=recv(session->rtcp.socket,mp->b_wptr,RTCP_MAX_RECV_BUFSIZE,0);
+ }else {
+ addrlen=sizeof (remaddr);
+ error=recvfrom (session->rtcp.socket, mp->b_wptr,
+ RTCP_MAX_RECV_BUFSIZE, 0,
+ (struct sockaddr *) &remaddr,
+ &addrlen);
+ }
+ if (error > 0)
+ {
+ /* resize the memory allocated to fit the udp message */
+
+ p = g_realloc (mp->b_wptr, error);
+ if (p != mp->b_wptr)
+ ortp_debug("The recv area has moved during reallocation.");
+ mp->b_datap->db_base = mp->b_rptr =
+ mp->b_wptr = p;
+ mp->b_wptr += error;
+ mp->b_datap->db_lim = mp->b_wptr;
+ /* then parse the message */
+ rtcp_parse (session, mp);
+ freemsg(mp);
+ session->rtcp.cached_mp=NULL;
+ if (addrlen>0){
+ /* store the sender rtcp address to send him receiver reports */
+ memcpy(&session->rtcp.rem_addr,&remaddr,addrlen);
+ }
+ }
+ else
+ {
+ if (error == 0)
+ {
+ g_warning
+ ("rtcp_recv: strange... recv() returned zero.");
+ }
+ else if (errno!=EWOULDBLOCK && errno!=EAGAIN)
+ {
+ if (session->on_network_error.count>0){
+ rtp_signal_table_emit3(&session->on_network_error,(gpointer)"Error receiving RTCP packet",INT_TO_POINTER(getSocketErrorCode()));
+ }else g_warning("Error receiving RTCP packet: %s.",getSocketError());
+ }
+ /* don't free the cached_mp, it will be reused next time */
+ return -1; /* avoids an infinite loop ! */
+ }
+ }
+ return error;
+}
+
+
+static void payload_type_changed_incoming(RtpSession *session, int paytype){
+ /* check if we support this payload type */
+ PayloadType *pt=rtp_profile_get_payload(session->profile,paytype);
+ if (pt!=0){
+ g_message ("rtp_parse: payload type changed to %i(%s) !",
+ paytype,pt->mime_type);
+ session->payload_type = paytype;
+ payload_type_changed(session,pt);
+ rtp_signal_table_emit (&session->on_payload_type_changed);
+ }else{
+ g_warning("Receiving packet with unknown payload type %i.",paytype);
+ }
+}
+
+
+/**
+ *rtp_session_recvm_with_ts:
+ *@session: a rtp session.
+ *@user_ts: a timestamp.
+ *
+ * Try to get a rtp packet presented as a mblk_t structure from the rtp session.
+ * The @user_ts parameter is relative to the first timestamp of the incoming stream. In other
+ * words, the application does not have to know the first timestamp of the stream, it can
+ * simply call for the first time this function with @user_ts=0, and then incrementing it
+ * as it want. The RtpSession takes care of synchronisation between the stream timestamp
+ * and the user timestamp given here.
+ *
+ *Returns: a rtp packet presented as a mblk_t.
+**/
+
+mblk_t *
+rtp_session_recvm_with_ts (RtpSession * session, guint32 user_ts)
+{
+ mblk_t *mp = NULL;
+ rtp_header_t *rtp;
+ guint32 ts;
+ guint32 packet_time;
+ RtpScheduler *sched=session->sched;
+ RtpStream *stream=&session->rtp;
+ gint rejected=0;
+
+ /* if we are scheduled, remember the scheduler time at which the application has
+ * asked for its first timestamp */
+
+ if (session->flags & RTP_SESSION_RECV_NOT_STARTED)
+ {
+
+ session->rtp.rcv_query_ts_offset = user_ts;
+ if (session->flags & RTP_SESSION_SCHEDULED)
+ {
+ session->rtp.rcv_time_offset = sched->time_;
+ //g_message("setting snd_time_offset=%i",session->rtp.snd_time_offset);
+ }
+ rtp_session_unset_flag (session,RTP_SESSION_RECV_NOT_STARTED);
+ }
+ session->rtp.rcv_last_app_ts = user_ts;
+ rtp_recv (session, user_ts);
+ rtcp_recv(session);
+ /* check for telephone event first */
+ /* first lock the session */
+ rtp_session_lock (session);
+ mp=getq(&session->rtp.tev_rq);
+ if (mp!=NULL){
+ rtp_signal_table_emit2(&session->on_telephone_event_packet,(gpointer)mp);
+ if (session->on_telephone_event.count>0){
+ rtp_session_check_telephone_events(session,mp);
+ }
+ freemsg(mp);
+ mp=NULL;
+ }
+
+ /* then now try to return a media packet, if possible */
+ /* first condition: if the session is starting, don't return anything
+ * until the queue size reaches jitt_comp */
+
+ if (session->flags & RTP_SESSION_RECV_SYNC)
+ {
+ rtp_header_t *oldest, *newest;
+ queue_t *q = &session->rtp.rq;
+ if (qempty(q))
+ {
+ ortp_debug ("Queue is empty.");
+ goto end;
+ }
+ oldest = (rtp_header_t *) qfirst(q)->b_rptr;
+ newest = (rtp_header_t *) qlast(q)->b_rptr;
+ if ((guint32) (newest->timestamp - oldest->timestamp) <
+ session->rtp.jittctl.jitt_comp_ts)
+ {
+ ortp_debug("Not enough packet bufferised.");
+ goto end;
+ }
+ /* enough packet bufferised */
+ mp = getq (&session->rtp.rq);
+ rtp = (rtp_header_t *) mp->b_rptr;
+ session->rtp.rcv_ts_offset = rtp->timestamp;
+ /* remember the timestamp offset between the stream timestamp (random)
+ * and the user timestamp, that very often starts at zero */
+ session->rtp.rcv_diff_ts = rtp->timestamp - user_ts;
+ /* remember the difference between the last received on the socket timestamp and the user timestamp */
+ session->rtp.hwrcv_diff_ts=session->rtp.rcv_diff_ts + session->rtp.jittctl.jitt_comp_ts;
+ session->rtp.rcv_last_ret_ts = user_ts; /* just to have an init value */
+ session->rtp.rcv_last_ts = rtp->timestamp;
+ session->recv_ssrc = rtp->ssrc;
+ /* delete the recv synchronisation flag */
+ rtp_session_unset_flag (session, RTP_SESSION_RECV_SYNC);
+ ortp_debug("Returning FIRST packet with ts=%i, hwrcv_diff_ts=%i, rcv_diff_ts=%i", rtp->timestamp,
+ session->rtp.hwrcv_diff_ts,session->rtp.rcv_diff_ts);
+
+ goto end;
+ }
+ /* else this the normal case */
+ /*calculate the stream timestamp from the user timestamp */
+ ts = user_ts + session->rtp.rcv_diff_ts;
+ session->rtp.rcv_last_ts = ts;
+ mp = rtp_getq (&session->rtp.rq, ts,&rejected);
+
+ stream->stats.skipped+=rejected;
+ ortp_global_stats.skipped+=rejected;
+
+ /* perhaps we can now make some checks to see if a resynchronization is needed */
+ /* TODO */
+ goto end;
+
+ end:
+ if (mp != NULL)
+ {
+ int msgsize = msgdsize (mp); /* evaluate how much bytes (including header) is received by app */
+ guint32 packet_ts;
+ ortp_global_stats.recv += msgsize;
+ stream->stats.recv += msgsize;
+ rtp = (rtp_header_t *) mp->b_rptr;
+ packet_ts=rtp->timestamp;
+ ortp_debug("Returning mp with ts=%i", packet_ts);
+ /* check for payload type changes */
+ if (session->payload_type != rtp->paytype)
+ {
+ payload_type_changed_incoming(session, rtp->paytype);
+ }
+ /* patch the packet so that it has a timestamp compensated by the
+ adaptive jitter buffer mechanism */
+ if (session->rtp.jittctl.adaptive){
+ rtp->timestamp-=session->rtp.jittctl.corrective_slide;
+ /*printf("Returned packet has timestamp %u, with clock slide compensated it is %u\n",packet_ts,rtp->timestamp);*/
+ }
+ }
+ else
+ {
+ ortp_debug ("No mp for timestamp queried");
+ stream->stats.unavaillable++;
+ ortp_global_stats.unavaillable++;
+ }
+ rtp_session_rtcp_process(session);
+ rtp_session_unlock (session);
+
+ if (session->flags & RTP_SESSION_SCHEDULED)
+ {
+ /* if we are in blocking mode, then suspend the calling process until timestamp
+ * wanted expires */
+ /* but we must not block the process if the timestamp wanted by the application is older
+ * than current time */
+ packet_time =
+ rtp_session_ts_to_time (session,
+ user_ts -
+ session->rtp.rcv_query_ts_offset) +
+ session->rtp.rcv_time_offset;
+ ortp_debug ("rtp_session_recvm_with_ts: packet_time=%i, time=%i",packet_time, sched->time_);
+ wait_point_lock(&session->recv_wp);
+ if (TIME_IS_STRICTLY_NEWER_THAN (packet_time, sched->time_))
+ {
+ wait_point_wakeup_at(&session->recv_wp,packet_time, (session->flags & RTP_SESSION_BLOCKING_MODE)!=0);
+ session_set_clr(&sched->r_sessions,session);
+ }
+ else session_set_set(&sched->r_sessions,session); /*to unblock _select() immediately */
+ wait_point_unlock(&session->recv_wp);
+ }
+ return mp;
+}
+
+
+gint msg_to_buf (mblk_t * mp, char *buffer, gint len)
+{
+ gint rlen = len;
+ mblk_t *m, *mprev;
+ gint mlen;
+ m = mp->b_cont;
+ mprev = mp;
+ while (m != NULL)
+ {
+ mlen = m->b_wptr - m->b_rptr;
+ if (mlen <= rlen)
+ {
+ mblk_t *consumed = m;
+ memcpy (buffer, m->b_rptr, mlen);
+ /* go to next mblk_t */
+ mprev->b_cont = m->b_cont;
+ m = m->b_cont;
+ consumed->b_cont = NULL;
+ freeb (consumed);
+ buffer += mlen;
+ rlen -= mlen;
+ }
+ else
+ { /*if mlen>rlen */
+ memcpy (buffer, m->b_rptr, rlen);
+ m->b_rptr += rlen;
+ return len;
+ }
+ }
+ return len - rlen;
+}
+
+/**
+ *rtp_session_recv_with_ts:
+ *@session: a rtp session.
+ *@buffer: a user supplied buffer to write the data.
+ *@len: the length in bytes of the user supplied buffer.
+ *@time: the timestamp wanted.
+ *@have_more: the address of an integer to indicate if more data is availlable for the given timestamp.
+ *
+ * Tries to read the bytes of the incoming rtp stream related to timestamp @time. In case
+ * where the user supplied buffer @buffer is not large enough to get all the data
+ * related to timestamp @time, then *( @have_more) is set to 1 to indicate that the application
+ * should recall the function with the same timestamp to get more data.
+ *
+ * When the rtp session is scheduled (see rtp_session_set_scheduling_mode() ), and the
+ * blocking mode is on (see rtp_session_set_blocking_mode() ), then the calling thread
+ * is suspended until the timestamp given as argument expires, whatever a received packet
+ * fits the query or not.
+ *
+ * Important note: it is clear that the application cannot know the timestamp of the first
+ * packet of the incoming stream, because it can be random. The @time timestamp given to the
+ * function is used relatively to first timestamp of the stream. In simple words, 0 is a good
+ * value to start calling this function.
+ *
+ * This function internally calls rtp_session_recvm_with_ts() to get a rtp packet. The content
+ * of this packet is then copied into the user supplied buffer in an intelligent manner:
+ * the function takes care of the size of the supplied buffer and the timestamp given in
+ * argument. Using this function it is possible to read continous audio data (e.g. pcma,pcmu...)
+ * with for example a standart buffer of size of 160 with timestamp incrementing by 160 while the incoming
+ * stream has a different packet size.
+ *
+ *Returns: if a packet was availlable with the corresponding timestamp supplied in argument
+ * then the number of bytes written in the user supplied buffer is returned. If no packets
+ * are availlable, either because the sender has not started to send the stream, or either
+ * because silence packet are not transmitted, or either because the packet was lost during
+ * network transport, then the function returns zero.
+**/
+gint rtp_session_recv_with_ts (RtpSession * session, gchar * buffer,
+ gint len, guint32 time, gint * have_more)
+{
+ mblk_t *mp;
+ gint rlen = len;
+ gint wlen, mlen;
+ guint32 ts_int = 0; /*the length of the data returned in the user supplied buffer, in TIMESTAMP UNIT */
+ PayloadType *payload;
+ RtpStream *stream=&session->rtp;
+
+ *have_more = 0;
+
+ mp = rtp_session_recvm_with_ts (session, time);
+ payload =rtp_profile_get_payload (session->profile,
+ session->payload_type);
+ if (payload==NULL){
+ g_warning("rtp_session_recv_with_ts: unable to recv an unsupported payload.");
+ if (mp!=NULL) freemsg(mp);
+ return -1;
+ }
+ if (!(session->flags & RTP_SESSION_RECV_SYNC))
+ {
+ //ortp_debug("time=%i rcv_last_ret_ts=%i",time,session->rtp.rcv_last_ret_ts);
+ if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN
+ (time, session->rtp.rcv_last_ret_ts))
+ {
+ /* the user has missed some data previously, so we are going to give him now. */
+ /* we must tell him to call the function once again with the same timestamp
+ * by setting *have_more=1 */
+ *have_more = 1;
+ }
+ if (payload->type == PAYLOAD_AUDIO_CONTINUOUS)
+ {
+ ts_int = (len * payload->bits_per_sample) >> 3;
+ session->rtp.rcv_last_ret_ts += ts_int;
+ //ortp_debug("ts_int=%i",ts_int);
+ }
+ else
+ ts_int = 0;
+ }
+ else return 0;
+
+ /* try to fill the user buffer */
+ while (1)
+ {
+
+ if (mp != NULL)
+ {
+ mlen = msgdsize (mp->b_cont);
+ wlen = msg_to_buf (mp, buffer, rlen);
+ buffer += wlen;
+ rlen -= wlen;
+ ortp_debug("mlen=%i wlen=%i rlen=%i", mlen, wlen,
+ rlen);
+ /* do we fill all the buffer ? */
+ if (rlen > 0)
+ {
+ /* we did not fill all the buffer */
+ freemsg (mp);
+ /* if we have continuous audio, try to get other packets to fill the buffer,
+ * ie continue the loop */
+ //ortp_debug("User buffer not filled entirely");
+ if (ts_int > 0)
+ {
+ time = session->rtp.rcv_last_ret_ts;
+ ortp_debug("Need more: will ask for %i.",
+ time);
+ }
+ else
+ return len - rlen;
+ }
+ else if (mlen > wlen)
+ {
+ int unread =
+ mlen - wlen + (mp->b_wptr -
+ mp->b_rptr);
+ /* not enough space in the user supplied buffer */
+ /* we re-enqueue the msg with its updated read pointers for next time */
+ ortp_debug ("Re-enqueuing packet.");
+ rtp_session_lock (session);
+ rtp_putq (&session->rtp.rq, mp);
+ rtp_session_unlock (session);
+ /* quite ugly: I change the stats ... */
+ ortp_global_stats.recv -= unread;
+ stream->stats.recv -= unread;
+ return len;
+ }
+ else
+ {
+ /* the entire packet was written to the user buffer */
+ freemsg (mp);
+ return len;
+ }
+ }
+ else
+ {
+ /* fill with a zero pattern (silence) */
+ if (payload->pattern_length != 0)
+ {
+ int i = 0, j = 0;
+ while (i < rlen)
+ {
+ buffer[i] = payload->zero_pattern[j];
+ i++;
+ j++;
+ if (j <= payload->pattern_length)
+ j = 0;
+ }
+ return len;
+ }
+ *have_more = 0;
+ return 0;
+ }
+ mp = rtp_session_recvm_with_ts (session, time);
+ payload = rtp_profile_get_payload (session->profile,
+ session->payload_type);
+ if (payload==NULL){
+ g_warning("rtp_session_recv_with_ts: unable to recv an unsupported payload.");
+ if (mp!=NULL) freemsg(mp);
+ return -1;
+ }
+ }
+ return -1;
+}
+/**
+ *rtp_session_get_current_send_ts:
+ *@session: a rtp session.
+ *
+ * When the rtp session is scheduled and has started to send packets, this function
+ * computes the timestamp that matches to the present time. Using this function can be
+ * usefull when sending discontinuous streams. Some time can be elapsed between the end
+ * of a stream burst and the begin of a new stream burst, and the application may be not
+ * not aware of this elapsed time. In order to get a valid (current) timestamp to pass to
+ * #rtp_session_send_with_ts() or #rtp_session_sendm_with_ts(), the application may
+ * use rtp_session_get_current_send_ts().
+ *
+ *Returns: the current send timestamp for the rtp session.
+**/
+guint32 rtp_session_get_current_send_ts(RtpSession *session)
+{
+ guint32 userts;
+ guint32 session_time;
+ RtpScheduler *sched=session->sched;
+ PayloadType *payload;
+ g_return_val_if_fail (session->payload_type<128, 0);
+ payload=rtp_profile_get_payload(session->profile,session->payload_type);
+ g_return_val_if_fail(payload!=NULL, 0);
+ if ( (session->flags & RTP_SESSION_SCHEDULED)==0 ){
+ g_warning("can't guess current timestamp because session is not scheduled.");
+ return 0;
+ }
+ session_time=sched->time_-session->rtp.snd_time_offset;
+ userts= (guint32)( ( (gdouble)(session_time) * (gdouble) payload->clock_rate )/ 1000.0)
+ + session->rtp.snd_ts_offset;
+ return userts;
+}
+
+/**
+ *rtp_session_get_current_recv_ts:
+ *@session: a rtp session.
+ *
+ * Same thing as rtp_session_get_current_send_ts() except that it's for an incoming stream.
+ * Works only on scheduled mode.
+ *
+ * Returns: the theoritical that would have to be receive now.
+ *
+**/
+guint32 rtp_session_get_current_recv_ts(RtpSession *session){
+ guint32 userts;
+ guint32 session_time;
+ RtpScheduler *sched=ortp_get_scheduler();
+ PayloadType *payload;
+ g_return_val_if_fail (session->payload_type<128, 0);
+ payload=rtp_profile_get_payload(session->profile,session->payload_type);
+ g_return_val_if_fail(payload!=NULL, 0);
+ if ( (session->flags & RTP_SESSION_SCHEDULED)==0 ){
+ g_warning("can't guess current timestamp because session is not scheduled.");
+ return 0;
+ }
+ session_time=sched->time_-session->rtp.rcv_time_offset;
+ userts= (guint32)( ( (gdouble)(session_time) * (gdouble) payload->clock_rate )/ 1000.0)
+ + session->rtp.rcv_ts_offset;
+ return userts;
+}
+
+/**
+ *rtp_session_set_time_jump_limit:
+ *@session: the rtp session
+ *@ts_step: a time interval in miliseconds
+ *
+ * oRTP has the possibility to inform the application through a callback registered
+ * with rtp_session_signal_connect about crazy incoming RTP stream that jumps from
+ * a timestamp N to N+<some crazy value>. This lets the opportunity for the application
+ * to reset the session in order to resynchronize, or any other action like stopping the call
+ * and reporting an error.
+**/
+void rtp_session_set_time_jump_limit(RtpSession *session, gint milisecs){
+ guint32 ts;
+ session->rtp.time_jump=milisecs;
+ ts=rtp_session_time_to_ts(session,milisecs);
+ if (ts==0) session->rtp.ts_jump=1<<31; /* do not detect ts jump */
+ else session->rtp.ts_jump=ts;
+}
+
+void rtp_session_uninit (RtpSession * session)
+{
+ /* first of all remove the session from the scheduler */
+ if (session->flags & RTP_SESSION_SCHEDULED)
+ {
+ rtp_scheduler_remove_session (session->sched,session);
+ }
+ /*flush all queues */
+ flushq (&session->rtp.rq, FLUSHALL);
+
+ /* close sockets */
+ close_socket (session->rtp.socket);
+ close_socket (session->rtcp.socket);
+
+ wait_point_uninit(&session->send_wp);
+ wait_point_uninit(&session->recv_wp);
+ g_mutex_free (session->lock);
+ session->lock=NULL;
+ if (session->current_tev!=NULL) freemsg(session->current_tev);
+ if (session->rtp.cached_mp!=NULL) freemsg(session->rtp.cached_mp);
+ if (session->rtcp.cached_mp!=NULL) freemsg(session->rtcp.cached_mp);
+ if (session->sd!=NULL) freemsg(session->sd);
+}
+
+/**
+ *rtp_session_reset:
+ *@session: a rtp session.
+ *
+ * Reset the session: local and remote addresses are kept unchanged but the internal
+ * queue for ordering and buffering packets is flushed, the session is ready to be
+ * re-synchronised to another incoming stream.
+ *
+**/
+void rtp_session_reset (RtpSession * session)
+{
+
+ if (session->flags & RTP_SESSION_SCHEDULED) rtp_session_lock (session);
+
+ flushq (&session->rtp.rq, FLUSHALL);
+ rtp_session_set_flag (session, RTP_SESSION_RECV_SYNC);
+ rtp_session_set_flag (session, RTP_SESSION_SEND_SYNC);
+ rtp_session_set_flag (session, RTP_SESSION_RECV_NOT_STARTED);
+ rtp_session_set_flag (session, RTP_SESSION_SEND_NOT_STARTED);
+ //session->ssrc=0;
+ session->rtp.snd_time_offset = 0;
+ session->rtp.snd_ts_offset = 0;
+ session->rtp.snd_rand_offset = 0;
+ session->rtp.snd_last_ts = 0;
+ session->rtp.rcv_time_offset = 0;
+ session->rtp.rcv_ts_offset = 0;
+ session->rtp.rcv_query_ts_offset = 0;
+ session->rtp.rcv_diff_ts = 0;
+ session->rtp.rcv_ts = 0;
+ session->rtp.rcv_last_ts = 0;
+ session->rtp.rcv_last_app_ts = 0;
+ session->rtp.hwrcv_extseq.one = 0;
+ session->rtp.hwrcv_since_last_SR=0;
+ session->rtp.snd_seq = 0;
+ rtp_stats_reset(&session->rtp.stats);
+ jitter_control_init(&session->rtp.jittctl,-1,NULL);
+
+ if (session->flags & RTP_SESSION_SCHEDULED) rtp_session_unlock (session);
+
+}
+
+/**
+ *rtp_session_destroy:
+ *@session: a rtp session.
+ *
+ * Destroys a rtp session.
+ *
+**/
+void rtp_session_destroy (RtpSession * session)
+{
+ rtp_session_uninit (session);
+ g_free (session);
+}
+
+guint32 rtp_session_time_to_ts(RtpSession *session, gint time){
+ PayloadType *payload;
+ g_return_val_if_fail (session->payload_type < 127, 0);
+ payload =
+ rtp_profile_get_payload (session->profile,
+ session->payload_type);
+ if (payload == NULL)
+ {
+ g_warning
+ ("rtp_session_ts_to_t: use of unsupported payload type.");
+ return 0;
+ }
+ /* the return value is in milisecond */
+ return (double)payload->clock_rate*(double)time/1000.0;
+}
+
+/* function used by the scheduler only:*/
+guint32 rtp_session_ts_to_time (RtpSession * session, guint32 timestamp)
+{
+ PayloadType *payload;
+ g_return_val_if_fail (session->payload_type < 127, 0);
+ payload =
+ rtp_profile_get_payload (session->profile,
+ session->payload_type);
+ if (payload == NULL)
+ {
+ g_warning
+ ("rtp_session_ts_to_t: use of unsupported payload type.");
+ return 0;
+ }
+ /* the return value is in milisecond */
+ return (guint32) (1000.0 *
+ ((double) timestamp /
+ (double) payload->clock_rate));
+}
+
+
+/* time is the number of miliseconds elapsed since the start of the scheduler */
+void rtp_session_process (RtpSession * session, guint32 time, RtpScheduler *sched)
+{
+ wait_point_lock(&session->send_wp);
+ if (wait_point_check(&session->send_wp,time)){
+ session_set_set(&sched->w_sessions,session);
+ wait_point_wakeup(&session->send_wp);
+ }
+ wait_point_unlock(&session->send_wp);
+
+ wait_point_lock(&session->recv_wp);
+ if (wait_point_check(&session->recv_wp,time)){
+ session_set_set(&sched->r_sessions,session);
+ wait_point_wakeup(&session->recv_wp);
+ }
+ wait_point_unlock(&session->recv_wp);
+}
+
+
+void rtp_session_make_time_distorsion(RtpSession *session, gint milisec)
+{
+ session->rtp.snd_time_offset+=milisec;
+}
+
+
+/* packet api */
+
+void rtp_add_csrc(mblk_t *mp, guint32 csrc)
+{
+ rtp_header_t *hdr=(rtp_header_t*)mp->b_rptr;
+ hdr->csrc[hdr->cc]=csrc;
+ hdr->cc++;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsession.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsession.h
new file mode 100644
index 00000000..e7702000
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsession.h
@@ -0,0 +1,287 @@
+ /*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef RTPSESSION_H
+#define RTPSESSION_H
+
+
+#include <rtpport.h>
+#include <rtp.h>
+#include <payloadtype.h>
+#include <sessionset.h>
+#include <rtcp.h>
+#include <str_utils.h>
+#include <rtpsignaltable.h>
+
+#include <stdio.h>
+
+
+#ifndef _WIN32
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <errno.h>
+# include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
+# include <unistd.h>
+# include <sys/time.h>
+#else
+# include <winsock2.h>
+#endif /* _WIN32 */
+
+
+
+typedef enum {
+ RTP_SESSION_RECVONLY,
+ RTP_SESSION_SENDONLY,
+ RTP_SESSION_SENDRECV
+} RtpSessionMode;
+
+
+
+typedef enum {
+ RTP_SESSION_RECV_SYNC=1, /* the rtp session is synchronising in the incoming stream */
+ RTP_SESSION_SEND_SYNC=1<<1, /* the rtp session is synchronising in the outgoing stream */
+ RTP_SESSION_SCHEDULED=1<<2, /* the rtp session has to be scheduled */
+ RTP_SESSION_BLOCKING_MODE=1<<3, /* in blocking mode */
+ RTP_SESSION_RECV_NOT_STARTED=1<<4, /* the application has not started to try to recv */
+ RTP_SESSION_SEND_NOT_STARTED=1<<5, /* the application has not started to send something */
+ RTP_SESSION_IN_SCHEDULER=1<<6, /* the rtp session is in the scheduler list */
+ RTP_SESSION_USING_EXT_SOCKETS=1<<7 /* the session is using externaly supplied sockets */
+}RtpSessionFlags;
+
+
+typedef struct _JitterControl
+{
+ gint jitt_comp; /* the user jitt_comp in miliseconds*/
+ gint jitt_comp_ts; /* the jitt_comp converted in rtp time (same unit as timestamp) */
+ gint adapt_jitt_comp_ts;
+ float slide;
+ float jitter;
+ gint count;
+ gint olddiff;
+ float inter_jitter; /* interarrival jitter as defined in the RFC */
+ gint corrective_step;
+ gint corrective_slide;
+ gboolean adaptive;
+} JitterControl;
+
+typedef struct _WaitPoint
+{
+ GMutex *lock;
+ GCond *cond;
+ guint32 time;
+ gboolean wakeup;
+} WaitPoint;
+
+typedef struct _RtpStream
+{
+ gint socket;
+ gint socktype;
+ gint max_rq_size;
+ gint time_jump;
+ guint32 ts_jump;
+ queue_t rq;
+ queue_t tev_rq;
+ mblk_t *cached_mp;
+#ifdef INET6
+ struct sockaddr_storage loc_addr;
+ struct sockaddr_storage rem_addr;
+#else
+ struct sockaddr_in loc_addr;
+ struct sockaddr_in rem_addr;
+#endif
+ int addrlen;
+ JitterControl jittctl;
+ guint32 snd_time_offset;/*the scheduler time when the application send its first timestamp*/
+ guint32 snd_ts_offset; /* the first application timestamp sent by the application */
+ guint32 snd_rand_offset; /* a random number added to the user offset to make the stream timestamp*/
+ guint32 snd_last_ts; /* the last stream timestamp sended */
+ guint32 rcv_time_offset; /*the scheduler time when the application ask for its first timestamp*/
+ guint32 rcv_ts_offset; /* the first stream timestamp */
+ guint32 rcv_query_ts_offset; /* the first user timestamp asked by the application */
+ guint32 rcv_diff_ts; /* difference between the first user timestamp and first stream timestamp */
+ guint32 hwrcv_diff_ts;
+ guint32 rcv_ts; /* to be unused */
+ guint32 rcv_last_ts; /* the last stream timestamp got by the application */
+ guint32 rcv_last_app_ts; /* the last application timestamp asked by the application */
+ guint32 rcv_last_ret_ts; /* the timestamp of the last sample returned (only for continuous audio)*/
+ poly32_t hwrcv_extseq; /* last received on socket extended sequence number */
+ guint32 hwrcv_seq_at_last_SR;
+ guint hwrcv_since_last_SR;
+ guint32 last_rcv_SR_ts; /* NTP timestamp (middle 32 bits) of last received SR */
+ struct timeval last_rcv_SR_time; /* time at which last SR was received */
+ guint16 snd_seq; /* send sequence number */
+ guint32 last_rtcp_report_snt_r; /* the time of the last rtcp report sent, in recv timestamp unit */
+ guint32 last_rtcp_report_snt_s; /* the time of the last rtcp report sent, in send timestamp unit */
+ guint32 rtcp_report_snt_interval; /* the interval in timestamp unit between rtcp report sent */
+ rtp_stats_t stats;
+}RtpStream;
+
+typedef struct _RtcpStream
+{
+ gint socket;
+ gint socktype;
+ mblk_t *cached_mp;
+#ifdef INET6
+ struct sockaddr_storage loc_addr;
+ struct sockaddr_storage rem_addr;
+#else
+ struct sockaddr_in loc_addr;
+ struct sockaddr_in rem_addr;
+#endif
+ int addrlen;
+} RtcpStream;
+
+typedef struct _RtpSession RtpSession;
+
+
+
+struct _RtpSession
+{
+ RtpSession *next; /* next RtpSession, when the session are enqueued by the scheduler */
+ RtpProfile *profile;
+ WaitPoint recv_wp;
+ WaitPoint send_wp;
+ GMutex *lock;
+ guint32 send_ssrc;
+ guint32 recv_ssrc;
+ gint payload_type;
+ gint max_buf_size;
+ RtpSignalTable on_ssrc_changed;
+ RtpSignalTable on_payload_type_changed;
+ RtpSignalTable on_telephone_event_packet;
+ RtpSignalTable on_telephone_event;
+ RtpSignalTable on_timestamp_jump;
+ RtpSignalTable on_network_error;
+ struct _OList *signal_tables;
+ RtpStream rtp;
+ RtcpStream rtcp;
+ RtpSessionMode mode;
+ struct _RtpScheduler *sched;
+ guint32 flags;
+ gint mask_pos; /* the position in the scheduler mask of RtpSession */
+ gpointer user_data;
+
+ /* telephony events extension */
+ gint telephone_events_pt; /* the payload type used for telephony events */
+ mblk_t *current_tev; /* the pending telephony events */
+ mblk_t *sd;
+ queue_t contributing_sources;
+};
+
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*private */
+void rtp_session_init(RtpSession *session, gint mode);
+#define rtp_session_lock(session) g_mutex_lock(session->lock)
+#define rtp_session_unlock(session) g_mutex_unlock(session->lock)
+#define rtp_session_set_flag(session,flag) (session)->flags|=(flag)
+#define rtp_session_unset_flag(session,flag) (session)->flags&=~(flag)
+void rtp_session_uninit(RtpSession *session);
+
+/* public API */
+RtpSession *rtp_session_new(gint mode);
+void rtp_session_set_scheduling_mode(RtpSession *session, gint yesno);
+void rtp_session_set_blocking_mode(RtpSession *session, gint yesno);
+void rtp_session_set_profile(RtpSession *session,RtpProfile *profile);
+#define rtp_session_get_profile(session) (session)->profile
+int rtp_session_signal_connect(RtpSession *session,const gchar *signal, RtpCallback cb, gpointer user_data);
+int rtp_session_signal_disconnect_by_callback(RtpSession *session,const gchar *signal, RtpCallback cb);
+void rtp_session_set_ssrc(RtpSession *session, guint32 ssrc);
+void rtp_session_set_seq_number(RtpSession *session, guint16 seq);
+guint16 rtp_session_get_seq_number(RtpSession *session);
+void rtp_session_set_jitter_compensation(RtpSession *session, int milisec);
+void rtp_session_enable_adaptive_jitter_compensation(RtpSession *session, gboolean val);
+gboolean rtp_session_adaptive_jitter_compensation_enabled(RtpSession *session);
+void rtp_session_set_time_jump_limit(RtpSession *session, gint miliseconds);
+int rtp_session_set_local_addr(RtpSession *session,const gchar *addr, gint port);
+gint rtp_session_set_remote_addr(RtpSession *session,const gchar *addr, gint port);
+/* alternatively to the set_remote_addr() and set_local_addr(), an application can give
+a valid socket (potentially connect()ed )to be used by the RtpSession */
+void rtp_session_set_sockets(RtpSession *session, gint rtpfd, gint rtcpfd);
+int rtp_session_set_payload_type(RtpSession *session, int paytype);
+int rtp_session_get_payload_type(RtpSession *session);
+int rtp_session_set_payload_type_with_string (RtpSession * session, const char * mime);
+/*low level recv and send functions */
+mblk_t * rtp_session_recvm_with_ts (RtpSession * session, guint32 user_ts);
+mblk_t * rtp_session_create_packet(RtpSession *session,gint header_size, const char *payload, gint payload_size);
+mblk_t * rtp_session_create_packet_with_data(RtpSession *session, char *payload, gint payload_size, void (*freefn)(void*));
+mblk_t * rtp_session_create_packet_in_place(RtpSession *session,char *buffer, gint size, void (*freefn)(void*) );
+gint rtp_session_sendm_with_ts (RtpSession * session, mblk_t *mp, guint32 userts);
+/* high level recv and send functions */
+gint rtp_session_recv_with_ts(RtpSession *session, gchar *buffer, gint len, guint32 time, gint *have_more);
+gint rtp_session_send_with_ts(RtpSession *session, const gchar *buffer, gint len, guint32 userts);
+
+
+guint32 rtp_session_get_current_send_ts(RtpSession *session);
+guint32 rtp_session_get_current_recv_ts(RtpSession *session);
+void rtp_session_flush_sockets(RtpSession *session);
+void rtp_session_reset(RtpSession *session);
+void rtp_session_destroy(RtpSession *session);
+
+#define rtp_session_get_stats(session) (&(session)->stats)
+#define rtp_session_reset_stats(session) memset(&(session)->stats,0,sizeof(rtp_stats_t))
+#define rtp_session_set_data(session,data) (session)->user_data=(data)
+#define rtp_session_get_data(session,data) ((session)->user_data)
+
+#define rtp_session_max_buf_size_set(session,bufsize) (session)->max_buf_size=(bufsize)
+
+/* in use with the scheduler to convert a timestamp in scheduler time unit (ms) */
+guint32 rtp_session_ts_to_time(RtpSession *session,guint32 timestamp);
+guint32 rtp_session_time_to_ts(RtpSession *session, gint time);
+/* this function aims at simulating senders with "imprecise" clocks, resulting in
+rtp packets sent with timestamp uncorrelated with the system clock .
+This is only availlable to sessions working with the oRTP scheduler */
+void rtp_session_make_time_distorsion(RtpSession *session, gint milisec);
+
+/*RTCP functions */
+void rtp_session_set_source_description(RtpSession *session, const gchar *cname,
+ const gchar *name, const gchar *email, const gchar *phone,
+ const gchar *loc, const gchar *tool, const gchar *note);
+void rtp_session_add_contributing_source(RtpSession *session, guint32 csrc,
+ const gchar *cname, const gchar *name, const gchar *email, const gchar *phone,
+ const gchar *loc, const gchar *tool, const gchar *note);
+void rtp_session_remove_contributing_sources(RtpSession *session, guint32 csrc);
+mblk_t* rtp_session_create_rtcp_sdes_packet(RtpSession *session);
+
+
+/* packet api */
+/* the first argument is a mblk_t. The header is supposed to be not splitted */
+#define rtp_set_markbit(mp,value) ((rtp_header_t*)((mp)->b_rptr))->markbit=(value)
+#define rtp_set_seqnumber(mp,seq) ((rtp_header_t*)((mp)->b_rptr))->seq_number=(seq)
+#define rtp_set_timestamp(mp,ts) ((rtp_header_t*)((mp)->b_rptr))->timestamp=(ts)
+#define rtp_set_ssrc(mp,_ssrc) ((rtp_header_t*)((mp)->b_rptr))->ssrc=(_ssrc)
+void rtp_add_csrc(mblk_t *mp,guint32 csrc);
+#define rtp_set_payload_type(mp,pt) ((rtp_header_t*)((mp)->b_rptr))->paytype=(pt)
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsignaltable.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsignaltable.c
new file mode 100644
index 00000000..35b19ae3
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsignaltable.c
@@ -0,0 +1,98 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+
+#include <rtpsession.h>
+#include "utils.h"
+
+
+void rtp_signal_table_init(RtpSignalTable *table,RtpSession *session, char *signal_name)
+{
+ memset(table,0,sizeof(RtpSignalTable));
+ table->session=session;
+ table->signal_name=signal_name;
+ session->signal_tables=o_list_append(session->signal_tables,(gpointer)table);
+}
+
+int rtp_signal_table_add(RtpSignalTable *table,RtpCallback cb, gpointer user_data)
+{
+ gint i;
+
+ for (i=0;i<RTP_CALLBACK_TABLE_MAX_ENTRIES;i++){
+ if (table->callback[i]==NULL){
+ table->callback[i]=cb;
+ table->user_data[i]=user_data;
+ table->count++;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void rtp_signal_table_emit(RtpSignalTable *table)
+{
+ gint i,c;
+
+ for (i=0,c=0;c<table->count;i++){
+ if (table->callback[i]!=NULL){
+ c++; /*I like it*/
+ table->callback[i](table->session,table->user_data[i]);
+ }
+ }
+}
+
+void rtp_signal_table_emit2(RtpSignalTable *table, gpointer arg)
+{
+ gint i,c;
+
+ for (i=0,c=0;c<table->count;i++){
+ if (table->callback[i]!=NULL){
+ c++; /*I like it*/
+ table->callback[i](table->session,arg,table->user_data[i]);
+ }
+ }
+}
+
+void rtp_signal_table_emit3(RtpSignalTable *table, gpointer arg1, gpointer arg2)
+{
+ gint i,c;
+
+ for (i=0,c=0;c<table->count;i++){
+ if (table->callback[i]!=NULL){
+ c++; /*I like it*/
+ table->callback[i](table->session,arg1,arg2,table->user_data[i]);
+ }
+ }
+}
+
+int rtp_signal_table_remove_by_callback(RtpSignalTable *table,RtpCallback cb)
+{
+ gint i;
+
+ for (i=0;i<RTP_CALLBACK_TABLE_MAX_ENTRIES;i++){
+ if (table->callback[i]==cb){
+ table->callback[i]=NULL;
+ table->user_data[i]=NULL;
+ table->count--;
+ return 0;
+ }
+ }
+ return -1;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsignaltable.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsignaltable.h
new file mode 100644
index 00000000..c6cbe960
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtpsignaltable.h
@@ -0,0 +1,47 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define RTP_CALLBACK_TABLE_MAX_ENTRIES 5
+
+typedef void (*RtpCallback)(struct _RtpSession *, ...);
+
+struct _RtpSignalTable
+{
+ RtpCallback callback[RTP_CALLBACK_TABLE_MAX_ENTRIES];
+ gpointer user_data[RTP_CALLBACK_TABLE_MAX_ENTRIES];
+ struct _RtpSession *session;
+ const char *signal_name;
+ gint count;
+};
+
+typedef struct _RtpSignalTable RtpSignalTable;
+
+void rtp_signal_table_init(RtpSignalTable *table,struct _RtpSession *session, char *signal_name);
+
+int rtp_signal_table_add(RtpSignalTable *table,RtpCallback cb, gpointer user_data);
+
+void rtp_signal_table_emit(RtpSignalTable *table);
+
+/* emit but with a second arg */
+void rtp_signal_table_emit2(RtpSignalTable *table, gpointer arg);
+
+/* emit but with a third arg */
+void rtp_signal_table_emit3(RtpSignalTable *table, gpointer arg1, gpointer arg2);
+
+int rtp_signal_table_remove_by_callback(RtpSignalTable *table,RtpCallback cb);
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtptimer.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtptimer.c
new file mode 100644
index 00000000..6ac57e72
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtptimer.c
@@ -0,0 +1,32 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "rtptimer.h"
+
+void rtp_timer_set_interval(RtpTimer *timer, struct timeval *interval)
+{
+ if (timer->state==RTP_TIMER_RUNNING){
+ g_warning("Cannot change timer interval while it is running.\n");
+ return;
+ }
+ timer->interval.tv_sec=interval->tv_sec;
+ timer->interval.tv_usec=interval->tv_usec;
+}
+
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtptimer.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtptimer.h
new file mode 100644
index 00000000..081e0892
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/rtptimer.h
@@ -0,0 +1,52 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef RTPTIMER_H
+#define RTPTIMER_H
+
+#ifndef _WIN32
+#include <sys/time.h>
+#else
+#include <time.h>
+#include "winsock2.h"
+#endif
+
+#include <rtpport.h>
+
+
+typedef void (*RtpTimerFunc)(void);
+
+struct _RtpTimer
+{
+ gint state;
+#define RTP_TIMER_RUNNING 1
+#define RTP_TIMER_STOPPED 0
+ RtpTimerFunc timer_init;
+ RtpTimerFunc timer_do;
+ RtpTimerFunc timer_uninit;
+ struct timeval interval;
+};
+
+typedef struct _RtpTimer RtpTimer;
+
+void rtp_timer_set_interval(RtpTimer *timer, struct timeval *interval);
+
+extern RtpTimer posix_timer;
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/scheduler.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/scheduler.c
new file mode 100644
index 00000000..17ff6748
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/scheduler.c
@@ -0,0 +1,235 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _WIN32 /* do not include ortp-config.h when we are on win32 */
+ #include <rtpport.h>
+ #include <sched.h>
+ #include <unistd.h>
+ #include <errno.h>
+#else
+ #include "ortp-config-win32.h"
+#endif
+
+
+
+#include "scheduler.h"
+
+// To avoid warning during compile
+extern void rtp_session_process (RtpSession * session, guint32 time, RtpScheduler *sched);
+
+
+void rtp_scheduler_init(RtpScheduler *sched)
+{
+ sched->list=0;
+ sched->time_=0;
+ /* default to the posix timer */
+ rtp_scheduler_set_timer(sched,&posix_timer);
+ sched->lock=g_mutex_new();
+ //sched->unblock_select_mutex=g_mutex_new();
+ sched->unblock_select_cond=g_cond_new();
+ sched->max_sessions=sizeof(SessionSet)*8;
+ session_set_init(&sched->all_sessions);
+ sched->all_max=0;
+ session_set_init(&sched->r_sessions);
+ sched->r_max=0;
+ session_set_init(&sched->w_sessions);
+ sched->w_max=0;
+ session_set_init(&sched->e_sessions);
+ sched->e_max=0;
+}
+
+RtpScheduler * rtp_scheduler_new()
+{
+ RtpScheduler *sched=g_malloc(sizeof(RtpScheduler));
+ memset(sched,0,sizeof(RtpScheduler));
+ rtp_scheduler_init(sched);
+ return sched;
+}
+
+void rtp_scheduler_set_timer(RtpScheduler *sched,RtpTimer *timer)
+{
+ if (sched->thread_running){
+ g_warning("Cannot change timer while the scheduler is running !!");
+ return;
+ }
+ sched->timer=timer;
+ /* report the timer increment */
+ sched->timer_inc=(timer->interval.tv_usec/1000) + (timer->interval.tv_sec*1000);
+}
+
+void rtp_scheduler_start(RtpScheduler *sched)
+{
+ if (sched->thread_running==0){
+ sched->thread_running=1;
+ g_mutex_lock(sched->lock);
+ sched->thread=g_thread_create((GThreadFunc)rtp_scheduler_schedule,(gpointer)sched,TRUE,NULL);
+ g_cond_wait(sched->unblock_select_cond,sched->lock);
+ g_mutex_unlock(sched->lock);
+ }
+ else g_warning("Scheduler thread already running.");
+
+}
+void rtp_scheduler_stop(RtpScheduler *sched)
+{
+ if (sched->thread_running==1)
+ {
+ sched->thread_running=0;
+ g_thread_join(sched->thread);
+ }
+ else g_warning("Scheduler thread is not running.");
+}
+
+void rtp_scheduler_destroy(RtpScheduler *sched)
+{
+ if (sched->thread_running) rtp_scheduler_stop(sched);
+ g_mutex_free(sched->lock);
+ //g_mutex_free(sched->unblock_select_mutex);
+ g_cond_free(sched->unblock_select_cond);
+ g_free(sched);
+}
+
+gpointer rtp_scheduler_schedule(gpointer psched)
+{
+ RtpScheduler *sched=(RtpScheduler*) psched;
+ RtpTimer *timer=sched->timer;
+ RtpSession *current;
+ int err;
+
+ /* try to get the real time priority by getting root*/
+#ifndef _WIN32
+#ifdef HAVE_SETEUID
+ err=seteuid(0);
+#else
+ err=setuid(0);
+#endif
+ if (err<0) g_message("Could not get root euid: %s",strerror(errno));
+#endif
+ g_message("scheduler: trying to reach real time kernel scheduling...");
+
+ /* take this lock to prevent the thread to start until g_thread_create() returns
+ because we need sched->thread to be initialized */
+ g_mutex_lock(sched->lock);
+ g_cond_signal(sched->unblock_select_cond); /* unblock the starting thread */
+ g_mutex_unlock(sched->lock);
+ g_thread_set_priority(sched->thread,G_THREAD_PRIORITY_HIGH);
+ timer->timer_init();
+ while(sched->thread_running)
+ {
+ /* do the processing here: */
+
+ g_mutex_lock(sched->lock);
+
+ current=sched->list;
+ /* processing all scheduled rtp sessions */
+ while (current!=NULL)
+ {
+ ortp_debug("scheduler: processing session=%p.\n",current);
+ rtp_session_process(current,sched->time_,sched);
+ current=current->next;
+ }
+ /* wake up all the threads that are sleeping in _select() */
+ g_cond_broadcast(sched->unblock_select_cond);
+ g_mutex_unlock(sched->lock);
+
+ /* now while the scheduler is going to sleep, the other threads can compute their
+ result mask and see if they have to leave, or to wait for next tick*/
+ //g_message("scheduler: sleeping.");
+ timer->timer_do();
+ sched->time_+=sched->timer_inc;
+ }
+ /* when leaving the thread, stop the timer */
+ timer->timer_uninit();
+ return NULL;
+}
+
+void rtp_scheduler_add_session(RtpScheduler *sched, RtpSession *session)
+{
+ RtpSession *oldfirst;
+ int i;
+ if (session->flags & RTP_SESSION_IN_SCHEDULER){
+ /* the rtp session is already scheduled, so return silently */
+ return;
+ }
+ rtp_scheduler_lock(sched);
+ /* enqueue the session to the list of scheduled sessions */
+ oldfirst=sched->list;
+ sched->list=session;
+ session->next=oldfirst;
+ if (sched->max_sessions==0){
+ g_error("rtp_scheduler_add_session: max_session=0 !");
+ }
+ /* find a free pos in the session mask*/
+ for (i=0;i<sched->max_sessions;i++){
+ if (!ORTP_FD_ISSET(i,&sched->all_sessions.rtpset)){
+ session->mask_pos=i;
+ session_set_set(&sched->all_sessions,session);
+ /* make a new session scheduled not blockable if it has not started*/
+ if (session->flags & RTP_SESSION_RECV_NOT_STARTED)
+ session_set_set(&sched->r_sessions,session);
+ if (session->flags & RTP_SESSION_SEND_NOT_STARTED)
+ session_set_set(&sched->w_sessions,session);
+ if (i>sched->all_max){
+ sched->all_max=i;
+ }
+ break;
+ }
+ }
+
+ rtp_session_set_flag(session,RTP_SESSION_IN_SCHEDULER);
+ rtp_scheduler_unlock(sched);
+}
+
+void rtp_scheduler_remove_session(RtpScheduler *sched, RtpSession *session)
+{
+ RtpSession *tmp;
+ int cond=1;
+ g_return_if_fail(session!=NULL);
+ if (!(session->flags & RTP_SESSION_IN_SCHEDULER)){
+ /* the rtp session is not scheduled, so return silently */
+ return;
+ }
+
+ rtp_scheduler_lock(sched);
+ tmp=sched->list;
+ if (tmp==session){
+ sched->list=tmp->next;
+ rtp_session_unset_flag(session,RTP_SESSION_IN_SCHEDULER);
+ session_set_clr(&sched->all_sessions,session);
+ rtp_scheduler_unlock(sched);
+ return;
+ }
+ /* go the position of session in the list */
+ while(cond){
+ if (tmp!=NULL){
+ if (tmp->next==session){
+ tmp->next=tmp->next->next;
+ cond=0;
+ }
+ else tmp=tmp->next;
+ }else {
+ /* the session was not found ! */
+ g_warning("rtp_scheduler_remove_session: the session was not found in the scheduler list!");
+ cond=0;
+ }
+ }
+ rtp_session_unset_flag(session,RTP_SESSION_IN_SCHEDULER);
+ /* delete the bit in the mask */
+ session_set_clr(&sched->all_sessions,session);
+ rtp_scheduler_unlock(sched);
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/scheduler.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/scheduler.h
new file mode 100644
index 00000000..91cde6a9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/scheduler.h
@@ -0,0 +1,70 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef SCHEDULER_H
+#define SCHEDULER_H
+
+#include <rtpsession.h>
+#include <sessionset.h>
+#include "rtptimer.h"
+#include "port_fct.h"
+
+
+struct _RtpScheduler {
+
+ RtpSession *list; /* list of scheduled sessions*/
+ SessionSet all_sessions; /* mask of scheduled sessions */
+ gint all_max; /* the highest pos in the all mask */
+ SessionSet r_sessions; /* mask of sessions that have a recv event */
+ gint r_max;
+ SessionSet w_sessions; /* mask of sessions that have a send event */
+ gint w_max;
+ SessionSet e_sessions; /* mask of session that have error event */
+ gint e_max;
+ gint max_sessions; /* the number of position in the masks */
+ /* GMutex *unblock_select_mutex; */
+ GCond *unblock_select_cond;
+ GMutex *lock;
+ GThread *thread;
+ gint thread_running;
+ struct _RtpTimer *timer;
+ guint32 time_; /*number of miliseconds elapsed since the start of the thread */
+ guint32 timer_inc; /* the timer increment in milisec */
+};
+
+typedef struct _RtpScheduler RtpScheduler;
+
+RtpScheduler * rtp_scheduler_new();
+void rtp_scheduler_set_timer(RtpScheduler *sched,RtpTimer *timer);
+void rtp_scheduler_start(RtpScheduler *sched);
+void rtp_scheduler_stop(RtpScheduler *sched);
+void rtp_scheduler_destroy(RtpScheduler *sched);
+
+void rtp_scheduler_add_session(RtpScheduler *sched, RtpSession *session);
+void rtp_scheduler_remove_session(RtpScheduler *sched, RtpSession *session);
+
+gpointer rtp_scheduler_schedule(gpointer sched);
+
+#define rtp_scheduler_lock(sched) g_mutex_lock((sched)->lock)
+#define rtp_scheduler_unlock(sched) g_mutex_unlock((sched)->lock)
+
+/* void rtp_scheduler_add_set(RtpScheduler *sched, SessionSet *set); */
+
+RtpScheduler * ortp_get_scheduler();
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/sessionset.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/sessionset.c
new file mode 100644
index 00000000..7b5ad921
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/sessionset.c
@@ -0,0 +1,187 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <ortp.h>
+#include <sessionset.h>
+#include "scheduler.h"
+
+/**
+ *session_set_init:
+ *@ss: a SessionSet statically allocated.
+ *
+ * Initializes a session set. It is unusefull to call this function on a session set object
+ * returned by session_set_new().
+ *
+**/
+
+
+/**
+ *session_set_new:
+ *
+ * Allocates and initialize a new empty session set.
+ *
+ *Returns: the session set.
+**/
+SessionSet * session_set_new()
+{
+ SessionSet *set=g_malloc(sizeof(SessionSet));
+ session_set_init(set);
+ return set;
+}
+
+
+/**
+ *session_set_destroy:
+ *@set: a SessionSet
+ * Destroys a session set.
+ *
+**/
+
+void session_set_destroy(SessionSet *set)
+{
+ g_free(set);
+}
+
+gint session_set_and(SessionSet *sched_set, gint maxs, SessionSet *user_set, SessionSet *result_set)
+{
+ guint32 *mask1,*mask2,*mask3;
+ gint i=0;
+ gint j,ret=0;
+ mask1=(guint32*)&sched_set->rtpset;
+ mask2=(guint32*)&user_set->rtpset;
+ mask3=(guint32*)&result_set->rtpset;
+ while(i<maxs+1){
+ *mask3=(*mask1) & (*mask2); /* computes the AND between the two masks*/
+ /* and unset the sessions that have been found from the sched_set */
+ *mask1=(*mask1) & (~(*mask3));
+ if ((*mask3)!=0){
+ for (j=0;j<32;j++){
+ if ( ((*mask3)>>j) & 1){
+ ret++;
+ }
+ }
+ }
+ i+=32;
+ mask1++;
+ mask2++;
+ mask3++;
+ }
+ //printf("session_set_and: ret=%i\n",ret);
+ return ret;
+}
+
+/**
+ *session_set_select:
+ *@recvs: a set of rtp sessions to be watched for read events
+ *@sends: a set of rtp sessions to be watched for write events
+ *@errors: a set of rtp sessions to be watched for errors
+ *
+ * This function performs similarly as libc select() function, but performs on #RtpSession
+ * instead of file descriptors.
+ * session_set_select() suspends the calling process until some events arrive on one of the
+ * three sets passed in argument. Two of the sets can be NULL.
+ * The first set @recvs is interpreted as a set of RtpSession waiting for receive events:
+ * a new buffer (perhaps empty) is availlable on one or more sessions of the set, or the last
+ * receive operation with rtp_session_recv_with_ts() would have finished if it were in
+ * blocking mode.
+ * The second set is interpreted as a set of RtpSession waiting for send events, i.e. the last
+ * rtp_session_send_with_ts() call on a session would have finished if it were in blocking mode.
+ *
+ * When some events arrived on some of sets, then the function returns and sets are changed
+ * to indicate the sessions where events happened.
+ * Sessions can be added to sets using session_set_set(), a session has to be tested to be
+ * part of a set using session_set_is_set().
+ *
+ *Returns: the number of sessions on which the selected events happened.
+**/
+int session_set_select(SessionSet *recvs, SessionSet *sends, SessionSet *errors)
+{
+ gint ret=0,bits;
+ SessionSet temp;
+ RtpScheduler *sched=ortp_get_scheduler();
+
+ /*lock the scheduler to not read the masks while they are being modified by the scheduler*/
+ rtp_scheduler_lock(sched);
+
+ while(1){
+ /* computes the SessionSet intersection (in the other words mask intersection) between
+ the mask given by the user and scheduler masks */
+ if (recvs!=NULL){
+ bits=session_set_and(&sched->r_sessions,sched->all_max,recvs,&temp);
+ if (bits>0){
+ ret+=bits;
+ /* copy the result set in the given user set */
+ session_set_copy(recvs,&temp);
+ }
+ }
+ if (sends!=NULL){
+ bits=session_set_and(&sched->w_sessions,sched->all_max,sends,&temp);
+ if (bits>0){
+ ret+=bits;
+ /* copy the result set in the given user set */
+ session_set_copy(sends,&temp);
+ }
+ }
+ if (errors!=NULL){
+ bits=session_set_and(&sched->e_sessions,sched->all_max,errors,&temp);
+ if (bits>0){
+ ret+=bits;
+ /* copy the result set in the given user set */
+ session_set_copy(errors,&temp);
+ }
+ }
+ if (ret>0){
+ /* there are set file descriptors, return immediately */
+ //printf("There are %i sessions set, returning.\n",ret);
+ rtp_scheduler_unlock(sched);
+ return ret;
+ }
+ //printf("There are %i sessions set.\n",ret);
+ /* else we wait until the next loop of the scheduler*/
+ g_cond_wait(sched->unblock_select_cond,sched->lock);
+ }
+
+ return -1;
+}
+
+/**
+ *session_set_set:
+ *@ss: a set (#SessionSet object)
+ *@rtpsession: a rtp session
+ *
+ * This macro adds rtp session @_session to set @_set.
+**/
+
+/**
+ *session_set_is_set:
+ *@ss: a set (#SessionSet object)
+ *@rtpsession: a rtp session
+ *
+ * This macro tests if @_session is part of @_set. 1 is returned if true, 0 else.
+**/
+
+/**
+ *session_set_clr:
+ *@ss: a set of sessions.
+ *@rtpsession: a rtp session.
+ *
+ * Removes the @_session from the _set.
+ *
+ *
+**/
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/sessionset.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/sessionset.h
new file mode 100644
index 00000000..623b9d10
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/sessionset.h
@@ -0,0 +1,102 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef SESSIONSET_H
+#define SESSIONSET_H
+
+
+#include <rtpsession.h>
+
+
+#ifndef _WIN32
+/* UNIX */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define ORTP_FD_SET(d, s) FD_SET(d, s)
+#define ORTP_FD_CLR(d, s) FD_CLR(d, s)
+#define ORTP_FD_ISSET(d, s) FD_ISSET(d, s)
+#define ORTP_FD_ZERO(s) FD_ZERO(s)
+
+typedef fd_set ortp_fd_set;
+
+
+#else
+/* WIN32 */
+
+#define ORTP_FD_ZERO(s) \
+ do { \
+ unsigned int __i; \
+ ortp_fd_set *__arr = (s); \
+ for (__i = 0; __i < sizeof (ortp_fd_set) / sizeof (ortp__fd_mask); ++__i) \
+ ORTP__FDS_BITS (__arr)[__i] = 0; \
+ } while (0)
+#define ORTP_FD_SET(d, s) (ORTP__FDS_BITS (s)[ORTP__FDELT(d)] |= ORTP__FDMASK(d))
+#define ORTP_FD_CLR(d, s) (ORTP__FDS_BITS (s)[ORTP__FDELT(d)] &= ~ORTP__FDMASK(d))
+#define ORTP_FD_ISSET(d, s) ((ORTP__FDS_BITS (s)[ORTP__FDELT(d)] & ORTP__FDMASK(d)) != 0)
+
+
+
+/* The fd_set member is required to be an array of longs. */
+typedef long int ortp__fd_mask;
+
+
+/* Number of bits per word of `fd_set' (some code assumes this is 32). */
+#define ORTP__FD_SETSIZE 1024
+
+/* It's easier to assume 8-bit bytes than to get CHAR_BIT. */
+#define ORTP__NFDBITS (8 * sizeof (ortp__fd_mask))
+#define ORTP__FDELT(d) ((d) / ORTP__NFDBITS)
+#define ORTP__FDMASK(d) ((ortp__fd_mask) 1 << ((d) % ORTP__NFDBITS))
+
+
+/* fd_set for select and pselect. */
+typedef struct
+ {
+ ortp__fd_mask fds_bits[ORTP__FD_SETSIZE / ORTP__NFDBITS];
+# define ORTP__FDS_BITS(set) ((set)->fds_bits)
+ } ortp_fd_set;
+
+
+#endif /*end WIN32*/
+
+struct _SessionSet
+{
+ ortp_fd_set rtpset;
+};
+
+
+typedef struct _SessionSet SessionSet;
+
+SessionSet * session_set_new();
+#define session_set_init(ss) ORTP_FD_ZERO(&(ss)->rtpset)
+#define session_set_set(ss,rtpsession) ORTP_FD_SET((rtpsession)->mask_pos,&(ss)->rtpset)
+#define session_set_is_set(ss,rtpsession) ORTP_FD_ISSET((rtpsession)->mask_pos,&(ss)->rtpset)
+#define session_set_clr(ss,rtpsession) ORTP_FD_CLR((rtpsession)->mask_pos,&(ss)->rtpset)
+
+#define session_set_copy(dest,src) memcpy(&(dest)->rtpset,&(src)->rtpset,sizeof(ortp_fd_set))
+
+void session_set_destroy(SessionSet *set);
+
+
+int session_set_select(SessionSet *recvs, SessionSet *sends, SessionSet *errors);
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/str_utils.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/str_utils.c
new file mode 100644
index 00000000..813ea707
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/str_utils.c
@@ -0,0 +1,297 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <rtpport.h>
+#include <rtp.h>
+#include <str_utils.h>
+
+#include <stdio.h>
+
+void qinit(queue_t *q){
+ mblk_init(&q->_q_first);
+ mblk_init(&q->_q_last);
+ q->_q_first.b_next=&q->_q_last;
+ q->_q_last.b_prev=&q->_q_first;
+ q->q_mcount=0;
+}
+
+void mblk_init(mblk_t *mp)
+{
+ mp->b_cont=mp->b_prev=mp->b_next=NULL;
+ mp->b_rptr=mp->b_wptr=NULL;
+}
+
+mblk_t *allocb(int size, int pri)
+{
+ mblk_t *mp;
+ dblk_t *datab;
+ gchar *buf;
+
+ mp=g_malloc(sizeof(mblk_t));
+ mblk_init(mp);
+ datab=g_malloc(sizeof(dblk_t));
+
+ buf=g_malloc(size);
+
+ datab->db_base=buf;
+ datab->db_lim=buf+size;
+ datab->ref_count=1;
+ datab->db_freefn=g_free;
+
+ mp->b_datap=datab;
+ mp->b_rptr=mp->b_wptr=buf;
+ mp->b_next=mp->b_prev=mp->b_cont=NULL;
+ return mp;
+}
+
+mblk_t *allocb_with_buf(char *buf, int size, int pri, void (*freefn)(void*) )
+{
+ mblk_t *mp;
+ dblk_t *datab;
+
+ mp=g_malloc(sizeof(mblk_t));
+ mblk_init(mp);
+ datab=g_malloc(sizeof(dblk_t));
+
+
+ datab->db_base=buf;
+ datab->db_lim=buf+size;
+ datab->ref_count=1;
+ datab->db_freefn=freefn;
+
+ mp->b_datap=datab;
+ mp->b_rptr=mp->b_wptr=buf;
+ mp->b_next=mp->b_prev=mp->b_cont=NULL;
+ return mp;
+}
+
+
+void freeb(mblk_t *mp)
+{
+ g_return_if_fail(mp->b_datap!=NULL);
+ g_return_if_fail(mp->b_datap->db_base!=NULL);
+
+ mp->b_datap->ref_count--;
+ if (mp->b_datap->ref_count==0)
+ {
+ if (mp->b_datap->db_freefn!=NULL)
+ mp->b_datap->db_freefn(mp->b_datap->db_base);
+ g_free(mp->b_datap);
+ }
+ g_free(mp);
+}
+
+void freemsg(mblk_t *mp)
+{
+ mblk_t *tmp1,*tmp2;
+ tmp1=mp;
+ while(tmp1!=NULL)
+ {
+ tmp2=tmp1->b_cont;
+ freeb(tmp1);
+ tmp1=tmp2;
+ }
+}
+
+mblk_t *dupb(mblk_t *mp)
+{
+ mblk_t *newm;
+ g_return_val_if_fail(mp->b_datap!=NULL,NULL);
+ g_return_val_if_fail(mp->b_datap->db_base!=NULL,NULL);
+
+ mp->b_datap->ref_count++;
+ newm=g_malloc(sizeof(mblk_t));
+ mblk_init(newm);
+ newm->b_datap=mp->b_datap;
+ newm->b_rptr=mp->b_rptr;
+ newm->b_wptr=mp->b_wptr;
+ return newm;
+}
+
+/* duplicates a complex mblk_t */
+mblk_t *dupmsg(mblk_t* m)
+{
+ mblk_t *newm=NULL,*mp,*prev;
+ prev=newm=dupb(m);
+ m=m->b_cont;
+ while (m!=NULL){
+ mp=dupb(m);
+ prev->b_cont=mp;
+ prev=mp;
+ m=m->b_cont;
+ }
+ return newm;
+}
+
+void putq(queue_t *q,mblk_t *mp)
+{
+ q->_q_last.b_prev->b_next=mp;
+ mp->b_prev=q->_q_last.b_prev;
+ mp->b_next=&q->_q_last;
+ q->_q_last.b_prev=mp;
+ q->q_mcount++;
+}
+
+mblk_t *getq(queue_t *q)
+{
+ mblk_t *tmp;
+ tmp=q->_q_first.b_next;
+ if (tmp==&q->_q_last) return NULL;
+ q->_q_first.b_next=tmp->b_next;
+ tmp->b_next->b_prev=&q->_q_first;
+ tmp->b_prev=NULL;
+ tmp->b_next=NULL;
+ q->q_mcount--;
+ return tmp;
+}
+
+/* insert mp in q just before emp */
+void insq(queue_t *q,mblk_t *emp, mblk_t *mp)
+{
+ if (emp==NULL){
+ putq(q,mp);
+ return;
+ }
+ q->q_mcount++;
+ emp->b_prev->b_next=mp;
+ mp->b_prev=emp->b_prev;
+ emp->b_prev=mp;
+ mp->b_next=emp;
+}
+
+void remq(queue_t *q, mblk_t *mp){
+ q->q_mcount--;
+ mp->b_prev->b_next=mp->b_next;
+ mp->b_next->b_prev=mp->b_prev;
+ mp->b_next=NULL;
+ mp->b_prev=NULL;
+}
+
+/* remove and free all messages in the q */
+void flushq(queue_t *q, int how)
+{
+ mblk_t *mp;
+
+ while ((mp=getq(q))!=NULL)
+ {
+ freemsg(mp);
+ }
+}
+
+gint msgdsize(mblk_t *mp)
+{
+ gint msgsize=0;
+ while(mp!=NULL){
+ msgsize+=mp->b_wptr-mp->b_rptr;
+ mp=mp->b_cont;
+ }
+ return msgsize;
+}
+
+mblk_t * msgpullup(mblk_t *mp,int len)
+{
+ mblk_t *newm;
+ gint msgsize=msgdsize(mp);
+ gint rlen;
+ gint mlen;
+
+
+ if ((len==-1) || (len>msgsize)) len=msgsize;
+ rlen=len;
+ newm=allocb(len,BPRI_MED);
+
+ while(mp!=NULL){
+ mlen=mp->b_wptr-mp->b_rptr;
+ if (rlen>=mlen)
+ {
+ memcpy(newm->b_wptr,mp->b_rptr,mlen);
+ rlen-=mlen;
+ newm->b_wptr+=mlen;
+ }
+ else /* rlen < mlen */
+ {
+ memcpy(newm->b_wptr,mp->b_rptr,rlen);
+ newm->b_wptr+=rlen;
+
+ /* put the end of the original message at the end of the new */
+ newm->b_cont=dupmsg(mp);
+ newm->b_cont->b_rptr+=rlen;
+ return newm;
+ }
+ mp=mp->b_cont;
+ }
+ return newm;
+}
+
+
+mblk_t *copyb(mblk_t *mp)
+{
+ mblk_t *newm;
+ gint len=mp->b_wptr-mp->b_rptr;
+ newm=allocb(len,BPRI_MED);
+ memcpy(newm->b_wptr,mp->b_rptr,len);
+ newm->b_wptr+=len;
+ return newm;
+}
+
+mblk_t *copymsg(mblk_t *mp)
+{
+ mblk_t *newm=0,*m;
+ m=newm=copyb(mp);
+ mp=mp->b_cont;
+ while(mp!=NULL){
+ m->b_cont=copyb(mp);
+ m=m->b_cont;
+ mp=mp->b_cont;
+ }
+ return newm;
+}
+
+mblk_t * appendb(mblk_t *mp, const char *data, int size, gboolean pad){
+ gint padcnt=0;
+ int i;
+ if (pad){
+ padcnt= (gint)(4L-( (long)(mp->b_wptr+size) % 4L)) % 4L;
+ }
+ if ((mp->b_wptr + size +padcnt) > (char*)mp->b_datap->db_lim){
+ /* buffer is not large enough: append a new block (with the same size ?)*/
+ int plen=(char*)mp->b_datap->db_lim - (char*) mp->b_datap->db_base;
+ mp->b_cont=allocb(MAX(plen,size),0);
+ mp=mp->b_cont;
+ }
+ if (size) memcpy(mp->b_wptr,data,size);
+ mp->b_wptr+=size;
+ for (i=0;i<padcnt;i++){
+ mp->b_wptr[0]=0;
+ mp->b_wptr++;
+ }
+ return mp;
+}
+
+void msgappend(mblk_t *mp, const char *data, int size, gboolean pad){
+ while(mp->b_cont!=NULL) mp=mp->b_cont;
+ appendb(mp,data,size,pad);
+}
+
+mblk_t *concatb(mblk_t *mp, mblk_t *newm){
+ while (mp->b_cont!=NULL) mp=mp->b_cont;
+ mp->b_cont=newm;
+ while(newm->b_cont!=NULL) newm=newm->b_cont;
+ return newm;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/str_utils.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/str_utils.h
new file mode 100644
index 00000000..b605fc2a
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/str_utils.h
@@ -0,0 +1,118 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef STR_UTILS_H
+#define STR_UTILS_H
+
+
+#include <rtpport.h>
+
+
+typedef struct msgb
+{
+ struct msgb *b_prev;
+ struct msgb *b_next;
+ struct msgb *b_cont;
+ struct datab *b_datap;
+ char *b_rptr;
+ char *b_wptr;
+} mblk_t;
+
+typedef struct datab
+{
+ char *db_base;
+ char *db_lim;
+ void (*db_freefn)(void*);
+ guint ref_count;
+} dblk_t;
+
+typedef struct _queue
+{
+ mblk_t _q_first;
+ mblk_t _q_last;
+ gint q_mcount; /*number of packet in the q */
+} queue_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void qinit(queue_t *q);
+
+void putq(queue_t *q, mblk_t *m);
+mblk_t * getq(queue_t *q);
+
+void insq(queue_t *q,mblk_t *emp, mblk_t *mp);
+
+void remq(queue_t *q, mblk_t *mp);
+
+void mblk_init(mblk_t *mp);
+
+/* allocates a mblk_t, that points to a datab_t, that points to a buffer of size size. */
+mblk_t *allocb(gint size,gint unused);
+#define BPRI_MED 0
+
+/* allocates a mblk_t, that points to a datab_t, that points to buf; buf will be freed using freefn */
+mblk_t *allocb_with_buf(char *buf, int size, int pri, void (*freefn)(void*) );
+
+/* frees a mblk_t, and if the datab ref_count is 0, frees it and the buffer too */
+void freeb(mblk_t *m);
+
+/* frees recursively (follow b_cont) a mblk_t, and if the datab
+ref_count is 0, frees it and the buffer too */
+void freemsg(mblk_t *mp);
+
+/* duplicates a mblk_t , buffer is not duplicated*/
+mblk_t *dupb(mblk_t *m);
+
+/* duplicates a complex mblk_t, buffer is not duplicated */
+mblk_t *dupmsg(mblk_t* m);
+
+/* remove and free all messages in the q */
+#define FLUSHALL 0
+void flushq(queue_t *q, int how);
+
+/* returns the size of data of a message */
+gint msgdsize(mblk_t *mp);
+
+/* concatenates all fragment of a complex message ( a new message is returned, old is untouched*/
+mblk_t * msgpullup(mblk_t *mp,int len);
+
+/* duplicates a single message, but with buffer included */
+mblk_t *copyb(mblk_t *mp);
+
+/* duplicates a complex message with buffer included */
+mblk_t *copymsg(mblk_t *mp);
+
+mblk_t * appendb(mblk_t *mp, const char *data, int size, gboolean pad);
+void msgappend(mblk_t *mp, const char *data, int size, gboolean pad);
+
+mblk_t *concatb(mblk_t *mp, mblk_t *newm);
+
+#define qempty(q) (&(q)->_q_last==(q)->_q_first.b_next)
+#define qfirst(q) ((q)->_q_first.b_next!=&(q)->_q_last ? (q)->_q_first.b_next : NULL)
+#define qbegin(q) ((q)->_q_first.b_next)
+#define qlast(q) ((q)->_q_last.b_prev!=&(q)->_q_first ? (q)->_q_last.b_prev : NULL)
+#define qend(q,mp) ((mp)==&(q)->_q_first || ((mp)==&(q)->_q_last))
+#define qnext(q,mp) ((mp)->b_next)
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/telephonyevents.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/telephonyevents.c
new file mode 100644
index 00000000..884226ea
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/telephonyevents.c
@@ -0,0 +1,338 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <telephonyevents.h>
+
+
+PayloadType telephone_event={
+ PAYLOAD_AUDIO_PACKETIZED, /*type */
+ 8000, /*clock rate */
+ 0, /* bytes per sample N/A */
+ NULL, /* zero pattern N/A*/
+ 0, /*pattern_length N/A */
+ 0, /* normal_bitrate */
+ "telephone-event",
+ 0 /*flags */
+};
+
+/* tell if the session supports telephony events. For this the telephony events payload_type
+ must be present in the rtp profile used by the session */
+/**
+ *rtp_session_telephone_events_supported:
+ *@session : a rtp session
+ *
+ * Tells whether telephony events payload type is supported within the context of the rtp
+ * session.
+ *
+ *Returns: the payload type number used for telephony events if found, -1 if not found.
+**/
+gint rtp_session_telephone_events_supported(RtpSession *session)
+{
+ /* search for a telephony event payload in the current profile */
+ session->telephone_events_pt=rtp_profile_get_payload_number_from_mime(session->profile,"telephone-event");
+ return session->telephone_events_pt;
+}
+
+
+/**
+ *rtp_session_create_telephone_event_packet:
+ *@session: a rtp session.
+ *@start: boolean to indicate if the marker bit should be set.
+ *
+ * Allocates a new rtp packet to be used to add named telephony events. The application can use
+ * then rtp_session_add_telephone_event() to add named events to the packet.
+ * Finally the packet has to be sent with rtp_session_sendm_with_ts().
+ *
+ *Returns: a message block containing the rtp packet if successfull, NULL if the rtp session
+ *cannot support telephony event (because the rtp profile it is bound to does not include
+ *a telephony event payload type).
+**/
+mblk_t *rtp_session_create_telephone_event_packet(RtpSession *session, int start)
+{
+ mblk_t *mp;
+ rtp_header_t *rtp;
+
+ g_return_val_if_fail(session->telephone_events_pt!=-1,NULL);
+
+ mp=allocb(RTP_FIXED_HEADER_SIZE+TELEPHONY_EVENTS_ALLOCATED_SIZE,BPRI_MED);
+ if (mp==NULL) return NULL;
+ rtp=(rtp_header_t*)mp->b_rptr;
+ rtp->version = 2;
+ rtp->markbit=start;
+ rtp->padbit = 0;
+ rtp->extbit = 0;
+ rtp->cc = 0;
+ rtp->ssrc = session->send_ssrc;
+ /* timestamp set later, when packet is sended */
+ /*seq number set later, when packet is sended */
+
+ /*set the payload type */
+ rtp->paytype=session->telephone_events_pt;
+
+ /*copy the payload */
+ mp->b_wptr+=RTP_FIXED_HEADER_SIZE;
+ return mp;
+}
+
+
+/**
+ *rtp_session_add_telephone_event:
+ *@session: a rtp session.
+ *@packet: a rtp packet as a #mblk_t
+ *@event: the event type as described in rfc2833, ie one of the TEV_ macros.
+ *@end: boolean to indicate if the end bit should be set. (end of tone)
+ *@volume: the volume of the telephony tone, as described in rfc2833
+ *@duration:the duration of the telephony tone, in timestamp unit.
+ *
+ * Adds a named telephony event to a rtp packet previously allocated using
+ * rtp_session_create_telephone_event_packet().
+ *
+ *Returns 0 on success.
+**/
+gint rtp_session_add_telephone_event(RtpSession *session,
+ mblk_t *packet, guchar event, gint end, guchar volume, guint16 duration)
+{
+ mblk_t *mp=packet;
+ telephone_event_t *event_hdr;
+
+
+ /* find the place where to add the new telephony event to the packet */
+ while(mp->b_cont!=NULL) mp=mp->b_cont;
+ /* see if we need to allocate a new mblk_t */
+ if ( (long)mp->b_wptr >= (long) mp->b_datap->db_lim){
+ mblk_t *newm=allocb(TELEPHONY_EVENTS_ALLOCATED_SIZE,BPRI_MED);
+ mp->b_cont=newm;
+ mp=mp->b_cont;
+ }
+ if (mp==NULL) return -1;
+ event_hdr=(telephone_event_t*)mp->b_wptr;
+ event_hdr->event=event;
+ event_hdr->R=0;
+ event_hdr->E=end;
+ event_hdr->volume=volume;
+ event_hdr->duration=htons(duration);
+ mp->b_wptr+=sizeof(telephone_event_t);
+ return 0;
+}
+/**
+ *rtp_session_send_dtmf:
+ *@session : a rtp session
+ *@dtmf : a character meaning the dtmf (ex: '1', '#' , '9' ...)
+ *@userts : the timestamp
+ *
+ * This functions creates telephony events packets for @dtmf and sends them.
+ * It uses rtp_session_create_telephone_event_packet() and
+ * rtp_session_add_telephone_event() to create them and finally
+ * rtp_session_sendm_with_ts() to send them.
+ *
+ *Returns: 0 if successfull, -1 if the session cannot support telephony events or if the dtmf
+ * given as argument is not valid.
+**/
+gint rtp_session_send_dtmf(RtpSession *session, gchar dtmf, guint32 userts)
+{
+ mblk_t *m1,*m2,*m3;
+ int tev_type;
+ /* create the first telephony event packet */
+ switch (dtmf){
+ case '1':
+ tev_type=TEV_DTMF_1;
+ break;
+ case '2':
+ tev_type=TEV_DTMF_2;
+ break;
+ case '3':
+ tev_type=TEV_DTMF_3;
+ break;
+ case '4':
+ tev_type=TEV_DTMF_4;
+ break;
+ case '5':
+ tev_type=TEV_DTMF_5;
+ break;
+ case '6':
+ tev_type=TEV_DTMF_6;
+ break;
+ case '7':
+ tev_type=TEV_DTMF_7;
+ break;
+ case '8':
+ tev_type=TEV_DTMF_8;
+ break;
+ case '9':
+ tev_type=TEV_DTMF_9;
+ break;
+ case '*':
+ tev_type=TEV_DTMF_STAR;
+ break;
+ case '0':
+ tev_type=TEV_DTMF_0;
+ break;
+ case '#':
+ tev_type=TEV_DTMF_POUND;
+ break;
+ default:
+ g_warning("Bad dtmf: %c.",dtmf);
+ return -1;
+ }
+
+ m1=rtp_session_create_telephone_event_packet(session,1);
+ if (m1==NULL) return -1;
+ rtp_session_add_telephone_event(session,m1,tev_type,0,0,160);
+ /* create a second packet */
+ m2=rtp_session_create_telephone_event_packet(session,0);
+ if (m2==NULL) return -1;
+ rtp_session_add_telephone_event(session,m2,tev_type,0,0,320);
+
+ /* create a third and final packet */
+ m3=rtp_session_create_telephone_event_packet(session,0);
+ if (m3==NULL) return -1;
+ rtp_session_add_telephone_event(session,m3,tev_type,1,0,480);
+
+ /* and now sends them */
+ rtp_session_sendm_with_ts(session,m1,userts);
+ rtp_session_sendm_with_ts(session,m2,userts);
+ /* the last packet is sent three times in order to improve reliability*/
+ m1=copymsg(m3);
+ m2=copymsg(m3);
+ /* NOTE: */
+ /* we need to copymsg() instead of dupmsg() because the buffers are modified when
+ the packet is sended because of the host-to-network conversion of timestamp,ssrc, csrc, and
+ seq number.
+ It could be avoided by making a copy of the buffer when sending physically the packet, but
+ it add one more copy for every buffer.
+ Using iomapped socket, it is possible to avoid the user to kernel copy.
+ */
+ rtp_session_sendm_with_ts(session,m3,userts);
+ rtp_session_sendm_with_ts(session,m1,userts);
+ rtp_session_sendm_with_ts(session,m2,userts);
+ return 0;
+}
+
+/**
+ *rtp_session_read_telephone_event:
+ *@session: a rtp session from which telephony events are received.
+ *@packet: a rtp packet as a mblk_t.
+ *@tab: the address of a pointer.
+ *
+ * Reads telephony events from a rtp packet. *@tab points to the beginning of the event buffer.
+ *
+ *Returns: the number of events in the packet if successfull, 0 if the packet did not
+ * contain telephony events.
+**/
+gint rtp_session_read_telephone_event(RtpSession *session,
+ mblk_t *packet,telephone_event_t **tab)
+{
+ int datasize;
+ gint num;
+ int i;
+ telephone_event_t *tev;
+ rtp_header_t *hdr=(rtp_header_t*)packet->b_rptr;
+ g_return_val_if_fail(packet->b_cont!=NULL,-1);
+ if (hdr->paytype!=session->telephone_events_pt) return 0; /* this is not tel ev.*/
+ datasize=msgdsize(packet);
+ tev=*tab=(telephone_event_t*)packet->b_cont->b_rptr;
+ /* convert from network to host order what should be */
+ num=datasize/sizeof(telephone_event_t);
+ for (i=0;i<num;i++)
+ {
+ tev[i].duration=ntohs(tev[i].duration);
+ }
+ return num;
+}
+
+
+static void notify_events_ended(RtpSession *session, telephone_event_t *events, int num){
+ int i;
+ for (i=0;i<num;i++){
+ if (events[i].E==1){
+ rtp_signal_table_emit2(&session->on_telephone_event,(gpointer)(long)events[i].event);
+ }
+ }
+}
+
+/* for high level telephony event callback */
+void rtp_session_check_telephone_events(RtpSession *session, mblk_t *m0)
+{
+ telephone_event_t *events,*evbuf;
+ int num;
+ int i;
+ mblk_t *mp;
+ rtp_header_t *hdr;
+ mblk_t *cur_tev;
+
+ hdr=(rtp_header_t*)m0->b_rptr;
+ mp=m0->b_cont;
+
+ num=(mp->b_wptr-mp->b_rptr)/sizeof(telephone_event_t);
+ events=(telephone_event_t*)mp->b_rptr;
+
+
+ if (hdr->markbit==1)
+ {
+ /* this is a start of new events. Store the event buffer for later use*/
+ if (session->current_tev!=NULL) {
+ freemsg(session->current_tev);
+ session->current_tev=NULL;
+ }
+ session->current_tev=copymsg(m0);
+ /* handle the case where the events are short enough to end within the packet that has the marker bit*/
+ notify_events_ended(session,events,num);
+ }
+ /* whatever there is a markbit set or not, we parse the packet and compare it to previously received one */
+ cur_tev=session->current_tev;
+ if (cur_tev!=NULL)
+ {
+ /* first compare timestamp, they must be identical */
+ if (((rtp_header_t*)cur_tev->b_rptr)->timestamp==
+ ((rtp_header_t*)m0->b_rptr)->timestamp)
+ {
+ evbuf=(telephone_event_t*)cur_tev->b_cont;
+ for (i=0;i<num;i++)
+ {
+ if (events[i].E==1)
+ {
+ /* update events that have ended */
+ if (evbuf[i].E==0){
+ evbuf[i].E=1;
+ /* this is a end of event, report it */
+ rtp_signal_table_emit2(&session->on_telephone_event,(gpointer)(long)events[i].event);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* timestamp are not identical: this is not the same events*/
+ if (session->current_tev!=NULL) {
+ freemsg(session->current_tev);
+ session->current_tev=NULL;
+ }
+ session->current_tev=dupmsg(m0);
+ }
+ }
+ else
+ {
+ /* there is no pending events, but we did not received marked bit packet
+ either the sending implementation is not compliant, either it has been lost,
+ we must deal with it anyway.*/
+ session->current_tev=copymsg(m0);
+ /* inform the application if there are tone ends */
+ notify_events_ended(session,events,num);
+ }
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/telephonyevents.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/telephonyevents.h
new file mode 100644
index 00000000..6f6936d5
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/telephonyevents.h
@@ -0,0 +1,98 @@
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef TELEPHONYEVENTS_H
+#define TELEPHONYEVENTS_H
+
+
+#include <rtpsession.h>
+
+
+struct _telephone_event
+{
+#ifdef WORDS_BIGENDIAN
+ guint32 event:8;
+ guint32 E:1;
+ guint32 R:1;
+ guint32 volume:6;
+ guint32 duration:16;
+#else
+ guint32 event:8;
+ guint32 volume:6;
+ guint32 R:1;
+ guint32 E:1;
+ guint32 duration:16;
+#endif
+};
+
+typedef struct _telephone_event telephone_event_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern PayloadType telephone_event;
+
+/* tell if the session supports telephony events. For this the telephony events payload_type
+ must be present in the rtp profile used by the session */
+
+/* low level functions */
+gint rtp_session_telephone_events_supported(RtpSession *session);
+
+mblk_t *rtp_session_create_telephone_event_packet(RtpSession *session, int start);
+
+gint rtp_session_add_telephone_event(RtpSession *session,
+ mblk_t *packet, guchar event, gint end, guchar volume, guint16 duration);
+
+gint rtp_session_read_telephone_event(RtpSession *session,
+ mblk_t *packet,telephone_event_t **tab);
+
+/* high level functions*/
+gint rtp_session_send_dtmf(RtpSession *session, gchar dtmf, guint32 userts);
+/* for high level telephony event callback */
+void rtp_session_check_telephone_events(RtpSession *session, mblk_t *m0);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* the size allocated for telephony events packets */
+#define TELEPHONY_EVENTS_ALLOCATED_SIZE (4*sizeof(telephone_event_t))
+
+/* list of named events */
+#define TEV_DTMF_0 (0)
+#define TEV_DTMF_1 (1)
+#define TEV_DTMF_2 (2)
+#define TEV_DTMF_3 (3)
+#define TEV_DTMF_4 (4)
+#define TEV_DTMF_5 (5)
+#define TEV_DTMF_6 (6)
+#define TEV_DTMF_7 (7)
+#define TEV_DTMF_8 (8)
+#define TEV_DTMF_9 (9)
+#define TEV_DTMF_STAR (10)
+#define TEV_DTMF_POUND (11)
+#define TEV_DTMF_A (12)
+#define TEV_DTMF_B (13)
+#define TEV_DTMF_C (14)
+#define TEV_DTMF_D (15)
+#define TEV_FLASH (16)
+
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/utils.c b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/utils.c
new file mode 100644
index 00000000..1ae601f4
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/utils.c
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * utils.c
+ *
+ * Wed Feb 23 14:15:36 2005
+ * Copyright 2005 Simon Morlat
+ * Email simon.morlat@linphone.org
+ ****************************************************************************/
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <rtpport.h>
+#include "utils.h"
+
+OList *o_list_new(void *data){
+ OList *new_elem=g_new0(OList,1);
+ new_elem->data=data;
+ return new_elem;
+}
+
+OList * o_list_append(OList *elem, void * data){
+ OList *new_elem=o_list_new(data);
+ OList *it=elem;
+ if (elem==NULL) return new_elem;
+ while (it->next!=NULL) it=o_list_next(it);
+ it->next=new_elem;
+ new_elem->prev=it;
+ return elem;
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/utils.h b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/utils.h
new file mode 100644
index 00000000..7b71daf8
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/third_party/ortp/utils.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * utils.h
+ *
+ * Wed Feb 23 14:15:36 2005
+ * Copyright 2005 Simon Morlat
+ * Email simon.morlat@linphone.org
+ ****************************************************************************/
+/*
+ The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
+ Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef UTILS_H
+#define UTILS_H
+
+struct _OList {
+ struct _OList *next;
+ struct _OList *prev;
+ void *data;
+};
+
+typedef struct _OList OList;
+
+
+#define o_list_next(elem) ((elem)->next)
+
+OList * o_list_append(OList *elem, void * data);
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/CMakeLists.txt
new file mode 100644
index 00000000..8b2e72d4
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmllite/CMakeLists.txt
@@ -0,0 +1,28 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions(
+ -DPOSIX
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../..
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### cricketxmllite (static) ###################
+
+tde_add_library( cricketxmllite STATIC_PIC
+ SOURCES
+ qname.cc xmlbuilder.cc xmlconstants.cc xmlelement.cc xmlnsstack.cc
+ xmlparser.cc xmlprinter.cc
+)
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/CMakeLists.txt
new file mode 100644
index 00000000..c68cc840
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/CMakeLists.txt
@@ -0,0 +1,29 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions(
+ -DPOSIX
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../..
+ ${CMAKE_BINARY_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### cricketxmpp (static) ######################
+
+tde_add_library( cricketxmpp STATIC_PIC
+ SOURCES
+ constants.cc jid.cc saslmechanism.cc xmppclient.cc xmppengineimpl.cc
+ xmppengineimpl_iq.cc xmpplogintask.cc xmppstanzaparser.cc xmpptask.cc
+)
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h
index f431b4e5..7a58cd6c 100644
--- a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h
@@ -31,6 +31,8 @@
#include "talk/base/linked_ptr.h"
#include "talk/base/scoped_ptr.h"
+#include <cstring>
+
namespace buzz {
class XmppPasswordImpl {
diff --git a/kopete/protocols/jabber/kioslave/CMakeLists.txt b/kopete/protocols/jabber/kioslave/CMakeLists.txt
new file mode 100644
index 00000000..12fa4173
--- /dev/null
+++ b/kopete/protocols/jabber/kioslave/CMakeLists.txt
@@ -0,0 +1,42 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/iris/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/iris/jabber
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/iris/xmpp-im
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/cutestuff/util
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES jabberdisco.protocol DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kio_jabberdisco (module) ##################
+
+tde_add_kpart( kio_jabberdisco AUTOMOC
+ SOURCES jabberdisco.cpp
+ LINK
+ jabberclient-static
+ iris_xmpp_core-static iris_xmpp_im-static iris_jabber-static iris-static
+ qca-static cutestuff_network-static cutestuff_util-static kio-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/jabber/libiris/CMakeLists.txt b/kopete/protocols/jabber/libiris/CMakeLists.txt
new file mode 100644
index 00000000..6c649aa5
--- /dev/null
+++ b/kopete/protocols/jabber/libiris/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( iris )
+add_subdirectory( qca )
+add_subdirectory( cutestuff )
diff --git a/kopete/protocols/jabber/libiris/cutestuff/CMakeLists.txt b/kopete/protocols/jabber/libiris/cutestuff/CMakeLists.txt
new file mode 100644
index 00000000..4f8cce38
--- /dev/null
+++ b/kopete/protocols/jabber/libiris/cutestuff/CMakeLists.txt
@@ -0,0 +1,13 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( network )
+add_subdirectory( util )
diff --git a/kopete/protocols/jabber/libiris/cutestuff/network/CMakeLists.txt b/kopete/protocols/jabber/libiris/cutestuff/network/CMakeLists.txt
new file mode 100644
index 00000000..151dd407
--- /dev/null
+++ b/kopete/protocols/jabber/libiris/cutestuff/network/CMakeLists.txt
@@ -0,0 +1,27 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../util
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../qca/src
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### cutestuff_network (static) ################
+
+tde_add_library( cutestuff_network STATIC_PIC AUTOMOC
+ SOURCES
+ bsocket.cpp httpconnect.cpp httppoll.cpp ndns.cpp servsock.cpp
+ socks.cpp srvresolver.cpp
+)
diff --git a/kopete/protocols/jabber/libiris/cutestuff/util/CMakeLists.txt b/kopete/protocols/jabber/libiris/cutestuff/util/CMakeLists.txt
new file mode 100644
index 00000000..13d55ca8
--- /dev/null
+++ b/kopete/protocols/jabber/libiris/cutestuff/util/CMakeLists.txt
@@ -0,0 +1,24 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### cutestuff_util (static) ###################
+
+tde_add_library( cutestuff_util STATIC_PIC AUTOMOC
+ SOURCES
+ base64.cpp bytestream.cpp qrandom.cpp safedelete.cpp sha1.cpp
+ showtextdlg.cpp
+)
diff --git a/kopete/protocols/jabber/libiris/iris/CMakeLists.txt b/kopete/protocols/jabber/libiris/iris/CMakeLists.txt
new file mode 100644
index 00000000..d5062694
--- /dev/null
+++ b/kopete/protocols/jabber/libiris/iris/CMakeLists.txt
@@ -0,0 +1,15 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( include )
+add_subdirectory( jabber )
+add_subdirectory( xmpp-core )
+add_subdirectory( xmpp-im )
diff --git a/kopete/protocols/jabber/libiris/iris/include/CMakeLists.txt b/kopete/protocols/jabber/libiris/iris/include/CMakeLists.txt
new file mode 100644
index 00000000..ff84643b
--- /dev/null
+++ b/kopete/protocols/jabber/libiris/iris/include/CMakeLists.txt
@@ -0,0 +1,24 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### iris (static) #############################
+
+tde_moc( SRCS im.h xmpp.h )
+
+tde_add_library( iris STATIC_PIC
+ SOURCES ${SRCS}
+)
diff --git a/kopete/protocols/jabber/libiris/iris/jabber/CMakeLists.txt b/kopete/protocols/jabber/libiris/iris/jabber/CMakeLists.txt
new file mode 100644
index 00000000..e73563f2
--- /dev/null
+++ b/kopete/protocols/jabber/libiris/iris/jabber/CMakeLists.txt
@@ -0,0 +1,40 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include
+ ${CMAKE_CURRENT_SOURCE_DIR}/../xmpp-im
+ ${CMAKE_CURRENT_SOURCE_DIR}/../xmpp-core
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../cutestuff/util
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../cutestuff/network
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../qca/src
+ ${CMAKE_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### iris_jabber (static) ######################
+
+add_custom_command( OUTPUT s5b.moc
+ COMMAND ${TMOC_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/s5b.cpp -o s5b.moc.cpp
+ COMMAND ${TMOC_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/s5b.h -o s5b.moc.h
+ COMMAND sed -i -e '/^\#include/d' s5b.moc.cpp
+ COMMAND cat s5b.moc.h s5b.moc.cpp > s5b.moc
+ DEPENDS s5b.cpp )
+
+set_source_files_properties( s5b.cpp PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/s5b.moc )
+
+tde_add_library( iris_jabber STATIC_PIC AUTOMOC
+ SOURCES
+ filetransfer.cpp s5b.cpp xmpp_ibb.cpp xmpp_jidlink.cpp all_mocs.cpp
+)
diff --git a/kopete/protocols/jabber/libiris/iris/xmpp-core/CMakeLists.txt b/kopete/protocols/jabber/libiris/iris/xmpp-core/CMakeLists.txt
new file mode 100644
index 00000000..4361f30e
--- /dev/null
+++ b/kopete/protocols/jabber/libiris/iris/xmpp-core/CMakeLists.txt
@@ -0,0 +1,38 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../qca/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../cutestuff/util
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../cutestuff/network
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### iris_xmpp_core (static) ########################
+
+add_custom_command( OUTPUT securestream.moc
+ COMMAND ${TMOC_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/securestream.cpp -o securestream.moc.cpp
+ COMMAND ${TMOC_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/securestream.h -o securestream.moc.h
+ COMMAND sed -i -e '/^\#include/d' securestream.moc.cpp
+ COMMAND cat securestream.moc.h securestream.moc.cpp > securestream.moc
+ DEPENDS securestream.cpp )
+
+set_source_files_properties( securestream.cpp PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/securestream.moc )
+
+tde_add_library( iris_xmpp_core STATIC_PIC
+ SOURCES
+ connector.cpp jid.cpp securestream.cpp tlshandler.cpp hash.cpp
+ protocol.cpp stream.cpp xmlprotocol.cpp parser.cpp simplesasl.cpp
+)
diff --git a/kopete/protocols/jabber/libiris/iris/xmpp-im/CMakeLists.txt b/kopete/protocols/jabber/libiris/iris/xmpp-im/CMakeLists.txt
new file mode 100644
index 00000000..58a1a034
--- /dev/null
+++ b/kopete/protocols/jabber/libiris/iris/xmpp-im/CMakeLists.txt
@@ -0,0 +1,37 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include
+ ${CMAKE_CURRENT_SOURCE_DIR}/../jabber
+ ${CMAKE_CURRENT_SOURCE_DIR}/../xmpp-core
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../cutestuff/util
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### iris_xmpp_im (static) #####################
+
+add_custom_command( OUTPUT types.moc
+ COMMAND ${TMOC_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/types.cpp -o types.moc
+ COMMAND sed -i -e '/^\#include \"/d' types.moc
+ DEPENDS types.cpp )
+
+set_source_files_properties( types.cpp PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/types.moc )
+
+tde_moc( MOCS xmpp_tasks.h )
+
+tde_add_library( iris_xmpp_im STATIC_PIC
+ SOURCES
+ client.cpp types.cpp xmpp_tasks.cpp xmpp_vcard.cpp xmpp_xmlcommon.cpp ${MOCS}
+)
diff --git a/kopete/protocols/jabber/libiris/qca/CMakeLists.txt b/kopete/protocols/jabber/libiris/qca/CMakeLists.txt
new file mode 100644
index 00000000..7356f221
--- /dev/null
+++ b/kopete/protocols/jabber/libiris/qca/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( src )
diff --git a/kopete/protocols/jabber/libiris/qca/src/CMakeLists.txt b/kopete/protocols/jabber/libiris/qca/src/CMakeLists.txt
new file mode 100644
index 00000000..46de2435
--- /dev/null
+++ b/kopete/protocols/jabber/libiris/qca/src/CMakeLists.txt
@@ -0,0 +1,22 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### qca (static) ##############################
+
+tde_add_library( qca STATIC_PIC AUTOMOC
+ SOURCES qca.cpp
+)
diff --git a/kopete/protocols/jabber/ui/CMakeLists.txt b/kopete/protocols/jabber/ui/CMakeLists.txt
new file mode 100644
index 00000000..a4488d62
--- /dev/null
+++ b/kopete/protocols/jabber/ui/CMakeLists.txt
@@ -0,0 +1,43 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../libkopete/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/iris/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/iris/jabber
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/iris/xmpp-im
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/qca/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/../libiris/cutestuff/util
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../libkopete
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../libkopete/ui
+ ${CMAKE_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopetejabberui (static) ###################
+
+tde_add_library( kopetejabberui STATIC_PIC AUTOMOC
+ SOURCES
+ dlgsendraw.ui dlgjabbersendraw.cpp dlgaddcontact.ui
+ jabberaddcontactpage.cpp dlgvcard.ui dlgjabbervcard.cpp
+ dlgjabberservices.cpp dlgregister.ui dlgjabberregister.cpp
+ dlgbrowse.ui dlgjabberbrowse.cpp dlgjabbereditaccountwidget.ui
+ jabbereditaccountwidget.cpp dlgjabberregisteraccount.ui
+ jabberregisteraccount.cpp dlgjabberchooseserver.ui
+ jabberchooseserver.cpp dlgchangepassword.ui
+ dlgjabberchangepassword.cpp empty.cpp dlgchatroomslist.ui
+ dlgjabberchatroomslist.cpp dlgchatjoin.ui dlgjabberchatjoin.cpp
+ dlgservices.ui
+)
diff --git a/kopete/protocols/meanwhile/CMakeLists.txt b/kopete/protocols/meanwhile/CMakeLists.txt
new file mode 100644
index 00000000..994f6e31
--- /dev/null
+++ b/kopete/protocols/meanwhile/CMakeLists.txt
@@ -0,0 +1,47 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include( ConfigureChecks.cmake )
+
+add_subdirectory( ui )
+add_subdirectory( icons )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+ ${MEANWHILE_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_meanwhile.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### new_target0 (module) #######################
+
+tde_add_kpart( new_target0 AUTOMOC
+ SOURCES
+ meanwhileprotocol.cpp meanwhileaddcontactpage.cpp
+ meanwhileeditaccountwidget.cpp meanwhileaccount.cpp
+ meanwhilecontact.cpp meanwhilesession.cpp meanwhileplugin.cpp
+ LINK kopetemeanwhileui-static kopete-shared ${MEANWHILE_LIBRARIES}
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/meanwhile/ConfigureChecks.cmake b/kopete/protocols/meanwhile/ConfigureChecks.cmake
new file mode 100644
index 00000000..58d8c67f
--- /dev/null
+++ b/kopete/protocols/meanwhile/ConfigureChecks.cmake
@@ -0,0 +1,15 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+pkg_search_module( MEANWHILE meanwhile )
+if( NOT MEANWHILE_FOUND )
+ tde_message_fatal( "meanwhile is required, but was not found on your system" )
+endif( )
diff --git a/kopete/protocols/meanwhile/icons/CMakeLists.txt b/kopete/protocols/meanwhile/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/protocols/meanwhile/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/protocols/meanwhile/ui/CMakeLists.txt b/kopete/protocols/meanwhile/ui/CMakeLists.txt
new file mode 100644
index 00000000..434f849b
--- /dev/null
+++ b/kopete/protocols/meanwhile/ui/CMakeLists.txt
@@ -0,0 +1,27 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopetemeanwhileui (static) ################
+
+tde_add_library( kopetemeanwhileui STATIC_PIC AUTOMOC
+ SOURCES
+ empty.cpp meanwhileeditaccountbase.ui meanwhileaddcontactbase.ui
+)
diff --git a/kopete/protocols/msn/CMakeLists.txt b/kopete/protocols/msn/CMakeLists.txt
new file mode 100644
index 00000000..77bd2cc7
--- /dev/null
+++ b/kopete/protocols/msn/CMakeLists.txt
@@ -0,0 +1,71 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( ui )
+add_subdirectory( icons )
+add_subdirectory( config )
+
+if( WITH_WEBCAM )
+ add_subdirectory( webcam )
+ add_definitions( -DMSN_WEBCAM )
+ set( WEBCAM_LIBRARIES mimicwrapper-static kopete_videodevice-shared ${GLIB2_LIBRARIES} )
+endif( )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}/webcam
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_msn.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES msnchatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_msn )
+
+
+##### kopete_msn (module) #######################
+
+tde_add_kpart( kopete_msn AUTOMOC
+ SOURCES
+ dummy.cpp webcam.cpp
+ LINK kopete_msn_shared-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kopete_msn_shared (shared) ################
+
+tde_add_library( kopete_msn_shared SHARED AUTOMOC
+ SOURCES
+ msnprotocol.cpp msnaccount.cpp msnaddcontactpage.cpp msncontact.cpp
+ msnsocket.cpp msnchatsession.cpp msndebugrawcmddlg.cpp
+ msnnotifysocket.cpp msnswitchboardsocket.cpp
+ msnfiletransfersocket.cpp msninvitation.cpp sha1.cpp
+ msnsecureloginhandler.cpp msnchallengehandler.cpp
+ dispatcher.cpp p2p.cpp messageformatter.cpp incomingtransfer.cpp
+ outgoingtransfer.cpp webcam.cpp
+ VERSION 0.0.0
+ LINK
+ kopetemsnui-static ${WEBCAM_LIBRARIES} kopete-shared
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/kopete/protocols/msn/config/CMakeLists.txt b/kopete/protocols/msn/config/CMakeLists.txt
new file mode 100644
index 00000000..7e0d1337
--- /dev/null
+++ b/kopete/protocols/msn/config/CMakeLists.txt
@@ -0,0 +1,38 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES
+ kopete_msn_config.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR}/kconfiguredialog )
+
+
+##### kcm_kopete_msn (module) ###################
+
+tde_add_kpart( kcm_kopete_msn AUTOMOC
+ SOURCES
+ msnprefs.ui msnpreferences.cpp
+ LINK kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/msn/icons/CMakeLists.txt b/kopete/protocols/msn/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/protocols/msn/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/protocols/msn/ui/CMakeLists.txt b/kopete/protocols/msn/ui/CMakeLists.txt
new file mode 100644
index 00000000..bd70ce80
--- /dev/null
+++ b/kopete/protocols/msn/ui/CMakeLists.txt
@@ -0,0 +1,29 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopetemsnui (static) ######################
+
+tde_add_library( kopetemsnui STATIC_PIC AUTOMOC
+ SOURCES
+ msnadd.ui msndebugrawcommand_base.ui msninfo.ui msneditaccountui.ui
+ msneditaccountwidget.cpp
+)
diff --git a/kopete/protocols/msn/webcam/CMakeLists.txt b/kopete/protocols/msn/webcam/CMakeLists.txt
new file mode 100644
index 00000000..aafa2d94
--- /dev/null
+++ b/kopete/protocols/msn/webcam/CMakeLists.txt
@@ -0,0 +1,28 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( libmimic )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+ ${GLIB2_INCLUDE_DIRS}
+)
+
+
+##### mimicwrapper (static) #####################
+
+tde_add_library( mimicwrapper STATIC_PIC AUTOMOC
+ SOURCES mimicwrapper.cpp msnwebcamdialog.cpp
+ LINK mimic-static
+)
diff --git a/kopete/protocols/msn/webcam/libmimic/CMakeLists.txt b/kopete/protocols/msn/webcam/libmimic/CMakeLists.txt
new file mode 100644
index 00000000..d98fc837
--- /dev/null
+++ b/kopete/protocols/msn/webcam/libmimic/CMakeLists.txt
@@ -0,0 +1,23 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${GLIB2_INCLUDE_DIRS}
+)
+
+
+##### mimic (static) ############################
+
+tde_add_library( mimic STATIC_PIC
+ SOURCES
+ mimic.c encode.c decode.c bitstring.c vlc_common.c vlc_encode.c
+ vlc_decode.c fdct_quant.c idct_dequant.c colorspace.c deblock.c
+)
diff --git a/kopete/protocols/oscar/CMakeLists.txt b/kopete/protocols/oscar/CMakeLists.txt
new file mode 100644
index 00000000..bbffa100
--- /dev/null
+++ b/kopete/protocols/oscar/CMakeLists.txt
@@ -0,0 +1,42 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( liboscar )
+add_subdirectory( aim )
+add_subdirectory( icq )
+add_subdirectory( icons )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/liboscar
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### kopete_oscar (shared) #####################
+
+tde_add_library( kopete_oscar SHARED AUTOMOC
+ SOURCES
+ oscaraccount.cpp oscarcontact.cpp oscarmyselfcontact.cpp
+ oscarencodingselectionbase.ui oscarencodingselectiondialog.cpp
+ oscarlistcontactsbase.ui oscarlistnonservercontacts.cpp
+ oscarvisibilitybase.ui oscarvisibilitydialog.cpp
+ oscarversionupdater.cpp
+ VERSION 2.0.0
+ LINK oscar-static kopete-shared
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/kopete/protocols/oscar/aim/CMakeLists.txt b/kopete/protocols/oscar/aim/CMakeLists.txt
new file mode 100644
index 00000000..75230df3
--- /dev/null
+++ b/kopete/protocols/oscar/aim/CMakeLists.txt
@@ -0,0 +1,47 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( ui )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../liboscar
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES
+ kopete_aim.desktop aim.protocol
+ DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kopete_aim (module) #######################
+
+tde_add_kpart( kopete_aim AUTOMOC
+ SOURCES
+ aimprotocol.cpp aimaccount.cpp aimcontact.cpp aimuserinfo.cpp
+ aimjoinchat.cpp aimchatsession.cpp
+ LINK
+ kopeteaimui-static kopete_oscar-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/oscar/aim/ui/CMakeLists.txt b/kopete/protocols/oscar/aim/ui/CMakeLists.txt
new file mode 100644
index 00000000..8f5ff329
--- /dev/null
+++ b/kopete/protocols/oscar/aim/ui/CMakeLists.txt
@@ -0,0 +1,31 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../liboscar
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopeteaimui (static) ######################
+
+tde_add_library( kopeteaimui STATIC_PIC AUTOMOC
+ SOURCES
+ aimaddcontactui.ui aimeditaccountui.ui aiminfobase.ui
+ aimjoinchatbase.ui aimaddcontactpage.cpp aimeditaccountwidget.cpp
+)
diff --git a/kopete/protocols/oscar/icons/CMakeLists.txt b/kopete/protocols/oscar/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/protocols/oscar/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/protocols/oscar/icq/CMakeLists.txt b/kopete/protocols/oscar/icq/CMakeLists.txt
new file mode 100644
index 00000000..20f8b11a
--- /dev/null
+++ b/kopete/protocols/oscar/icq/CMakeLists.txt
@@ -0,0 +1,45 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( ui )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../liboscar
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_icq.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+install( FILES x-icq.desktop DESTINATION ${MIME_INSTALL_DIR}/application )
+
+
+##### kopete_icq (module) #######################
+
+tde_add_kpart( kopete_icq AUTOMOC
+ SOURCES
+ icqpresence.cpp icqaccount.cpp icqcontact.cpp icqprotocol.cpp
+ LINK
+ kopeteicqui-static kopete_oscar-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/oscar/icq/ui/CMakeLists.txt b/kopete/protocols/oscar/icq/ui/CMakeLists.txt
new file mode 100644
index 00000000..9da3ac25
--- /dev/null
+++ b/kopete/protocols/oscar/icq/ui/CMakeLists.txt
@@ -0,0 +1,34 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../..
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../liboscar
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopeteicqui (static) ######################
+
+tde_add_library( kopeteicqui STATIC_PIC AUTOMOC
+ SOURCES
+ icqadd.ui icqeditaccountui.ui icqeditaccountwidget.cpp
+ icqgeneralinfo.ui icqotherinfowidget.ui icqworkinfowidget.ui
+ icqinterestinfowidget.ui icquserinfowidget.cpp icqauthreplyui.ui
+ icqauthreplydialog.cpp icqaddcontactpage.cpp icqsearchbase.ui
+ icqsearchdialog.cpp
+)
diff --git a/kopete/protocols/oscar/liboscar/CMakeLists.txt b/kopete/protocols/oscar/liboscar/CMakeLists.txt
new file mode 100644
index 00000000..6053541f
--- /dev/null
+++ b/kopete/protocols/oscar/liboscar/CMakeLists.txt
@@ -0,0 +1,46 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### oscar (static) ############################
+
+tde_add_library( oscar STATIC_PIC AUTOMOC
+ SOURCES
+ oscarutils.cpp client.cpp task.cpp connector.cpp
+ inputprotocolbase.cpp coreprotocol.cpp flapprotocol.cpp
+ snacprotocol.cpp transfer.cpp rtf.cc bytestream.cpp
+ oscarclientstream.cpp safedelete.cpp stream.cpp oscarconnector.cpp
+ oscarbytestream.cpp buffer.cpp md5.c logintask.cpp aimlogintask.cpp
+ icqlogintask.cpp closeconnectiontask.cpp rateclassmanager.cpp
+ serverversionstask.cpp rateinfotask.cpp errortask.cpp
+ locationrightstask.cpp profiletask.cpp blmlimitstask.cpp
+ servicesetuptask.cpp icbmparamstask.cpp ssimanager.cpp rateclass.cpp
+ rateclass.h prmparamstask.cpp ssiparamstask.cpp ssilisttask.cpp
+ ssiactivatetask.cpp clientreadytask.cpp senddcinfotask.cpp
+ sendidletimetask.cpp ownuserinfotask.cpp connection.cpp
+ onlinenotifiertask.cpp userdetails.cpp ssimodifytask.cpp
+ oscartypeclasses.cpp oscarmessage.cpp messagereceivertask.cpp
+ sendmessagetask.cpp icqtask.cpp offlinemessagestask.cpp
+ ssiauthtask.cpp userinfotask.cpp icquserinfo.cpp icquserinfotask.cpp
+ usersearchtask.cpp warningtask.cpp changevisibilitytask.cpp
+ typingnotifytask.cpp buddyicontask.cpp serverredirecttask.cpp
+ oscarsettings.cpp chatnavservicetask.cpp connectionhandler.cpp
+ chatservicetask.cpp
+)
diff --git a/kopete/protocols/sms/CMakeLists.txt b/kopete/protocols/sms/CMakeLists.txt
new file mode 100644
index 00000000..017ae01e
--- /dev/null
+++ b/kopete/protocols/sms/CMakeLists.txt
@@ -0,0 +1,48 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( ui )
+add_subdirectory( services )
+add_subdirectory( icons )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/services
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_sms.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kopete_sms (module) #######################
+
+tde_add_kpart( kopete_sms AUTOMOC
+ SOURCES
+ smsaddcontactpage.cpp smscontact.cpp smseditaccountwidget.cpp
+ smsprotocol.cpp serviceloader.cpp smsservice.cpp
+ smsuserpreferences.cpp smsaccount.cpp
+ LINK
+ kopetesmsui-static kopetesmsservices-static kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/sms/icons/CMakeLists.txt b/kopete/protocols/sms/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/protocols/sms/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/protocols/sms/services/CMakeLists.txt b/kopete/protocols/sms/services/CMakeLists.txt
new file mode 100644
index 00000000..c9942bd6
--- /dev/null
+++ b/kopete/protocols/sms/services/CMakeLists.txt
@@ -0,0 +1,32 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+# FIXME KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+include( ConfigureChecks.cmake )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopetesmsservices (static) ################
+
+tde_add_library( kopetesmsservices STATIC_PIC AUTOMOC
+ SOURCES
+ smssend.cpp smssendprefs.ui smssendprovider.cpp smsclient.cpp
+ smsclientprefs.ui gsmlib.cpp gsmlibprefs.ui kopete_unix_serial.cpp
+ LINK ${GSM_LIBRARY}
+)
diff --git a/kopete/protocols/sms/services/ConfigureChecks.cmake b/kopete/protocols/sms/services/ConfigureChecks.cmake
new file mode 100644
index 00000000..4ed454b4
--- /dev/null
+++ b/kopete/protocols/sms/services/ConfigureChecks.cmake
@@ -0,0 +1,30 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+if( WITH_GSM )
+
+ tde_save( CMAKE_REQUIRED_INCLUDES )
+ set( CMAKE_REQUIRED_INCLUDES ${TQT_INCLUDE_DIRS} )
+ check_include_file_cxx( gsmlib/gsm_util.h HAVE_GSMLIB_GSM_UTIL_H )
+ tde_restore( CMAKE_REQUIRED_INCLUDES )
+
+ if( HAVE_GSMLIB_GSM_UTIL_H )
+ set( INCLUDE_SMSGSM 1 )
+ find_library( GSM_LIBRARY gsmme )
+ endif( )
+
+ if( NOT (HAVE_GSMLIB_GSM_UTIL_H AND GSM_LIBRARY) )
+ tde_message_fatal( "gsmlib is required, but was not found on your system" )
+ endif( )
+
+endif( )
+
+configure_file( config.h.cmake config.h @ONLY )
diff --git a/kopete/protocols/sms/services/config.h.cmake b/kopete/protocols/sms/services/config.h.cmake
new file mode 100644
index 00000000..9555d535
--- /dev/null
+++ b/kopete/protocols/sms/services/config.h.cmake
@@ -0,0 +1 @@
+#cmakedefine INCLUDE_SMSGSM 1
diff --git a/kopete/protocols/sms/ui/CMakeLists.txt b/kopete/protocols/sms/ui/CMakeLists.txt
new file mode 100644
index 00000000..619f7a88
--- /dev/null
+++ b/kopete/protocols/sms/ui/CMakeLists.txt
@@ -0,0 +1,24 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopetesmsui (static) ######################
+
+tde_add_library( kopetesmsui STATIC_PIC AUTOMOC
+ SOURCES
+ smsadd.ui smsactprefs.ui smsuserprefs.ui empty.cpp
+)
diff --git a/kopete/protocols/testbed/CMakeLists.txt b/kopete/protocols/testbed/CMakeLists.txt
new file mode 100644
index 00000000..6052845a
--- /dev/null
+++ b/kopete/protocols/testbed/CMakeLists.txt
@@ -0,0 +1,44 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( icons )
+add_subdirectory( ui )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES kopete_testbed.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kopete_testbed (module) ###################
+
+tde_add_kpart( kopete_testbed AUTOMOC
+ SOURCES
+ testbedprotocol.cpp testbedcontact.cpp testbedaccount.cpp
+ testbedaddcontactpage.cpp testbedaddui.ui
+ testbededitaccountwidget.cpp testbedaccountpreferences.ui
+ testbedfakeserver.cpp testbedincomingmessage.cpp
+ LINK kopetetestbedui-static kopete-shared kopete_videodevice-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/testbed/icons/CMakeLists.txt b/kopete/protocols/testbed/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/protocols/testbed/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/protocols/testbed/testbedaccount.h b/kopete/protocols/testbed/testbedaccount.h
index 52261cb7..b58249c6 100644
--- a/kopete/protocols/testbed/testbedaccount.h
+++ b/kopete/protocols/testbed/testbedaccount.h
@@ -59,7 +59,7 @@ public:
/**
* 'Connect' to the testbed server. Only sets myself() online.
*/
- virtual void connect( const Kopete::OnlineStatus& initialStatus = Kopete::OnlineStatus::OnlineStatus() );
+ virtual void connect( const Kopete::OnlineStatus& initialStatus = Kopete::OnlineStatus() );
/**
* Disconnect from the server. Only sets myself() offline.
*/
diff --git a/kopete/protocols/testbed/ui/CMakeLists.txt b/kopete/protocols/testbed/ui/CMakeLists.txt
new file mode 100644
index 00000000..febe5b7b
--- /dev/null
+++ b/kopete/protocols/testbed/ui/CMakeLists.txt
@@ -0,0 +1,25 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopetetestbedui (static) ##################
+
+tde_add_library( kopetetestbedui STATIC_PIC AUTOMOC
+ SOURCES testbedwebcamdialog.cpp
+)
diff --git a/kopete/protocols/winpopup/CMakeLists.txt b/kopete/protocols/winpopup/CMakeLists.txt
new file mode 100644
index 00000000..e80e8e51
--- /dev/null
+++ b/kopete/protocols/winpopup/CMakeLists.txt
@@ -0,0 +1,51 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( ui )
+add_subdirectory( icons )
+add_subdirectory( libwinpopup )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_CURRENT_SOURCE_DIR}/libwinpopup
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES
+ kopete_wp.desktop
+ DESTINATION ${SERVICES_INSTALL_DIR} )
+
+install( PROGRAMS
+ winpopup-send.sh winpopup-install.sh
+ DESTINATION ${BIN_INSTALL_DIR} )
+
+
+##### kopete_wp (module) ########################
+
+tde_add_kpart( kopete_wp AUTOMOC
+ SOURCES
+ wpprotocol.cpp wpcontact.cpp wpaddcontact.cpp wpeditaccount.cpp
+ wpaccount.cpp wpuserinfo.cpp
+ LINK
+ kopetewpui-static winpopup-static kopete-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/winpopup/icons/CMakeLists.txt b/kopete/protocols/winpopup/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/protocols/winpopup/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/protocols/winpopup/libwinpopup/CMakeLists.txt b/kopete/protocols/winpopup/libwinpopup/CMakeLists.txt
new file mode 100644
index 00000000..4f11898b
--- /dev/null
+++ b/kopete/protocols/winpopup/libwinpopup/CMakeLists.txt
@@ -0,0 +1,24 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### winpopup (static) #########################
+
+tde_add_library( winpopup STATIC_PIC AUTOMOC
+ SOURCES libwinpopup.cpp
+)
diff --git a/kopete/protocols/winpopup/ui/CMakeLists.txt b/kopete/protocols/winpopup/ui/CMakeLists.txt
new file mode 100644
index 00000000..d73253ce
--- /dev/null
+++ b/kopete/protocols/winpopup/ui/CMakeLists.txt
@@ -0,0 +1,25 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopetewpui (static) #######################
+
+tde_add_library( kopetewpui STATIC_PIC AUTOMOC
+ SOURCES
+ wpaddcontactbase.ui wpeditaccountbase.ui empty.cpp
+ wpuserinfowidget.ui
+)
diff --git a/kopete/protocols/yahoo/CMakeLists.txt b/kopete/protocols/yahoo/CMakeLists.txt
new file mode 100644
index 00000000..124fc32a
--- /dev/null
+++ b/kopete/protocols/yahoo/CMakeLists.txt
@@ -0,0 +1,49 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( libkyahoo )
+add_subdirectory( ui )
+add_subdirectory( icons )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/ui
+ ${CMAKE_BINARY_DIR}/kopete/libkopete/ui
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/libkyahoo
+ ${CMAKE_CURRENT_SOURCE_DIR}/ui
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES yahooconferenceui.rc yahoochatui.rc DESTINATION ${DATA_INSTALL_DIR}/kopete_yahoo )
+install( FILES kopete_yahoo.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+##### kopete_yahoo (module) #####################
+
+tde_add_kpart( kopete_yahoo AUTOMOC
+ SOURCES
+ yahooprotocol.cpp yahooeditaccount.cpp yahooaddcontact.cpp
+ yahooaccount.cpp yahoocontact.cpp yahooconferencemessagemanager.cpp
+ yahoochatsession.cpp yahooverifyaccount.cpp yahoowebcam.cpp
+ LINK kyahoo-static kopeteyahooui-static kopeteui-static kopete-shared kopete_videodevice-shared
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/kopete/protocols/yahoo/icons/CMakeLists.txt b/kopete/protocols/yahoo/icons/CMakeLists.txt
new file mode 100644
index 00000000..ba51467b
--- /dev/null
+++ b/kopete/protocols/yahoo/icons/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/kopete/icons )
diff --git a/kopete/protocols/yahoo/libkyahoo/CMakeLists.txt b/kopete/protocols/yahoo/libkyahoo/CMakeLists.txt
new file mode 100644
index 00000000..a4ba8ba0
--- /dev/null
+++ b/kopete/protocols/yahoo/libkyahoo/CMakeLists.txt
@@ -0,0 +1,48 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include( ConfigureChecks.cmake )
+
+if( HAVE_INTTYPES_H )
+ add_definitions( -DHAVE_INTTYPES_H )
+elseif( HAVE_STDINT_H )
+ add_definitions( -DHAVE_STDINT_H )
+endif()
+
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kyahoo (static) ###########################
+
+tde_add_library( kyahoo STATIC_PIC AUTOMOC
+ SOURCES
+ client.cpp task.cpp connector.cpp inputprotocolbase.cpp
+ ymsgprotocol.cpp ymsgtransfer.cpp transfer.cpp
+ yahoobytestream.cpp bytestream.cpp yahooclientstream.cpp
+ yahooconnector.cpp safedelete.cpp stream.cpp sha1.c
+ md5.c crypt.c coreprotocol.cpp logintask.cpp libyahoo.c
+ yahoo_fn.c listtask.cpp statusnotifiertask.cpp
+ mailnotifiertask.cpp messagereceivertask.cpp
+ sendnotifytask.cpp sendmessagetask.cpp logofftask.cpp
+ changestatustask.cpp modifybuddytask.cpp picturenotifiertask.cpp
+ requestpicturetask.cpp yahoobuddyiconloader.cpp
+ stealthtask.cpp sendpicturetask.cpp webcamtask.cpp
+ conferencetask.cpp sendauthresptask.cpp pingtask.cpp
+ yabtask.cpp yabentry.cpp modifyyabtask.cpp chatsessiontask.cpp
+ sendfiletask.cpp filetransfernotifiertask.cpp
+ receivefiletask.cpp yahoochattask.cpp
+)
diff --git a/kopete/protocols/yahoo/libkyahoo/ConfigureChecks.cmake b/kopete/protocols/yahoo/libkyahoo/ConfigureChecks.cmake
new file mode 100644
index 00000000..e7af0c6c
--- /dev/null
+++ b/kopete/protocols/yahoo/libkyahoo/ConfigureChecks.cmake
@@ -0,0 +1,16 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+check_include_file( inttypes.h HAVE_INTTYPES_H )
+check_include_file( stdint.h HAVE_STDINT_H )
+
+check_include_file( string.h HAVE_STRING_H )
+check_include_file( strings.h HAVE_STRINGS_H )
diff --git a/kopete/protocols/yahoo/ui/CMakeLists.txt b/kopete/protocols/yahoo/ui/CMakeLists.txt
new file mode 100644
index 00000000..4da1fb8a
--- /dev/null
+++ b/kopete/protocols/yahoo/ui/CMakeLists.txt
@@ -0,0 +1,30 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_SOURCE_DIR}/kopete/libkopete
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+)
+
+
+##### kopeteyahooui (static) ####################
+
+tde_add_library( kopeteyahooui STATIC_PIC AUTOMOC
+ SOURCES
+ yahooadd.ui yahooeditaccountbase.ui yahooinvitelistbase.ui
+ yahooinvitelistimpl.cpp empty.cpp yahooverifyaccountbase.ui
+ yahoostealthsetting.ui yahoowebcamdialog.cpp yahoogeneralinfowidget.ui
+ yahoouserinfodialog.cpp yahooworkinfowidget.ui
+ yahoootherinfowidget.ui
+)
diff --git a/kopete/sounds/CMakeLists.txt b/kopete/sounds/CMakeLists.txt
new file mode 100644
index 00000000..5d56e236
--- /dev/null
+++ b/kopete/sounds/CMakeLists.txt
@@ -0,0 +1,15 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ Kopete_Event.ogg Kopete_Received.ogg
+ Kopete_Sent.ogg Kopete_User_is_Online.ogg
+ DESTINATION ${SOUND_INSTALL_DIR} )
diff --git a/kopete/styles/CMakeLists.txt b/kopete/styles/CMakeLists.txt
new file mode 100644
index 00000000..a98079ab
--- /dev/null
+++ b/kopete/styles/CMakeLists.txt
@@ -0,0 +1,18 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Kopete )
+add_subdirectory( Hacker )
+add_subdirectory( Clean )
+add_subdirectory( Clear )
+add_subdirectory( Konqi )
+add_subdirectory( Retropete )
+add_subdirectory( Gaim )
diff --git a/kopete/styles/Clean/CMakeLists.txt b/kopete/styles/Clean/CMakeLists.txt
new file mode 100644
index 00000000..f08e42e2
--- /dev/null
+++ b/kopete/styles/Clean/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Contents )
diff --git a/kopete/styles/Clean/Contents/CMakeLists.txt b/kopete/styles/Clean/Contents/CMakeLists.txt
new file mode 100644
index 00000000..88724a18
--- /dev/null
+++ b/kopete/styles/Clean/Contents/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Resources )
diff --git a/kopete/styles/Clean/Contents/Resources/CMakeLists.txt b/kopete/styles/Clean/Contents/Resources/CMakeLists.txt
new file mode 100644
index 00000000..336beb9f
--- /dev/null
+++ b/kopete/styles/Clean/Contents/Resources/CMakeLists.txt
@@ -0,0 +1,18 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( images )
+add_subdirectory( Incoming )
+add_subdirectory( Outgoing )
+
+install( FILES
+ main.css Footer.html Header.html Status.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Clean/Contents/Resources )
diff --git a/kopete/styles/Clean/Contents/Resources/Incoming/CMakeLists.txt b/kopete/styles/Clean/Contents/Resources/Incoming/CMakeLists.txt
new file mode 100644
index 00000000..589b000e
--- /dev/null
+++ b/kopete/styles/Clean/Contents/Resources/Incoming/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ buddy_icon.png Content.html NextContent.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Clean/Contents/Resources/Incoming )
diff --git a/kopete/styles/Clean/Contents/Resources/Outgoing/CMakeLists.txt b/kopete/styles/Clean/Contents/Resources/Outgoing/CMakeLists.txt
new file mode 100644
index 00000000..65bc355f
--- /dev/null
+++ b/kopete/styles/Clean/Contents/Resources/Outgoing/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ buddy_icon.png Content.html NextContent.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Clean/Contents/Resources/Outgoing )
diff --git a/kopete/styles/Clean/Contents/Resources/images/CMakeLists.txt b/kopete/styles/Clean/Contents/Resources/images/CMakeLists.txt
new file mode 100644
index 00000000..878bac8d
--- /dev/null
+++ b/kopete/styles/Clean/Contents/Resources/images/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ action.png important.png internal.png
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Clean/Contents/Resources/images )
diff --git a/kopete/styles/Clear/CMakeLists.txt b/kopete/styles/Clear/CMakeLists.txt
new file mode 100644
index 00000000..f08e42e2
--- /dev/null
+++ b/kopete/styles/Clear/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Contents )
diff --git a/kopete/styles/Clear/Contents/CMakeLists.txt b/kopete/styles/Clear/Contents/CMakeLists.txt
new file mode 100644
index 00000000..88724a18
--- /dev/null
+++ b/kopete/styles/Clear/Contents/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Resources )
diff --git a/kopete/styles/Clear/Contents/Resources/CMakeLists.txt b/kopete/styles/Clear/Contents/Resources/CMakeLists.txt
new file mode 100644
index 00000000..a5277126
--- /dev/null
+++ b/kopete/styles/Clear/Contents/Resources/CMakeLists.txt
@@ -0,0 +1,19 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( images )
+add_subdirectory( Incoming )
+add_subdirectory( Outgoing )
+add_subdirectory( Variants )
+
+install( FILES
+ main.css Footer.html Header.html Status.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Clear/Contents/Resources )
diff --git a/kopete/styles/Clear/Contents/Resources/Incoming/CMakeLists.txt b/kopete/styles/Clear/Contents/Resources/Incoming/CMakeLists.txt
new file mode 100644
index 00000000..ca799fcb
--- /dev/null
+++ b/kopete/styles/Clear/Contents/Resources/Incoming/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ buddy_icon.png Content.html NextContent.html Action.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Clear/Contents/Resources/Incoming )
diff --git a/kopete/styles/Clear/Contents/Resources/Outgoing/CMakeLists.txt b/kopete/styles/Clear/Contents/Resources/Outgoing/CMakeLists.txt
new file mode 100644
index 00000000..e5247e97
--- /dev/null
+++ b/kopete/styles/Clear/Contents/Resources/Outgoing/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ buddy_icon.png Content.html NextContent.html Action.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Clear/Contents/Resources/Outgoing )
diff --git a/kopete/styles/Clear/Contents/Resources/Variants/CMakeLists.txt b/kopete/styles/Clear/Contents/Resources/Variants/CMakeLists.txt
new file mode 100644
index 00000000..f51a21fb
--- /dev/null
+++ b/kopete/styles/Clear/Contents/Resources/Variants/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ No_avatars.css
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Clear/Contents/Resources/Variants )
diff --git a/kopete/styles/Clear/Contents/Resources/images/CMakeLists.txt b/kopete/styles/Clear/Contents/Resources/images/CMakeLists.txt
new file mode 100644
index 00000000..0956fac6
--- /dev/null
+++ b/kopete/styles/Clear/Contents/Resources/images/CMakeLists.txt
@@ -0,0 +1,25 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ body-background.png footer-outbound-right.png
+ body-inbound-arrow.png header-inbound-background.png
+ body-inbound-avatar.png header-inbound-left.png
+ body-inbound-background.png header-inbound-right.png
+ body-inbound-left.png header-outbound-background.png
+ body-inbound-right.png header-outbound-left.png
+ body-outbound-arrow.png header-outbound-right.png
+ body-outbound-avatar.png icon-action.png body-outbound-left.png
+ icon-highlighted.png body-outbound-right.png icon-internal.png
+ footer-inbound-background.png icon-me.png footer-inbound-left.png
+ icon-time.png footer-inbound-right.png icon-you.png
+ footer-outbound-background.png footer-outbound-left.png
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Clear/Contents/Resources/images )
diff --git a/kopete/styles/Gaim/CMakeLists.txt b/kopete/styles/Gaim/CMakeLists.txt
new file mode 100644
index 00000000..f08e42e2
--- /dev/null
+++ b/kopete/styles/Gaim/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Contents )
diff --git a/kopete/styles/Gaim/Contents/CMakeLists.txt b/kopete/styles/Gaim/Contents/CMakeLists.txt
new file mode 100644
index 00000000..88724a18
--- /dev/null
+++ b/kopete/styles/Gaim/Contents/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Resources )
diff --git a/kopete/styles/Gaim/Contents/Resources/CMakeLists.txt b/kopete/styles/Gaim/Contents/Resources/CMakeLists.txt
new file mode 100644
index 00000000..f212a870
--- /dev/null
+++ b/kopete/styles/Gaim/Contents/Resources/CMakeLists.txt
@@ -0,0 +1,18 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Incoming )
+add_subdirectory( Outgoing )
+add_subdirectory( Variants )
+
+install( FILES
+ main.css Footer.html Header.html Status.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Gaim/Contents/Resources )
diff --git a/kopete/styles/Gaim/Contents/Resources/Incoming/CMakeLists.txt b/kopete/styles/Gaim/Contents/Resources/Incoming/CMakeLists.txt
new file mode 100644
index 00000000..f4a2302f
--- /dev/null
+++ b/kopete/styles/Gaim/Contents/Resources/Incoming/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ Action.html Content.html NextContent.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Gaim/Contents/Resources/Incoming )
diff --git a/kopete/styles/Gaim/Contents/Resources/Outgoing/CMakeLists.txt b/kopete/styles/Gaim/Contents/Resources/Outgoing/CMakeLists.txt
new file mode 100644
index 00000000..32d0ae5d
--- /dev/null
+++ b/kopete/styles/Gaim/Contents/Resources/Outgoing/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ Action.html Content.html NextContent.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Gaim/Contents/Resources/Outgoing )
diff --git a/kopete/styles/Gaim/Contents/Resources/Variants/CMakeLists.txt b/kopete/styles/Gaim/Contents/Resources/Variants/CMakeLists.txt
new file mode 100644
index 00000000..fda30228
--- /dev/null
+++ b/kopete/styles/Gaim/Contents/Resources/Variants/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ No-Colors.css Name-Colors.css Status-Colors.css Contact-Colors.css
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Gaim/Contents/Resources/Variants )
diff --git a/kopete/styles/Hacker/CMakeLists.txt b/kopete/styles/Hacker/CMakeLists.txt
new file mode 100644
index 00000000..5169384b
--- /dev/null
+++ b/kopete/styles/Hacker/CMakeLists.txt
@@ -0,0 +1,16 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Contents )
+
+install( FILES
+ COPYRIGHT README gpl.txt
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Hacker )
diff --git a/kopete/styles/Hacker/Contents/CMakeLists.txt b/kopete/styles/Hacker/Contents/CMakeLists.txt
new file mode 100644
index 00000000..08fdf1cc
--- /dev/null
+++ b/kopete/styles/Hacker/Contents/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Resources )
+
+install( FILES Info.plist DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Hacker/Contents )
diff --git a/kopete/styles/Hacker/Contents/Resources/CMakeLists.txt b/kopete/styles/Hacker/Contents/Resources/CMakeLists.txt
new file mode 100644
index 00000000..bdfe0c38
--- /dev/null
+++ b/kopete/styles/Hacker/Contents/Resources/CMakeLists.txt
@@ -0,0 +1,19 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( images )
+add_subdirectory( Incoming )
+add_subdirectory( Outgoing )
+add_subdirectory( Variants )
+
+install( FILES
+ main.css Footer.html Header.html Status.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Hacker/Contents/Resources )
diff --git a/kopete/styles/Hacker/Contents/Resources/Incoming/CMakeLists.txt b/kopete/styles/Hacker/Contents/Resources/Incoming/CMakeLists.txt
new file mode 100644
index 00000000..9bdedfce
--- /dev/null
+++ b/kopete/styles/Hacker/Contents/Resources/Incoming/CMakeLists.txt
@@ -0,0 +1,15 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ Content.html Context.html NextContent.html
+ NextContext.html buddy_icon.png Action.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Hacker/Contents/Resources/Incoming )
diff --git a/kopete/styles/Hacker/Contents/Resources/Outgoing/CMakeLists.txt b/kopete/styles/Hacker/Contents/Resources/Outgoing/CMakeLists.txt
new file mode 100644
index 00000000..bd242686
--- /dev/null
+++ b/kopete/styles/Hacker/Contents/Resources/Outgoing/CMakeLists.txt
@@ -0,0 +1,15 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ Content.html NextContent.html Context.html
+ NextContext.html buddy_icon.png Action.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Hacker/Contents/Resources/Outgoing )
diff --git a/kopete/styles/Hacker/Contents/Resources/Variants/CMakeLists.txt b/kopete/styles/Hacker/Contents/Resources/Variants/CMakeLists.txt
new file mode 100644
index 00000000..b4aac5a5
--- /dev/null
+++ b/kopete/styles/Hacker/Contents/Resources/Variants/CMakeLists.txt
@@ -0,0 +1,15 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ Dark2.css Dark.css Light2.css Light.css Dark2-Noback.css
+ Dark-Noback.css Light2-Noback.css Light-Noback.css
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Hacker/Contents/Resources/Variants )
diff --git a/kopete/styles/Hacker/Contents/Resources/images/CMakeLists.txt b/kopete/styles/Hacker/Contents/Resources/images/CMakeLists.txt
new file mode 100644
index 00000000..143190e2
--- /dev/null
+++ b/kopete/styles/Hacker/Contents/Resources/images/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ background.png background2.png kopete.png
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Hacker/Contents/Resources/images )
diff --git a/kopete/styles/Konqi/CMakeLists.txt b/kopete/styles/Konqi/CMakeLists.txt
new file mode 100644
index 00000000..f08e42e2
--- /dev/null
+++ b/kopete/styles/Konqi/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Contents )
diff --git a/kopete/styles/Konqi/Contents/CMakeLists.txt b/kopete/styles/Konqi/Contents/CMakeLists.txt
new file mode 100644
index 00000000..88724a18
--- /dev/null
+++ b/kopete/styles/Konqi/Contents/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Resources )
diff --git a/kopete/styles/Konqi/Contents/Resources/CMakeLists.txt b/kopete/styles/Konqi/Contents/Resources/CMakeLists.txt
new file mode 100644
index 00000000..1a69df52
--- /dev/null
+++ b/kopete/styles/Konqi/Contents/Resources/CMakeLists.txt
@@ -0,0 +1,18 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Incoming )
+add_subdirectory( Outgoing )
+add_subdirectory( Variants )
+
+install( FILES
+ main.css Footer.html Header.html Status.html puce.png
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Konqi/Contents/Resources )
diff --git a/kopete/styles/Konqi/Contents/Resources/Incoming/CMakeLists.txt b/kopete/styles/Konqi/Contents/Resources/Incoming/CMakeLists.txt
new file mode 100644
index 00000000..1653fd32
--- /dev/null
+++ b/kopete/styles/Konqi/Contents/Resources/Incoming/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ buddy_icon.png Content.html NextContent.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Konqi/Contents/Resources/Incoming )
diff --git a/kopete/styles/Konqi/Contents/Resources/Outgoing/CMakeLists.txt b/kopete/styles/Konqi/Contents/Resources/Outgoing/CMakeLists.txt
new file mode 100644
index 00000000..9b3f366f
--- /dev/null
+++ b/kopete/styles/Konqi/Contents/Resources/Outgoing/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ buddy_icon.png Content.html NextContent.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Konqi/Contents/Resources/Outgoing )
diff --git a/kopete/styles/Konqi/Contents/Resources/Variants/CMakeLists.txt b/kopete/styles/Konqi/Contents/Resources/Variants/CMakeLists.txt
new file mode 100644
index 00000000..5aec1cab
--- /dev/null
+++ b/kopete/styles/Konqi/Contents/Resources/Variants/CMakeLists.txt
@@ -0,0 +1,19 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( konqui )
+
+install( FILES
+ Side_blue_moon.css Side_blue_without_transparency.css
+ Side_green_without_trans.css Side_blue.css
+ Side_blue_moon_without_transparency.css Side_green.css
+ Side_green_without_transparency.css
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Konqi/Contents/Resources/Variants )
diff --git a/kopete/styles/Konqi/Contents/Resources/Variants/konqui/CMakeLists.txt b/kopete/styles/Konqi/Contents/Resources/Variants/konqui/CMakeLists.txt
new file mode 100644
index 00000000..fc87b8ab
--- /dev/null
+++ b/kopete/styles/Konqi/Contents/Resources/Variants/konqui/CMakeLists.txt
@@ -0,0 +1,16 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ cadre1.png cadre2.png cadre3.png cadre4.png
+ cadre5.png cadre6.png konqui-blue.png
+ konqui-green.png konqui-moon.jpg
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Konqi/Contents/Resources/Variants/konqui )
diff --git a/kopete/styles/Kopete/CMakeLists.txt b/kopete/styles/Kopete/CMakeLists.txt
new file mode 100644
index 00000000..f08e42e2
--- /dev/null
+++ b/kopete/styles/Kopete/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Contents )
diff --git a/kopete/styles/Kopete/Contents/CMakeLists.txt b/kopete/styles/Kopete/Contents/CMakeLists.txt
new file mode 100644
index 00000000..88724a18
--- /dev/null
+++ b/kopete/styles/Kopete/Contents/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Resources )
diff --git a/kopete/styles/Kopete/Contents/Resources/CMakeLists.txt b/kopete/styles/Kopete/Contents/Resources/CMakeLists.txt
new file mode 100644
index 00000000..ee273f43
--- /dev/null
+++ b/kopete/styles/Kopete/Contents/Resources/CMakeLists.txt
@@ -0,0 +1,19 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( images )
+add_subdirectory( Incoming )
+add_subdirectory( Outgoing )
+add_subdirectory( Variants )
+
+install( FILES
+ main.css Footer.html Header.html Status.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Kopete/Contents/Resources )
diff --git a/kopete/styles/Kopete/Contents/Resources/Incoming/CMakeLists.txt b/kopete/styles/Kopete/Contents/Resources/Incoming/CMakeLists.txt
new file mode 100644
index 00000000..03eb154c
--- /dev/null
+++ b/kopete/styles/Kopete/Contents/Resources/Incoming/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ buddy_icon.png Content.html NextContent.html Action.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Kopete/Contents/Resources/Incoming )
diff --git a/kopete/styles/Kopete/Contents/Resources/Outgoing/CMakeLists.txt b/kopete/styles/Kopete/Contents/Resources/Outgoing/CMakeLists.txt
new file mode 100644
index 00000000..5b1f22e5
--- /dev/null
+++ b/kopete/styles/Kopete/Contents/Resources/Outgoing/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ buddy_icon.png Content.html NextContent.html Action.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Kopete/Contents/Resources/Outgoing )
diff --git a/kopete/styles/Kopete/Contents/Resources/Variants/CMakeLists.txt b/kopete/styles/Kopete/Contents/Resources/Variants/CMakeLists.txt
new file mode 100644
index 00000000..62829811
--- /dev/null
+++ b/kopete/styles/Kopete/Contents/Resources/Variants/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ Big_pictures.css Contact_color.css
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Kopete/Contents/Resources/Variants )
diff --git a/kopete/styles/Kopete/Contents/Resources/images/CMakeLists.txt b/kopete/styles/Kopete/Contents/Resources/images/CMakeLists.txt
new file mode 100644
index 00000000..3eb4783d
--- /dev/null
+++ b/kopete/styles/Kopete/Contents/Resources/images/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ action.png important.png system.png
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Kopete/Contents/Resources/images )
diff --git a/kopete/styles/Retropete/CMakeLists.txt b/kopete/styles/Retropete/CMakeLists.txt
new file mode 100644
index 00000000..f08e42e2
--- /dev/null
+++ b/kopete/styles/Retropete/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Contents )
diff --git a/kopete/styles/Retropete/Contents/CMakeLists.txt b/kopete/styles/Retropete/Contents/CMakeLists.txt
new file mode 100644
index 00000000..88724a18
--- /dev/null
+++ b/kopete/styles/Retropete/Contents/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Resources )
diff --git a/kopete/styles/Retropete/Contents/Resources/CMakeLists.txt b/kopete/styles/Retropete/Contents/Resources/CMakeLists.txt
new file mode 100644
index 00000000..10f01f85
--- /dev/null
+++ b/kopete/styles/Retropete/Contents/Resources/CMakeLists.txt
@@ -0,0 +1,17 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( Incoming )
+add_subdirectory( Outgoing )
+
+install( FILES
+ main.css Footer.html Header.html Status.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Retropete/Contents/Resources )
diff --git a/kopete/styles/Retropete/Contents/Resources/Incoming/CMakeLists.txt b/kopete/styles/Retropete/Contents/Resources/Incoming/CMakeLists.txt
new file mode 100644
index 00000000..e06e0d1b
--- /dev/null
+++ b/kopete/styles/Retropete/Contents/Resources/Incoming/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ Action.html Content.html NextContent.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Retropete/Contents/Resources/Incoming )
diff --git a/kopete/styles/Retropete/Contents/Resources/Outgoing/CMakeLists.txt b/kopete/styles/Retropete/Contents/Resources/Outgoing/CMakeLists.txt
new file mode 100644
index 00000000..24ef9703
--- /dev/null
+++ b/kopete/styles/Retropete/Contents/Resources/Outgoing/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES
+ Action.html Content.html NextContent.html
+ DESTINATION ${DATA_INSTALL_DIR}/kopete/styles/Retropete/Contents/Resources/Outgoing )