| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595 |
- // BUD v0.1.5 RC1 by Slice
- #include <a_samp>
- #include <a_http>
- // :D
- #define BUD:: BUD_
- #define opt. opt_
- #define private stock static
- #define global stock
- // :D!
- #define BUD_Notice(%0) (printf("BUD - Notice: " %0))
- #define BUD_Warning(%0) (printf("BUD - Warning: " %0))
- #define BUD_Error(%0) (printf("BUD - Error: " %0))
- // This is so the constants can be defined before inclusion.
- #if !defined BUD_USE_WHIRLPOOL
- #define BUD_USE_WHIRLPOOL (false)
- #endif
- #if !defined BUD_MAX_DATABASE_NAME
- #define BUD_MAX_DATABASE_NAME (16)
- #endif
- #if !defined BUD_MAX_COLUMNS
- #define BUD_MAX_COLUMNS (12)
- #endif
- #if !defined BUD_MAX_COLUMN_NAME
- #define BUD_MAX_COLUMN_NAME (16)
- #endif
- #if !defined BUD_CHECK_STRING_LENGTH
- #define BUD_CHECK_STRING_LENGTH (false)
- #endif
- #if !defined BUD_MAX_ENTRY_STRING
- #define BUD_MAX_ENTRY_STRING (64)
- #endif
- #if !defined BUD_MULTIGET_MAX_ENTRIES
- #define BUD_MULTIGET_MAX_ENTRIES (16)
- #endif
- #if !defined BUD_MULTISET_MAX_ENTRIES
- #define BUD_MULTISET_MAX_ENTRIES (16)
- #endif
- #if !defined BUD_MULTISET_MAX_STRING_SIZE
- #define BUD_MULTISET_MAX_STRING_SIZE (BUD::MAX_ENTRY_STRING)
- #endif
- #if !defined BUD_MULTISET_BUFFER_SIZE
- #define BUD_MULTISET_BUFFER_SIZE (2048)
- #endif
- #if !defined BUD_BUFFER_SIZE
- #define BUD_BUFFER_SIZE (3072)
- #endif
- #define DEFAULT_DATABASE_NAME "bud.db" // No need to change this; do it via the settings instead.
- #define BUD_VERSION_MINOR 0
- #define BUD_VERSION_MAJOR 1
- #define BUD_VERSION_BUILD 5
- #define INVALID_DB (DB:0)
- #define BUD_NO_RESULT (DBResult:0)
- #define BUD_INVALID_UID (-1)
- #define BUD_Results:%0<%1> %0[%1][2]
- #if !defined cellbytes
- #define __undef_celbytes
-
- #define cellbytes (cellbits / 8)
- #endif
- enum BUD::e_COLUMN_TYPES {
- BUD::TYPE_NUMBER,
- BUD::TYPE_FLOAT,
- BUD::TYPE_STRING
- };
- enum BUD::e_OPTIONS {
- opt.Database,
- opt.Asynchronous,
- opt.KeepAliveTime,
- opt.IntEntryDefault,
- opt.FloatEntryDefault,
- opt.DatabaseOpenTimeOut,
- opt.CheckForUpdates
- };
- enum BUD::e_SORT_ORDER {
- BUD::SORT_ASC,
- BUD::SORT_DESC,
- BUD::SORT_ASCENDING = 0,
- BUD::SORT_DESCENDING
- };
- // No need to change this either; use BUD::VerifyColumn(column[], type) instead.
- #define DEFAULT_COLUMNS "uid INTEGER PRIMARY KEY, name TEXT, passhash BLOB"
- private
- bool:g_bIsInitialized = false,
- g_szDatabaseName[BUD::MAX_DATABASE_NAME] = "bud.db",
- g_iColumnCount,
- g_szColumnName[BUD::MAX_COLUMNS][BUD::MAX_COLUMN_NAME],
- DB:g_dbKeptAlive = INVALID_DB,
- g_iKeepAlive = 2000,
- g_iKeepAliveTimer = -1,
- bool:g_bAsynchronous = true,
- g_iIntEntryDefault = 0,
- Float:g_fFloatEntryDefault = 0.0,
- g_iDatabaseOpenTimeOut = 3000,
- bool:g_bCheckForUpdates = true,
- g_szBuffer[BUD::BUFFER_SIZE]
- ;
- // Prevent it from causing issues if WP_Hash is defined before or after this.
- #if (BUD::USE_WHIRLPOOL)
- #if defined WP_Hash
- #define BUD_WhirlpoolHash WP_Hash
- #else
- native BUD::WhirlpoolHash(buffer[], len = sizeof(buffer), const str[]) = WP_Hash;
- #endif
- #endif
- // Close the database connection when it has been unused for g_iKeepAlive ms
- private bool:BUD::GetDB() {
- if (g_iKeepAliveTimer == -1) {
- new
- iStartTick = GetTickCount()
- ;
-
- do
- g_dbKeptAlive = db_open(g_szDatabaseName);
- while (g_dbKeptAlive == INVALID_DB && GetTickCount() - iStartTick < g_iDatabaseOpenTimeOut);
-
- if (g_dbKeptAlive == INVALID_DB) {
- BUD::Error("Unable to open the database \"%s\".", g_szDatabaseName);
-
- return false;
- } else {
- if (g_bAsynchronous)
- db_query(g_dbKeptAlive, "PRAGMA synchronous = 0");
- else
- db_query(g_dbKeptAlive, "PRAGMA synchronous = 3");
- }
- } else {
- KillTimer(g_iKeepAliveTimer);
- }
-
- g_iKeepAliveTimer = SetTimer("BUD_CloseDB", g_iKeepAlive, false);
-
- return true;
- }
- forward BUD::CloseDB();
- public BUD::CloseDB() {
- g_iKeepAliveTimer = -1;
-
- db_close(g_dbKeptAlive);
-
- g_dbKeptAlive = INVALID_DB;
- }
- global BUD::Setting(BUD::e_OPTIONS:iSetting, _:...) {
- switch (iSetting) {
- case opt.Database: {
- if (g_bIsInitialized) {
- BUD::Warning("opt.Database has to be set before BUD::Initialize() is called.");
-
- return;
- }
-
- __getstringarg(g_szDatabaseName, 1);
- }
-
- case opt.Asynchronous: {
- new
- bool:bNewSetting = getarg(1) ? true : false
- ;
-
- if (g_bAsynchronous != bNewSetting) {
- g_bAsynchronous = bNewSetting;
-
- if (g_dbKeptAlive != INVALID_DB) {
- if (g_bAsynchronous)
- db_query(g_dbKeptAlive, "PRAGMA synchronous = 0");
- else
- db_query(g_dbKeptAlive, "PRAGMA synchronous = 3");
- }
- }
- }
-
- case opt.KeepAliveTime: {
- g_iKeepAlive = max(0, getarg(1));
- }
-
- case opt.IntEntryDefault: {
- g_iIntEntryDefault = getarg(1);
- }
-
- case opt.FloatEntryDefault: {
- g_fFloatEntryDefault = getarg(1);
- }
-
- case opt.DatabaseOpenTimeOut: {
- g_iDatabaseOpenTimeOut = getarg(1);
- }
-
- case opt.CheckForUpdates: {
- if (g_bIsInitialized) {
- BUD::Warning("opt.CheckForUpdates has to be set before BUD::Initialize() is called.");
-
- return;
- }
-
- g_bCheckForUpdates = getarg(1) ? true : false;
- }
-
- default: {
- BUD::Warning("Unknown setting ID passed in BUD::Setting (%d).", _:iSetting);
- }
- }
- }
- #if !(BUD::USE_WHIRLPOOL)
- #if !defined MAX_PASSWORD_LENGTH
- #define MAX_PASSWORD_LENGTH (64)
- #define UNDEFINE_MAX_PASSWORD_LENGTH (true)
- #else
- #define UNDEFINE_MAX_PASSWORD_LENGTH (false)
- #endif
-
- stock BUD::chrfind(needle, haystack[], start = 0) { // Y_Less
- while (haystack[start]) if (haystack[start++] == needle) return start - 1;
- return -1;
- }
-
- stock BUD::JSCHash(const __pass[],__passhash[MAX_PASSWORD_LENGTH + 1]) { // By JSC (Y_Less's dad); ported by Y_Less
- static
- __charset[] = \"4YLi6pOX)Mudvbc_IFVB/8HZ\2r(fGjaN0oU9C1Wywnq*smKQRxJDhkAS|53EzglT7tPe",
- __css = 69;
- new
- __j = strlen(__pass);
- new
- __sum = __j,
- __tmp = 0,
- __i,
- __mod;
- for (__i = 0; __i < MAX_PASSWORD_LENGTH || __i < __j; __i++) {
- __mod = __i % MAX_PASSWORD_LENGTH;
- __tmp = (__i >= __j) ? __charset[(7 * __i) % __css] : __pass[__i];
- __sum = (__sum + BUD::chrfind(__tmp, __charset) + 1) % __css;
- __passhash[__mod] = __charset[(__sum + __passhash[__mod]) % __css];
- }
- __passhash[MAX_PASSWORD_LENGTH] = '\0';
- }
- #else
- #define UNDEFINE_MAX_PASSWORD_LENGTH (false)
- #endif
- global bool:BUD::Initialize() {
- if (g_bIsInitialized) {
- BUD::Notice("Initialization aborted; BUD is already initialized.");
-
- return true;
- }
-
- #if (BUD::USE_WHIRLPOOL)
- new szBuffer[129];
-
- BUD::WhirlpoolHash(szBuffer, _, "I like cookies.");
-
- if (strcmp(szBuffer, "516A210D9C04CFE36568BEDA5287977572CCC618126B188B02F0BCFB92EE5B7EBA9F3D6DE2DE8FC0BB4C9E6111B93CF6482CCCD5639A94F125CFF7B829275933"))
- BUD::Warning("Whirlpool isn't behaving as expected; this might cause problems with the authentication.");
- #endif
-
- if (!g_szDatabaseName[0]) {
- BUD::Warning("The database name was not specified; default will be applied (\"" DEFAULT_DATABASE_NAME "\").");
-
- g_szDatabaseName = DEFAULT_DATABASE_NAME;
- }
-
- if (!fexist(g_szDatabaseName)) {
- BUD::Notice("The database \"%s\" doesn't exist; it will be created.", g_szDatabaseName);
-
- if (!BUD::CreateDatabase())
- return false;
- }
-
- BUD::ReloadTableInfo();
- BUD::IntegrityCheck();
-
- if (g_bCheckForUpdates)
- BUD::CheckForUpdates();
-
- g_bIsInitialized = true;
-
- printf("BUD v" #BUD::VERSION_MAJOR "." #BUD::VERSION_MINOR "." #BUD::VERSION_BUILD " BETA loaded.");
-
- return true;
- }
- global bool:BUD::Exit() {
- if (g_iKeepAliveTimer != -1) {
- KillTimer(g_iKeepAliveTimer);
-
- BUD::CloseDB();
- }
-
- g_bIsInitialized = false;
- }
- private BUD::IntegrityCheck() {
- if (!BUD::GetDB())
- return;
-
- new
- DBResult:dbrResult
- ;
-
- dbrResult = db_query(g_dbKeptAlive, "PRAGMA integrity_check");
-
- if (dbrResult) {
- new
- iRow,
- szField[64]
- ;
-
- do {
- db_get_field(dbrResult, 0, szField, sizeof(szField) - 1);
-
- if (iRow == 0 && !strcmp("ok", szField))
- break;
- else
- BUD::Warning("Database integrity check says: %s", szField);
-
- iRow++;
- }
- while (db_next_row(dbrResult));
-
- db_free_result(dbrResult);
- }
- }
- private BUD::CreateDatabase() {
- if (!BUD::GetDB())
- return false;
-
- db_query(g_dbKeptAlive, "CREATE TABLE users (" DEFAULT_COLUMNS ")");
-
- return true;
- }
- private BUD::ReloadTableInfo() {
- new
- DBResult:dbrResult
- ;
-
- if (!BUD::GetDB())
- return;
-
- dbrResult = db_query(g_dbKeptAlive, "PRAGMA table_info('users')");
-
- g_iColumnCount = 0;
-
- if (dbrResult) {
- new
- szColumnName[BUD::MAX_COLUMN_NAME]
- ;
-
- do {
- if (g_iColumnCount + 1 >= BUD::MAX_COLUMNS) {
- BUD::Warning("There are more columns in the \"users\" table than BUD::MAX_COLUMNS. Increase the limit!");
-
- break;
- }
-
- db_get_field(dbrResult, 1, szColumnName, BUD::MAX_COLUMN_NAME - 1);
-
- memcpy(g_szColumnName[g_iColumnCount++], szColumnName, .numbytes = (BUD::MAX_COLUMN_NAME * (cellbits / 8)));
- }
- while (db_next_row(dbrResult));
-
- db_free_result(dbrResult);
- } else
- BUD::Warning("Failed to get the table info from \"%s\"; some columns could be missing.", g_szDatabaseName);
- }
- global BUD::VerifyColumn(const szColumnName[], BUD::e_COLUMN_TYPES:iType, { _,Float }:...) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szColumnName) >= BUD::MAX_COLUMN_NAME)
- return false;
- #endif
-
- if (!(BUD::e_COLUMN_TYPES:0 <= iType <= BUD::e_COLUMN_TYPES)) {
- BUD::Error("Invalid type given to BUD::VerifyColumn.");
-
- return;
- }
-
- if (!g_iColumnCount) {
- BUD::Notice("Because the table info wasn't retrieved, columns cannot be verified.");
-
- return;
- }
-
- new
- bool:bColumnCreated = false
- ;
-
- recheck:
-
- for (new i = 0; i < g_iColumnCount; i++) {
- if (!strcmp(g_szColumnName[i], szColumnName, true))
- return;
- }
-
- if (!bColumnCreated) {
- BUD::Notice("The column \"%s\" doesn't exist; attempting to create it.", szColumnName);
-
- if (!BUD::GetDB())
- return;
-
- switch (iType) {
- case BUD::TYPE_NUMBER: {
- new
- iDefaultValue
- ;
-
- if (numargs() != 3)
- iDefaultValue = 0;
- else
- iDefaultValue = getarg(2);
-
- format(g_szBuffer, sizeof(g_szBuffer), "ALTER TABLE `users` ADD COLUMN `%s` INTEGER DEFAULT(%d)", szColumnName, iDefaultValue);
- }
-
- case BUD::TYPE_FLOAT: {
- new
- Float:fDefaultValue
- ;
-
- if (numargs() != 3)
- fDefaultValue = 0.0;
- else
- fDefaultValue = Float:getarg(2);
-
- format(g_szBuffer, sizeof(g_szBuffer), "ALTER TABLE `users` ADD COLUMN `%s` REAL DEFAULT(%f)", szColumnName, fDefaultValue);
- }
-
- case BUD::TYPE_STRING: {
- new
- szDefaultValue[BUD::MAX_ENTRY_STRING * 2]
- ;
-
- if (numargs() == 3) {
- __getstringarg(szDefaultValue, 2);
-
- szDefaultValue[BUD::MAX_ENTRY_STRING - 1] = EOS;
-
- BUD::EscapeSqlString(szDefaultValue);
- }
-
- format(g_szBuffer, sizeof(g_szBuffer), "ALTER TABLE `users` ADD COLUMN `%s` TEXT DEFAULT('%s')", szColumnName, szDefaultValue);
- }
-
- default: {
- return;
- }
- }
-
- db_free_result(
- db_query(g_dbKeptAlive, g_szBuffer)
- );
-
- bColumnCreated = true;
-
- BUD::ReloadTableInfo();
-
- goto recheck;
- }
-
- BUD::Error("Failed to create the column \"%s\"; this could be because of an invalid column name.", szColumnName);
- }
- global bool:BUD::IsNameRegistered(const szName[]) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szName) >= MAX_PLAYER_NAME)
- return false;
- #endif
-
- if (!BUD::GetDB())
- return true; // Better return true here to prevent any very circumstantial hijacking.
-
- new
- DBResult:dbrResult,
- bool:bIsRegistered = false
- ;
-
- format(g_szBuffer, sizeof(g_szBuffer), "SELECT `uid` FROM `users` WHERE `name` = '%s' COLLATE NOCASE", szName);
-
- dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
-
- if (dbrResult) {
- if (db_num_rows(dbrResult) >= 1)
- bIsRegistered = true;
-
- db_free_result(dbrResult);
- }
-
- return bIsRegistered;
- }
- global bool:BUD::RegisterName(const szName[], const szPassword[]) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szName) >= MAX_PLAYER_NAME)
- return false;
- #endif
-
- if (BUD::IsNameRegistered(szName))
- return false;
-
- new
- #if (BUD::USE_WHIRLPOOL)
- szPasshash[129],
- #else
- szPasshash[MAX_PASSWORD_LENGTH + 1],
- #endif
- DBResult:dbrResult
- ;
-
- #if (BUD::USE_WHIRLPOOL)
- g_szBuffer = "INSERT INTO users(`name`, `passhash`) VALUES('";
- #else
- g_szBuffer = "INSERT INTO users(`name`, `passhash`) VALUES('";
- #endif
-
- if (!BUD::GetDB())
- return false;
-
- #if (BUD::USE_WHIRLPOOL)
- BUD::WhirlpoolHash(szPasshash, _, szPassword);
- #else
- BUD::JSCHash(szPassword, szPasshash);
- #endif
-
-
- strcat(g_szBuffer, szName);
-
- #if (BUD::USE_WHIRLPOOL)
- strcat(g_szBuffer, "', x'");
- #else
- strcat(g_szBuffer, "', '");
- #endif
-
- strcat(g_szBuffer, szPasshash);
- strcat(g_szBuffer, "')");
-
- dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
-
- if (dbrResult)
- db_free_result(dbrResult);
-
- if (BUD::IsNameRegistered(szName))
- return true;
-
- return false;
- }
- global BUD::UnregisterName(const szName[]) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szName) >= MAX_PLAYER_NAME)
- return false;
- #endif
-
- if (!BUD::IsNameRegistered(szName))
- return false;
-
- if (!BUD::GetDB())
- return false;
-
- g_szBuffer = "DELETE FROM `users` WHERE `name`='";
-
- strcat(g_szBuffer, szName);
- strcat(g_szBuffer, "' COLLATE NOCASE");
-
- db_query(g_dbKeptAlive, g_szBuffer);
-
- if (BUD::IsNameRegistered(szName))
- return false;
-
- return true;
- }
- global bool:BUD::CheckAuth(const szName[], const szPassword[]) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szName) >= MAX_PLAYER_NAME)
- return false;
- #endif
-
- if (!BUD::GetDB())
- return false;
-
- new
- #if (BUD::USE_WHIRLPOOL)
- szPasshash[129],
- #else
- szPasshash[MAX_PASSWORD_LENGTH + 1],
- #endif
- DBResult:dbrResult,
- bool:bAuthenticated = false
- ;
-
- #if (BUD::USE_WHIRLPOOL)
- g_szBuffer = "SELECT `uid` FROM `users` WHERE `name`='";
- #else
- g_szBuffer = "SELECT `uid` FROM `users` WHERE `name`='";
- #endif
-
- #if (BUD::USE_WHIRLPOOL)
- BUD::WhirlpoolHash(szPasshash, _, szPassword);
- #else
- BUD::JSCHash(szPassword, szPasshash);
- #endif
-
- strcat(g_szBuffer, szName);
-
- #if (BUD::USE_WHIRLPOOL)
- strcat(g_szBuffer, "' AND `passhash`=x'");
- #else
- strcat(g_szBuffer, "' AND `passhash`='");
- #endif
-
- strcat(g_szBuffer, szPasshash);
- strcat(g_szBuffer, "' COLLATE NOCASE");
-
- dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
-
- if (dbrResult) {
- if (db_num_rows(dbrResult) == 1)
- bAuthenticated = true;
-
- db_free_result(dbrResult);
- }
-
- return bAuthenticated;
- }
- global BUD::GetNameUID(const szName[]) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szName) >= BUD::MAX_PLAYER_NAME)
- return BUD::INVALID_UID;
- #endif
-
- if (!BUD::GetDB())
- return BUD::INVALID_UID;
-
- new
- DBResult:dbrResult
- ;
-
- format(g_szBuffer, sizeof(g_szBuffer), "SELECT `uid` FROM `users` WHERE `name`='%s' COLLATE NOCASE", szName);
-
- dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
-
- if (dbrResult) {
- new
- iUID = BUD::INVALID_UID
- ;
-
- if (db_num_rows(dbrResult) == 1) {
- db_get_field(dbrResult, 0, g_szBuffer, sizeof(g_szBuffer) - 1);
-
- iUID = strval(g_szBuffer);
- }
-
- db_free_result(dbrResult);
-
- return iUID;
- }
-
- return BUD::INVALID_UID;
- }
- global Float:BUD::GetFloatEntry(iUID, const szColumn[]) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
- return g_fFloatEntryDefault;
- #endif
-
- if (!BUD::GetDB())
- return g_fFloatEntryDefault;
-
- new
- DBResult:dbrResult
- ;
-
- format(g_szBuffer, sizeof(g_szBuffer), "SELECT `%s` FROM `users` WHERE `uid`='%d'", szColumn, iUID);
-
- dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
-
- if (dbrResult) {
- if (db_num_rows(dbrResult) == 1)
- db_get_field(dbrResult, 0, g_szBuffer, sizeof(g_szBuffer) - 1);
- else
- g_szBuffer[0] = EOS;
-
- db_free_result(dbrResult);
-
- if (g_szBuffer[0])
- return floatstr(g_szBuffer);
- }
-
- return g_fFloatEntryDefault;
- }
- global BUD::GetIntEntry(iUID, const szColumn[]) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
- return g_iIntEntryDefault;
- #endif
-
- if (!BUD::GetDB())
- return g_iIntEntryDefault;
-
- new
- DBResult:dbrResult
- ;
-
- format(g_szBuffer, sizeof(g_szBuffer), "SELECT `%s` FROM `users` WHERE `uid`='%d'", szColumn, iUID);
-
- dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
-
- if (dbrResult) {
- if (db_num_rows(dbrResult) == 1)
- db_get_field(dbrResult, 0, g_szBuffer, sizeof(g_szBuffer) - 1);
- else
- g_szBuffer[0] = EOS;
-
- db_free_result(dbrResult);
-
- if (g_szBuffer[0])
- return strval(g_szBuffer);
- }
-
- return g_iIntEntryDefault;
- }
- global BUD::GetStringEntry(iUID, const szColumn[], szOutput[], iSize = sizeof(szOutput)) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME) {
- szOutput[0] = EOS;
-
- return;
- }
- #endif
-
- if (!BUD::GetDB()) {
- szOutput[0] = EOS;
-
- return;
- }
-
- new
- DBResult:dbrResult
- ;
-
- format(g_szBuffer, sizeof(g_szBuffer), "SELECT `%s` FROM `users` WHERE `uid`='%d'", szColumn, iUID);
-
- dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
-
- if (dbrResult) {
- if (db_num_rows(dbrResult) == 1)
- db_get_field(dbrResult, 0, szOutput, iSize - 1);
- else
- szOutput[0] = EOS;
-
- db_free_result(dbrResult);
- }
- }
- global bool:BUD::MultiGet(iUID, const szTypeDefinitions[], { _, Float }:...) {
- new
- iEntries = numargs() - 2
- ;
-
- if (iEntries & 0b1) {
- BUD::Error("A parameter is missing in BUD::MultiGet; expecting a variable in the end.", numargs() - 2);
-
- return false;
- }
-
- iEntries /= 2;
-
- if (iEntries > BUD::MULTIGET_MAX_ENTRIES) {
- BUD::Error("Too many entires passed to BUD::MultiGet; entires: %d, limit: %d.", iEntries, BUD::MULTIGET_MAX_ENTRIES);
-
- return false;
- }
-
- new
- iNumTypeDefinitions,
- iTypeDefinitions[BUD::MULTIGET_MAX_ENTRIES char],
- iTypeLengths[BUD::MULTIGET_MAX_ENTRIES]
- ;
-
- for (new i = 0, l = strlen(szTypeDefinitions); i < l; i++) {
- switch (szTypeDefinitions[i]) {
- case 'i', 'd', 'f': {
- iTypeDefinitions{ iNumTypeDefinitions++ } = szTypeDefinitions[i];
- }
-
- case 's': {
- if (szTypeDefinitions[i + 1] == '[' && szTypeDefinitions[i + 2]) {
- ++i;
-
- new
- szLength[11],
- iEndingBracket = strfind(szTypeDefinitions, "]", .pos = i + 2)
- ;
-
- if (iEndingBracket != -1) {
- strmid(szLength, szTypeDefinitions, i + 1, iEndingBracket);
-
- iTypeLengths[iNumTypeDefinitions] = strval(szLength);
-
- if (iTypeLengths[iNumTypeDefinitions] <= 0) {
- BUD::Error("Invalid string length given in the type definitions for BUD::MultiGet: %d.", iTypeLengths[iNumTypeDefinitions]);
-
- return false;
- }
-
- iTypeDefinitions{ iNumTypeDefinitions++ } = 's';
-
- i = iEndingBracket;
-
- continue;
- }
- }
-
- BUD::Error("String size has to be passed in the type definitions for BUD::MultiGet; example: \"iffs[32]ii\".", iNumTypeDefinitions, iEntries);
-
- return false;
- }
-
- default: {
- BUD::Error("Unknown type definition passed to BUD::MultiGet; expected: i/s/f, given: %c.", szTypeDefinitions[i]);
-
- return false;
- }
- }
- }
-
- if (iEntries != iNumTypeDefinitions) {
- BUD::Error("The number of type definitions doesn't match the number of entries passed to BUD::MultiGet; typedefs: %d, entries: %d.", iNumTypeDefinitions, iEntries);
-
- return false;
- }
-
- if (!BUD::GetDB())
- return false;
-
- new
- szColumn[BUD::MAX_COLUMN_NAME],
- iColumnArg
- ;
-
- g_szBuffer = "SELECT `";
-
- for (new iEntry = 0; iEntry < iEntries; iEntry++) {
- iColumnArg = 2 + iEntry * 2;
-
- __getstringarg(szColumn, iColumnArg);
-
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
- return false;
- #endif
-
- strcat(g_szBuffer, szColumn);
-
- if (iEntry < iEntries - 1)
- strcat(g_szBuffer, "`,`");
- }
-
- strcat(g_szBuffer, "` FROM `users` WHERE `uid`=");
-
- new
- szUID[11],
- DBResult:dbrResult
- ;
-
- valstr(szUID, iUID);
-
- strcat(g_szBuffer, szUID);
-
- dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
-
- if (dbrResult) {
- new
- iRows = db_num_rows(dbrResult)
- ;
-
- if (iRows == 1) {
- new
- iFields = db_num_fields(dbrResult)
- ;
-
- if (iEntries != iFields)
- BUD::Warning("The number of entries requested doesn't match the given number; requested: %d, given: %d", iEntries, iFields);
-
- for (new iField = 0; iField < iFields; iField++) {
- if (iTypeDefinitions{ iField } == 's')
- db_get_field(dbrResult, iField, g_szBuffer, iTypeLengths[iField] - 1);
- else
- db_get_field(dbrResult, iField, g_szBuffer, sizeof(g_szBuffer) - 1);
-
- switch (iTypeDefinitions{ iField }) {
- case 'i', 'd': {
- setarg(2 + iField * 2 + 1, .value = strval(g_szBuffer));
- }
-
- case 'f': {
- setarg(2 + iField * 2 + 1, .value = _:floatstr(g_szBuffer));
- }
-
- case 's': {
- __setstringarg(2 + iField * 2 + 1, g_szBuffer);
- }
- }
- }
- } else if (iRows > 1) {
- BUD::Error("Multiple rows fetched from one UID; UID: %d, rows: %d", iUID, iRows);
-
- db_free_result(dbrResult);
-
- return false;
- }
-
- db_free_result(dbrResult);
-
- return true;
- }
-
- return false;
- }
- global bool:BUD::MultiSet(iUID, const szTypeDefinitions[], { _, Float }:...) {
- new
- iEntries = numargs() - 2
- ;
-
- if (iEntries & 0b1) {
- BUD::Error("A parameter is missing in BUD::MultiSet; expecting a variable/value in the end.", numargs() - 2);
-
- return false;
- }
-
- iEntries /= 2;
-
- if (iEntries > BUD::MULTISET_MAX_ENTRIES) {
- BUD::Error("Too many entires passed to BUD::MultiSet; entires: %d, limit: %d.", iEntries, BUD::MULTISET_MAX_ENTRIES);
-
- return false;
- }
-
- new
- iNumTypeDefinitions = strlen(szTypeDefinitions)
- ;
-
- if (iEntries != iNumTypeDefinitions) {
- BUD::Error("The number of type definitions doesn't match the number of entries passed to BUD::MultiSet; typedefs: %d, entries: %d.", iNumTypeDefinitions, iEntries);
-
- return false;
- }
-
- for (new i = 0; i < iNumTypeDefinitions; i++) {
- switch (szTypeDefinitions[i]) {
- case 'i', 'd', 'f', 's': { }
- default: {
- BUD::Error("Unknown type definition passed to BUD::MultiSet; expected: i/s/f, given: %c.", szTypeDefinitions[i]);
-
- return false;
- }
- }
- }
-
- if (!BUD::GetDB())
- return false;
-
- new
- szColumn[BUD::MAX_COLUMN_NAME],
- iColumnArg,
- szValue[BUD::MULTISET_MAX_STRING_SIZE * 2]
- ;
-
- g_szBuffer = "UPDATE `users` SET ";
-
- for (new iEntry = 0; iEntry < iEntries; iEntry++) {
- iColumnArg = 2 + iEntry * 2;
-
- __getstringarg(szColumn, iColumnArg);
-
- ++iColumnArg;
-
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
- return false;
- #endif
-
- strcat(g_szBuffer, "`");
- strcat(g_szBuffer, szColumn);
- strcat(g_szBuffer, "`=");
-
- switch (szTypeDefinitions[iEntry]) {
- case 'i', 'd': {
- valstr(szValue, getarg(iColumnArg));
- }
-
- case 'f': {
- format(szValue, sizeof(szValue), "%f", Float:getarg(iColumnArg));
- }
-
- case 's': {
- __getstringarg(szValue, iColumnArg, BUD::MULTISET_MAX_STRING_SIZE);
-
- szValue[BUD::MULTISET_MAX_STRING_SIZE - 1] = EOS;
-
- BUD::EscapeSqlString(szValue);
-
- strcat(g_szBuffer, "'");
- }
- }
-
- strcat(g_szBuffer, szValue);
-
- if (szTypeDefinitions[iEntry] == 's')
- strcat(g_szBuffer, "'");
-
- if (iEntry < iEntries - 1)
- strcat(g_szBuffer, ", ");
- }
-
- valstr(szValue, iUID);
-
- strcat(g_szBuffer, " WHERE `uid`=");
- strcat(g_szBuffer, szValue);
-
- db_query(g_dbKeptAlive, g_szBuffer);
-
- return true;
- }
- global bool:BUD::SetIntEntry(iUID, const szColumn[], iInput) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
- return false;
- #endif
-
- if (!BUD::GetDB())
- return false;
-
- format(g_szBuffer, sizeof(g_szBuffer), "UPDATE `users` SET `%s`=%d WHERE `uid`=%d", szColumn, iInput, iUID);
-
- db_query(g_dbKeptAlive, g_szBuffer);
-
- return true;
- }
- global bool:BUD::SetFloatEntry(iUID, const szColumn[], Float:fInput) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
- return false;
- #endif
-
- if (!BUD::GetDB())
- return false;
-
- format(g_szBuffer, sizeof(g_szBuffer), "UPDATE `users` SET `%s`=%f WHERE `uid`=%d", szColumn, fInput, iUID);
-
- db_query(g_dbKeptAlive, g_szBuffer);
-
- return true;
- }
- global bool:BUD::SetStringEntry(iUID, const szColumn[], const szInput[], iSize = sizeof(szInput)) {
- #if (BUD::CHECK_STRING_LENGTH)
- if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME || strlen(szInput) >= BUD::MAX_ENTRY_STRING)
- return false;
- #endif
-
- if (!BUD::GetDB())
- return false;
-
- new
- szUID[11]
- ;
-
- memcpy(g_szBuffer, szInput, .numbytes = (iSize * (cellbits / 8))+4);
-
- BUD::EscapeSqlString(g_szBuffer);
-
- valstr(szUID, iUID);
-
- strins(g_szBuffer, "UPDATE `users` SET `", 0);
- strins(g_szBuffer, szColumn, 20);
- strins(g_szBuffer, "`='", 20 + strlen(szColumn));
- strcat(g_szBuffer, "' WHERE `uid`=");
- strcat(g_szBuffer, szUID);
-
- db_query(g_dbKeptAlive, g_szBuffer);
-
- return true;
- }
- global BUD::EscapeSqlString(szString[], iEnclosingChar = '\'', iSize = sizeof(szString)) {
- new
- iLength = strlen(szString),
- szInsert[2]
- ;
-
- szInsert[0] = iEnclosingChar;
-
- for (new i = 0; i <= iLength; i++) {
- if (szString[i] == iEnclosingChar) {
-
- if (i > iLength - 1) {
- szString[i] = EOS;
-
- break;
- } else {
- if (iLength >= iSize - 1) {
- szString[iLength - 1] = EOS;
-
- --iLength;
- }
-
- strins(szString, szInsert, i, iSize);
-
- ++iLength;
- ++i;
- }
- }
- }
- }
- global DBResult:BUD::RunQuery(szQuery[], bool:bStoreResult) {
- if (!BUD::GetDB()) {
- BUD::Error("No DB in BUD::RunQuery.");
-
- return BUD::NO_RESULT;
- }
-
- new
- DBResult:dbrResult = db_query(g_dbKeptAlive, szQuery)
- ;
-
- if (dbrResult) {
- if (bStoreResult) {
- SetTimerEx("BUD_FreeResult", 0, false, "i", _:dbrResult);
-
- return dbrResult;
- } else
- db_free_result(dbrResult);
- }
-
- return BUD::NO_RESULT;
- }
- forward BUD::FreeResult(DBResult:dbrResult);
- public BUD::FreeResult(DBResult:dbrResult) {
- db_free_result(dbrResult);
- }
- global BUD::GetSortedData(brResults[][], const szColumnName[], BUD::e_SORT_ORDER:iSortOrder = BUD::SORT_DESC, const szConditions[] = "", iResults = sizeof(brResults)) {
- if (!BUD::GetDB())
- return -1;
-
- new
- DBResult:dbrResult,
- iReturn = -1
- ;
-
- format(g_szBuffer, sizeof(g_szBuffer), "SELECT `uid`, `%s` FROM `users` %s ORDER BY `%s` %s LIMIT %d", szColumnName, szConditions, szColumnName, (BUD::SORT_ASC == iSortOrder) ? ("ASC") : ("DESC"), iResults);
-
- dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
-
- if (dbrResult) {
- if (db_num_rows(dbrResult) > 0) {
- new
- iIndex
- ;
-
- do {
- db_get_field(dbrResult, 0, g_szBuffer, sizeof(g_szBuffer) - 1);
-
- brResults[iIndex][0] = strval(g_szBuffer);
-
- db_get_field(dbrResult, 1, g_szBuffer, sizeof(g_szBuffer) - 1);
-
- brResults[iIndex][1] = strval(g_szBuffer);
-
- ++iIndex;
- }
- while (db_next_row(dbrResult) && iIndex < iResults);
-
- iReturn = iIndex;
- }
-
- db_free_result(dbrResult);
- }
-
- return iReturn;
- }
- global bool:BUD::GetNamesForSortedData(brResults[][], iResults, szaNames[][], iMaxName = sizeof(szaNames[])) {
- if (!BUD::GetDB())
- return false;
-
- new
- szUID[11],
- iUID,
- i,
- DBResult:dbrResult
- ;
-
- g_szBuffer = "SELECT `uid`, `name` FROM `users` WHERE `uid` IN (";
-
- for (i = 0; i < iResults; i++) {
- valstr(szUID, brResults[i][0]);
-
- strcat(g_szBuffer, szUID);
-
- if (i + 1 < iResults)
- strcat(g_szBuffer, ",");
- }
-
- strcat(g_szBuffer, ")");
-
- dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
-
- if (dbrResult) {
- if (db_num_rows(dbrResult) > 0) {
- new
- iIndex,
- bool:bFound
- ;
-
- do {
- db_get_field(dbrResult, 0, szUID, sizeof(szUID) - 1);
-
- iUID = strval(szUID);
-
- bFound = false;
-
- for (i = 0; i < iResults; i++) {
- if (brResults[i][0] == iUID) {
- db_get_field(dbrResult, 1, szaNames[i], iMaxName - 1);
-
- bFound = true;
-
- break;
- }
- }
-
- if (!bFound) {
- new
- szName[MAX_PLAYER_NAME + 1]
- ;
-
- db_get_field(dbrResult, 1, szName, sizeof(szName) - 1);
-
- BUD::Warning("Unable to find the place for %s (%d) in BUD::GetNamesForSortedData.", szName, iUID);
-
- szaNames[i][0] = 0;
-
- strcat(szaNames[i], "UNKNOWN", iMaxName);
- }
-
- ++iIndex;
- }
- while (db_next_row(dbrResult) && iIndex < iResults);
- }
-
- db_free_result(dbrResult);
-
- return true;
- }
-
- return false;
- }
- forward BUD::funcinc();
- public BUD::funcinc() {
- new szNothing[1];
-
- strcat(szNothing, "");
- format(szNothing, 0, "");
- printf("");
- }
- global DBResult:BUD::RunQueryEx(const szQuery[], bool:bStoreResult = false, {Float, _}:...) {
- if (!BUD::GetDB()) {
- BUD::Error("No DB in BUD::RunQuery.");
-
- return BUD::NO_RESULT;
- }
-
- const
- STATIC_ARGS = 2
- ;
-
- new
- iPos = -1,
- iArg = STATIC_ARGS,
- iIndex = 0,
- iArgumentAddress,
-
- iArguments, // Number of arguments
- aiArguments[128] // Argument addresses
- ;
-
- static
- axArguments[128], // "x" as in any tag. Contains single cell arguments.
- s_szStringBuffer[10240 + 1] // The last cell is used to see if the buffer ran out of space; hence the + 1.
- ;
-
- s_szStringBuffer[0] = 0;
-
- while (-1 != (iPos = strfind(szQuery, "%", _, iPos))) {
- if (szQuery[++iPos] == '%')
- continue;
-
- while (szQuery[iPos]) {
- switch (szQuery[iPos]) {
- case 'a' .. 'z', 'A' .. 'Z':
- break;
-
- case ' ', '*', '.', '!', '-', '?', '0' .. '9': {
- iPos++;
-
- continue;
- }
- }
- }
-
- switch (szQuery[iPos]) {
- case '\0': {
- break;
- }
-
- case 's': {
- iIndex += strlen(s_szStringBuffer[iIndex]);
-
- if (iIndex)
- iIndex++;
-
- if (iIndex >= sizeof(s_szStringBuffer) - 1) {
- BUD::Error("The string buffer in BUD::RunQueryEx is out of space. You must increase the size of it.");
-
- return BUD::NO_RESULT;
- }
-
- __getstringarg(s_szStringBuffer[iIndex], iArg, sizeof(s_szStringBuffer) - iIndex);
-
- if (s_szStringBuffer[sizeof(s_szStringBuffer) - 2]) {
- BUD::Error("The string buffer in BUD::RunQueryEx ran out of space. You must increase the size of it.");
-
- return BUD::NO_RESULT;
- }
-
- BUD::EscapeSqlString(s_szStringBuffer[iIndex], _, sizeof(s_szStringBuffer) - iIndex);
-
- #emit CONST.pri s_szStringBuffer
- #emit STOR.S.pri iArgumentAddress
-
- iArgumentAddress += iIndex * 4;
-
- aiArguments[iArguments++] = iArgumentAddress;
- }
-
- default: {
- axArguments[iArg] = getarg(iArg);
-
- #emit CONST.pri axArguments
- #emit STOR.S.pri iArgumentAddress
-
- iArgumentAddress += iArg * 4;
-
- aiArguments[iArguments++] = iArgumentAddress;
- }
- }
-
- iArg++;
-
- if (iArg >= sizeof(axArguments) - 1) {
- BUD::Error("Argument limit exceeded in BUD::RunQueryEx.");
-
- return BUD::NO_RESULT;
- }
- }
-
- new
- iArgCount = (3 + iArguments) * 4,
- i = iArguments,
- iSize = sizeof(s_szStringBuffer)
- ;
-
- while (--i >= 0) {
- iArg = aiArguments[i];
-
- #emit PUSH.S iArg
- }
-
- #emit PUSH.S szQuery
- #emit PUSH.S iSize
- #emit CONST.pri s_szStringBuffer
- #emit PUSH.pri
- #emit PUSH.S iArgCount
- #emit SYSREQ.C format
- iArgCount += 4;
- #emit LCTRL 4
- #emit LOAD.S.alt iArgCount
- #emit ADD
- #emit SCTRL 4
-
- new
- DBResult:dbrResult = db_query(g_dbKeptAlive, s_szStringBuffer)
- ;
-
- if (dbrResult) {
- if (bStoreResult) {
- SetTimerEx("BUD_FreeResult", 0, false, "i", _:dbrResult);
-
- return dbrResult;
- } else
- db_free_result(dbrResult);
- }
-
- return BUD::NO_RESULT;
- }
- // Inspired by Y_Less!
- private BUD::CheckForUpdates() {
- HTTP(0xFA7E, HTTP_GET, "spelsajten.net/bud_version.php?version=0x" #BUD_VERSION_MINOR #BUD_VERSION_MAJOR #BUD_VERSION_BUILD, "", "BUD_HTTPResponse");
- }
- forward BUD::HTTPResponse(iIndex, iResponseCode, szData[]);
- public BUD::HTTPResponse(iIndex, iResponseCode, szData[]) {
- if (iResponseCode == 200) {
- switch (szData[0]) {
- case '0': return; // Up-to-date
- case '1': BUD::Notice("There is a new update available.");
- case '2': BUD::Warning("There is a new version out; upgrading is strongly recommended.");
- case '3': { // New version available; upgrading has to be done.
- new
- iTick = GetTickCount()
- ;
-
- BUD::Error("This version is outdated; you have to upgrade your script because of security reasons.");
-
- SetGameModeText("LOOK AT THE SERVER LOG");
-
- while (GetTickCount() - iTick < 3000) {}
-
- SendRconCommand("exit");
- }
- }
- } else {
- if (iResponseCode < 100)
- BUD::Notice("Unable to check for updates; internal error code %d.", iResponseCode);
- else
- BUD::Notice("Unable to check for updates; HTTP error code %d.", iResponseCode);
- }
- }
- // Y_Less
- private __getstringarg(dest[], arg, len = sizeof (dest))
- {
- // Get the address of the previous function's stack. First get the index of
- // the argument required.
- #emit LOAD.S.pri arg
- // Then convert that number to bytes from cells.
- #emit SMUL.C 4
- // Get the previous function's frame. Stored in variable 0 (in the current
- // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
- // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
- // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
- // count (in C pointer speak).
- #emit LOAD.S.alt 0
- // Add the frame pointer to the argument offset in bytes.
- #emit ADD
- // Add 12 to skip over the function header.
- #emit ADD.C 12
- // Load the address stored in the specified address.
- #emit LOAD.I
- // Push the length for "strcat".
- #emit PUSH.S len
- // Push the address we just determined was the source.
- #emit PUSH.pri
- // Load the address of the destination.
- #emit LOAD.S.alt dest
- // Blank the first cell so "strcat" behaves like "strcpy".
- #emit CONST.pri 0
- // Store the loaded number 0 to the loaded address.
- #emit STOR.I
- // Push the loaded address.
- #emit PUSH.alt
- // Push the number of parameters passed (in bytes) to the function.
- #emit PUSH.C 12
- // Call the function.
- #emit SYSREQ.C strcat
- // Restore the stack to its level before we called this native.
- #emit STACK 16
- }
- // Modification of above
- stock __setstringarg(iArg, const szValue[], iLength = sizeof(szValue)) {
- new
- iAddress
- ;
- // Get the address of the previous function's stack. First get the index of
- // the argument required.
- #emit LOAD.S.pri iArg
- // Then convert that number to bytes from cells.
- #emit SMUL.C 4
- // Get the previous function's frame.
- #emit LOAD.S.alt 0
- // Add the frame pointer to the argument offset in bytes.
- #emit ADD
- // Add 12 to skip over the function header.
- #emit ADD.C 12
- // Load the address stored in the specified address.
- #emit LOAD.I
- #emit STOR.S.PRI iAddress
- // Push the length (last argument first)
- #emit PUSH.S iLength
- // Push the new value (source) szValue
- #emit PUSH.S szValue
- // Blank out the first cell of the argument
- #emit CONST.pri 0
- #emit SREF.S.pri iAddress
-
- // Push the destination
- #emit PUSH.S iAddress
- // Push the number of parameters passed (in bytes) to the function.
- #emit PUSH.C 12
-
- // Call the function.
- #emit SYSREQ.C strcat
-
- // Restore the stack to its level before we called this native.
- #emit STACK 16
- }
- #if (BUD::USE_WHIRLPOOL && UNDEFINE_MAX_PASSWORD_LENGTH)
- #undef MAX_PASSWORD_LENGTH
- #endif
- #undef UNDEFINE_MAX_PASSWORD_LENGTH
- #undef INVALID_DB
- #undef DEFAULT_COLUMNS
- #undef DEFAULT_DATABASE_NAME
- #undef BUD_Notice
- #undef BUD_Warning
- #undef BUD_Error
- #undef private
- #undef global
- #if defined __undef_celbytes
- #undef __undef_celbytes
- #undef cellbytes
- #endif
|