mux2.6/0000700000175000017500000000000011025753746012005 5ustar sdennissdennismux2.6/ATTACK0000600000175000017500000000760111025753746012705 0ustar sdennissdennisTinyMUX 2.6: ATTACK Last Update: December 2006 You should familiarize yourself with defensive procedures that serve to thwart the effects of attacks. Don't wait until an attack is mounted against your game to begin learning how to defend it against an attacker. Practice for this eventuality now. Player Creation: ---------------- If you are running an open game, it is possible for an automated script to create players faster than you can can destroy them. Even if a group of people are doing it manually, the odds are they can create player objects faster than you can destroy them. As a WIZARD, there are a few remedies available to you: @disable logins As #1, there are some additional remedies available to you: @admin register_site=0/0 @aahear attack: --------------- With TinyMUX 2.2 and later, the @aahear exploit is no longer as useful to attackers as it once was. This attack was usually mixed with other forms of attack to obscure it. @pemit/page attack: ------------------- The combination of lwho() and @pemit can be used for spamming. As a player, WIZARD, or #1, you can prevent being spammed by: &CANPAGEME me=0 @lock/page me=CANPAGEME/1 @admin pemit_far_players=0 (the default) Attack on the queue: -------------------- Usually, putting lots of commands on the queue will drain an attackers store of coins. However, if they happen to obtain the free_money power (or WIZARD permissions...by which time you're toast anyway), then they can attack the queue. As a WIZARD or #1, there are a few remedies available to you: @disable dequeueing Attribute attack: ----------------- The server will not allow more than a few thousand attributes per object. This attack is no longer feasible. Attribute Name Attack: ---------------------- Attribute names are different than the attribute values they name. By default, mortals are not allowed to create more than 5000 new names per hour. See 'wizhelp user_attrib_per_hour'. However, the site admin still needs to keep an eye on attribute names as described below in 'General Server Hygiene'. @Mail Attack: ------------- Mortals are not allowed to send more than 50 @mails per hour. However, the site admin still needs to keep an eye on the size of @mail. See 'wizhelp mail_per_hour'. CPU Slaming: ------------ There are ways of consuming hours and days of CPU time with carefully chosen softcode. The lag_limit configuration option controls the point at which the server abbreviates its efforts. In some ways, this is like hitting a Function Invocation Limit. One additional thing that hitting a lag_limit does is @halt the offending code. General server hygiene: ----------------------- There are a few things you should do on a regular basis: - Backups. Off-line backups. Don't expect much sympathy if you can't put your hands on a good backup. - Good backups. Manually verify that your backups are valid and complete. Don't expect much sympathy if you can't put your hands on a good backup. Did you put your backup on a ZIP disk? Can you still read it? Do you smoke? - Backup often. How much work are you willing to lose? - Keep an eye on how much CPU and memory your server process is consuming. Your memory usage will gradual increase and slowly approach some number. If your memory usage suddenly goes above this, something is wrong. If your CPU usage is not usually 0% or on a busy game, less than 5% for awhile, Look for an attack in progress. Get a 'feel' for what is normal for you game and be sensitive to what might be abnormal. ps ux -A - Keep an eye on attribute names (Vattr names) with the following command: @list hashstats The column you care about is the 'entries' column. This number will always increase, however, stale names can be removed by #1 using the @dbclean command. Run @dbclean approximately every 3 months. mux2.6/INSTALL0000600000175000017500000001111011025753746013032 0ustar sdennissdennisTinyMUX 2.6: INSTALL Last Update: January 2008 Please note that there are two sets of instructions included in this file. Please skip to 'Instructions for Existing Games' for how to upgrade your server or to compile in preparation for moving an existing game. Instructions for New Installations: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. cd src/ to the source directory. Run './configure'. This will customize autoconf.h and Makefile for your system. Optional packages are documented separately and enabled with the following configuration options: --enable-firanmux For use by FiranMUX. Not recommended generally. --enable-memorybased See docs/MEMORY. --enable-realitylvls See REALITY and REALITY.SETUP. --enable-wodrealms See docs/REALMS. --enable-deprecated Enables deprecated features. 2. Edit the Configuration section of the Makefile. This is usually not needed. Most likely, all you will need to change are any C++ flags needed by your particular C++ compiler, (in particular -fpcc-struct-return), and any esoteric libraries needed by your system. There may also be some #defines in config.h that you may want to change, but in general, the defaults should not be changed. 3. Run make depend, then make. This will produce netmux, slave, and dbconvert. 4. When starting from a TinyMUX from scratch, do the following: - cd to the game directory. 'cd ../game' - Make your configuration file, as described in docs/CONFIGURATION - Type './Startmux'. TinyMUX 2.6 automatically creates a minimal DB if one does not exist in the game/data directory. - Log into the game as player wizard 'connect wizard potrzebie', and shut it down again. 5. Edit the .txt files in game/text to your liking. In particular, connect.txt and motd.txt. 6. Start up TinyMUX 2.6 by running './Startmux' again. 7. @ccreate a channel named 'Public', and a channel named 'Guests' from within the TinyMUX. Created players will automatically be joined to 'Public' with alias 'pub', guests will automatically join 'Guests' with alias 'g'. Changes to dbconvert: ~~~~~~~~~~~~~~~~~~~~ - dbconvert is the means by which the binary game data is converted to flatfile format and back again. The db_load and db_unload scripts simplify the process for the user. - The syntax of the scripts is: - './db_load netmux netmux.flat netmux.db' This converts a flatfile database to binary for use by the server and would be done with dbconvert thus: ../bin/dbconvert -dnetmux -inetmux.flat -onetmux.db -l - './db_unload netmux netmux.db.new netmux.flat' This converts binary data to flatfile for would be done with dbconvert thus: ../bin/dbconvert -dnetmux -inetmux.db.new -onetmux.flat -u Instructions for Existing Games: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [NOTE: It is HIGHLY recommended that you preserve a previous setup if you can, to make conversion a bit less painful. If you had one while converting, make sure the conversion process has completed successfully before you delete your old distribution. We cannot stress enough to you the importance of protecting your data throughout any conversion or upgrade.] 1. cd src/ to the source directory. Run './configure'. This will customize autoconf.h and Makefile for your system. Add the option '--enable-wodrealms' to enable WOD Realms (See docs/REALMS). Add '--enable-memorybased' to enable Memory-Based database handling (as opposed to the default disk-based database handling. See docs/MEMORY). 2. Edit the Configuration section of the Makefile. This is usually not needed. Most likely, all you will need to change are any C++ flags needed by your particular C++ compiler, (in particular -fpcc-struct-return), and any esoteric libraries needed by your system. There may also be some #defines in config.h that you may want to change, but in general, the defaults should not be changed. 3. Run make depend, then make. This will produce netmux, slave, and dbconvert. 4. - Put databases in game/data. - Put text files in game/text. - The scripts db_load, db_unload, and db_check may be found in the game/data directory. - If you changed the GAMENAME in mux.config, be sure to change the filenames in GAMENAME.conf as well. - If you had a mail database previously, adjust mail_expiration accordingly, BEFORE you restart the game, or else ALL @mail older than the default value of 14 days will be deleted. 5. Start TinyMUX 2.6 by running './Startmux'. mux2.6/src/0000700000175000017500000000000011025753746012574 5ustar sdennissdennismux2.6/src/attrcache.cpp0000600000175000017500000003155011025753746015244 0ustar sdennissdennis/*! \file attrcache.cpp * Attribute caching module. * * $Id: attrcache.cpp 3049 2007-12-30 06:35:41Z brazilofmux $ * * The functions here manage the upper-level attribute value cache for * disk-based mode. It's not used in memory-based builds. The lower-level * cache is managed in svdhash.cpp * * The upper-level cache is organized by a CHashTable and a linked list. The * former allows random access while the linked list helps find the * least-recently-used attribute. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #if !defined(MEMORY_BASED) static CHashFile hfAttributeFile; static bool cache_initted = false; static bool cache_redirected = false; #define N_TEMP_FILES 8 static FILE *TempFiles[N_TEMP_FILES]; CLinearTimeAbsolute cs_ltime; #pragma pack(1) typedef struct tagAttrRecord { Aname attrKey; char attrText[LBUF_SIZE]; } ATTR_RECORD, *PATTR_RECORD; #pragma pack() static ATTR_RECORD TempRecord; typedef struct tagCacheEntryHeader { struct tagCacheEntryHeader *pPrevEntry; struct tagCacheEntryHeader *pNextEntry; Aname attrKey; size_t nSize; } CENT_HDR, *PCENT_HDR; static PCENT_HDR pCacheHead = 0; static PCENT_HDR pCacheTail = 0; static size_t CacheSize = 0; int cache_init(const char *game_dir_file, const char *game_pag_file, int nCachePages) { if (cache_initted) { return HF_OPEN_STATUS_ERROR; } int cc = hfAttributeFile.Open(game_dir_file, game_pag_file, nCachePages); if (cc != HF_OPEN_STATUS_ERROR) { // Mark caching system live // cache_initted = true; cs_ltime.GetUTC(); } return cc; } void cache_redirect(void) { for (int i = 0; i < N_TEMP_FILES; i++) { char TempFileName[20]; mux_sprintf(TempFileName, sizeof(TempFileName), "$convtemp.%d", i); mux_assert(mux_fopen(&TempFiles[i], TempFileName, "wb+")); mux_assert(TempFiles[i]); setvbuf(TempFiles[i], NULL, _IOFBF, 16384); } cache_redirected = true; } void cache_pass2(void) { ATTR_RECORD Record; cache_redirected = false; fprintf(stderr, "2nd Pass:\n"); for (int i = 0; i < N_TEMP_FILES; i++) { fprintf(stderr, "File %d: ", i); long int li = fseek(TempFiles[i], 0, SEEK_SET); mux_assert(0L == li); int cnt = 1000; size_t nSize; for (;;) { size_t cc = fread(&nSize, 1, sizeof(nSize), TempFiles[i]); if (cc != sizeof(nSize)) { break; } cc = fread(&Record, 1, nSize, TempFiles[i]); mux_assert(cc == nSize); cache_put(&Record.attrKey, Record.attrText, nSize - sizeof(Aname)); if (cnt-- == 0) { fputc('.', stderr); fflush(stderr); cnt = 1000; } } fclose(TempFiles[i]); char TempFileName[20]; mux_sprintf(TempFileName, sizeof(TempFileName), "$convtemp.%d", i); RemoveFile(TempFileName); fprintf(stderr, ENDLINE); } } void cache_cleanup(void) { for (int i = 0; i < N_TEMP_FILES; i++) { fclose(TempFiles[i]); char TempFileName[20]; mux_sprintf(TempFileName, sizeof(TempFileName), "$convtemp.%d", i); RemoveFile(TempFileName); } } void cache_close(void) { hfAttributeFile.CloseAll(); cache_initted = false; } void cache_tick(void) { hfAttributeFile.Tick(); } static void REMOVE_ENTRY(PCENT_HDR pEntry) { // How is X positioned? // if (pEntry == pCacheHead) { if (pEntry == pCacheTail) { // HEAD --> X --> 0 // 0 <-- <-- TAIL // // ASSERT: pEntry->pNextEntry == 0; // ASSERT: pEntry->pPrevEntry == 0; // pCacheHead = pCacheTail = 0; } else { // HEAD --> X --> Y --> 0 // 0 <-- <-- <-- TAIL // // ASSERT: pEntry->pNextEntry != 0; // ASSERT: pEntry->pPrevEntry == 0; // pCacheHead = pEntry->pNextEntry; pCacheHead->pPrevEntry = 0; pEntry->pNextEntry = 0; } } else if (pEntry == pCacheTail) { // HEAD --> Y --> X --> 0 // 0 <-- <-- <-- TAIL // // ASSERT: pEntry->pNextEntry == 0; // ASSERT: pEntry->pPrevEntry != 0; // pCacheTail = pEntry->pPrevEntry; pCacheTail->pNextEntry = 0; pEntry->pPrevEntry = 0; } else { // HEAD --> Y --> X --> Z --> 0 // 0 <-- <-- <-- <-- TAIL // // ASSERT: pEntry->pNextEntry != 0; // ASSERT: pEntry->pNextEntry != 0; // pEntry->pNextEntry->pPrevEntry = pEntry->pPrevEntry; pEntry->pPrevEntry->pNextEntry = pEntry->pNextEntry; pEntry->pNextEntry = 0; pEntry->pPrevEntry = 0; } } static void ADD_ENTRY(PCENT_HDR pEntry) { if (pCacheHead) { pCacheHead->pPrevEntry = pEntry; } pEntry->pNextEntry = pCacheHead; pEntry->pPrevEntry = 0; pCacheHead = pEntry; if (!pCacheTail) { pCacheTail = pCacheHead; } } static void TrimCache(void) { // Check to see if the cache needs to be trimmed. // while (CacheSize > mudconf.max_cache_size) { // Blow something away. // PCENT_HDR pCacheEntry = pCacheTail; if (!pCacheEntry) { CacheSize = 0; break; } REMOVE_ENTRY(pCacheEntry); CacheSize -= pCacheEntry->nSize; hashdeleteLEN(&(pCacheEntry->attrKey), sizeof(Aname), &mudstate.acache_htab); MEMFREE(pCacheEntry); pCacheEntry = NULL; } } const char *cache_get(Aname *nam, size_t *pLen) { if ( nam == (Aname *) 0 || !cache_initted) { *pLen = 0; return NULL; } PCENT_HDR pCacheEntry = NULL; if (!mudstate.bStandAlone) { // Check the cache, first. // pCacheEntry = (PCENT_HDR)hashfindLEN(nam, sizeof(Aname), &mudstate.acache_htab); if (pCacheEntry) { // It was in the cache, so move this entry to the head of the queue. // and return a pointer to it. // REMOVE_ENTRY(pCacheEntry); ADD_ENTRY(pCacheEntry); if (sizeof(CENT_HDR) < pCacheEntry->nSize) { *pLen = pCacheEntry->nSize - sizeof(CENT_HDR); return (char *)(pCacheEntry+1); } else { *pLen = 0; return NULL; } } } UINT32 nHash = CRC32_ProcessInteger2(nam->object, nam->attrnum); UINT32 iDir = hfAttributeFile.FindFirstKey(nHash); while (iDir != HF_FIND_END) { HP_HEAPLENGTH nRecord; hfAttributeFile.Copy(iDir, &nRecord, &TempRecord); if ( TempRecord.attrKey.attrnum == nam->attrnum && TempRecord.attrKey.object == nam->object) { int nLength = nRecord - sizeof(Aname); *pLen = nLength; if (!mudstate.bStandAlone) { // Add this information to the cache. // pCacheEntry = (PCENT_HDR)MEMALLOC(sizeof(CENT_HDR)+nLength); if (pCacheEntry) { pCacheEntry->attrKey = *nam; pCacheEntry->nSize = nLength + sizeof(CENT_HDR); CacheSize += pCacheEntry->nSize; memcpy((char *)(pCacheEntry+1), TempRecord.attrText, nLength); ADD_ENTRY(pCacheEntry); hashaddLEN(nam, sizeof(Aname), pCacheEntry, &mudstate.acache_htab); TrimCache(); } } return TempRecord.attrText; } iDir = hfAttributeFile.FindNextKey(iDir, nHash); } // We didn't find that one. // if (!mudstate.bStandAlone) { // Add this information to the cache. // pCacheEntry = (PCENT_HDR)MEMALLOC(sizeof(CENT_HDR)); if (pCacheEntry) { pCacheEntry->attrKey = *nam; pCacheEntry->nSize = sizeof(CENT_HDR); CacheSize += pCacheEntry->nSize; ADD_ENTRY(pCacheEntry); hashaddLEN(nam, sizeof(Aname), pCacheEntry, &mudstate.acache_htab); TrimCache(); } } *pLen = 0; return NULL; } // cache_put no longer frees the pointer. // bool cache_put(Aname *nam, const char *value, size_t len) { if ( !value || !nam || !cache_initted || len == 0) { return false; } #ifndef WIN32 if (mudstate.write_protect) { Log.tinyprintf("cache_put((%d,%d), '%s', %u) while database is write-protected" ENDLINE, nam->object, nam->attrnum, value, len); return false; } #endif if (len > sizeof(TempRecord.attrText)) { len = sizeof(TempRecord.attrText); } // Removal from DB. // UINT32 nHash = CRC32_ProcessInteger2(nam->object, nam->attrnum); if (cache_redirected) { TempRecord.attrKey = *nam; memcpy(TempRecord.attrText, value, len); TempRecord.attrText[len-1] = '\0'; int iFile = (N_TEMP_FILES-1) & (nHash >> 29); size_t nSize = len+sizeof(Aname); fwrite(&nSize, 1, sizeof(nSize), TempFiles[iFile]); fwrite(&TempRecord, 1, nSize, TempFiles[iFile]); return true; } UINT32 iDir = hfAttributeFile.FindFirstKey(nHash); while (iDir != HF_FIND_END) { HP_HEAPLENGTH nRecord; hfAttributeFile.Copy(iDir, &nRecord, &TempRecord); if ( TempRecord.attrKey.attrnum == nam->attrnum && TempRecord.attrKey.object == nam->object) { hfAttributeFile.Remove(iDir); } iDir = hfAttributeFile.FindNextKey(iDir, nHash); } TempRecord.attrKey = *nam; memcpy(TempRecord.attrText, value, len); TempRecord.attrText[len-1] = '\0'; // Insertion into DB. // if (!hfAttributeFile.Insert((HP_HEAPLENGTH)(len+sizeof(Aname)), nHash, &TempRecord)) { Log.tinyprintf("cache_put((%d,%d), '%s', %u) failed" ENDLINE, nam->object, nam->attrnum, value, len); } if (!mudstate.bStandAlone) { // Update cache. // PCENT_HDR pCacheEntry = (PCENT_HDR)hashfindLEN(nam, sizeof(Aname), &mudstate.acache_htab); if (pCacheEntry) { // It was in the cache, so delete it. // REMOVE_ENTRY(pCacheEntry); CacheSize -= pCacheEntry->nSize; hashdeleteLEN((char *)nam, sizeof(Aname), &mudstate.acache_htab); MEMFREE(pCacheEntry); pCacheEntry = NULL; } // Add information about the new entry back into the cache. // size_t nSizeOfEntry = sizeof(CENT_HDR) + len; pCacheEntry = (PCENT_HDR)MEMALLOC(nSizeOfEntry); if (pCacheEntry) { pCacheEntry->attrKey = *nam; pCacheEntry->nSize = nSizeOfEntry; CacheSize += pCacheEntry->nSize; memcpy((char *)(pCacheEntry+1), TempRecord.attrText, len); ADD_ENTRY(pCacheEntry); hashaddLEN(nam, sizeof(Aname), pCacheEntry, &mudstate.acache_htab); TrimCache(); } } return true; } bool cache_sync(void) { hfAttributeFile.Sync(); return true; } // Delete this attribute from the database. // void cache_del(Aname *nam) { if ( !nam || !cache_initted) { return; } #ifndef WIN32 if (mudstate.write_protect) { Log.tinyprintf("cache_del((%d,%d)) while database is write-protected" ENDLINE, nam->object, nam->attrnum); return; } #endif UINT32 nHash = CRC32_ProcessInteger2(nam->object, nam->attrnum); UINT32 iDir = hfAttributeFile.FindFirstKey(nHash); while (iDir != HF_FIND_END) { HP_HEAPLENGTH nRecord; hfAttributeFile.Copy(iDir, &nRecord, &TempRecord); if ( TempRecord.attrKey.attrnum == nam->attrnum && TempRecord.attrKey.object == nam->object) { hfAttributeFile.Remove(iDir); } iDir = hfAttributeFile.FindNextKey(iDir, nHash); } if (!mudstate.bStandAlone) { // Update cache. // PCENT_HDR pCacheEntry = (PCENT_HDR)hashfindLEN(nam, sizeof(Aname), &mudstate.acache_htab); if (pCacheEntry) { // It was in the cache, so delete it. // REMOVE_ENTRY(pCacheEntry); CacheSize -= pCacheEntry->nSize;; hashdeleteLEN((char *)nam, sizeof(Aname), &mudstate.acache_htab); MEMFREE(pCacheEntry); pCacheEntry = NULL; } } } #endif // MEMORY_BASED mux2.6/src/muxcli.cpp0000600000175000017500000001433711025753746014613 0ustar sdennissdennis// muxcli.cpp // // $Id: muxcli.cpp 3454 2008-04-01 22:39:40Z brazilofmux $ // #include "copyright.h" #include #include "muxcli.h" // 0 -- A non-option argument. // 1 -- A short-option argument. // 2 -- A long-option argument. // 3 -- An 'end of options' indicator. // static int iArgType(char *pArg) { // How many characters from "--" does the argument match? // static char aHHN[3] = "--"; int iType = 0; for (; iType < 3 && aHHN[iType] == pArg[iType]; iType++) { // Nothing } if (iType > 3) { iType = 3; } // "-" is a special case. It is a non-option argument. // if (iType == 1 && pArg[1] == '\0') { iType = 0; } return iType; } // Examples: // // 1. prog -c123 --> (c,123) // 2. prog -c 123 --> (c,123) // 3. prog -c=123 --> (c,123) // 4. prog -cs 123 --> (c,123) (s) // 5. prog -sc=123 --> (s) (c,123) // 6. prog -cs123 --> (c,s123) // void CLI_Process ( int argc, char *argv[], CLI_OptionEntry *aOptionTable, int nOptionTable, CLI_CALLBACKFUNC *pFunc ) { int minNonOption = 0; int bEndOfOptions = 0; for (int i = 1; i < argc; i++) { char *pArgv = argv[i]; int iType = 0; if (!bEndOfOptions) { iType = iArgType(pArgv); } if (iType == 0) { // Non-option argument. // if (minNonOption <= i) { // We haven't associated it with an option, yet, so // pass it in by itself. // pFunc(0, pArgv); } continue; } if (minNonOption < i+1) { minNonOption = i+1; } if (iType == 3) { // A "--" causes the remaining unpaired arguments to be // treated as non-option arguments. // bEndOfOptions = 1; continue; } const char *p = pArgv+iType; if (iType == 2) { // We have a long option. // const char *pEqual = strchr(p, '='); size_t nLen; if (pEqual) { nLen = pEqual - p; } else { nLen = strlen(p); } for (int j = 0; j < nOptionTable; j++) { if ( !strncmp(aOptionTable[j].m_Flag, p, nLen) && aOptionTable[j].m_Flag[nLen] == '\0') { switch (aOptionTable[j].m_ArgControl) { case CLI_NONE: pFunc(aOptionTable + j, 0); break; case CLI_OPTIONAL: case CLI_REQUIRED: if (pEqual) { pFunc(aOptionTable + j, pEqual+1); break; } int bFound = 0; for (; minNonOption < argc; minNonOption++) { int iType2 = iArgType(argv[minNonOption]); if (iType2 == 0) { pFunc(aOptionTable + j, argv[minNonOption]); minNonOption++; bFound = 1; break; } else if (iType2 == 3) { // End of options. Stop. // break; } } if ( !bFound && aOptionTable[j].m_ArgControl == CLI_OPTIONAL) { pFunc(aOptionTable + j, 0); } break; } break; } } continue; } // At this point, the only possibilities left are a short // option. // while (*p) { int ch = *p++; for (int j = 0; j < nOptionTable; j++) { if ( aOptionTable[j].m_Flag[0] == ch && aOptionTable[j].m_Flag[1] == '\0') { switch (aOptionTable[j].m_ArgControl) { case CLI_NONE: pFunc(aOptionTable + j, 0); break; case CLI_OPTIONAL: case CLI_REQUIRED: if (*p) { // Value follows option letter // if (*p == '=') { p++; } pFunc(aOptionTable + j, p); p = ""; break; } int bFound = 0; for (; minNonOption < argc; minNonOption++) { int iType2 = iArgType(argv[minNonOption]); if (iType2 == 0) { pFunc(aOptionTable + j, argv[minNonOption]); minNonOption++; bFound = 1; break; } else if (iType2 == 3) { // End of options. Stop. // break; } } if ( !bFound && aOptionTable[j].m_ArgControl == CLI_OPTIONAL) { pFunc(aOptionTable + j, 0); } break; } break; } } } } } mux2.6/src/svdhash.cpp0000600000175000017500000025320511025753746014751 0ustar sdennissdennis// svdhash.cpp -- CHashPage, CHashFile, CHashTable modules. // // $Id: svdhash.cpp 2475 2007-09-15 16:18:35Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #define DO_COMMIT int cs_writes = 0; // total writes int cs_reads = 0; // total reads int cs_dels = 0; // total deletes int cs_fails = 0; // attempts to grab nonexistent int cs_syncs = 0; // total cache syncs int cs_dbreads = 0; // total read-throughs int cs_dbwrites = 0; // total write-throughs int cs_whits = 0; // writes into cached pages int cs_rhits = 0; // read from cached pages static const UINT32 CRC32_Table[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; // Portable CRC-32 routine. These slower routines are less compiler and // platform dependent and still get the job done. // UINT32 CRC32_ProcessBuffer ( UINT32 ulCrc, const void *arg_pBuffer, size_t nBuffer ) { UINT8 *pBuffer = (UINT8 *)arg_pBuffer; ulCrc = ~ulCrc; while (nBuffer--) { ulCrc = CRC32_Table[((UINT8)*pBuffer++) ^ (UINT8)ulCrc] ^ (ulCrc >> 8); } return ~ulCrc; } UINT32 CRC32_ProcessInteger(UINT32 nInteger) { UINT32 ulCrc; ulCrc = ~nInteger; ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); return ~ulCrc; } UINT32 CRC32_ProcessInteger2(UINT32 nInteger1, UINT32 nInteger2) { UINT32 ulCrc; ulCrc = ~nInteger1; ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); ulCrc ^= nInteger2; ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8); return ~ulCrc; } #define DO1(buf,i) {s1 += buf[i]; s2 += s1;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); UINT32 HASH_ProcessBuffer ( UINT32 ulHash, const void *arg_pBuffer, size_t nBuffer ) { UINT8 *pBuffer = (UINT8 *)arg_pBuffer; ulHash = ~ulHash; if (nBuffer <= 16) { pBuffer -= 16 - nBuffer; switch (nBuffer) { case 16: ulHash = CRC32_Table[pBuffer[0] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 15: ulHash = CRC32_Table[pBuffer[1] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 14: ulHash = CRC32_Table[pBuffer[2] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 13: ulHash = CRC32_Table[pBuffer[3] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 12: ulHash = CRC32_Table[pBuffer[4] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 11: ulHash = CRC32_Table[pBuffer[5] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 10: ulHash = CRC32_Table[pBuffer[6] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 9: ulHash = CRC32_Table[pBuffer[7] ^ (UINT8)ulHash] ^ (ulHash >> 8); #if defined(UNALIGNED32) && defined(WORDS_LITTLEENDIAN) case 8: ulHash ^= *(UINT32 *)(pBuffer + 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash ^= *(UINT32 *)(pBuffer + 12); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); return ~ulHash; #else case 8: ulHash = CRC32_Table[pBuffer[8] ^ (UINT8)ulHash] ^ (ulHash >> 8); #endif case 7: ulHash = CRC32_Table[pBuffer[9] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 6: ulHash = CRC32_Table[pBuffer[10] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 5: ulHash = CRC32_Table[pBuffer[11] ^ (UINT8)ulHash] ^ (ulHash >> 8); #if defined(UNALIGNED32) && defined(WORDS_LITTLEENDIAN) case 4: ulHash ^= *(UINT32 *)(pBuffer + 12); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); return ~ulHash; #else case 4: ulHash = CRC32_Table[pBuffer[12] ^ (UINT8)ulHash] ^ (ulHash >> 8); #endif case 3: ulHash = CRC32_Table[pBuffer[13] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 2: ulHash = CRC32_Table[pBuffer[14] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 1: ulHash = CRC32_Table[pBuffer[15] ^ (UINT8)ulHash] ^ (ulHash >> 8); case 0: return ~ulHash; } } size_t nSmall = nBuffer & 15; size_t nMedium = (nBuffer >> 4) & 255; size_t nLarge = nBuffer >> 12; UINT32 s1 = ulHash & 0xFFFF; UINT32 s2 = (ulHash >> 16) & 0xFFFF; while (nLarge--) { int k = 256; while (k) { DO16(pBuffer); pBuffer += 16; k--; } ulHash = ~s1; ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash ^= s2; ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = ~ulHash; s1 = ulHash & 0xFFFF; s2 = (ulHash >> 16) & 0xFFFF; } while (nMedium--) { DO16(pBuffer); pBuffer += 16; } pBuffer -= 15 - nSmall; switch (nSmall) { case 15: s1 += pBuffer[0]; s2 += s1; case 14: s1 += pBuffer[1]; s2 += s1; case 13: s1 += pBuffer[2]; s2 += s1; case 12: s1 += pBuffer[3]; s2 += s1; case 11: s1 += pBuffer[4]; s2 += s1; case 10: s1 += pBuffer[5]; s2 += s1; case 9: s1 += pBuffer[6]; s2 += s1; case 8: s1 += pBuffer[7]; s2 += s1; case 7: s1 += pBuffer[8]; s2 += s1; case 6: s1 += pBuffer[9]; s2 += s1; case 5: s1 += pBuffer[10]; s2 += s1; case 4: s1 += pBuffer[11]; s2 += s1; case 3: s1 += pBuffer[12]; s2 += s1; case 2: s1 += pBuffer[13]; s2 += s1; case 1: s1 += pBuffer[14]; s2 += s1; case 0: break; } ulHash = ~s1; ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash ^= s2; ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8); return ~ulHash; } #define NUMBER_OF_PRIMES 177 const int Primes[NUMBER_OF_PRIMES] = { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 0 }; static void ChoosePrimes(int TableSize, HP_HEAPOFFSET HashPrimes[16]) { int LargestPrime = TableSize/2; if (LargestPrime > Primes[NUMBER_OF_PRIMES-2]) { LargestPrime = Primes[NUMBER_OF_PRIMES-2]; } int Spacing = LargestPrime/16; // Pick a set primes that are evenly spaced from (0 to LargestPrime) // We divide this interval into 16 equal sized zones. We want to find // one prime number that best represents that zone. // int iZone, iPrime; for (iZone = 1, iPrime = 0; iPrime < 16; iZone += Spacing) { // Search for a prime number that is less than the target zone // number given by iZone. // int Lower = Primes[0]; for (int jPrime = 0; Primes[jPrime] != 0; jPrime++) { if ( jPrime != 0 && TableSize % Primes[jPrime] == 0) { continue; } int Upper = Primes[jPrime]; if ( Lower <= iZone && iZone <= Upper) { // Choose the closest lower prime number. // if (iZone - Lower <= Upper - iZone) { HashPrimes[iPrime++] = static_cast(Lower); } else { HashPrimes[iPrime++] = static_cast(Upper); } break; } Lower = Upper; } } // Alternate negative and positive numbers // for (iPrime = 0; iPrime < 16; iPrime += 2) { HashPrimes[iPrime] = static_cast(TableSize-HashPrimes[iPrime]); } // Shuffle the set of primes to reduce correlation with bits in // hash key. // for (iPrime = 0; iPrime < 16-1; iPrime++) { int Pick = (int)RandomINT32(0, 15-iPrime); HP_HEAPOFFSET Temp = HashPrimes[Pick]; HashPrimes[Pick] = HashPrimes[15-iPrime]; HashPrimes[15-iPrime] = Temp; } } static const UINT32 anGroupMask[33] = { 0x00000000U, 0x80000000U, 0xC0000000U, 0xE0000000U, 0xF0000000U, 0xF8000000U, 0xFC000000U, 0xFE000000U, 0xFF000000U, 0xFF800000U, 0xFFC00000U, 0xFFE00000U, 0xFFF00000U, 0xFFF80000U, 0xFFFC0000U, 0xFFFE0000U, 0xFFFF0000U, 0xFFFF8000U, 0xFFFFC000U, 0xFFFFE000U, 0xFFFFF000U, 0xFFFFF800U, 0xFFFFFC00U, 0xFFFFFE00U, 0xFFFFFF00U, 0xFFFFFF80U, 0xFFFFFFC0U, 0xFFFFFFE0U, 0xFFFFFFF0U, 0xFFFFFFF8U, 0xFFFFFFFCU, 0xFFFFFFFEU, 0xFFFFFFFFU }; bool CHashPage::Allocate(unsigned int nPageSize) { if (m_nPageSize) return false; m_nPageSize = nPageSize; m_pPage = new unsigned char[nPageSize]; if (m_pPage) { return true; } return false; } CHashPage::CHashPage(void) { m_nPageSize = 0; m_pPage = 0; } CHashPage::~CHashPage(void) { if (m_pPage) { delete [] m_pPage; m_pPage = 0; } } // GetStats // // This functions returns the number of records in this hash page and the // number of bytes that these records would take up in a fresh page. // // It also tries to leave room for a record of size nExtra. // // This function is useful for reallocating the page // void CHashPage::GetStats ( HP_HEAPLENGTH nExtra, int *pnRecords, HP_HEAPLENGTH *pnAllocatedSize, UINT32 *pnGoodDirSize ) { UINT32 nSize = 0; UINT32 nCount = 0; // Count and measure all the records in this page. // for (UINT32 iDir = 0; iDir < m_pHeader->m_nDirSize; iDir++) { if (m_pDirectory[iDir] < HP_DIR_DELETED) // ValidateAllocatedBlock(iDir)) { nCount++; HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[iDir]); HP_HEAPLENGTH nRequired = EXPAND_TO_BOUNDARY( HP_SIZEOF_HEAPNODE + pNode->u.s.nRecordSize); if (nRequired < HP_MIN_HEAP_ALLOC) { nRequired = HP_MIN_HEAP_ALLOC; } nSize += nRequired; } } *pnRecords = nCount; *pnAllocatedSize = static_cast(nSize); // If we have records to talk about, or even if we are trying to reserve // space, then do the math. // UINT32 nGoodDirSize = 100; if ( nExtra != 0 || nCount != 0) { size_t nSpaceTmp = ((unsigned char *)m_pTrailer) - ((unsigned char *)m_pDirectory); mux_assert(nSpaceTmp <= UINT32_MAX_VALUE); UINT32 nSpace = static_cast(nSpaceTmp); UINT32 nMinDirSize = nCount; UINT32 nMaxDirSize = (nSpace - nSize)/sizeof(HP_HEAPOFFSET); if (nExtra) { nExtra += HP_SIZEOF_HEAPNODE; if (nExtra < HP_MIN_HEAP_ALLOC) { nExtra = HP_MIN_HEAP_ALLOC; } nExtra = EXPAND_TO_BOUNDARY(nExtra); nCount++; nSize += nExtra; } #define FILL_FACTOR 1 UINT32 nAverageSize = (nSize + nCount/2)/nCount; UINT32 nHeapGoal = (nSpace * nAverageSize)/(nAverageSize + sizeof(HP_HEAPOFFSET) + FILL_FACTOR); nGoodDirSize = (nSpace - nHeapGoal + sizeof(HP_HEAPOFFSET)/2)/sizeof(HP_HEAPOFFSET); if (nGoodDirSize < nMinDirSize) { nGoodDirSize = nMinDirSize; } else if (nGoodDirSize > nMaxDirSize) { nGoodDirSize = nMaxDirSize; } } *pnGoodDirSize = nGoodDirSize; } void CHashPage::SetFixedPointers(void) { m_pHeader = (HP_PHEADER)m_pPage; m_pDirectory = (HP_PHEAPOFFSET)(m_pHeader+1); m_pTrailer = (HP_PTRAILER)(m_pPage + m_nPageSize - sizeof(HP_TRAILER)); } void CHashPage::Empty(UINT32 arg_nDepth, UINT32 arg_nHashGroup, UINT32 arg_nDirSize) { memset(m_pPage, 0, m_nPageSize); SetFixedPointers(); m_pHeader->m_nDepth = static_cast(arg_nDepth); m_pHeader->m_nDirSize = static_cast(arg_nDirSize); m_pHeader->m_nHashGroup = arg_nHashGroup; m_pHeader->m_nTotalInsert = 0; m_pHeader->m_nDirEmptyLeft = arg_nDirSize; // Number of entries marked HP_DIR_EMPTY. if (arg_nDirSize > 0) { ChoosePrimes(arg_nDirSize, m_pHeader->m_Primes); for (UINT32 iDir = 0; iDir < arg_nDirSize; iDir++) { m_pDirectory[iDir] = HP_DIR_EMPTY; } } SetVariablePointers(); // Setup initial free list. // HP_PHEAPNODE pNode = (HP_PHEAPNODE)m_pHeapStart; pNode->nBlockSize = (HP_HEAPLENGTH)(m_pHeapEnd - m_pHeapStart); pNode->u.oNext = HP_NIL_OFFSET; m_pHeader->m_oFreeList = 0; // This is intentionally zero (i.e., m_pHeapStart - m_pHeapStart). } #ifdef HP_PROTECTION void CHashPage::Protection(void) { UINT32 ul = HASH_ProcessBuffer(0, m_pPage, m_nPageSize-sizeof(HP_TRAILER)); m_pTrailer->m_checksum = ul; } bool CHashPage::Validate(void) { UINT32 ul = HASH_ProcessBuffer(0, m_pPage, m_nPageSize-sizeof(HP_TRAILER)); if (ul != m_pTrailer->m_checksum) { return false; } return true; } // ValidateBlock. // // This function validates a block associated with a particular // Dir entry and blows that entry away if it's suspect. // bool CHashPage::ValidateAllocatedBlock(UINT32 iDir) { if (iDir >= m_pHeader->m_nDirSize) { return false; } if (m_pDirectory[iDir] >= HP_DIR_DELETED) { return false; } // Use directory entry to go find heap node. The record itself follows. // unsigned char *pBlockStart = m_pHeapStart + m_pDirectory[iDir]; unsigned char *pBlockEnd = pBlockStart + HP_MIN_HEAP_ALLOC; if (pBlockStart < m_pHeapStart || m_pHeapEnd <= pBlockEnd) { // Wow. We have a problem here. There is no good way of // finding this record anymore, so just mark it as // deleted. A sweep of the heap will reclaim any lost // free space. // m_pDirectory[iDir] = HP_DIR_DELETED; } else { HP_PHEAPNODE pNode = (HP_PHEAPNODE)pBlockStart; pBlockEnd = pBlockStart + pNode->nBlockSize; if (m_pHeapEnd < pBlockEnd || pNode->u.s.nRecordSize > pNode->nBlockSize) { // Wow. Record hangs off the end of the heap space, or the record // is larger than the block that holds it. // m_pDirectory[iDir] = HP_DIR_DELETED; } else { return true; } } return false; } bool CHashPage::ValidateFreeBlock(HP_HEAPOFFSET oBlock) { // If the free list is empty, then this can't be a valid free block. // if (m_pHeader->m_oFreeList == HP_NIL_OFFSET) { return false; } // Go find heap node. The record itself follows. // unsigned char *pBlockStart = m_pHeapStart + oBlock; unsigned char *pBlockEnd = pBlockStart + HP_MIN_HEAP_ALLOC; if (pBlockStart < m_pHeapStart || m_pHeapEnd < pBlockEnd) { // Wow. We have a problem here. There is no good way of // finding this record anymore, so just empty the free list // and hope to either rehash the page into a new page, or // sweep the heap and re-establish the free list. // m_pHeader->m_oFreeList = HP_NIL_OFFSET; } else { HP_PHEAPNODE pNode = (HP_PHEAPNODE)pBlockStart; pBlockEnd = pBlockStart + pNode->nBlockSize; if (m_pHeapEnd < pBlockEnd) { // Wow. Record hangs off the end of the heap space. // m_pHeader->m_oFreeList = HP_NIL_OFFSET; } else { return true; } } return false; } // ValidateFreeList - Checks the validity of the free list // bool CHashPage::ValidateFreeList(void) { HP_HEAPOFFSET oCurrent = m_pHeader->m_oFreeList; while (oCurrent != HP_NIL_OFFSET) { if (ValidateFreeBlock(oCurrent)) { HP_PHEAPNODE pCurrent = (HP_PHEAPNODE)(m_pHeapStart + oCurrent); if (oCurrent >= pCurrent->u.oNext) { Log.WriteString("CHashPage::ValidateFreeList - Free list is corrupt." ENDLINE); m_pHeader->m_oFreeList = HP_NIL_OFFSET; return false; } oCurrent = pCurrent->u.oNext; } else { Log.WriteString("CHashPage::ValidateFreeList - Free list is corrupt." ENDLINE); m_pHeader->m_oFreeList = HP_NIL_OFFSET; return false; } } return true; } #endif // HP_PROTECTION // Insert - Inserts a new record if there is room. // int CHashPage::Insert(HP_HEAPLENGTH nRecord, UINT32 nHash, void *pRecord) { int ret = HP_INSERT_SUCCESS; m_pHeader->m_nTotalInsert++; for (int nTries = 0; nTries < 2; nTries++) { #ifdef HP_PROTECTION // First, is this page dealing with keys like this at all? // UINT32 nDepth = m_pHeader->m_nDepth; if ((nHash & anGroupMask[nDepth]) != m_pHeader->m_nHashGroup) { Log.WriteString("CHashPage::Insert - Inserting into the wrong page." ENDLINE); return HP_INSERT_ERROR_ILLEGAL; } #endif // HP_PROTECTION // Where do we begin our first probe? // UINT32 di = m_pHeader->m_Primes[nHash & 15]; UINT32 iDir = (nHash >> 4) % (m_pHeader->m_nDirSize); m_nProbesLeft = m_pHeader->m_nDirSize; while (m_nProbesLeft-- && (m_pDirectory[iDir] < HP_DIR_DELETED)) { iDir += di; if (iDir >= (m_pHeader->m_nDirSize)) { iDir -= (m_pHeader->m_nDirSize); } } if (m_nProbesLeft >= 0) { if (m_pHeader->m_nDirEmptyLeft < m_nDirEmptyTrigger) { if (!Defrag(nRecord)) { return HP_INSERT_ERROR_FULL; } ret = HP_INSERT_SUCCESS_DEFRAG; continue; } if (HeapAlloc(iDir, nRecord, nHash, pRecord)) { return ret; } } if (!Defrag(nRecord)) { return HP_INSERT_ERROR_FULL; } ret = HP_INSERT_SUCCESS_DEFRAG; } return HP_INSERT_ERROR_FULL; } // Find - Finds the first record with the given hash key and returns its // directory index or HP_DIR_EMPTY if no hash keys are found. // // Call iDir = FindFirstKey(hash) the first time, and then call // iDir = FindNextKey(iDir, hash) every time after than until // iDir == HP_DIR_EMPTY to interate through all the records with the // desired hash key. // UINT32 CHashPage::FindFirstKey(UINT32 nHash, unsigned int *numchecks) { #ifdef HP_PROTECTION // First, is this page dealing with keys like this at all? // UINT32 nDepth = m_pHeader->m_nDepth; if ((nHash & anGroupMask[nDepth]) != m_pHeader->m_nHashGroup) { return HP_DIR_EMPTY; } #endif // HP_PROTECTION const UINT32 nDirSize = m_pHeader->m_nDirSize; // Where do we begin our first probe? // UINT32 iDir = (nHash >> 4) % nDirSize; UINT32 sOffset = m_pDirectory[iDir]; if (sOffset < HP_DIR_DELETED) { HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + sOffset); if (pNode->u.s.nHash == nHash) { m_nProbesLeft = nDirSize - 1; *numchecks = 1; return iDir; } } else if (HP_DIR_EMPTY == sOffset) { m_nProbesLeft = nDirSize; *numchecks = 0; return HP_DIR_EMPTY; } // HP_DIR_DELETED == sOffset // || pNode->u.s.nHash != nHash m_nProbesLeft = nDirSize - 1; UINT32 di = m_pHeader->m_Primes[nHash & 15]; iDir += di; if (iDir >= nDirSize) { iDir -= nDirSize; } sOffset = m_pDirectory[iDir]; while (sOffset != HP_DIR_EMPTY) { m_nProbesLeft--; if (sOffset != HP_DIR_DELETED) { HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + sOffset); if (pNode->u.s.nHash == nHash) { *numchecks = nDirSize - m_nProbesLeft; return iDir; } } if (!m_nProbesLeft) break; iDir += di; if (iDir >= nDirSize) { iDir -= nDirSize; } sOffset = m_pDirectory[iDir]; } *numchecks = nDirSize - m_nProbesLeft; return HP_DIR_EMPTY; } // Find - Finds the next record with the given hash key and returns its // directory index or HP_DIR_EMPTY if no hash keys are found. // // UINT32 CHashPage::FindNextKey(UINT32 iDir, UINT32 nHash, unsigned int *numchecks) { *numchecks = 0; #ifdef HP_PROTECTION // First, is this page dealing with keys like this at all? // UINT32 nDepth = m_pHeader->m_nDepth; if ((nHash & anGroupMask[nDepth]) != m_pHeader->m_nHashGroup) { return HP_DIR_EMPTY; } #endif // HP_PROTECTION UINT32 nDirSize = m_pHeader->m_nDirSize; // Where do we begin our first probe? If this is the first call, i will be HP_DIR_EMPTY. // On calls after that, it will be what we returned on the previous call. // UINT32 di = m_pHeader->m_Primes[nHash & 15]; iDir += di; if (iDir >= nDirSize) { iDir -= nDirSize; } while (m_nProbesLeft && (m_pDirectory[iDir] != HP_DIR_EMPTY)) { m_nProbesLeft--; (*numchecks)++; if (m_pDirectory[iDir] != HP_DIR_DELETED) { if (m_pDirectory[iDir] < HP_DIR_DELETED) // ValidateAllocatedBlock(iDir)) { HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[iDir]); if (pNode->u.s.nHash == nHash) { return iDir; } } } iDir += di; if (iDir >= nDirSize) { iDir -= nDirSize; } } return HP_DIR_EMPTY; } // HeapAlloc - Return true if there was enough room to copy the record into the heap, otherwise, // it returns false. // bool CHashPage::HeapAlloc(UINT32 iDir, HP_HEAPLENGTH nRecord, UINT32 nHash, void *pRecord) { //ValidateFreeList(); if (m_pDirectory[iDir] < HP_DIR_DELETED) { return false; } // How much space do we need? // HP_HEAPLENGTH nRequired = EXPAND_TO_BOUNDARY(HP_SIZEOF_HEAPNODE + nRecord); if (nRequired < HP_MIN_HEAP_ALLOC) { nRequired = HP_MIN_HEAP_ALLOC; } // Search through the free list for something of the right size. // HP_HEAPOFFSET oNext = m_pHeader->m_oFreeList; HP_PHEAPOFFSET poPrev = &(m_pHeader->m_oFreeList); while (oNext != HP_NIL_OFFSET) { #if 0 if (!ValidateFreeBlock(oPrevious)) { ValidateFreeList(); return false; } #endif // 0 unsigned char *pBlockStart = m_pHeapStart + oNext; HP_PHEAPNODE pNode = (HP_PHEAPNODE)pBlockStart; if (pNode->nBlockSize >= nRequired) { // We found something of the correct size. // // Do we cut it into two blocks or take the whole thing? // UINT32 nNewBlockSize = pNode->nBlockSize - nRequired; if (nNewBlockSize >= EXPAND_TO_BOUNDARY(HP_MIN_HEAP_ALLOC+1)) { // There is enough for leftovers, split it. // HP_PHEAPNODE pNewNode = (HP_PHEAPNODE)(pBlockStart + nRequired); pNewNode->nBlockSize = static_cast(nNewBlockSize); pNewNode->u.oNext = pNode->u.oNext; // Update current node. // pNode->nBlockSize = nRequired; pNode->u.s.nHash = nHash; pNode->u.s.nRecordSize = nRecord; // Update Free list pointer. // *poPrev = static_cast(*poPrev + nRequired); } else { // Take the whole thing. // *poPrev = pNode->u.oNext; pNode->u.s.nHash = nHash; pNode->u.s.nRecordSize = nRecord; } memcpy(pNode+1, pRecord, nRecord); if (m_pDirectory[iDir] == HP_DIR_EMPTY) { m_pHeader->m_nDirEmptyLeft--; } m_pDirectory[iDir] = (HP_HEAPOFFSET)(pBlockStart - m_pHeapStart); return true; } poPrev = &(pNode->u.oNext); oNext = pNode->u.oNext; } return false; } // HeapFree - Returns to the heap the space for the record associated with iDir. It // always succeeds even if there wasn't a record there to delete. // void CHashPage::HeapFree(UINT32 iDir) { //ValidateFreeList(); if (m_pDirectory[iDir] < HP_DIR_DELETED) // ValidateAllocatedBlock(iDir)) { HP_HEAPOFFSET oBlock = m_pDirectory[iDir]; HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + oBlock); // Clear it. The reason for clearing is that it makes debugging easier, // and also, if the file is compressed by the file system, a string // of zeros will yield a smaller result. // HP_HEAPLENGTH nBlockSize = pNode->nBlockSize; memset(pNode, 0, nBlockSize); pNode->nBlockSize = nBlockSize; // Push it onto the free list. // pNode->u.oNext = m_pHeader->m_oFreeList; m_pHeader->m_oFreeList = oBlock; m_pDirectory[iDir] = HP_DIR_DELETED; } } void CHashPage::HeapCopy(UINT32 iDir, HP_PHEAPLENGTH pnRecord, void *pRecord) { if (pnRecord == 0 || pRecord == 0) return; if (m_pDirectory[iDir] < HP_DIR_DELETED) // ValidateAllocatedBlock(iDir)) { HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[iDir]); // Copy the record. // *pnRecord = pNode->u.s.nRecordSize; memcpy(pRecord, pNode+1, pNode->u.s.nRecordSize); } } void CHashPage::HeapUpdate(UINT32 iDir, HP_HEAPLENGTH nRecord, void *pRecord) { if (nRecord == 0 || pRecord == 0) return; if (m_pDirectory[iDir] < HP_DIR_DELETED) // ValidateAllocatedBlock(iDir)) { HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[iDir]); if (pNode->u.s.nRecordSize != nRecord) return; memcpy(pNode+1, pRecord, nRecord); } } bool CHashPage::Split(CHashPage &hp0, CHashPage &hp1) { // Figure out what a good directory size is given the actual records in this page. // int nRecords; HP_HEAPLENGTH nAllocatedSize; UINT32 nGoodDirSize; GetStats(0, &nRecords, &nAllocatedSize, &nGoodDirSize); if (nRecords == 0) { Log.WriteString("Why are we splitting a page with no records in it?" ENDLINE); return false; } // Initialize that type of HashPage and copy records over. // UINT32 nNewDepth = m_pHeader->m_nDepth + 1; UINT32 nBitMask = 1 << (32-nNewDepth); UINT32 nHashGroup0 = m_pHeader->m_nHashGroup & (~nBitMask); UINT32 nHashGroup1 = nHashGroup0 | nBitMask; hp0.Empty(nNewDepth, nHashGroup0, nGoodDirSize); hp1.Empty(nNewDepth, nHashGroup1, nGoodDirSize); for (int iDir = 0; iDir < m_pHeader->m_nDirSize; iDir++) { if (m_pDirectory[iDir] < HP_DIR_DELETED) // ValidateAllocatedBlock(iDir)) { HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[iDir]); UINT32 nHash = pNode->u.s.nHash; if ((nHash & anGroupMask[nNewDepth]) == (nHashGroup0 & anGroupMask[nNewDepth])) { if (!IS_HP_SUCCESS(hp0.Insert(pNode->u.s.nRecordSize, nHash, pNode+1))) { Log.WriteString("CHashPage::Split - Ran out of room." ENDLINE); return false; } } else if ((nHash & anGroupMask[nNewDepth]) == (nHashGroup1 & anGroupMask[nNewDepth])) { if (!IS_HP_SUCCESS(hp1.Insert(pNode->u.s.nRecordSize, nHash, pNode+1))) { Log.WriteString("CHashPage::Split - Ran out of room." ENDLINE); return false; } } else { Log.WriteString("CHashPage::Split - This record fits in neither page...lost." ENDLINE); return false; } } } #if 0 int nRecords0, nRecords1; HP_HEAPLENGTH nAllocatedSize0, nAllocatedSize1; int temp; hp0.GetStats(0, &nRecords0, &nAllocatedSize0, &temp); hp1.GetStats(0, &nRecords1, &nAllocatedSize1, &temp); Log.tinyprintf("Split (%d %d) page into (%d %d) and (%d %d)" ENDLINE, nRecords, nAllocatedSize, nRecords0, nAllocatedSize0, nRecords1, nAllocatedSize1); if (nRecords0 + nRecords1 != nRecords) { Log.WriteString("Lost something" ENDLINE); return false; } #endif // 0 return true; } void CHashPage::GetRange ( UINT32 arg_nDirDepth, UINT32 &nStart, UINT32 &nEnd ) { UINT32 nBase = 0; int nShift = 32 - arg_nDirDepth; if (arg_nDirDepth > 0) { nBase = m_pHeader->m_nHashGroup >> nShift; } UINT32 ulMask = anGroupMask[nShift + m_pHeader->m_nDepth]; nStart = nBase & ulMask; nEnd = nBase | ~ulMask; } #if !defined(MEMORY_BASED) #ifdef WIN32 bool CHashPage::WritePage(HANDLE hFile, HF_FILEOFFSET oWhere) { cs_dbwrites++; for ( ; ; MuxAlarm.Sleep(time_250ms)) { if (SetFilePointer(hFile, oWhere, 0, FILE_BEGIN) == 0xFFFFFFFFUL) { Log.tinyprintf("CHashPage::Write - SetFilePointer error %u." ENDLINE, GetLastError()); continue; } DWORD nWritten; if (!WriteFile(hFile, m_pPage, m_nPageSize, &nWritten, 0) || nWritten != m_nPageSize) { UINT32 cc = GetLastError(); if (cc != ERROR_LOCK_VIOLATION) { Log.tinyprintf("CHashPage::Write - WriteFile error %u." ENDLINE, cc); } continue; } return true; } } bool CHashPage::ReadPage(HANDLE hFile, HF_FILEOFFSET oWhere) { cs_dbreads++; SetFixedPointers(); for ( ; ; MuxAlarm.Sleep(time_250ms)) { if (SetFilePointer(hFile, oWhere, 0, FILE_BEGIN) == 0xFFFFFFFFUL) { Log.tinyprintf("CHashPage::Read - SetFilePointer error %u." ENDLINE, GetLastError()); continue; } DWORD nRead; if (!ReadFile(hFile, m_pPage, m_nPageSize, &nRead, 0) || nRead != m_nPageSize) { UINT32 cc = GetLastError(); if (cc != ERROR_LOCK_VIOLATION) { Log.tinyprintf("CHashPage::Read - ReadFile error %u." ENDLINE, cc); } continue; } SetVariablePointers(); return true; } } #else // WIN32 bool CHashPage::WritePage(HANDLE hFile, HF_FILEOFFSET oWhere) { cs_dbwrites++; int cnt = 60; for ( ; cnt; MuxAlarm.Sleep(time_1s), cnt--) { #ifdef HAVE_PWRITE int cc = pwrite(hFile, m_pPage, m_nPageSize, oWhere); #else if (mux_lseek(hFile, oWhere, SEEK_SET) == (off_t)-1) { Log.tinyprintf("CHashPage::Write - lseek error %u." ENDLINE, errno); continue; } int cc = mux_write(hFile, m_pPage, m_nPageSize); #endif // HAVE_PWRITE if ((int)m_nPageSize != cc) { if (cc == -1) { Log.tinyprintf("CHashPage::Write - write error %u." ENDLINE, errno); } else { // Our write request was only partially filled. The disk is // probably full. // Log.tinyprintf("CHashPage::Write - partial write." ENDLINE); } } return true; } // Don't struggle further. You'll just make it worse. // mudstate.shutdown_flag = true; return false; } bool CHashPage::ReadPage(HANDLE hFile, HF_FILEOFFSET oWhere) { cs_dbreads++; SetFixedPointers(); int cnt = 60; for ( ; cnt; MuxAlarm.Sleep(time_1s), cnt--) { #ifdef HAVE_PREAD int cc = pread(hFile, m_pPage, m_nPageSize, oWhere); #else if (mux_lseek(hFile, oWhere, SEEK_SET) == (off_t)-1) { Log.tinyprintf("CHashPage::Read - lseek error %u." ENDLINE, errno); continue; } int cc = mux_read(hFile, m_pPage, m_nPageSize); #endif // HAVE_PREAD if ((int)m_nPageSize != cc) { if (cc == -1) { Log.tinyprintf("CHashPage::Read - read error %u." ENDLINE, errno); } else { // Our read request was only partially filled. Surrender. // Log.tinyprintf("CHashPage::Read - partial read." ENDLINE); } continue; } SetVariablePointers(); return true; } // Don't struggle further. You'll just make it worse. // mudstate.shutdown_flag = true; return false; } #endif // WIN32 #endif // MEMORY_BASED UINT32 CHashPage::GetDepth(void) { return m_pHeader->m_nDepth; } // Defrag // // Moves all the records together, and re-establishes a single-element free list at the end. // bool CHashPage::Defrag(HP_HEAPLENGTH nExtra) { CHashPage *hpNew = new CHashPage; if (!hpNew) return false; if (!hpNew->Allocate(m_nPageSize)) { delete hpNew; return false; } // Figure out what a good directory size is given the actual records in this page. // int nRecords; HP_HEAPLENGTH nAllocatedSize; UINT32 nGoodDirSize; GetStats(nExtra, &nRecords, &nAllocatedSize, &nGoodDirSize); // Initialize that type of HashPage and copy records over. // hpNew->Empty(m_pHeader->m_nDepth, m_pHeader->m_nHashGroup, nGoodDirSize); int errInserted = HP_INSERT_SUCCESS; for (int iDir = 0; iDir < m_pHeader->m_nDirSize && IS_HP_SUCCESS(errInserted); iDir++) { if (m_pDirectory[iDir] < HP_DIR_DELETED) // ValidateAllocatedBlock(iDir)) { HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[iDir]); errInserted = hpNew->Insert(pNode->u.s.nRecordSize, pNode->u.s.nHash, pNode+1); } } if (IS_HP_SUCCESS(errInserted)) { // Swap buffers. // unsigned char *tmp; tmp = hpNew->m_pPage; hpNew->m_pPage = m_pPage; m_pPage = tmp; SetFixedPointers(); SetVariablePointers(); delete hpNew; return true; } delete hpNew; return false; } void CHashPage::SetVariablePointers(void) { m_pHeapStart = (unsigned char *)(m_pDirectory + m_pHeader->m_nDirSize); m_pHeapEnd = (unsigned char *)(m_pTrailer); // If less than 14.29% of the entries are empty, then do another Defrag. // m_nDirEmptyTrigger = (m_pHeader->m_nDirSize)/7; } UINT32 CHashPage::FindFirst(HP_PHEAPLENGTH pnRecord, void *pRecord) { for (m_iDir = 0; m_iDir < m_pHeader->m_nDirSize; m_iDir++) { if (m_pDirectory[m_iDir] < HP_DIR_DELETED) // ValidateAllocatedBlock(iDir)) { HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[m_iDir]); *pnRecord = pNode->u.s.nRecordSize; memcpy(pRecord, pNode+1, pNode->u.s.nRecordSize); return m_iDir; } } return HP_DIR_EMPTY; } UINT32 CHashPage::FindNext(HP_PHEAPLENGTH pnRecord, void *pRecord) { for (m_iDir++; m_iDir < m_pHeader->m_nDirSize; m_iDir++) { if (m_pDirectory[m_iDir] < HP_DIR_DELETED) // ValidateAllocatedBlock(iDir)) { HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[m_iDir]); *pnRecord = pNode->u.s.nRecordSize; memcpy(pRecord, pNode+1, pNode->u.s.nRecordSize); return m_iDir; } } return HP_DIR_EMPTY; } #if !defined(MEMORY_BASED) CHashFile::CHashFile(void) { SeedRandomNumberGenerator(); m_Cache = NULL; m_nCache = 0; Init(); } void CHashFile::Init(void) { #ifdef WIN32 m_hDirFile = INVALID_HANDLE_VALUE; m_hPageFile = INVALID_HANDLE_VALUE; #else m_hDirFile = MUX_OPEN_INVALID_HANDLE_VALUE; m_hPageFile = MUX_OPEN_INVALID_HANDLE_VALUE; #endif m_nDir = 0; m_nDirDepth = 0; m_pDir = NULL; m_hpCacheLookup = NULL; iCache = 0; m_iLastFlushed = 0; } #ifdef WIN32 void CHashFile::WriteDirectory(void) { if (INVALID_HANDLE_VALUE == m_hDirFile) { return; } SetFilePointer(m_hDirFile, 0, 0, FILE_BEGIN); DWORD nWritten; WriteFile(m_hDirFile, m_pDir, sizeof(HF_FILEOFFSET)*m_nDir, &nWritten, 0); SetEndOfFile(m_hDirFile); #ifdef DO_COMMIT if (!mudstate.bStandAlone) { FlushFileBuffers(m_hDirFile); } #endif // DO_COMMIT } #else // WIN32 void CHashFile::WriteDirectory(void) { if (MUX_OPEN_INVALID_HANDLE_VALUE == m_hDirFile) { return; } #ifdef HAVE_PWRITE pwrite(m_hDirFile, m_pDir, sizeof(HF_FILEOFFSET)*m_nDir, 0); #else mux_lseek(m_hDirFile, 0, SEEK_SET); mux_write(m_hDirFile, m_pDir, sizeof(HF_FILEOFFSET)*m_nDir); #endif // HAVE_PWRITE //SetEndOfFile(m_hDirFile); #ifdef DO_COMMIT if (!mudstate.bStandAlone) { fsync(m_hDirFile); } #endif // DO_COMMIT } #endif // WIN32 bool CHashFile::InitializeDirectory(unsigned int n) { if (m_pDir) { delete [] m_pDir; m_pDir = NULL; } if (m_hpCacheLookup) { delete [] m_hpCacheLookup; m_hpCacheLookup = NULL; } m_nDir = n; m_nDirDepth = 0; n >>= 1; while (n) { m_nDirDepth++; n >>= 1; } m_pDir = NULL; try { m_pDir = new HF_FILEOFFSET[m_nDir]; } catch (...) { ; // Nothing. } if (NULL == m_pDir) { return false; } m_hpCacheLookup = NULL; try { m_hpCacheLookup = new int[m_nDir]; } catch (...) { ; // Nothing. } if (NULL == m_hpCacheLookup) { if (m_pDir) { delete [] m_pDir; m_pDir = NULL; } return false; } for (unsigned int i = 0; i < m_nDir; i++) { m_pDir[i] = 0xFFFFFFFFUL; m_hpCacheLookup[i] = -1; } return true; } bool CHashFile::CreateFileSet(const char *szDirFile, const char *szPageFile) { CloseAll(); bool bSuccess; #ifdef WIN32 m_hPageFile = CreateFile(szPageFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_RANDOM_ACCESS, NULL); bSuccess = (INVALID_HANDLE_VALUE != m_hPageFile); #else // WIN32 bSuccess = mux_open(&m_hPageFile, szPageFile, O_RDWR|O_BINARY|O_CREAT|O_TRUNC); #endif // WIN32 if (!bSuccess) { return false; } #ifdef WIN32 m_hDirFile = CreateFile(szDirFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN, NULL); bSuccess = (INVALID_HANDLE_VALUE != m_hDirFile); #else // WIN32 bSuccess = mux_open(&m_hDirFile, szDirFile, O_RDWR|O_BINARY|O_CREAT|O_TRUNC); #endif // WIN32 if (!bSuccess) { return false; } // Create empty structures in memory and write them out. // if (!InitializeDirectory(2)) { return false; } iCache = AllocateEmptyPage(0, 0); if (iCache < 0) { return false; } m_Cache[iCache].m_hp.Empty(0, 0UL, 100); m_Cache[iCache].m_o = 0UL; m_pDir[0] = m_pDir[1] = m_Cache[iCache].m_o; m_hpCacheLookup[0] = m_hpCacheLookup[1] = iCache; m_Cache[iCache].m_iState = HF_CACHE_UNPROTECTED; oEndOfFile = HF_SIZEOF_PAGE; #ifdef DO_COMMIT FlushCache(iCache); #endif // DO_COMMIT WriteDirectory(); return true; } bool CHashFile::RebuildDirectory(void) { // Initialize in-memory page directory // if (!InitializeDirectory(2)) { return false; } // Re-build the directory from CHashPages. // for (UINT32 oPage = 0; oPage < oEndOfFile; oPage += HF_SIZEOF_PAGE) { int iCache; if ((iCache = AllocateEmptyPage(0, NULL)) < 0) { Log.WriteString("CHashFile::RebuildDirectory. AllocateEmptyPage failed. DB DAMAGE." ENDLINE); return false; } if (m_Cache[iCache].m_hp.ReadPage(m_hPageFile, oPage)) { m_Cache[iCache].m_o = oPage; m_Cache[iCache].m_iState = HF_CACHE_CLEAN; ResetAge(iCache); } else { Log.WriteString("CHashFile::RebuildDirectory. ReadPage failed to get the page. DB DAMAGE." ENDLINE); } UINT32 nPageDepth = m_Cache[iCache].m_hp.GetDepth(); while (m_nDirDepth < nPageDepth) { if (!DoubleDirectory()) { return false; } } UINT32 nStart, nEnd; m_Cache[iCache].m_hp.GetRange(m_nDirDepth, nStart, nEnd); for ( ; nStart <= nEnd; nStart++) { if (m_pDir[nStart] != 0xFFFFFFFFUL) { Log.WriteString("CHashFile::Open - The keyspace of pages in Page File overlap." ENDLINE); return false; } m_pDir[nStart] = oPage; m_hpCacheLookup[nStart] = iCache; } } // Validate that the directory does not have holes. // for (UINT32 iFileDir = 0; iFileDir < m_nDir; iFileDir++) { if (m_pDir[iFileDir] == 0xFFFFFFFFUL) { Log.WriteString("CHashFile::Open - Page File is incomplete." ENDLINE); return false; } } WriteDirectory(); return true; } bool CHashFile::ReadDirectory(void) { #ifdef WIN32 UINT32 cc = SetFilePointer(m_hDirFile, 0, 0, FILE_END); #else // WIN32 UINT32 cc = mux_lseek(m_hDirFile, 0, SEEK_END); #endif // WIN32 if (cc == 0xFFFFFFFFUL) { return false; } InitializeDirectory(cc / HF_SIZEOF_FILEOFFSET); #ifdef WIN32 cc = SetFilePointer(m_hDirFile, 0, 0, FILE_BEGIN); DWORD nRead; if (!ReadFile(m_hDirFile, m_pDir, sizeof(HF_FILEOFFSET)*m_nDir, &nRead, 0)) { return false; } #else // WIN32 #ifdef HAVE_PREAD pread(m_hDirFile, m_pDir, sizeof(HF_FILEOFFSET)*m_nDir, 0); #else mux_lseek(m_hDirFile, 0, SEEK_SET); mux_read(m_hDirFile, m_pDir, sizeof(HF_FILEOFFSET)*m_nDir); #endif // HAVE_PREAD #endif // WIN32 return true; } void CHashFile::InitCache(int nCachePages) { if (m_Cache) { return; } // Allocate hash page cache. // m_nCache = nCachePages; m_Cache = new HF_CACHE[m_nCache]; ISOUTOFMEMORY(m_Cache); for (int i = 0; i < m_nCache; i++) { m_Cache[i].m_hp.Allocate(HF_SIZEOF_PAGE); m_Cache[i].m_iState = HF_CACHE_EMPTY; m_Cache[i].m_o = 0UL; m_Cache[i].m_iYounger = i-1; m_Cache[i].m_iOlder = i+1; } m_Cache[0].m_iYounger = m_nCache-1; m_Cache[m_nCache-1].m_iOlder = 0; m_iOldest = 0; } int CHashFile::Open(const char *szDirFile, const char *szPageFile, int nCachePages) { CloseAll(); FinalCache(); InitCache(nCachePages); // First let's try to open the page file. This is the more important file. // bool bSuccess; #ifdef WIN32 m_hPageFile = CreateFile(szPageFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_RANDOM_ACCESS, NULL); bSuccess = (INVALID_HANDLE_VALUE != m_hPageFile); #else // WIN32 bSuccess = mux_open(&m_hPageFile, szPageFile, O_RDWR|O_BINARY); #endif // WIN32 if (!bSuccess) { // The PageFile doesn't exist, so we have'ta create both of them. // if (!CreateFileSet(szDirFile, szPageFile)) { CloseAll(); return HF_OPEN_STATUS_ERROR; } return HF_OPEN_STATUS_NEW; } // We have a page file open. Let's check how big it is. If it's // zero-length, the page file is useless to use, and we need to go through // the standard creation process. If the size is not a multiple of // HF_SIZEOF_PAGE, we need to fail. // #ifdef WIN32 oEndOfFile = SetFilePointer(m_hPageFile, 0, 0, FILE_END); #else // WIN32 oEndOfFile = mux_lseek(m_hPageFile, 0, SEEK_END); #endif // WIN32 if (oEndOfFile == 0xFFFFFFFFUL) { CloseAll(); return HF_OPEN_STATUS_ERROR; } else if (oEndOfFile == 0UL) { // The PageFile exists, but it's zero-length, so we have'ta create // both of them. // if (!CreateFileSet(szDirFile, szPageFile)) { CloseAll(); return HF_OPEN_STATUS_ERROR; } return HF_OPEN_STATUS_NEW; } else if ((oEndOfFile % HF_SIZEOF_PAGE) != 0) { // This is not a mulitple of HP_SIZEOF_PAGE. Weird unknown format. // CloseAll(); return HF_OPEN_STATUS_ERROR; } // Now that the page file appears valid so far, let's see if the directory // file is there. This file is not strictly necessary, we can rebuild it. // However, having it helps us to open faster. // #ifdef WIN32 m_hDirFile = CreateFile(szDirFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN, NULL); bSuccess = (INVALID_HANDLE_VALUE != m_hDirFile); #else // WIN32 bSuccess = mux_open(&m_hDirFile, szDirFile, O_RDWR|O_BINARY); #endif // WIN32 if (!bSuccess) { // The Directory doesn't exist, so we create it anew, and rebuild the // index. #ifdef WIN32 m_hDirFile = CreateFile(szDirFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN, NULL); bSuccess = (INVALID_HANDLE_VALUE != m_hDirFile); #else // WIN32 bSuccess = mux_open(&m_hDirFile, szDirFile, O_RDWR|O_BINARY|O_CREAT|O_TRUNC); #endif // WIN32 if (!bSuccess) { CloseAll(); return HF_OPEN_STATUS_ERROR; } if (!RebuildDirectory()) { CloseAll(); return HF_OPEN_STATUS_ERROR; } return HF_OPEN_STATUS_OLD; } // Read in the directory. // if (!ReadDirectory()) { CloseAll(); return HF_OPEN_STATUS_ERROR; } return HF_OPEN_STATUS_OLD; } void CHashFile::Sync(void) { #ifdef WIN32 if (INVALID_HANDLE_VALUE != m_hPageFile) #else if (MUX_OPEN_INVALID_HANDLE_VALUE != m_hPageFile) #endif { cs_syncs++; bool bAllFlushed = true; for (int i = 0; i < m_nCache; i++) { if (!FlushCache(i)) { bAllFlushed = false; } } if (!bAllFlushed) { Log.WriteString("CHashFile::Sync. Could not flush all the pages. DB DAMAGE." ENDLINE); } #ifdef DO_COMMIT if (!mudstate.bStandAlone) { #ifdef WIN32 FlushFileBuffers(m_hPageFile); #else // WIN32 fsync(m_hPageFile); #endif // WIN32 } #endif // DO_COMMIT } #ifdef DO_COMMIT #ifdef WIN32 if ( INVALID_HANDLE_VALUE != m_hDirFile #else if ( MUX_OPEN_INVALID_HANDLE_VALUE != m_hDirFile #endif && !mudstate.bStandAlone) { #ifdef WIN32 FlushFileBuffers(m_hDirFile); #else // WIN32 fsync(m_hDirFile); #endif // WIN32 } #endif // DO_COMMIT } void CHashFile::CloseAll(void) { #ifdef WIN32 if (INVALID_HANDLE_VALUE != m_hPageFile) #else if (MUX_OPEN_INVALID_HANDLE_VALUE != m_hPageFile) #endif { Sync(); if (m_pDir) { MEMFREE(m_pDir); m_pDir = NULL; } if (m_hpCacheLookup) { delete [] m_hpCacheLookup; m_hpCacheLookup = NULL; } #ifdef WIN32 CloseHandle(m_hPageFile); #else // WIN32 mux_close(m_hPageFile); #endif // WIN32 } #ifdef WIN32 if (INVALID_HANDLE_VALUE != m_hDirFile) #else if (MUX_OPEN_INVALID_HANDLE_VALUE != m_hDirFile) #endif { #ifdef WIN32 CloseHandle(m_hDirFile); #else // WIN32 mux_close(m_hDirFile); #endif // WIN32 } Init(); } void CHashFile::FinalCache(void) { if (m_Cache) { delete [] m_Cache; m_Cache = NULL; m_nCache = 0; } } CHashFile::~CHashFile(void) { FinalCache(); CloseAll(); } bool CHashFile::Insert(HP_HEAPLENGTH nRecord, UINT32 nHash, void *pRecord) { cs_writes++; for (;;) { UINT32 iFileDir = nHash >> (32-m_nDirDepth); if (iFileDir >= m_nDir) { Log.WriteString("CHashFile::Insert - iFileDir out of range." ENDLINE); return false; } iCache = ReadCache(iFileDir, &cs_whits); if (iCache < 0) { Log.WriteString("CHashFile::Insert - Page wasn't valid." ENDLINE); return false; } UINT32 nStart, nEnd; m_Cache[iCache].m_hp.GetRange(m_nDirDepth, nStart, nEnd); if (iFileDir < nStart || nEnd < iFileDir) { Log.tinyprintf("CHashFile::Insert - Directory entry (0x%08X) points to the wrong page (0x%08X-0x%08X)." ENDLINE, iFileDir, nStart, nEnd); return false; } int errInserted = m_Cache[iCache].m_hp.Insert(nRecord, nHash, pRecord); if (IS_HP_SUCCESS(errInserted)) { // The record was inserted successfully, so the page is dirty. // m_Cache[iCache].m_iState = HF_CACHE_UNPROTECTED; break; } else if (HP_INSERT_ERROR_ILLEGAL == errInserted) { return false; } #ifndef WIN32 // First, if we are @dumping, then we have a @forked process // that is also reading from the file. We must pause and let // this reader process finish. // if ( !mudstate.bStandAlone && mudstate.dumping) { STARTLOG(LOG_DBSAVES, "DMP", "DUMP"); log_text("Waiting on previously-forked child before page-splitting... "); ENDLOG; do { // We have a forked dump in progress, so we will wait until the // child exits. // MuxAlarm.Sleep(time_1s); } while (mudstate.dumping); } #endif // !WIN32 // If the depth of this page is already as deep as the directory // depth,then we must increase depth of the directory, first. // if (m_nDirDepth == m_Cache[iCache].m_hp.GetDepth()) { if (!DoubleDirectory()) { return false; } } // Split this page into two pages. We become a new one, and we // are given a pointer to the other one. // int Safe[2]; int nSafe = 0; int iEmpty0, iEmpty1; Safe[nSafe++] = iCache; iEmpty0 = AllocateEmptyPage(nSafe, Safe); if (iEmpty0 < 0) return false; if (iCache == iEmpty0) { Log.WriteString("CHashFile::Split - iCache == iEmpty0" ENDLINE); return false; } Safe[nSafe++] = iEmpty0; iEmpty1 = AllocateEmptyPage(nSafe, Safe); if (iEmpty1 < 0) return false; if (iCache == iEmpty1) { Log.WriteString("CHashFile::Split - iCache == iEmpty1" ENDLINE); return false; } if (iEmpty0 == iEmpty1) { Log.WriteString("CHashFile::Split - iEmpty0 == iEmpty1" ENDLINE); return false; } if (!m_Cache[iCache].m_hp.Split(m_Cache[iEmpty0].m_hp, m_Cache[iEmpty1].m_hp)) { return false; } // Tack another page onto the end of the .pag file. // long oNew = oEndOfFile; oEndOfFile += HF_SIZEOF_PAGE; // iEmpty0 => iCache. iEmpty1 => end of file // m_Cache[iCache].m_iState = HF_CACHE_EMPTY; m_Cache[iEmpty0].m_o = m_Cache[iCache].m_o; m_Cache[iEmpty1].m_o = oNew; m_Cache[iEmpty0].m_iState = HF_CACHE_UNPROTECTED; m_Cache[iEmpty1].m_iState = HF_CACHE_UNPROTECTED; // Update the directory. // m_Cache[iEmpty0].m_hp.GetRange(m_nDirDepth, nStart, nEnd); for ( ; nStart <= nEnd; nStart++) { m_hpCacheLookup[nStart] = iEmpty0; } m_Cache[iEmpty1].m_hp.GetRange(m_nDirDepth, nStart, nEnd); for ( ; nStart <= nEnd; nStart++) { m_pDir[nStart] = oNew; m_hpCacheLookup[nStart] = iEmpty1; } // Flush the pages out. // FlushCache(iEmpty1); FlushCache(iEmpty0); #ifdef DO_COMMIT if (!mudstate.bStandAlone) { #ifdef WIN32 FlushFileBuffers(m_hPageFile); #else // WIN32 fsync(m_hPageFile); #endif // WIN32 } #endif // DO_COMMIT // Write Directory // #ifdef WIN32 SetFilePointer(m_hDirFile, 0, 0, FILE_BEGIN); DWORD nWritten; WriteFile(m_hDirFile, m_pDir, sizeof(HF_FILEOFFSET)*m_nDir, &nWritten, 0); #else // WIN32 #ifdef HAVE_PWRITE pwrite(m_hDirFile, m_pDir, sizeof(HF_FILEOFFSET)*m_nDir, 0); #else mux_lseek(m_hDirFile, 0, SEEK_SET); mux_write(m_hDirFile, m_pDir, sizeof(HF_FILEOFFSET)*m_nDir); #endif // HAVE_PWRITE #endif // WIN32 #ifdef DO_COMMIT if (!mudstate.bStandAlone) { #ifdef WIN32 FlushFileBuffers(m_hDirFile); #else // WIN32 fsync(m_hDirFile); #endif // WIN32 } #endif // DO_COMMIT } return true; } bool CHashFile::DoubleDirectory(void) { unsigned int nNewDir = 2 * m_nDir; UINT32 nNewDirDepth = m_nDirDepth + 1; HF_PFILEOFFSET pNewDir = NULL; try { pNewDir = new HF_FILEOFFSET[nNewDir]; } catch (...) { ; // Nothing. } if (NULL == pNewDir) { return false; } int *pNewCacheLookup = NULL; try { pNewCacheLookup = new int[nNewDir]; } catch (...) { ; // Nothing. } if (NULL == pNewCacheLookup) { if (pNewDir) { delete [] pNewDir; pNewDir = NULL; } return false; } unsigned int iNewDir = 0; for (unsigned int iDir = 0; iDir < m_nDir; iDir++) { pNewDir[iNewDir] = m_pDir[iDir]; pNewDir[iNewDir+1] = m_pDir[iDir]; pNewCacheLookup[iNewDir] = m_hpCacheLookup[iDir]; pNewCacheLookup[iNewDir+1] = m_hpCacheLookup[iDir]; iNewDir += 2; } // Write out the new directory. It's always larger than // the previous one. // WriteDirectory(); delete [] m_pDir; m_pDir = pNewDir; delete [] m_hpCacheLookup; m_hpCacheLookup = pNewCacheLookup; m_nDirDepth = nNewDirDepth; m_nDir = nNewDir; return true; } UINT32 CHashFile::FindFirstKey(UINT32 nHash) { cs_reads++; UINT32 iFileDir = nHash >> (32-m_nDirDepth); if (iFileDir >= m_nDir) { Log.WriteString("CHashFile::Insert - iFileDir out of range." ENDLINE); cs_fails++; return HF_FIND_END; } iCache = ReadCache(iFileDir, &cs_rhits); if (iCache < 0) { cs_fails++; return HF_FIND_END; } UINT32 nStart, nEnd; m_Cache[iCache].m_hp.GetRange(m_nDirDepth, nStart, nEnd); if (iFileDir < nStart || nEnd < iFileDir) { Log.tinyprintf("CHashFile::Find - Directory entry (0x%08X) points to the wrong page (0x%08X-0x%08X)." ENDLINE, iFileDir, nStart, nEnd); return HF_FIND_END; } unsigned int numchecks; UINT32 iDir = m_Cache[iCache].m_hp.FindFirstKey(nHash, &numchecks); if (iDir == HP_DIR_EMPTY) { cs_fails++; return HF_FIND_END; } return iDir; } UINT32 CHashFile::FindNextKey(UINT32 iDir, UINT32 nHash) { cs_reads++; unsigned int numchecks; iDir = m_Cache[iCache].m_hp.FindNextKey(iDir, nHash, &numchecks); if (iDir == HP_DIR_EMPTY) { cs_fails++; return HF_FIND_END; } return iDir; } void CHashFile::Copy(UINT32 iDir, HP_PHEAPLENGTH pnRecord, void *pRecord) { m_Cache[iCache].m_hp.HeapCopy(iDir, pnRecord, pRecord); } void CHashFile::Remove(UINT32 iDir) { cs_dels++; m_Cache[iCache].m_hp.HeapFree(iDir); m_Cache[iCache].m_iState = HF_CACHE_UNPROTECTED; } bool CHashFile::FlushCache(int iCache) { switch (m_Cache[iCache].m_iState) { case HF_CACHE_UNPROTECTED: #ifdef HP_PROTECTION m_Cache[iCache].m_hp.Protection(); #endif // HP_PROTECTION case HF_CACHE_UNWRITTEN: if (m_Cache[iCache].m_hp.WritePage(m_hPageFile, m_Cache[iCache].m_o)) { m_Cache[iCache].m_iState = HF_CACHE_CLEAN; } else { return false; } } return true; } int CHashFile::AllocateEmptyPage(int nSafe, int Safe[]) { int cnt = m_nCache; while (cnt--) { int i = m_iOldest; bool bExclude = false; for (int j = 0; j < nSafe; j++) { if (Safe[j] == i) { bExclude = true; break; } } ResetAge(i); if ( !bExclude && FlushCache(i)) { if (HF_CACHE_EMPTY != m_Cache[i].m_iState) { UINT32 nStart, nEnd; m_Cache[i].m_hp.GetRange(m_nDirDepth, nStart, nEnd); for ( ; nStart <= nEnd; nStart++) { m_hpCacheLookup[nStart] = -1; } m_Cache[i].m_iState = HF_CACHE_EMPTY; } return i; } } return -1; } void CHashFile::ResetAge(int iEntry) { if (iEntry == m_iOldest) { // Rotate the doubly-linked list to make the oldest entry the // youngest. // m_iOldest = m_Cache[m_iOldest].m_iYounger; } else if (iEntry == m_Cache[m_iOldest].m_iOlder) { // This is already the youngest entry. // } else { // Unlink this entry. // int iYounger = m_Cache[iEntry].m_iYounger; int iOlder = m_Cache[iEntry].m_iOlder; m_Cache[iYounger].m_iOlder = iOlder; m_Cache[iOlder].m_iYounger = iYounger; // Re-link at the young end of the queue. // iYounger = m_iOldest; iOlder = m_Cache[iYounger].m_iOlder; m_Cache[iEntry].m_iOlder = iOlder; m_Cache[iEntry].m_iYounger = iYounger; m_Cache[iYounger].m_iOlder = iEntry; m_Cache[iOlder].m_iYounger = iEntry; } } void CHashFile::Tick(void) { int nCycle = mudconf.check_interval; if (mudconf.dump_interval < nCycle) { nCycle = mudconf.dump_interval; } CLinearTimeDelta ltdCycle; ltdCycle.SetSeconds(nCycle); int n = (mudconf.cache_tick_period*m_nCache)/ltdCycle; if (n < 1) { n = 1; } for (int i = 0; i < n; i++) { // Go ahead and flush a cache entry...just to keep the sync load // down a bit. This gives the cache time to age, and yet, pushes // the pages off to the disk eventually and gradually. // FlushCache(m_iLastFlushed++); if (m_iLastFlushed >= m_nCache) { m_iLastFlushed = 0; } } } int CHashFile::ReadCache(UINT32 iFileDir, int *phits) { int iCache = m_hpCacheLookup[iFileDir]; HF_FILEOFFSET oPage = m_pDir[iFileDir]; if ( iCache != -1 && m_Cache[iCache].m_iState != HF_CACHE_EMPTY && m_Cache[iCache].m_o == oPage) { ResetAge(iCache); (*phits)++; return iCache; } if ((iCache = AllocateEmptyPage(0, NULL)) >= 0) { if (m_Cache[iCache].m_hp.ReadPage(m_hPageFile, oPage)) { //if (m_Cache[i].m_hp.Validate()) //{ m_Cache[iCache].m_o = oPage; m_Cache[iCache].m_iState = HF_CACHE_CLEAN; ResetAge(iCache); UINT32 nStart, nEnd; m_Cache[iCache].m_hp.GetRange(m_nDirDepth, nStart, nEnd); for ( ; nStart <= nEnd; nStart++) { m_hpCacheLookup[nStart] = iCache; } return iCache; //} } else { Log.WriteString("CHashFile::ReadCache. ReadPage failed to get the page. DB DAMAGE." ENDLINE); } } return -1; } #endif // MEMORY_BASED CHashTable::CHashTable(void) { SeedRandomNumberGenerator(); Init(); } void CHashTable::Init(void) { m_nDir = 2; m_nDirDepth = 1; m_pDir = new pCHashPage[m_nDir]; if (m_pDir) { m_pDir[1] = m_pDir[0] = new CHashPage; if (m_pDir[0]) { if (m_pDir[0]->Allocate(HT_SIZEOF_PAGE)) { m_pDir[0]->Empty(0, 0UL, 100); } else { delete m_pDir[0]; m_pDir[0] = NULL; } } } m_nPages = 1; m_nEntries = 0; m_nDeletions = 0; m_nScans = 0; m_nHits = 0; m_nChecks = 0; m_nMaxScan = 0; } void CHashTable::ResetStats(void) { m_nScans = 0; m_nHits = 0; m_nChecks = 0; } bool CHashTable::Insert(HP_HEAPLENGTH nRecord, UINT32 nHash, void *pRecord) { for (;;) { UINT32 iTableDir = nHash >> (32 - m_nDirDepth); #ifdef HP_PROTECTION if (iTableDir >= m_nDir) { Log.WriteString("CHashTable::Insert - iTableDir out of range." ENDLINE); return false; } #endif // HP_PROTECTION m_hpLast = m_pDir[iTableDir]; if (!m_hpLast) { Log.WriteString("CHashTable::Insert - Page wasn't valid." ENDLINE); return false; } UINT32 nStart, nEnd; #ifdef HP_PROTECTION m_hpLast->GetRange(m_nDirDepth, nStart, nEnd); if (iTableDir < nStart || nEnd < iTableDir) { Log.WriteString("CHashTable::Insert - Directory points to the wrong page." ENDLINE); return false; } #endif // HP_PROTECTION int errInserted = m_hpLast->Insert(nRecord, nHash, pRecord); if (IS_HP_SUCCESS(errInserted)) { if (errInserted == HP_INSERT_SUCCESS_DEFRAG) { // Otherwise, this value will be over inflated. // m_nMaxScan = 0; } break; } if (errInserted == HP_INSERT_ERROR_ILLEGAL) { return false; } // If the depth of this page is already as deep as the directory // depth,then we must increase depth of the directory, first. // if (m_nDirDepth == m_hpLast->GetDepth()) { if (!DoubleDirectory()) { return false; } } // Split this page into two pages. We become a new one, and we // are given a pointer to the other one. // CHashPage *hpEmpty0 = new CHashPage; if (!hpEmpty0) return false; if (!hpEmpty0->Allocate(HT_SIZEOF_PAGE)) { delete hpEmpty0; return false; } CHashPage *hpEmpty1 = new CHashPage; if (!hpEmpty1) return false; if (!hpEmpty1->Allocate(HT_SIZEOF_PAGE)) { delete hpEmpty0; delete hpEmpty1; return false; } if (!m_hpLast->Split(*hpEmpty0, *hpEmpty1)) { return false; } // Otherwise, this value will be over inflated. // m_nMaxScan = 0; // Now, update the directory. // hpEmpty0->GetRange(m_nDirDepth, nStart, nEnd); for ( ; nStart <= nEnd; nStart++) { m_pDir[nStart] = hpEmpty0; } hpEmpty1->GetRange(m_nDirDepth, nStart, nEnd); for ( ; nStart <= nEnd; nStart++) { m_pDir[nStart] = hpEmpty1; } m_nPages++; delete m_hpLast; m_hpLast = 0; } m_nEntries++; return true; } bool CHashTable::DoubleDirectory(void) { unsigned int nNewDir = 2 * m_nDir; unsigned int nNewDirDepth = m_nDirDepth + 1; pCHashPage *pNewDir = new pCHashPage[nNewDir]; if (pNewDir) { unsigned int iNewDir = 0; for (unsigned int iDir = 0; iDir < m_nDir; iDir++) { pNewDir[iNewDir++] = m_pDir[iDir]; pNewDir[iNewDir++] = m_pDir[iDir]; } delete [] m_pDir; m_pDir = pNewDir; m_nDirDepth = nNewDirDepth; m_nDir = nNewDir; return true; } return false; } UINT32 CHashTable::FindFirstKey(UINT32 nHash) { m_nScans++; UINT32 iTableDir = nHash >> (32-m_nDirDepth); #ifdef HP_PROTECTION if (iTableDir >= m_nDir) { Log.WriteString("CHashTable::Insert - iTableDir out of range." ENDLINE); return HF_FIND_END; } #endif // HP_PROTECTION m_hpLast = m_pDir[iTableDir]; if (!m_hpLast) { Log.WriteString("CHashTable::Insert - Page wasn't valid." ENDLINE); return HF_FIND_END; } #ifdef HP_PROTECTION UINT32 nStart, nEnd; m_hpLast->GetRange(m_nDirDepth, nStart, nEnd); if (iTableDir < nStart || nEnd < iTableDir) { Log.WriteString("CHashTable::Find - Directory points to the wrong page." ENDLINE); return HF_FIND_END; } #endif // HP_PROTECTION unsigned int numchecks; UINT32 iDir = m_hpLast->FindFirstKey(nHash, &numchecks); m_nChecks += numchecks; if (numchecks > m_nMaxScan) { m_nMaxScan = numchecks; } if (iDir == HP_DIR_EMPTY) { return HF_FIND_END; } m_nHits++; return iDir; } UINT32 CHashTable::FindNextKey(UINT32 iDir, UINT32 nHash) { m_nScans++; unsigned int numchecks; iDir = m_hpLast->FindNextKey(iDir, nHash, &numchecks); m_nChecks += numchecks; if (numchecks > m_nMaxScan) { m_nMaxScan = numchecks; } if (iDir == HP_DIR_EMPTY) { return HF_FIND_END; } m_nHits++; return iDir; } void CHashTable::Copy(UINT32 iDir, HP_PHEAPLENGTH pnRecord, void *pRecord) { m_hpLast->HeapCopy(iDir, pnRecord, pRecord); } void CHashTable::Remove(UINT32 iDir) { m_nEntries--; m_nDeletions++; m_hpLast->HeapFree(iDir); } void CHashTable::Update(UINT32 iDir, HP_HEAPLENGTH nRecord, void *pRecord) { m_hpLast->HeapUpdate(iDir, nRecord, pRecord); } CHashTable::~CHashTable(void) { Final(); } void CHashTable::Final(void) { if (m_pDir) { m_hpLast = 0; for (unsigned int i = 0; i < m_nDir; i++) { CHashPage *hp = m_pDir[i]; if (hp != m_hpLast && hp) { delete hp; m_hpLast = hp; } } delete [] m_pDir; m_pDir = NULL; } } void CHashTable::Reset(void) { Final(); Init(); } UINT32 CHashTable::FindFirst(HP_PHEAPLENGTH pnRecord, void *pRecord) { m_hpLast = 0; for (m_iPage = 0; m_iPage < m_nDir; m_iPage++) { if (m_pDir[m_iPage] == m_hpLast) continue; m_hpLast = m_pDir[m_iPage]; if (m_hpLast) { UINT32 iDir = m_hpLast->FindFirst(pnRecord, pRecord); if (iDir != HP_DIR_EMPTY) { return iDir; } } } return HF_FIND_END; } UINT32 CHashTable::FindNext(HP_PHEAPLENGTH pnRecord, void *pRecord) { if (m_hpLast) { UINT32 iDir = m_hpLast->FindNext(pnRecord, pRecord); if (iDir != HP_DIR_EMPTY) { return iDir; } } // Move on to the next page. // for ( ; m_iPage < m_nDir; m_iPage++) { // Move on to the next page. // if (m_pDir[m_iPage] == m_hpLast) continue; m_hpLast = m_pDir[m_iPage]; if (m_hpLast) { UINT32 iDir = m_hpLast->FindFirst(pnRecord, pRecord); if (iDir != HP_DIR_EMPTY) { return iDir; } } } return HF_FIND_END; } unsigned int CHashTable::GetEntryCount() { return m_nEntries; } void CHashTable::GetStats ( unsigned int *hashsize, int *entries, INT64 *deletes, INT64 *scans, INT64 *hits, INT64 *checks, int *max_scan ) { *hashsize = m_nPages; *entries = m_nEntries; *deletes = m_nDeletions; *scans = m_nScans; *hits = m_nHits; *checks = m_nChecks; *max_scan = m_nMaxScan; } CLogFile Log; void CLogFile::WriteInteger(int iNumber) { char aTempBuffer[20]; size_t nTempBuffer = mux_ltoa(iNumber, aTempBuffer); WriteBuffer(nTempBuffer, aTempBuffer); } void CLogFile::WriteBuffer(size_t nString, const char *pString) { if (!bEnabled) { return; } #ifdef WIN32 EnterCriticalSection(&csLog); #endif // WIN32 while (nString > 0) { size_t nAvailable = SIZEOF_LOG_BUFFER - m_nBuffer; if (nAvailable == 0) { Flush(); continue; } size_t nToMove = nAvailable; if (nString < nToMove) { nToMove = nString; } // Move nToMove bytes from pString to aBuffer+nBuffer // memcpy(m_aBuffer+m_nBuffer, pString, nToMove); pString += nToMove; nString -= nToMove; m_nBuffer += nToMove; } Flush(); #ifdef WIN32 LeaveCriticalSection(&csLog); #endif // WIN32 } void CLogFile::WriteString(const char *pString) { size_t nString = strlen(pString); WriteBuffer(nString, pString); } void DCL_CDECL CLogFile::tinyprintf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); char aTempBuffer[SIZEOF_LOG_BUFFER]; size_t nString = mux_vsnprintf(aTempBuffer, SIZEOF_LOG_BUFFER, fmt, ap); va_end(ap); WriteBuffer(nString, aTempBuffer); } static void MakeLogName ( const char *pBasename, const char *szPrefix, CLinearTimeAbsolute lta, char *szLogName, size_t nLogName ) { char szTimeStamp[18]; lta.ReturnUniqueString(szTimeStamp, sizeof(szTimeStamp)); if ( pBasename && pBasename[0] != '\0') { mux_sprintf(szLogName, nLogName, "%s/%s-%s.log", pBasename, szPrefix, szTimeStamp); } else { mux_sprintf(szLogName, nLogName, "%s-%s.log", szPrefix, szTimeStamp); } } bool CLogFile::CreateLogFile(void) { CloseLogFile(); m_nSize = 0; bool bSuccess; #ifdef WIN32 m_hFile = CreateFile(m_szFilename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN, NULL); bSuccess = (INVALID_HANDLE_VALUE != m_hFile); #else // WIN32 bSuccess = mux_open(&m_fdFile, m_szFilename, O_RDWR|O_BINARY|O_CREAT|O_TRUNC); #endif // WIN32 return bSuccess; } void CLogFile::AppendLogFile(void) { CloseLogFile(); bool bSuccess; #ifdef WIN32 m_hFile = CreateFile(m_szFilename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN, NULL); bSuccess = (INVALID_HANDLE_VALUE != m_hFile); #else // WIN32 bSuccess = mux_open(&m_fdFile, m_szFilename, O_RDWR|O_BINARY); #endif // WIN32 if (bSuccess) { #ifdef WIN32 SetFilePointer(m_hFile, 0, 0, FILE_END); #else // WIN32 mux_lseek(m_fdFile, 0, SEEK_END); #endif // WIN32 } } void CLogFile::CloseLogFile(void) { #ifdef WIN32 if (INVALID_HANDLE_VALUE != m_hFile) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; } #else if (MUX_OPEN_INVALID_HANDLE_VALUE != m_fdFile) { mux_close(m_fdFile); m_fdFile = MUX_OPEN_INVALID_HANDLE_VALUE; } #endif } #define FILE_SIZE_TRIGGER (512*1024UL) void CLogFile::Flush(void) { if ( m_nBuffer <= 0 || !bEnabled) { return; } if (bUseStderr) { fwrite(m_aBuffer, m_nBuffer, 1, stderr); } else { m_nSize += m_nBuffer; #ifdef WIN32 unsigned long nWritten; WriteFile(m_hFile, m_aBuffer, (DWORD)m_nBuffer, &nWritten, NULL); #else // WIN32 mux_write(m_fdFile, m_aBuffer, m_nBuffer); #endif // WIN32 if (m_nSize > FILE_SIZE_TRIGGER) { CloseLogFile(); m_ltaStarted.GetLocal(); MakeLogName(m_pBasename, m_szPrefix, m_ltaStarted, m_szFilename, sizeof(m_szFilename)); CreateLogFile(); } } m_nBuffer = 0; } void CLogFile::SetPrefix(const char *szPrefix) { if ( !bUseStderr && strcmp(szPrefix, m_szPrefix) != 0) { if (bEnabled) { CloseLogFile(); } char szNewName[SIZEOF_PATHNAME]; MakeLogName(m_pBasename, szPrefix, m_ltaStarted, szNewName, sizeof(szNewName)); if (bEnabled) { ReplaceFile(m_szFilename, szNewName); } mux_strncpy(m_szPrefix, szPrefix, 31); mux_strncpy(m_szFilename, szNewName, SIZEOF_PATHNAME-1); if (bEnabled) { AppendLogFile(); } } } void CLogFile::SetBasename(const char *pBasename) { if (m_pBasename) { MEMFREE(m_pBasename); m_pBasename = NULL; } if ( pBasename && strcmp(pBasename, "-") == 0) { bUseStderr = true; } else { bUseStderr = false; if (pBasename) { m_pBasename = StringClone(pBasename); } else { m_pBasename = StringClone(""); } } } CLogFile::CLogFile(void) { #ifdef WIN32 InitializeCriticalSection(&csLog); #endif // WIN32 m_ltaStarted.GetLocal(); #ifdef WIN32 m_hFile = INVALID_HANDLE_VALUE; #else m_fdFile = MUX_OPEN_INVALID_HANDLE_VALUE; #endif m_nSize = 0; m_nBuffer = 0; bEnabled = false; bUseStderr = true; m_pBasename = NULL; m_szPrefix[0] = '\0'; m_szFilename[0] = '\0'; } void CLogFile::StartLogging() { if (!bUseStderr) { m_ltaStarted.GetLocal(); MakeLogName(m_pBasename, m_szPrefix, m_ltaStarted, m_szFilename, sizeof(m_szFilename)); CreateLogFile(); } bEnabled = true; } void CLogFile::StopLogging(void) { Flush(); bEnabled = false; if (!bUseStderr) { CloseLogFile(); m_szPrefix[0] = '\0'; m_szFilename[0] = '\0'; SetBasename(NULL); } } CLogFile::~CLogFile(void) { StopLogging(); #ifdef WIN32 DeleteCriticalSection(&csLog); #endif // WIN32 } #ifdef MEMORY_ACCOUNTING #pragma pack(1) typedef struct { void *address; int size; UINT32 fileline; } AllocDataRec; typedef struct { size_t nSize; int line; char filename[1]; } IdentDataRec; #pragma pack() bool bMemAccountingInitialized = false; CHashFile hfAllocData; CHashFile hfIdentData; extern long DebugTotalMemory; UINT32 HashPointer(void *vp) { UINT32 nHash1 = HASH_ProcessBuffer(0, &vp, sizeof(void *)); UINT32 nHash2 = CRC32_ProcessBuffer(0, &vp, sizeof(void *)); mux_assert(nHash1 == nHash2); return nHash1; } unsigned long HashFileLine(const char *fn, int line) { UINT32 nHash1 = CRC32_ProcessInteger(line); nHash1 = HASH_ProcessBuffer(nHash1, fn, strlen(fn)+1); UINT32 nHash2 = CRC32_ProcessInteger(line); nHash2 = CRC32_ProcessBuffer(nHash2, fn, strlen(fn)+1); mux_assert(nHash1 == nHash2); return nHash1; } bool SubtractSpaceFromFileLine ( UINT32 nHash, int size, size_t *pnSpace, int *pAllocLine, char *file ) { *pnSpace = 0; *pAllocLine = -1; UINT32 iDir = hfIdentData.FindFirstKey(nHash); if (iDir != HF_FIND_END) { HP_HEAPLENGTH nIdent; char Buffer[1024]; hfIdentData.Copy(iDir, &nIdent, Buffer); hfIdentData.Remove(iDir); IdentDataRec *idr = (IdentDataRec *)Buffer; *pAllocLine = idr->line; strcpy(file, idr->filename); idr->nSize -= size; *pnSpace = idr->nSize; hfIdentData.Insert(nIdent, nHash, Buffer); } return true; } unsigned long AddSpaceToFileLine ( const char *file, int line, size_t nSpace, size_t *pnTotalSpace ) { *pnTotalSpace = 0; HP_HEAPLENGTH nIdent; char Buffer[1024]; IdentDataRec *idr = (IdentDataRec *)Buffer; UINT32 nHash = HashFileLine(file, line); bool bFound = false; again: UINT32 iDir = hfIdentData.FindFirstKey(nHash); while (iDir != HF_FIND_END) { hfIdentData.Copy(iDir, &nIdent, Buffer); if ( line == idr->line && strcmp(idr->filename, file) == 0) { hfIdentData.Remove(iDir); nSpace += idr->nSize; bFound = true; goto again; } iDir = hfIdentData.FindNextKey(iDir, nHash); } if (!bFound) { idr->line = line; strcpy(idr->filename, file); char *p = idr->filename + strlen(idr->filename) + 1; nIdent = p - Buffer; } idr->nSize = nSpace; hfIdentData.Insert(nIdent, nHash, Buffer); *pnTotalSpace = nSpace; return nHash; } void AccountForAllocation(void *pointer, size_t size, const char *file, int line) { DebugTotalMemory += size; AllocDataRec adr; adr.address = pointer; adr.size = size; unsigned long nHash = HashPointer(pointer); again: UINT32 iDir = hfAllocData.FindFirstKey(nHash); while (iDir != HF_FIND_END) { AllocDataRec adr2; HP_HEAPLENGTH nRecord; hfAllocData.Copy(iDir, &nRecord, &adr2); if (adr2.address == adr.address) { // Whoa! We've been told this new pointer, but it's not. // fprintf(stderr, "The heap is giving us unfreed pointers (0x%08X). Weird.\n", adr.address); hfAllocData.Remove(iDir); goto again; } iDir = hfAllocData.FindNextKey(iDir, nHash); } size_t TotalSpace; adr.fileline = AddSpaceToFileLine(file, line, size, &TotalSpace); hfAllocData.Insert(sizeof(adr), nHash, &adr); fprintf(stderr, "malloc %d bytes %s, %d\n bringing total to %d bytes\n", size, file, line, TotalSpace); } void AccountForFree(void *pointer, const char *file, int line) { unsigned long nHash = HashPointer(pointer); bool bFound = false; again: UINT32 iDir = hfAllocData.FindFirstKey(nHash); while (iDir != HF_FIND_END) { // We found it. // HP_HEAPLENGTH nRecord; AllocDataRec adr; hfAllocData.Copy(iDir, &nRecord, &adr); if (adr.address == pointer) { bFound = true; hfAllocData.Remove(iDir); DebugTotalMemory -= adr.size; size_t nSpace; int AllocLine; char filename[1024]; if (SubtractSpaceFromFileLine(adr.fileline, adr.size, &nSpace, &AllocLine, filename)) { fprintf(stderr, "free %d bytes on %s, %d ...\n allocated on %s, %d...\n leaving total of %d bytes\n", adr.size, file, line, filename, AllocLine, nSpace); } else { fprintf(stderr, "free %d bytes on %s, %d ...\n allocated on UNKNOWN\n", adr.size, file, line); } goto again; } iDir = hfAllocData.FindNextKey(iDir, nHash); } if (!bFound) { // Problems. // fprintf(stderr, "We are freeing unallocated pointers (0x%08X) on %s, %d\n", pointer, file, line); } } int iRecursion = 0; void *MemAllocate(size_t size, const char *file, int line) { void *vp = malloc(size); if (vp) { if (bMemAccountingInitialized) { if (iRecursion == 0) { iRecursion++; AccountForAllocation(vp, size, file, line); iRecursion--; } } else { fprintf(stderr, "malloc not intitalized on %s, %d.\n", file, line); } } else { fprintf(stderr, "malloc ran out of memory on %s, %d.\n", file, line); } return vp; } void MemFree(void *pointer, const char *file, int line) { if (pointer) { if (bMemAccountingInitialized) { if (iRecursion == 0) { iRecursion++; AccountForFree(pointer, file, line); iRecursion--; } } else { fprintf(stderr, "free called on %s, %d before initialized with 0x%08X\n", file, line, pointer); } free(pointer); } else { fprintf(stderr, "We tried to free(0) on %s, %d\n", file, line); } } void *MemRealloc(void *pointer, size_t size, const char *file, int line) { if (pointer) { AccountForFree(pointer, file, line); } void * vp = realloc(pointer, size); if (vp) { AccountForAllocation(vp, size, file, line); } return vp; } #endif // MEMORY_ACCOUNTING mux2.6/src/walkdb.cpp0000600000175000017500000007540611025753746014562 0ustar sdennissdennis// walkdb.cpp -- Support for commands that walk the entire db. // // $Id: walkdb.cpp 2734 2007-10-28 23:02:55Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "misc.h" #include "attrs.h" #include "command.h" // Bind occurances of the universal var in ACTION to ARG, then run ACTION. // Cmds run in low-prio Q after a 1 sec delay for the first one. // static void bind_and_queue(dbref executor, dbref caller, dbref enactor, int eval, char *action, char *argstr, char *cargs[], int ncargs, int number) { char *command = replace_tokens(action, argstr, mux_ltoa_t(number), NULL); CLinearTimeAbsolute lta; wait_que(executor, caller, enactor, eval, false, lta, NOTHING, 0, command, ncargs, cargs, mudstate.global_regs); free_lbuf(command); } // New @dolist. i.e.: // @dolist #12 #34 #45 #123 #34644=@emit [name(##)] // // New switches added 12/92, /space (default) delimits list using spaces, // and /delimit allows specification of a delimiter. // void do_dolist(dbref executor, dbref caller, dbref enactor, int eval, int key, char *list, char *command, char *cargs[], int ncargs) { if (!list || *list == '\0') { notify(executor, "That's terrific, but what should I do with the list?"); return; } char *objstring, delimiter = ' '; int number = 0; char *curr = list; if (key & DOLIST_DELIMIT) { char *tempstr = parse_to(&curr, ' ', EV_STRIP_CURLY); if (strlen(tempstr) > 1) { notify(executor, "The delimiter must be a single character!"); return; } delimiter = *tempstr; } while (curr && *curr) { while (*curr == delimiter) { curr++; } if (*curr) { number++; objstring = parse_to(&curr, delimiter, EV_STRIP_CURLY); bind_and_queue(executor, caller, enactor, eval, command, objstring, cargs, ncargs, number); } } if (key & DOLIST_NOTIFY) { char *tbuf = alloc_lbuf("dolist.notify_cmd"); mux_strncpy(tbuf, "@notify/quiet me", LBUF_SIZE-1); CLinearTimeAbsolute lta; wait_que(executor, caller, enactor, eval, false, lta, NOTHING, A_SEMAPHORE, tbuf, ncargs, cargs, mudstate.global_regs); free_lbuf(tbuf); } } // Regular @find command // void do_find(dbref executor, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); char *buff; if (!payfor(executor, mudconf.searchcost)) { buff = tprintf("You don't have enough %s.", mudconf.many_coins); notify_quiet(executor, buff); return; } dbref i, low_bound, high_bound; parse_range(&name, &low_bound, &high_bound); for (i = low_bound; i <= high_bound; i++) { if ( (Typeof(i) != TYPE_EXIT) && Controls(executor, i) && (!*name || string_match(PureName(i), name))) { buff = unparse_object(executor, i, false); notify(executor, buff); free_lbuf(buff); } } notify(executor, "***End of List***"); } // --------------------------------------------------------------------------- // get_stats, do_stats: Get counts of items in the db. // bool get_stats(dbref player, dbref who, STATS *info) { // Do we have permission? // if (Good_obj(who) && !Controls(player, who) && !Stat_Any(player)) { notify(player, NOPERM_MESSAGE); return false; } // Can we afford it? // if (!payfor(player, mudconf.searchcost)) { notify(player, tprintf("You don't have enough %s.", mudconf.many_coins)); return false; } info->s_total = 0; info->s_rooms = 0; info->s_exits = 0; info->s_things = 0; info->s_players = 0; info->s_garbage = 0; dbref i; DO_WHOLE_DB(i) { if ((who == NOTHING) || (who == Owner(i))) { info->s_total++; if (Going(i) && (Typeof(i) != TYPE_ROOM)) { info->s_garbage++; continue; } switch (Typeof(i)) { case TYPE_ROOM: info->s_rooms++; break; case TYPE_EXIT: info->s_exits++; break; case TYPE_THING: info->s_things++; break; case TYPE_PLAYER: info->s_players++; break; default: info->s_garbage++; } } } return true; } // Reworked by R'nice // void do_stats(dbref executor, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); dbref owner; switch (key) { case STAT_ALL: owner = NOTHING; break; case STAT_ME: owner = Owner(executor); break; case STAT_PLAYER: if (!(name && *name)) { int nNextFree = mudstate.freelist; if (mudstate.freelist == NOTHING) { nNextFree = mudstate.db_top; } notify(executor, tprintf("The universe contains %d objects (next free is #%d).", mudstate.db_top, nNextFree)); return; } owner = lookup_player(executor, name, true); if (owner == NOTHING) { notify(executor, "Not found."); return; } break; default: notify(executor, "Illegal combination of switches."); return; } STATS statinfo; if (!get_stats(executor, owner, &statinfo)) { return; } notify(executor, tprintf( "%d objects = %d rooms, %d exits, %d things, %d players. (%d garbage)", statinfo.s_total, statinfo.s_rooms, statinfo.s_exits, statinfo.s_things, statinfo.s_players, statinfo.s_garbage)); } int chown_all(dbref from_player, dbref to_player, dbref acting_player, int key) { if (!isPlayer(from_player)) { from_player = Owner(from_player); } if (!isPlayer(to_player)) { to_player = Owner(to_player); } int count = 0; if ( God(from_player) && !God(acting_player)) { notify(acting_player, NOPERM_MESSAGE); } else { int i; int quota_out = 0; int quota_in = 0; FLAGSET clearflags; FLAGSET setflags; bool bClearPowers; TranslateFlags_Chown(clearflags.word, setflags.word, &bClearPowers, acting_player, key); DO_WHOLE_DB(i) { if ( Owner(i) == from_player && Owner(i) != i) { switch (Typeof(i)) { case TYPE_PLAYER: s_Owner(i, i); quota_out += mudconf.player_quota; break; case TYPE_THING: s_Owner(i, to_player); quota_out += mudconf.thing_quota; quota_in -= mudconf.thing_quota; break; case TYPE_ROOM: s_Owner(i, to_player); quota_out += mudconf.room_quota; quota_in -= mudconf.room_quota; break; case TYPE_EXIT: s_Owner(i, to_player); quota_out += mudconf.exit_quota; quota_in -= mudconf.exit_quota; break; default: s_Owner(i, to_player); } if (key & CHOWN_NOZONE) { s_Zone(i, NOTHING); } SetClearFlags(i, clearflags.word, setflags.word); if (bClearPowers) { s_Powers(i, 0); s_Powers2(i, 0); } // Always halt the queue. // halt_que(NOTHING, i); count++; } } add_quota(from_player, quota_out); add_quota(to_player, quota_in); } return count; } void do_chownall ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *from, char *to ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); init_match(executor, from, TYPE_PLAYER); match_neighbor(); match_absolute(); match_player(); dbref victim = noisy_match_result(); if (NOTHING == victim) { return; } else if (!isPlayer(victim)) { notify(executor, "Victim must be a player."); return; } dbref recipient = executor; if ( NULL != to && to[0] != '\0') { init_match(executor, to, TYPE_PLAYER); match_neighbor(); match_absolute(); match_player(); recipient = noisy_match_result(); if (NOTHING == recipient) { return; } } int count = chown_all(victim, recipient, executor, key); if (!Quiet(executor)) { notify(executor, tprintf("%d objects @chowned.", count)); } } #define ANY_OWNER (-2) static void er_mark_disabled(dbref player) { notify(player, "The mark commands are not allowed while DB cleaning is enabled."); notify(player, "Use the '@disable cleaning' command to disable automatic cleaning."); notify(player, "Remember to '@unmark_all' before re-enabling automatic cleaning."); } // --------------------------------------------------------------------------- // do_search: Walk the db reporting various things (or setting/clearing mark // bits) // bool search_setup(dbref player, char *searchfor, SEARCH *parm) { // Crack arg into =,, // char *pname = parse_to(&searchfor, '=', EV_STRIP_TS); if (!pname || !*pname) { pname = (char *)"me"; } else { mux_strlwr(pname); } char *searchtype; if (searchfor && *searchfor) { searchtype = strrchr(pname, ' '); if (searchtype) { *searchtype++ = '\0'; } else { searchtype = pname; pname = (char *)""; } } else { searchtype = (char *)""; } // If the player name is quoted, strip the quotes. // if (*pname == '\"') { size_t k = strlen(pname) - 1; if (pname[k] == '"') { pname[k] = '\0'; pname++; } } // Strip any range arguments. // parse_range(&searchfor, &parm->low_bound, &parm->high_bound); // Set limits on who we search. // parm->s_owner = Owner(player); parm->s_wizard = Search(player); parm->s_rst_owner = NOTHING; if (!*pname) { parm->s_rst_owner = parm->s_wizard ? ANY_OWNER : player; } else if (pname[0] == '#') { parm->s_rst_owner = mux_atol(&pname[1]); if (!Good_obj(parm->s_rst_owner)) { parm->s_rst_owner = NOTHING; } else if (Typeof(parm->s_rst_owner) != TYPE_PLAYER) { parm->s_rst_owner = NOTHING; } } else if (strcmp(pname, "me") == 0) { parm->s_rst_owner = player; } else { parm->s_rst_owner = lookup_player(player, pname, true); } if (parm->s_rst_owner == NOTHING) { notify(player, tprintf("%s: No such player", pname)); return false; } // Set limits on what we search for. // int err = 0; parm->s_rst_name = NULL; parm->s_rst_eval = NULL; parm->s_rst_type = NOTYPE; parm->s_parent = NOTHING; parm->s_zone = NOTHING; for (int i = FLAG_WORD1; i <= FLAG_WORD3; i++) { parm->s_fset.word[i] = 0; } parm->s_pset.word1 = 0; parm->s_pset.word2 = 0; switch (searchtype[0]) { case '\0': // The no class requested class :) // break; case 'e': if (string_prefix("exits", searchtype)) { parm->s_rst_name = searchfor; parm->s_rst_type = TYPE_EXIT; } else if (string_prefix("evaluate", searchtype)) { parm->s_rst_eval = searchfor; } else if (string_prefix("eplayer", searchtype)) { parm->s_rst_type = TYPE_PLAYER; parm->s_rst_eval = searchfor; } else if (string_prefix("eroom", searchtype)) { parm->s_rst_type = TYPE_ROOM; parm->s_rst_eval = searchfor; } else if (string_prefix("eobject", searchtype)) { parm->s_rst_type = TYPE_THING; parm->s_rst_eval = searchfor; } else if (string_prefix("ething", searchtype)) { parm->s_rst_type = TYPE_THING; parm->s_rst_eval = searchfor; } else if (string_prefix("eexit", searchtype)) { parm->s_rst_type = TYPE_EXIT; parm->s_rst_eval = searchfor; } else { err = 1; } break; case 'f': if (string_prefix("flags", searchtype)) { // convert_flags ignores previous values of flag_mask and // s_rst_type while setting them. // if ( !convert_flags( player, searchfor, &parm->s_fset, &parm->s_rst_type) ) { return false; } } else { err = 1; } break; case 'n': if (string_prefix("name", searchtype)) { parm->s_rst_name = searchfor; } else { err = 1; } break; case 'o': if (string_prefix("objects", searchtype)) { parm->s_rst_name = searchfor; parm->s_rst_type = TYPE_THING; } else { err = 1; } break; case 'p': if (string_prefix("players", searchtype)) { parm->s_rst_name = searchfor; parm->s_rst_type = TYPE_PLAYER; if (!*pname) { parm->s_rst_owner = ANY_OWNER; } } else if (string_prefix("parent", searchtype)) { parm->s_parent = match_controlled(player, searchfor); if (!Good_obj(parm->s_parent)) { return false; } if (!*pname) { parm->s_rst_owner = ANY_OWNER; } } else if (string_prefix("power", searchtype)) { if (!decode_power(player, searchfor, &parm->s_pset)) { return false; } } else { err = 1; } break; case 'r': if (string_prefix("rooms", searchtype)) { parm->s_rst_name = searchfor; parm->s_rst_type = TYPE_ROOM; } else { err = 1; } break; case 't': if (string_prefix("type", searchtype)) { if (searchfor[0] == '\0') { break; } if (string_prefix("rooms", searchfor)) { parm->s_rst_type = TYPE_ROOM; } else if (string_prefix("exits", searchfor)) { parm->s_rst_type = TYPE_EXIT; } else if (string_prefix("objects", searchfor)) { parm->s_rst_type = TYPE_THING; } else if (string_prefix("things", searchfor)) { parm->s_rst_type = TYPE_THING; } else if (string_prefix("garbage", searchfor)) { parm->s_rst_type = TYPE_GARBAGE; } else if (string_prefix("players", searchfor)) { parm->s_rst_type = TYPE_PLAYER; if (!*pname) { parm->s_rst_owner = ANY_OWNER; } } else { notify(player, tprintf("%s: unknown type", searchfor)); return false; } } else if (string_prefix("things", searchtype)) { parm->s_rst_name = searchfor; parm->s_rst_type = TYPE_THING; } else { err = 1; } break; case 'z': if (string_prefix("zone", searchtype)) { parm->s_zone = match_controlled(player, searchfor); if (!Good_obj(parm->s_zone)) { return false; } if (!*pname) { parm->s_rst_owner = ANY_OWNER; } } else { err = 1; } break; default: err = 1; } if (err) { notify(player, tprintf("%s: unknown class", searchtype)); return false; } // Make sure player is authorized to do the search. // if ( !parm->s_wizard && (parm->s_rst_type != TYPE_PLAYER) && (parm->s_rst_owner != player) && (parm->s_rst_owner != ANY_OWNER)) { notify(player, "You need a search warrant to do that!"); return false; } // Make sure player has money to do the search. // if (!payfor(player, mudconf.searchcost)) { notify(player, tprintf("You don't have enough %s to search. (You need %d)", mudconf.many_coins, mudconf.searchcost)); return false; } return true; } void search_perform(dbref executor, dbref caller, dbref enactor, SEARCH *parm) { POWER thing1powers, thing2powers; char *result, *bp, *str; char *buff = alloc_sbuf("search_perform.num"); int save_invk_ctr = mudstate.func_invk_ctr; dbref thing; for (thing = parm->low_bound; thing <= parm->high_bound; thing++) { mudstate.func_invk_ctr = save_invk_ctr; // Check for matching type. // if ( (parm->s_rst_type != NOTYPE) && (parm->s_rst_type != Typeof(thing))) { continue; } // Check for matching owner. // if ( (parm->s_rst_owner != ANY_OWNER) && (parm->s_rst_owner != Owner(thing))) { continue; } // Toss out destroyed things. // if (Going(thing)) { continue; } // Check for matching parent. // if ( (parm->s_parent != NOTHING) && (parm->s_parent != Parent(thing))) { continue; } // Check for matching zone. // if ( (parm->s_zone != NOTHING) && (parm->s_zone != Zone(thing))) { continue; } // Check for matching flags. // bool b = false; for (int i = FLAG_WORD1; i <= FLAG_WORD3; i++) { FLAG f = parm->s_fset.word[i]; if ((db[thing].fs.word[i] & f) != f) { b = true; break; } } if (b) { continue; } // Check for matching power. // thing1powers = Powers(thing); thing2powers = Powers2(thing); if ((thing1powers & parm->s_pset.word1) != parm->s_pset.word1) { continue; } if ((thing2powers & parm->s_pset.word2) != parm->s_pset.word2) { continue; } // Check for matching name. // if (parm->s_rst_name != NULL) { if (!string_prefix(PureName(thing), parm->s_rst_name)) continue; } // Check for successful evaluation. // if (parm->s_rst_eval != NULL) { buff[0] = '#'; mux_ltoa(thing, buff+1); char *buff2 = replace_tokens(parm->s_rst_eval, buff, NULL, NULL); result = bp = alloc_lbuf("search_perform"); str = buff2; mux_exec(result, &bp, executor, caller, enactor, EV_FCHECK | EV_EVAL | EV_NOTRACE, &str, NULL, 0); *bp = '\0'; free_lbuf(buff2); if (!*result || !xlate(result)) { free_lbuf(result); continue; } free_lbuf(result); } // It passed everything. Amazing. // olist_add(thing); } free_sbuf(buff); mudstate.func_invk_ctr = save_invk_ctr; } static void search_mark(dbref player, int key) { dbref thing; bool is_marked; int nchanged = 0; for (thing = olist_first(); thing != NOTHING; thing = olist_next()) { is_marked = Marked(thing); // Don't bother checking if marking and already marked (or if // unmarking and not marked) // if ( ((key == SRCH_MARK) && is_marked) || ((key == SRCH_UNMARK) && !is_marked)) { continue; } // Toggle the mark bit and update the counters. // if (key == SRCH_MARK) { Mark(thing); nchanged++; } else { Unmark(thing); nchanged++; } } notify( player, tprintf("%d objects %smarked", nchanged, ((key == SRCH_MARK) ? "" : "un")) ); return; } void do_search(dbref executor, dbref caller, dbref enactor, int eval, int key, char *arg) { UNUSED_PARAMETER(eval); char *buff, *outbuf, *bp; dbref thing, from, to; SEARCH searchparm; if ((key != SRCH_SEARCH) && (mudconf.control_flags & CF_DBCHECK)) { er_mark_disabled(executor); return; } if (!search_setup(executor, arg, &searchparm)) { return; } olist_push(); search_perform(executor, caller, enactor, &searchparm); bool destitute = true; bool flag; // If we are doing a @mark command, handle that here. // if (key != SRCH_SEARCH) { search_mark(executor, key); olist_pop(); return; } outbuf = alloc_lbuf("do_search.outbuf"); int rcount = 0; int ecount = 0; int tcount = 0; int pcount = 0; // Room search. // if ( searchparm.s_rst_type == TYPE_ROOM || searchparm.s_rst_type == NOTYPE) { flag = true; for (thing = olist_first(); thing != NOTHING; thing = olist_next()) { if (Typeof(thing) != TYPE_ROOM) { continue; } if (flag) { flag = false; destitute = false; notify(executor, "\nROOMS:"); } buff = unparse_object(executor, thing, false); notify(executor, buff); free_lbuf(buff); rcount++; } } // Exit search. // if ( searchparm.s_rst_type == TYPE_EXIT || searchparm.s_rst_type == NOTYPE) { flag = true; for (thing = olist_first(); thing != NOTHING; thing = olist_next()) { if (Typeof(thing) != TYPE_EXIT) { continue; } if (flag) { flag = false; destitute = false; notify(executor, "\nEXITS:"); } from = Exits(thing); to = Location(thing); bp = outbuf; buff = unparse_object(executor, thing, false); safe_str(buff, outbuf, &bp); free_lbuf(buff); safe_str(" [from ", outbuf, &bp); buff = unparse_object(executor, from, false); safe_str(((from == NOTHING) ? "NOWHERE" : buff), outbuf, &bp); free_lbuf(buff); safe_str(" to ", outbuf, &bp); buff = unparse_object(executor, to, false); safe_str(((to == NOTHING) ? "NOWHERE" : buff), outbuf, &bp); free_lbuf(buff); safe_chr(']', outbuf, &bp); *bp = '\0'; notify(executor, outbuf); ecount++; } } // Object search // if ( searchparm.s_rst_type == TYPE_THING || searchparm.s_rst_type == NOTYPE) { flag = true; for (thing = olist_first(); thing != NOTHING; thing = olist_next()) { if (Typeof(thing) != TYPE_THING) { continue; } if (flag) { flag = false; destitute = false; notify(executor, "\nOBJECTS:"); } bp = outbuf; buff = unparse_object(executor, thing, false); safe_str(buff, outbuf, &bp); free_lbuf(buff); safe_str(" [owner: ", outbuf, &bp); buff = unparse_object(executor, Owner(thing), false); safe_str(buff, outbuf, &bp); free_lbuf(buff); safe_chr(']', outbuf, &bp); *bp = '\0'; notify(executor, outbuf); tcount++; } } // Player search // if ( searchparm.s_rst_type == TYPE_PLAYER || searchparm.s_rst_type == NOTYPE) { flag = true; for (thing = olist_first(); thing != NOTHING; thing = olist_next()) { if (Typeof(thing) != TYPE_PLAYER) { continue; } if (flag) { flag = false; destitute = false; notify(executor, "\nPLAYERS:"); } bp = outbuf; buff = unparse_object(executor, thing, 0); safe_str(buff, outbuf, &bp); free_lbuf(buff); if (searchparm.s_wizard) { safe_str(" [location: ", outbuf, &bp); buff = unparse_object(executor, Location(thing), false); safe_str(buff, outbuf, &bp); free_lbuf(buff); safe_chr(']', outbuf, &bp); } *bp = '\0'; notify(executor, outbuf); pcount++; } } // If nothing found matching search criteria. // if (destitute) { notify(executor, "Nothing found."); } else { mux_sprintf(outbuf, LBUF_SIZE, "\nFound: Rooms...%d Exits...%d Objects...%d Players...%d", rcount, ecount, tcount, pcount); notify(executor, outbuf); } free_lbuf(outbuf); olist_pop(); } // --------------------------------------------------------------------------- // do_markall: set or clear the mark bits of all objects in the db. // void do_markall(dbref executor, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); int i; if (mudconf.control_flags & CF_DBCHECK) { er_mark_disabled(executor); return; } if (key == MARK_SET) { Mark_all(i); } else if (key == MARK_CLEAR) { Unmark_all(i); } if (!Quiet(executor)) { notify(executor, "Done."); } } // --------------------------------------------------------------------------- // do_apply_marked: Perform a command for each marked obj in the db. // void do_apply_marked( dbref executor, dbref caller, dbref enactor, int eval, int key, char *command, char *cargs[], int ncargs) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); if (mudconf.control_flags & CF_DBCHECK) { er_mark_disabled(executor); return; } char *buff = alloc_sbuf("do_apply_marked"); int i; int number = 0; DO_WHOLE_DB(i) { if (Marked(i)) { buff[0] = '#'; mux_ltoa(i, buff+1); number++; bind_and_queue(executor, caller, enactor, eval, command, buff, cargs, ncargs, number); } } free_sbuf(buff); if (!Quiet(executor)) { notify(executor, "Done."); } } // --------------------------------------------------------------------------- // Object list management routines: olist_push, olist_pop, olist_add, // olist_first, olist_next // // olist_push: Create a new object list at the top of the object list stack. // void olist_push(void) { OLSTK *ol = NULL; try { ol = new OLSTK; } catch (...) { ; // Nothing. } if (NULL != ol) { ol->next = mudstate.olist; mudstate.olist = ol; ol->head = NULL; ol->tail = NULL; ol->cblock = NULL; ol->count = 0; ol->citm = 0; } else { ISOUTOFMEMORY(ol); } } // olist_pop: Pop one entire list off the object list stack. // void olist_pop(void) { OLSTK *ol = mudstate.olist->next; OBLOCK *op, *onext; for (op = mudstate.olist->head; op != NULL; op = onext) { onext = op->next; free_lbuf(op); } delete mudstate.olist; mudstate.olist = ol; } // olist_add: Add an entry to the object list. // void olist_add(dbref item) { OBLOCK *op; if (!mudstate.olist->head) { op = (OBLOCK *) alloc_lbuf("olist_add.first"); mudstate.olist->head = mudstate.olist->tail = op; mudstate.olist->count = 0; op->next = NULL; } else if (mudstate.olist->count >= OBLOCK_SIZE) { op = (OBLOCK *) alloc_lbuf("olist_add.next"); mudstate.olist->tail->next = op; mudstate.olist->tail = op; mudstate.olist->count = 0; op->next = NULL; } else { op = mudstate.olist->tail; } op->data[mudstate.olist->count++] = item; } // olist_first: Return the first entry in the object list. // dbref olist_first(void) { if (!mudstate.olist->head) { return NOTHING; } if ( (mudstate.olist->head == mudstate.olist->tail) && (mudstate.olist->count == 0)) { return NOTHING; } mudstate.olist->cblock = mudstate.olist->head; mudstate.olist->citm = 0; return mudstate.olist->cblock->data[mudstate.olist->citm++]; } dbref olist_next(void) { if (!mudstate.olist->cblock) { return NOTHING; } if ( (mudstate.olist->cblock == mudstate.olist->tail) && (mudstate.olist->citm >= mudstate.olist->count)) { return NOTHING; } dbref thing = mudstate.olist->cblock->data[mudstate.olist->citm++]; if (mudstate.olist->citm >= OBLOCK_SIZE) { mudstate.olist->cblock = mudstate.olist->cblock->next; mudstate.olist->citm = 0; } return thing; } mux2.6/src/vattr.h0000600000175000017500000000113711025753746014111 0ustar sdennissdennis// vattr.h -- Definitions for user-defined attributes. // // $Id: vattr.h 8 2006-09-05 01:55:58Z brazilofmux $ // extern ATTR *vattr_rename_LEN(char *pOldName, size_t nOldName, char *pNewName, size_t nNewName); extern ATTR *vattr_find_LEN(const char *pAttrName, size_t nAttrName); extern ATTR *vattr_alloc_LEN(char *pAttrName, size_t nAttrName, int flags); extern ATTR *vattr_define_LEN(char *pAttrName, size_t nAttrName, int number, int flags); extern void vattr_delete_LEN(char *pName, size_t nName); extern ATTR *vattr_first(void); extern ATTR *vattr_next(ATTR *); extern void list_vhashstats(dbref); mux2.6/src/timer.cpp0000600000175000017500000004643211025753746014433 0ustar sdennissdennis// timer.cpp -- Mini-task scheduler for timed events. // // $Id: timer.cpp 2803 2007-11-27 00:30:39Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include #include "command.h" #include "mguests.h" CScheduler scheduler; // Free List Reconstruction Task routine. // void dispatch_FreeListReconstruction(void *pUnused, int iUnused) { UNUSED_PARAMETER(pUnused); UNUSED_PARAMETER(iUnused); if (mudconf.control_flags & CF_DBCHECK) { const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< dbck >"; do_dbck(NOTHING, NOTHING, NOTHING, 0); Guest.CleanUp(); pcache_trim(); pool_reset(); mudstate.debug_cmd = cmdsave; } // Schedule ourselves again. // CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); CLinearTimeDelta ltd; ltd.SetSeconds(mudconf.check_interval); mudstate.check_counter = ltaNow + ltd; scheduler.DeferTask(mudstate.check_counter, PRIORITY_SYSTEM, dispatch_FreeListReconstruction, 0, 0); } // Database Dump Task routine. // void dispatch_DatabaseDump(void *pUnused, int iUnused) { UNUSED_PARAMETER(pUnused); UNUSED_PARAMETER(iUnused); int nNextTimeInSeconds = mudconf.dump_interval; if (mudconf.control_flags & CF_CHECKPOINT) { const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< dump >"; #ifndef WIN32 if (mudstate.dumping) { // There is a dump in progress. These usually happen very quickly. // We will reschedule ourselves to try again in 20 seconds. // Ordinarily, you would think "...a dump is a dump...", but some // dumps might not be the type of dump we're going to do. // nNextTimeInSeconds = 20; } else #endif // !WIN32 { fork_and_dump(0); } mudstate.debug_cmd = cmdsave; } // Schedule ourselves again. // CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); CLinearTimeDelta ltd; ltd.SetSeconds(nNextTimeInSeconds); mudstate.dump_counter = ltaNow + ltd; scheduler.DeferTask(mudstate.dump_counter, PRIORITY_SYSTEM, dispatch_DatabaseDump, 0, 0); } // Idle Check Task routine. // void dispatch_IdleCheck(void *pUnused, int iUnused) { UNUSED_PARAMETER(pUnused); UNUSED_PARAMETER(iUnused); if (mudconf.control_flags & CF_IDLECHECK) { const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< idlecheck >"; check_idle(); mudstate.debug_cmd = cmdsave; } // Schedule ourselves again. // CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); CLinearTimeDelta ltd; ltd.SetSeconds(mudconf.idle_interval); mudstate.idle_counter = ltaNow + ltd; scheduler.DeferTask(mudstate.idle_counter, PRIORITY_SYSTEM, dispatch_IdleCheck, 0, 0); } // Check Events Task routine. // void dispatch_CheckEvents(void *pUnused, int iUnused) { UNUSED_PARAMETER(pUnused); UNUSED_PARAMETER(iUnused); if (mudconf.control_flags & CF_EVENTCHECK) { const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< eventcheck >"; check_events(); mudstate.debug_cmd = cmdsave; } // Schedule ourselves again. // CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); CLinearTimeDelta ltd = time_15m; mudstate.events_counter = ltaNow + ltd; scheduler.DeferTask(mudstate.events_counter, PRIORITY_SYSTEM, dispatch_CheckEvents, 0, 0); } #ifndef MEMORY_BASED void dispatch_CacheTick(void *pUnused, int iUnused) { UNUSED_PARAMETER(pUnused); UNUSED_PARAMETER(iUnused); const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< cachetick >"; CLinearTimeDelta ltd = 0; if (mudconf.cache_tick_period <= ltd) { mudconf.cache_tick_period.SetSeconds(1); } cache_tick(); // Schedule ourselves again. // CLinearTimeAbsolute ltaNextTime; ltaNextTime.GetUTC(); ltaNextTime += mudconf.cache_tick_period; scheduler.DeferTask(ltaNextTime, PRIORITY_SYSTEM, dispatch_CacheTick, 0, 0); mudstate.debug_cmd = cmdsave; } #endif // !MEMORY_BASED #if 0 void dispatch_CleanChannels(void *pUnused, int iUnused) { const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< cleanchannels >"; do_cleanupchannels(); // Schedule ourselves again. // CLinearTimeAbsolute ltaNextTime; ltaNextTime.GetUTC(); CLinearTimeDelta ltd = time_15m; ltaNextTime += ltd; scheduler.DeferTask(ltaNextTime, PRIORITY_SYSTEM, dispatch_CleanChannels, 0, 0); mudstate.debug_cmd = cmdsave; } #endif // 0 static void dispatch_CanRestart(void *pUnused, int iUnused) { UNUSED_PARAMETER(pUnused); UNUSED_PARAMETER(iUnused); mudstate.bCanRestart = true; } void init_timer(void) { CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); // Setup re-occuring Free List Reconstruction task. // CLinearTimeDelta ltd; ltd.SetSeconds((mudconf.check_offset == 0) ? mudconf.check_interval : mudconf.check_offset); mudstate.check_counter = ltaNow + ltd; scheduler.DeferTask(mudstate.check_counter, PRIORITY_SYSTEM, dispatch_FreeListReconstruction, 0, 0); // Setup re-occuring Database Dump task. // ltd.SetSeconds((mudconf.dump_offset == 0) ? mudconf.dump_interval : mudconf.dump_offset); mudstate.dump_counter = ltaNow + ltd; scheduler.DeferTask(mudstate.dump_counter, PRIORITY_SYSTEM, dispatch_DatabaseDump, 0, 0); // Setup re-occuring Idle Check task. // ltd.SetSeconds(mudconf.idle_interval); mudstate.idle_counter = ltaNow + ltd; scheduler.DeferTask(mudstate.idle_counter, PRIORITY_SYSTEM, dispatch_IdleCheck, 0, 0); // Setup re-occuring Check Events task. // mudstate.events_counter = ltaNow + time_15s; scheduler.DeferTask(mudstate.events_counter, PRIORITY_SYSTEM, dispatch_CheckEvents, 0, 0); #ifndef MEMORY_BASED // Setup re-occuring cache_tick task. // ltd.SetSeconds(0); if (mudconf.cache_tick_period <= ltd) { mudconf.cache_tick_period.SetSeconds(1); } scheduler.DeferTask(ltaNow+mudconf.cache_tick_period, PRIORITY_SYSTEM, dispatch_CacheTick, 0, 0); #endif // !MEMORY_BASED #if 0 // Setup comsys channel scrubbing. // scheduler.DeferTask(ltaNow+time_45s, PRIORITY_SYSTEM, dispatch_CleanChannels, 0, 0); #endif // 0 // Setup one-shot task to enable restarting 10 seconds after startmux. // scheduler.DeferTask(ltaNow+time_15s, PRIORITY_OBJECT, dispatch_CanRestart, 0, 0); } /* * --------------------------------------------------------------------------- * * do_timewarp: Adjust various internal timers. */ void do_timewarp(dbref executor, dbref caller, dbref enactor, int eval, int key, char *arg) { UNUSED_PARAMETER(eval); int secs; secs = mux_atol(arg); // Sem/Wait queues // if ((key == 0) || (key & TWARP_QUEUE)) { do_queue(executor, caller, enactor, 0, QUEUE_WARP, arg); } // Once these are adjusted, we need to Cancel and reschedule the task. // CLinearTimeDelta ltd; ltd.SetSeconds(secs); if (key & TWARP_DUMP) { mudstate.dump_counter -= ltd; scheduler.CancelTask(dispatch_DatabaseDump, 0, 0); scheduler.DeferTask(mudstate.dump_counter, PRIORITY_SYSTEM, dispatch_DatabaseDump, 0, 0); } if (key & TWARP_CLEAN) { mudstate.check_counter -= ltd; scheduler.CancelTask(dispatch_FreeListReconstruction, 0, 0); scheduler.DeferTask(mudstate.check_counter, PRIORITY_SYSTEM, dispatch_FreeListReconstruction, 0, 0); } if (key & TWARP_IDLE) { mudstate.idle_counter -= ltd; scheduler.CancelTask(dispatch_IdleCheck, 0, 0); scheduler.DeferTask(mudstate.idle_counter, PRIORITY_SYSTEM, dispatch_IdleCheck, 0, 0); } if (key & TWARP_EVENTS) { mudstate.events_counter -= ltd; scheduler.CancelTask(dispatch_CheckEvents, 0, 0); scheduler.DeferTask(mudstate.events_counter, PRIORITY_SYSTEM, dispatch_CheckEvents, 0, 0); } } #define INITIAL_TASKS 100 CTaskHeap::CTaskHeap(void) { m_nCurrent = 0; m_iVisitedMark = 0; m_nAllocated = INITIAL_TASKS; m_pHeap = new PTASK_RECORD[m_nAllocated]; if (!m_pHeap) { m_nAllocated = 0; } } CTaskHeap::~CTaskHeap(void) { while (m_nCurrent--) { PTASK_RECORD pTask = m_pHeap[m_nCurrent]; if (pTask) { delete pTask; } m_pHeap[m_nCurrent] = NULL; } if (m_pHeap) { delete [] m_pHeap; } } bool CTaskHeap::Insert(PTASK_RECORD pTask, SCHCMP *pfCompare) { if (m_nCurrent == m_nAllocated) { if (!Grow()) { return false; } } pTask->m_iVisitedMark = m_iVisitedMark-1; m_pHeap[m_nCurrent] = pTask; m_nCurrent++; SiftUp(m_nCurrent-1, pfCompare); return true; } bool CTaskHeap::Grow(void) { // Grow the heap. // int n = GrowFiftyPercent(m_nAllocated, INITIAL_TASKS, INT_MAX); PTASK_RECORD *p = NULL; try { p = new PTASK_RECORD[n]; } catch (...) { ; // Nothing. } if (!p) { return false; } memcpy(p, m_pHeap, sizeof(PTASK_RECORD)*m_nCurrent); m_nAllocated = n; delete [] m_pHeap; m_pHeap = p; return true; } void CTaskHeap::Shrink(void) { // Shrink the heap. // int n = m_nAllocated/2; if ( n <= INITIAL_TASKS || n <= m_nCurrent) { return; } PTASK_RECORD *p = NULL; try { p = new PTASK_RECORD[n]; } catch (...) { ; // Nothing. } if (!p) { return; } memcpy(p, m_pHeap, sizeof(PTASK_RECORD)*m_nCurrent); m_nAllocated = n; delete [] m_pHeap; m_pHeap = p; } PTASK_RECORD CTaskHeap::PeekAtTopmost(void) { if (m_nCurrent <= 0) { return NULL; } return m_pHeap[0]; } PTASK_RECORD CTaskHeap::RemoveTopmost(SCHCMP *pfCompare) { return Remove(0, pfCompare); } void CTaskHeap::CancelTask(FTASK *fpTask, void *arg_voidptr, int arg_Integer) { for (int i = 0; i < m_nCurrent; i++) { PTASK_RECORD p = m_pHeap[i]; if ( p->fpTask == fpTask && p->arg_voidptr == arg_voidptr && p->arg_Integer == arg_Integer) { p->fpTask = NULL; } } } static int ComparePriority(PTASK_RECORD pTaskA, PTASK_RECORD pTaskB) { int i = (pTaskA->iPriority) - (pTaskB->iPriority); if (i == 0) { // Must subtract so that ticket rollover is handled properly. // return (pTaskA->m_Ticket) - (pTaskB->m_Ticket); } return i; } static int CompareWhen(PTASK_RECORD pTaskA, PTASK_RECORD pTaskB) { // Can't simply subtract because comparing involves a truncation cast. // if (pTaskA->ltaWhen < pTaskB->ltaWhen) { return -1; } else if (pTaskA->ltaWhen > pTaskB->ltaWhen) { return 1; } else { // Must subtract so that ticket rollover is handled properly. // return (pTaskA->m_Ticket) - (pTaskB->m_Ticket); } } void CScheduler::DeferTask(const CLinearTimeAbsolute& ltaWhen, int iPriority, FTASK *fpTask, void *arg_voidptr, int arg_Integer) { PTASK_RECORD pTask = new TASK_RECORD; if (!pTask) return; pTask->ltaWhen = ltaWhen; pTask->iPriority = iPriority; pTask->fpTask = fpTask; pTask->arg_voidptr = arg_voidptr; pTask->arg_Integer = arg_Integer; pTask->m_Ticket = m_Ticket++; // Must add to the WhenHeap so that network is still serviced. // if (!m_WhenHeap.Insert(pTask, CompareWhen)) { delete pTask; } } void CScheduler::DeferImmediateTask(int iPriority, FTASK *fpTask, void *arg_voidptr, int arg_Integer) { PTASK_RECORD pTask = new TASK_RECORD; if (!pTask) return; //pTask->ltaWhen = ltaWhen; pTask->iPriority = iPriority; pTask->fpTask = fpTask; pTask->arg_voidptr = arg_voidptr; pTask->arg_Integer = arg_Integer; pTask->m_Ticket = m_Ticket++; // Must add to the WhenHeap so that network is still serviced. // if (!m_WhenHeap.Insert(pTask, CompareWhen)) { delete pTask; } } void CScheduler::CancelTask(FTASK *fpTask, void *arg_voidptr, int arg_Integer) { m_WhenHeap.CancelTask(fpTask, arg_voidptr, arg_Integer); m_PriorityHeap.CancelTask(fpTask, arg_voidptr, arg_Integer); } void CScheduler::ReadyTasks(const CLinearTimeAbsolute& ltaNow) { // Move ready-to-run tasks off the WhenHeap and onto the PriorityHeap. // PTASK_RECORD pTask = m_WhenHeap.PeekAtTopmost(); while ( pTask && pTask->ltaWhen < ltaNow) { pTask = m_WhenHeap.RemoveTopmost(CompareWhen); if (pTask) { if ( NULL == pTask->fpTask || !m_PriorityHeap.Insert(pTask, ComparePriority)) { delete pTask; } } pTask = m_WhenHeap.PeekAtTopmost(); } } int CScheduler::RunTasks(const CLinearTimeAbsolute& ltaNow) { ReadyTasks(ltaNow); if (mudconf.active_q_chunk) { return RunTasks(mudconf.active_q_chunk); } else { return RunAllTasks(); } } int CScheduler::RunTasks(int iCount) { int nTasks = 0; while (iCount--) { PTASK_RECORD pTask = m_PriorityHeap.PeekAtTopmost(); if (!pTask) break; if (pTask->iPriority > m_minPriority) { // This is related to CF_DEQUEUE and also to untimed (SUSPENDED) // semaphore entries that we would like to manage together with // the timed ones. // break; } pTask = m_PriorityHeap.RemoveTopmost(ComparePriority); if (pTask) { if (pTask->fpTask) { pTask->fpTask(pTask->arg_voidptr, pTask->arg_Integer); nTasks++; } delete pTask; } } return nTasks; } int CScheduler::RunAllTasks(void) { int nTotalTasks = 0; int nTasks; do { nTasks = RunTasks(100); nTotalTasks += nTasks; } while (nTasks); return nTotalTasks; } bool CScheduler::WhenNext(CLinearTimeAbsolute *ltaWhen) { // Check the Priority Queue first. // PTASK_RECORD pTask = m_PriorityHeap.PeekAtTopmost(); if (pTask) { if (pTask->iPriority <= m_minPriority) { ltaWhen->SetSeconds(0); return true; } } // Check the When Queue next. // pTask = m_WhenHeap.PeekAtTopmost(); if (pTask) { *ltaWhen = pTask->ltaWhen; return true; } return false; } #define HEAP_LEFT_CHILD(x) (2*(x)+1) #define HEAP_RIGHT_CHILD(x) (2*(x)+2) #define HEAP_PARENT(x) (((x)-1)/2) void CTaskHeap::SiftDown(int iSubRoot, SCHCMP *pfCompare) { int parent = iSubRoot; int child = HEAP_LEFT_CHILD(parent); PTASK_RECORD Ref = m_pHeap[parent]; while (child < m_nCurrent) { int rightchild = HEAP_RIGHT_CHILD(parent); if (rightchild < m_nCurrent) { if (pfCompare(m_pHeap[rightchild], m_pHeap[child]) < 0) { child = rightchild; } } if (pfCompare(Ref, m_pHeap[child]) <= 0) break; m_pHeap[parent] = m_pHeap[child]; parent = child; child = HEAP_LEFT_CHILD(parent); } m_pHeap[parent] = Ref; } void CTaskHeap::SiftUp(int child, SCHCMP *pfCompare) { while (child) { int parent = HEAP_PARENT(child); if (pfCompare(m_pHeap[parent], m_pHeap[child]) <= 0) break; PTASK_RECORD Tmp; Tmp = m_pHeap[child]; m_pHeap[child] = m_pHeap[parent]; m_pHeap[parent] = Tmp; child = parent; } } PTASK_RECORD CTaskHeap::Remove(int iNode, SCHCMP *pfCompare) { if (iNode < 0 || m_nCurrent <= iNode) return NULL; PTASK_RECORD pTask = m_pHeap[iNode]; m_nCurrent--; m_pHeap[iNode] = m_pHeap[m_nCurrent]; SiftDown(iNode, pfCompare); SiftUp(iNode, pfCompare); return pTask; } void CTaskHeap::Update(int iNode, SCHCMP *pfCompare) { if (iNode < 0 || m_nCurrent <= iNode) { return; } SiftDown(iNode, pfCompare); SiftUp(iNode, pfCompare); } void CScheduler::TraverseUnordered(SCHLOOK *pfLook) { if (m_WhenHeap.TraverseUnordered(pfLook, CompareWhen)) { m_PriorityHeap.TraverseUnordered(pfLook, ComparePriority); } } void CScheduler::TraverseOrdered(SCHLOOK *pfLook) { m_PriorityHeap.TraverseOrdered(pfLook, ComparePriority); m_WhenHeap.TraverseOrdered(pfLook, CompareWhen); } // The following guarantees that in spite of any changes to the heap // we will visit every record exactly once. It does not attempt to // visit these records in any particular order. // int CTaskHeap::TraverseUnordered(SCHLOOK *pfLook, SCHCMP *pfCompare) { // Indicate that everything has not been visited. // m_iVisitedMark++; if (m_iVisitedMark == 0) { // We rolled over. Yeah, this code will probably never run, but // let's go ahead and mark all the records as visited anyway. // for (int i = 0; i < m_nCurrent; i++) { PTASK_RECORD p = m_pHeap[i]; p->m_iVisitedMark = m_iVisitedMark; } m_iVisitedMark++; } int bUnvisitedRecords; do { bUnvisitedRecords = false; for (int i = 0; i < m_nCurrent; i++) { PTASK_RECORD p = m_pHeap[i]; if (p->m_iVisitedMark == m_iVisitedMark) { // We have already seen this one. // continue; } bUnvisitedRecords = true; p->m_iVisitedMark = m_iVisitedMark; int cmd = pfLook(p); switch (cmd) { case IU_REMOVE_TASK: Remove(i, pfCompare); break; case IU_DONE: return false; case IU_UPDATE_TASK: Update(i, pfCompare); break; } } } while (bUnvisitedRecords); return true; } // The following does not allow for changes during the traversal, but // but it does visit each record in sorted order (When-order or // Priority-order depending on the heap). // int CTaskHeap::TraverseOrdered(SCHLOOK *pfLook, SCHCMP *pfCompare) { Sort(pfCompare); for (int i = m_nCurrent-1; i >= 0; i--) { PTASK_RECORD p = m_pHeap[i]; int cmd = pfLook(p); if (IU_DONE == cmd) { break; } } Remake(pfCompare); return true; } void CTaskHeap::Sort(SCHCMP *pfCompare) { int s_nCurrent = m_nCurrent; while (m_nCurrent--) { PTASK_RECORD p = m_pHeap[m_nCurrent]; m_pHeap[m_nCurrent] = m_pHeap[0]; m_pHeap[0] = p; SiftDown(0, pfCompare); } m_nCurrent = s_nCurrent; } void CTaskHeap::Remake(SCHCMP *pfCompare) { int s_nCurrent = m_nCurrent; m_nCurrent = 0; while (s_nCurrent--) { m_nCurrent++; SiftUp(m_nCurrent-1, pfCompare); } } void CScheduler::SetMinPriority(int arg_minPriority) { m_minPriority = arg_minPriority; } void CScheduler::Shrink(void) { m_WhenHeap.Shrink(); m_PriorityHeap.Shrink(); } mux2.6/src/pcre.cpp0000600000175000017500000073451711025753746014254 0ustar sdennissdennis/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. See the file Tech.Notes for some information on the internals. Written by: Philip Hazel Copyright (c) 1997-2003 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- */ /* Modified by Shawn Wagner for MUX to fit in one file and remove things we don't use, like a bunch of API functions and utf-8 support. If you want the full thing, see http://www.pcre.org. Patched by Alierak to protect against integer overflow in repeat counts. */ #include "autoconf.h" #include "config.h" #include #include #include #include #include #include "pcre.h" #include "externs.h" #include "timeutil.h" /* Bits of PCRE's config.h */ #define LINK_SIZE 2 #define MATCH_LIMIT 100000 #define NEWLINE '\n' /* Bits of internal.h */ /* This header contains definitions that are shared between the different modules, but which are not relevant to the outside. */ /* PCRE keeps offsets in its compiled code as 2-byte quantities by default. These are used, for example, to link from the start of a subpattern to its alternatives and its end. The use of 2 bytes per offset limits the size of the compiled regex to around 64K, which is big enough for almost everybody. However, I received a request for an even bigger limit. For this reason, and also to make the code easier to maintain, the storing and loading of offsets from the byte string is now handled by the macros that are defined here. The macros are controlled by the value of LINK_SIZE. This defaults to 2 in the config.h file, but can be overridden by using -D on the command line. This is automated on Unix systems via the "configure" command. */ #define PUT(a,n,d) \ (a[n] = static_cast((d) >> 8)), \ (a[(n)+1] = static_cast((d) & 255)) #define GET(a,n) \ (((a)[n] << 8) | (a)[(n)+1]) #define MAX_PATTERN_SIZE (1 << 16) /* Convenience macro defined in terms of the others */ #define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE /* PCRE uses some other 2-byte quantities that do not change when the size of offsets changes. There are used for repeat counts and for other things such as capturing parenthesis numbers in back references. */ #define PUT2(a,n,d) \ a[n] = static_cast((d) >> 8); \ a[(n)+1] = static_cast((d) & 255) #define GET2(a,n) \ (((a)[n] << 8) | (a)[(n)+1]) #define PUT2INC(a,n,d) PUT2(a,n,d), a += 2 /* These are the public options that can change during matching. */ #define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL) /* Private options flags start at the most significant end of the four bytes, but skip the top bit so we can use ints for convenience without getting tangled with negative values. The public options defined in pcre.h start at the least significant end. Make sure they don't overlap, though now that we have expanded to four bytes there is plenty of space. */ #define PCRE_FIRSTSET 0x40000000 /* first_byte is set */ #define PCRE_REQCHSET 0x20000000 /* req_byte is set */ #define PCRE_STARTLINE 0x10000000 /* start after \n for multiline */ #define PCRE_ICHANGED 0x08000000 /* i option changes within regex */ /* Options for the "extra" block produced by pcre_study(). */ #define PCRE_STUDY_MAPPED 0x01 /* a map of starting chars exists */ /* Masks for identifying the public options which are permitted at compile time, run time or study time, respectively. */ #define PUBLIC_OPTIONS \ (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \ PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \ PCRE_NO_AUTO_CAPTURE|PCRE_NO_UTF8_CHECK) #define PUBLIC_EXEC_OPTIONS \ (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK) #define PUBLIC_STUDY_OPTIONS 0 /* None defined */ /* Magic number to provide a small check against being handed junk. */ #define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */ /* Negative values for the firstchar and reqchar variables */ #define REQ_UNSET (-2) #define REQ_NONE (-1) /* Flags added to firstbyte or reqbyte; a "non-literal" item is either a variable-length repeat, or a anything other than literal characters. */ #define REQ_CASELESS 0x0100 /* indicates caselessness */ #define REQ_VARY 0x0200 /* reqbyte followed non-literal item */ /* Miscellaneous definitions */ /* Escape items that are just an encoding of a particular data value. Note that ESC_n is defined as yet another macro, which is set in config.h to either \n (the default) or \r (which some people want). */ #ifndef ESC_e #define ESC_e 27 #endif #ifndef ESC_f #define ESC_f '\f' #endif #ifndef ESC_n #define ESC_n NEWLINE #endif #ifndef ESC_r #define ESC_r '\r' #endif /* We can't officially use ESC_t because it is a POSIX reserved identifier (presumably because of all the others like size_t). */ #ifndef ESC_tee #define ESC_tee '\t' #endif /* These are escaped items that aren't just an encoding of a particular data value such as \n. They must have non-zero values, as check_escape() returns their negation. Also, they must appear in the same order as in the opcode definitions below, up to ESC_z. There's a dummy for OP_ANY because it corresponds to "." rather than an escape sequence. The final one must be ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two tests in the code for an escape greater than ESC_b and less than ESC_Z to detect the types that may be repeated. These are the types that consume a character. If any new escapes are put in between that don't consume a character, that code will have to change. */ enum { ESC_A = 1, ESC_G, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_dum1, ESC_C, ESC_Z, ESC_z, ESC_E, ESC_Q, ESC_REF }; /* Flag bits and data types for the extended class (OP_XCLASS) for classes that contain UTF-8 characters with values greater than 255. */ #define XCL_NOT 0x01 /* Flag: this is a negative class */ #define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ #define XCL_END 0 /* Marks end of individual items */ #define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ #define XCL_RANGE 2 /* A range (two multibyte chars) follows */ /* Opcode table: OP_BRA must be last, as all values >= it are used for brackets that extract substrings. Starting from 1 (i.e. after OP_END), the values up to OP_EOD must correspond in order to the list of escapes immediately above. Note that whenever this list is updated, the two macro definitions that follow must also be updated to match. */ enum { OP_END, /* 0 End of pattern */ /* Values corresponding to backslashed metacharacters */ OP_SOD, /* 1 Start of data: \A */ OP_SOM, /* 2 Start of match (subject + offset): \G */ OP_NOT_WORD_BOUNDARY, /* 3 \B */ OP_WORD_BOUNDARY, /* 4 \b */ OP_NOT_DIGIT, /* 5 \D */ OP_DIGIT, /* 6 \d */ OP_NOT_WHITESPACE, /* 7 \S */ OP_WHITESPACE, /* 8 \s */ OP_NOT_WORDCHAR, /* 9 \W */ OP_WORDCHAR, /* 10 \w */ OP_ANY, /* 11 Match any character */ OP_ANYBYTE, /* 12 Match any byte (\C); different to OP_ANY for UTF-8 */ OP_EODN, /* 13 End of data or \n at end of data: \Z. */ OP_EOD, /* 14 End of data: \z */ OP_OPT, /* 15 Set runtime options */ OP_CIRC, /* 16 Start of line - varies with multiline switch */ OP_DOLL, /* 17 End of line - varies with multiline switch */ OP_CHARS, /* 18 Match string of characters */ OP_NOT, /* 19 Match anything but the following char */ OP_STAR, /* 20 The maximizing and minimizing versions of */ OP_MINSTAR, /* 21 all these opcodes must come in pairs, with */ OP_PLUS, /* 22 the minimizing one second. */ OP_MINPLUS, /* 23 This first set applies to single characters */ OP_QUERY, /* 24 */ OP_MINQUERY, /* 25 */ OP_UPTO, /* 26 From 0 to n matches */ OP_MINUPTO, /* 27 */ OP_EXACT, /* 28 Exactly n matches */ OP_NOTSTAR, /* 29 The maximizing and minimizing versions of */ OP_NOTMINSTAR, /* 30 all these opcodes must come in pairs, with */ OP_NOTPLUS, /* 31 the minimizing one second. */ OP_NOTMINPLUS, /* 32 This set applies to "not" single characters */ OP_NOTQUERY, /* 33 */ OP_NOTMINQUERY, /* 34 */ OP_NOTUPTO, /* 35 From 0 to n matches */ OP_NOTMINUPTO, /* 36 */ OP_NOTEXACT, /* 37 Exactly n matches */ OP_TYPESTAR, /* 38 The maximizing and minimizing versions of */ OP_TYPEMINSTAR, /* 39 all these opcodes must come in pairs, with */ OP_TYPEPLUS, /* 40 the minimizing one second. These codes must */ OP_TYPEMINPLUS, /* 41 be in exactly the same order as those above. */ OP_TYPEQUERY, /* 42 This set applies to character types such as \d */ OP_TYPEMINQUERY, /* 43 */ OP_TYPEUPTO, /* 44 From 0 to n matches */ OP_TYPEMINUPTO, /* 45 */ OP_TYPEEXACT, /* 46 Exactly n matches */ OP_CRSTAR, /* 47 The maximizing and minimizing versions of */ OP_CRMINSTAR, /* 48 all these opcodes must come in pairs, with */ OP_CRPLUS, /* 49 the minimizing one second. These codes must */ OP_CRMINPLUS, /* 50 be in exactly the same order as those above. */ OP_CRQUERY, /* 51 These are for character classes and back refs */ OP_CRMINQUERY, /* 52 */ OP_CRRANGE, /* 53 These are different to the three seta above. */ OP_CRMINRANGE, /* 54 */ OP_CLASS, /* 55 Match a character class, chars < 256 only */ OP_NCLASS, /* 56 Same, but the bitmap was created from a negative class - the difference is relevant only when a UTF-8 character > 255 is encountered. */ OP_XCLASS, /* 57 Extended class for handling UTF-8 chars within the class. This does both positive and negative. */ OP_REF, /* 58 Match a back reference */ OP_RECURSE, /* 59 Match a numbered subpattern (possibly recursive) */ OP_CALLOUT, /* 60 Call out to external function if provided */ OP_ALT, /* 61 Start of alternation */ OP_KET, /* 62 End of group that doesn't have an unbounded repeat */ OP_KETRMAX, /* 63 These two must remain together and in this */ OP_KETRMIN, /* 64 order. They are for groups the repeat for ever. */ /* The assertions must come before ONCE and COND */ OP_ASSERT, /* 65 Positive lookahead */ OP_ASSERT_NOT, /* 66 Negative lookahead */ OP_ASSERTBACK, /* 67 Positive lookbehind */ OP_ASSERTBACK_NOT, /* 68 Negative lookbehind */ OP_REVERSE, /* 69 Move pointer back - used in lookbehind assertions */ /* ONCE and COND must come after the assertions, with ONCE first, as there's a test for >= ONCE for a subpattern that isn't an assertion. */ OP_ONCE, /* 70 Once matched, don't back up into the subpattern */ OP_COND, /* 71 Conditional group */ OP_CREF, /* 72 Used to hold an extraction string number (cond ref) */ OP_BRAZERO, /* 73 These two must remain together and in this */ OP_BRAMINZERO, /* 74 order. */ OP_BRANUMBER, /* 75 Used for extracting brackets whose number is greater than can fit into an opcode. */ OP_BRA /* 76 This and greater values are used for brackets that extract substrings up to a basic limit. After that, use is made of OP_BRANUMBER. */ }; /* WARNING: There is an implicit assumption in study.c that all opcodes are less than 128 in value. This makes handling UTF-8 character sequences easier. */ /* This macro defines textual names for all the opcodes. There are used only for debugging, in pcre.c when DEBUG is defined, and also in pcretest.c. The macro is referenced only in printint.c. */ #define OP_NAME_LIST \ "End", "\\A", "\\G", "\\B", "\\b", "\\D", "\\d", \ "\\S", "\\s", "\\W", "\\w", "Any", "Anybyte", "\\Z", "\\z", \ "Opt", "^", "$", "chars", "not", \ "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ "*", "*?", "+", "+?", "?", "??", "{", "{", \ "class", "nclass", "xclass", "Ref", "Recurse", "Callout", \ "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not", \ "AssertB", "AssertB not", "Reverse", "Once", "Cond", "Cond ref",\ "Brazero", "Braminzero", "Branumber", "Bra" /* This macro defines the length of fixed length operations in the compiled regex. The lengths are used when searching for specific things, and also in the debugging printing of a compiled regex. We use a macro so that it can be incorporated both into pcre.c and pcretest.c without being publicly exposed. As things have been extended, some of these are no longer fixed lenths, but are minima instead. For example, the length of a single-character repeat may vary in UTF-8 mode. The code that uses this table must know about such things. */ #define OP_LENGTHS \ 1, /* End */ \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* \A, \G, \B, \B, \D, \d, \S, \s, \W, \w */ \ 1, 1, 1, 1, 2, 1, 1, /* Any, Anybyte, \Z, \z, Opt, ^, $ */ \ 2, /* Chars - the minimum length */ \ 2, /* not */ \ /* Positive single-char repeats ** These are */ \ 2, 2, 2, 2, 2, 2, /* *, *?, +, +?, ?, ?? ** minima in */ \ 4, 4, 4, /* upto, minupto, exact ** UTF-8 mode */ \ /* Negative single-char repeats - only for chars < 256 */ \ 2, 2, 2, 2, 2, 2, /* NOT *, *?, +, +?, ?, ?? */ \ 4, 4, 4, /* NOT upto, minupto, exact */ \ /* Positive type repeats */ \ 2, 2, 2, 2, 2, 2, /* Type *, *?, +, +?, ?, ?? */ \ 4, 4, 4, /* Type upto, minupto, exact */ \ /* Character class & ref repeats */ \ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \ 5, 5, /* CRRANGE, CRMINRANGE */ \ 33, /* CLASS */ \ 33, /* NCLASS */ \ 0, /* XCLASS - variable length */ \ 3, /* REF */ \ 1+LINK_SIZE, /* RECURSE */ \ 2, /* CALLOUT */ \ 1+LINK_SIZE, /* Alt */ \ 1+LINK_SIZE, /* Ket */ \ 1+LINK_SIZE, /* KetRmax */ \ 1+LINK_SIZE, /* KetRmin */ \ 1+LINK_SIZE, /* Assert */ \ 1+LINK_SIZE, /* Assert not */ \ 1+LINK_SIZE, /* Assert behind */ \ 1+LINK_SIZE, /* Assert behind not */ \ 1+LINK_SIZE, /* Reverse */ \ 1+LINK_SIZE, /* Once */ \ 1+LINK_SIZE, /* COND */ \ 3, /* CREF */ \ 1, 1, /* BRAZERO, BRAMINZERO */ \ 3, /* BRANUMBER */ \ 1+LINK_SIZE /* BRA */ \ /* The highest extraction number before we have to start using additional bytes. (Originally PCRE didn't have support for extraction counts highter than this number.) The value is limited by the number of opcodes left after OP_BRA, i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional opcodes. */ #define EXTRACT_BASIC_MAX 150 /* A magic value for OP_CREF to indicate the "in recursion" condition. */ #define CREF_RECURSE 0xffff /* The texts of compile-time error messages are defined as macros here so that they can be accessed by the POSIX wrapper and converted into error codes. Yes, I could have used error codes in the first place, but didn't feel like changing just to accommodate the POSIX wrapper. */ #define ERR1 "\\ at end of pattern" #define ERR2 "\\c at end of pattern" #define ERR3 "unrecognized character follows \\" #define ERR4 "numbers out of order in {} quantifier" #define ERR5 "number too big in {} quantifier" #define ERR6 "missing terminating ] for character class" #define ERR7 "invalid escape sequence in character class" #define ERR8 "range out of order in character class" #define ERR9 "nothing to repeat" #define ERR10 "operand of unlimited repeat could match the empty string" #define ERR11 "internal error: unexpected repeat" #define ERR12 "unrecognized character after (?" #define ERR13 "POSIX named classes are supported only within a class" #define ERR14 "missing )" #define ERR15 "reference to non-existent subpattern" #define ERR16 "erroffset passed as NULL" #define ERR17 "unknown option bit(s) set" #define ERR18 "missing ) after comment" #define ERR19 "parentheses nested too deeply" #define ERR20 "regular expression too large" #define ERR21 "failed to get memory" #define ERR22 "unmatched parentheses" #define ERR23 "internal error: code overflow" #define ERR24 "unrecognized character after (?<" #define ERR25 "lookbehind assertion is not fixed length" #define ERR26 "malformed number after (?(" #define ERR27 "conditional group contains more than two branches" #define ERR28 "assertion expected after (?(" #define ERR29 "(?R or (?digits must be followed by )" #define ERR30 "unknown POSIX class name" #define ERR31 "POSIX collating elements are not supported" #define ERR32 "this version of PCRE is not compiled with PCRE_UTF8 support" #define ERR33 "spare error" #define ERR34 "character value in \\x{...} sequence is too large" #define ERR35 "invalid condition (?(0)" #define ERR36 "\\C not allowed in lookbehind assertion" #define ERR37 "PCRE does not support \\L, \\l, \\N, \\P, \\p, \\U, \\u, or \\X" #define ERR38 "number after (?C is > 255" #define ERR39 "closing ) for (?C expected" #define ERR40 "recursive call could loop indefinitely" #define ERR41 "unrecognized character after (?P" #define ERR42 "syntax error after (?P" #define ERR43 "two named groups have the same name" #define ERR44 "invalid UTF-8 string" /* All character handling must be done as unsigned characters. Otherwise there are problems with top-bit-set characters and functions such as isspace(). However, we leave the interface to the outside world as char *, because that should make things easier for callers. We define a short type for unsigned char to save lots of typing. I tried "uchar", but it causes problems on Digital Unix, where it is defined in sys/types, so use "uschar" instead. */ typedef unsigned char uschar; /* The real format of the start of the pcre block; the index of names and the code vector run on as long as necessary after the end. */ typedef struct real_pcre { unsigned long int magic_number; size_t size; /* Total that was malloced */ const unsigned char *tables; /* Pointer to tables */ unsigned long int options; unsigned short int top_bracket; unsigned short int top_backref; unsigned short int first_byte; unsigned short int req_byte; unsigned short int name_entry_size; /* Size of any name items; 0 => none */ unsigned short int name_count; /* Number of name items */ } real_pcre; /* The format of the block used to store data from pcre_study(). */ typedef struct pcre_study_data { size_t size; /* Total that was malloced */ uschar options; uschar start_bits[32]; } pcre_study_data; /* Structure for passing "static" information around between the functions doing the compiling, so that they are thread-safe. */ typedef struct compile_data { const uschar *lcc; /* Points to lower casing table */ const uschar *fcc; /* Points to case-flipping table */ const uschar *cbits; /* Points to character type table */ const uschar *ctypes; /* Points to table of type maps */ const uschar *start_code; /* The start of the compiled code */ uschar *name_table; /* The name/number table */ int names_found; /* Number of entries so far */ int name_entry_size; /* Size of each entry */ int top_backref; /* Maximum back reference */ unsigned int backref_map; /* Bitmap of low back refs */ int req_varyopt; /* "After variable item" flag for reqbyte */ } compile_data; /* Structure for maintaining a chain of pointers to the currently incomplete branches, for testing for left recursion. */ typedef struct branch_chain { struct branch_chain *outer; uschar *current; } branch_chain; /* Structure for items in a linked list that represents an explicit recursive call within the pattern. */ typedef struct recursion_info { struct recursion_info *prevrec; /* Previous recursion record (or NULL) */ int group_num; /* Number of group that was called */ const uschar *after_call; /* "Return value": points after the call in the expr */ const uschar *save_start; /* Old value of md->start_match */ int *offset_save; /* Pointer to start of saved offsets */ int saved_max; /* Number of saved offsets */ } recursion_info; /* When compiling in a mode that doesn't use recursive calls to match(), a structure is used to remember local variables on the heap. It is defined in pcre.c, close to the match() function, so that it is easy to keep it in step with any changes of local variable. However, the pointer to the current frame must be saved in some "static" place over a longjmp(). We declare the structure here so that we can put a pointer in the match_data structure. NOTE: This isn't used for a "normal" compilation of pcre. */ /* Structure for passing "static" information around between the functions doing the matching, so that they are thread-safe. */ typedef struct match_data { unsigned long int match_call_count; /* As it says */ unsigned long int match_limit;/* As it says */ int *offset_vector; /* Offset vector */ int offset_end; /* One past the end */ int offset_max; /* The maximum usable for return data */ const uschar *lcc; /* Points to lower casing table */ const uschar *ctypes; /* Points to table of type maps */ bool offset_overflow; /* Set if too many extractions */ bool notbol; /* NOTBOL flag */ bool noteol; /* NOTEOL flag */ bool utf8; /* UTF8 flag */ bool endonly; /* Dollar not before final \n */ bool notempty; /* Empty string match not wanted */ const uschar *start_code; /* For use when recursing */ const uschar *start_subject; /* Start of the subject string */ const uschar *end_subject; /* End of the subject string */ const uschar *start_match; /* Start of this match attempt */ const uschar *end_match_ptr; /* Subject position at end match */ int end_offset_top; /* Highwater mark at end of match */ int capture_last; /* Most recent capture number */ int start_offset; /* The start offset value */ recursion_info *recursive; /* Linked list of recursion data */ void *callout_data; /* To pass back to callouts */ } match_data; /* Bit definitions for entries in the pcre_ctypes table. */ #define ctype_space 0x01 #define ctype_letter 0x02 #define ctype_digit 0x04 #define ctype_xdigit 0x08 #define ctype_word 0x10 /* alphameric or '_' */ #define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */ /* Offsets for the bitmap tables in pcre_cbits. Each table contains a set of bits for a class map. Some classes are built by combining these tables. */ #define cbit_space 0 /* [:space:] or \s */ #define cbit_xdigit 32 /* [:xdigit:] */ #define cbit_digit 64 /* [:digit:] or \d */ #define cbit_upper 96 /* [:upper:] */ #define cbit_lower 128 /* [:lower:] */ #define cbit_word 160 /* [:word:] or \w */ #define cbit_graph 192 /* [:graph:] */ #define cbit_print 224 /* [:print:] */ #define cbit_punct 256 /* [:punct:] */ #define cbit_cntrl 288 /* [:cntrl:] */ #define cbit_length 320 /* Length of the cbits table */ /* Offsets of the various tables from the base tables pointer, and total length. */ #define lcc_offset 0 #define fcc_offset 256 #define cbits_offset 512 #define ctypes_offset (cbits_offset + cbit_length) #define tables_length (ctypes_offset + 256) /* End of internal.h */ /* chartables.c */ /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This file is automatically written by the dftables auxiliary program. If you edit it by hand, you might like to edit the Makefile to prevent its ever being regenerated. This file is #included in the compilation of pcre.c to build the default character tables which are used when no tables are passed to the compile function. */ static unsigned char pcre_default_tables[] = { /* This table is a lower casing table. */ 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, /* This table is a case flipping table. */ 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, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,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, /* This table contains bit maps for various character classes. Each map is 32 bytes long and the bits run from the least significant end of each byte. The classes that have their own maps are: space, xdigit, digit, upper, lower, word, graph print, punct, and cntrl. Other classes are built from combinations. */ 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc, 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* This table identifies various classes of character by individual bits: 0x01 white space character 0x02 letter 0x04 decimal digit 0x08 hexadecimal digit 0x10 alphanumeric or '_' 0x80 regular expression metacharacter or binary zero */ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ 0x00,0x01,0x01,0x00,0x01,0x01,0x00,0x00, /* 8- 15 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */ 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */ 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */ 0x12,0x12,0x12,0x80,0x00,0x00,0x80,0x10, /* X - _ */ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */ 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ /* End of chartables.c */ /* get.c */ /************************************************* * Copy captured string to given buffer * *************************************************/ /* This function copies a single captured substring into a given buffer. Note that we use memcpy() rather than strncpy() in case there are binary zeros in the string. Arguments: subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) stringnumber the number of the required substring buffer where to put the substring size the size of the buffer Returns: if successful: the length of the copied string, not including the zero that is put on the end; can be zero if not successful: PCRE_ERROR_NOMEMORY (-6) buffer too small PCRE_ERROR_NOSUBSTRING (-7) no such captured substring */ int pcre_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int size) { int yield; if (stringnumber < 0 || stringnumber >= stringcount) return PCRE_ERROR_NOSUBSTRING; stringnumber *= 2; yield = ovector[stringnumber+1] - ovector[stringnumber]; if (size < yield + 1) return PCRE_ERROR_NOMEMORY; memcpy(buffer, subject + ovector[stringnumber], yield); buffer[yield] = 0; return yield; } /* End of get.c */ /* maketables.c */ /************************************************* * Create PCRE character tables * *************************************************/ /* This function builds a set of character tables for use by PCRE and returns a pointer to them. They are build using the ctype functions, and consequently their contents will depend upon the current locale setting. When compiled as part of the library, the store is obtained via malloc(), but when compiled inside dftables, use malloc(). Arguments: none Returns: pointer to the contiguous block of data */ const unsigned char * pcre_maketables(void) { unsigned char *yield, *p; int i; yield = static_cast(malloc(tables_length)); if (yield == NULL) return NULL; p = yield; /* First comes the lower casing table */ for (i = 0; i < 256; i++) { *p++ = mux_tolower(i); } /* Next the case-flipping table */ for (i = 0; i < 256; i++) { *p++ = mux_islower(i)? mux_toupper(i) : mux_tolower(i); } /* Then the character class tables. Don't try to be clever and save effort on exclusive ones - in some locales things may be different. Note that the table for "space" includes everything "isspace" gives, including VT in the default locale. This makes it work for the POSIX class [:space:]. */ memset(p, 0, cbit_length); for (i = 0; i < 256; i++) { if (mux_isdigit(i)) { p[cbit_digit + i/8] |= 1 << (i&7); p[cbit_word + i/8] |= 1 << (i&7); } if (mux_isupper(i)) { p[cbit_upper + i/8] |= 1 << (i&7); p[cbit_word + i/8] |= 1 << (i&7); } if (mux_islower(i)) { p[cbit_lower + i/8] |= 1 << (i&7); p[cbit_word + i/8] |= 1 << (i&7); } if (i == '_') p[cbit_word + i/8] |= 1 << (i&7); if (mux_isspace(i)) p[cbit_space + i/8] |= 1 << (i&7); if (mux_isxdigit(i))p[cbit_xdigit + i/8] |= 1 << (i&7); if (isgraph(i)) p[cbit_graph + i/8] |= 1 << (i&7); if (mux_isprint(i)) p[cbit_print + i/8] |= 1 << (i&7); if (ispunct(i)) p[cbit_punct + i/8] |= 1 << (i&7); if (iscntrl(i)) p[cbit_cntrl + i/8] |= 1 << (i&7); } p += cbit_length; /* Finally, the character type table. In this, we exclude VT from the white space chars, because Perl doesn't recognize it as such for \s and for comments within regexes. */ for (i = 0; i < 256; i++) { unsigned char x = 0; if (i != 0x0b && mux_isspace(i)) x += ctype_space; if (mux_isalpha(i)) x += ctype_letter; if (mux_isdigit(i)) x += ctype_digit; if (mux_isxdigit(i)) x += ctype_xdigit; if (mux_isalnum(i) || i == '_') x += ctype_word; if (strchr("*+?{^.$|()[", i) != 0) x += ctype_meta; *p++ = x; } return yield; } /* End of maketables.c */ /* study.c */ /************************************************* * Set a bit and maybe its alternate case * *************************************************/ /* Given a character, set its bit in the table, and also the bit for the other version of a letter if we are caseless. Arguments: start_bits points to the bit map c is the character caseless the caseless flag cd the block with char table pointers Returns: nothing */ static void set_bit(uschar *start_bits, int c, bool caseless, compile_data *cd) { start_bits[c/8] |= (1 << (c&7)); if (caseless && (cd->ctypes[c] & ctype_letter) != 0) start_bits[cd->fcc[c]/8] |= (1 << (cd->fcc[c]&7)); } /************************************************* * Create bitmap of starting chars * *************************************************/ /* This function scans a compiled unanchored expression and attempts to build a bitmap of the set of initial characters. If it can't, it returns false. As time goes by, we may be able to get more clever at doing this. Arguments: code points to an expression start_bits points to a 32-byte table, initialized to 0 caseless the current state of the caseless flag utf8 true if in UTF-8 mode cd the block with char table pointers Returns: true if table built, false otherwise */ static bool set_start_bits(const uschar *code, uschar *start_bits, bool caseless, bool utf8, compile_data *cd) { register int c; /* This next statement and the later reference to dummy are here in order to trick the optimizer of the IBM C compiler for OS/2 into generating correct code. Apparently IBM isn't going to fix the problem, and we would rather not disable optimization (in this module it actually makes a big difference, and the pcre module can use all the optimization it can get). */ volatile int dummy; do { const uschar *tcode = code + 1 + LINK_SIZE; bool try_next = true; while (try_next) { /* If a branch starts with a bracket or a positive lookahead assertion, recurse to set bits from within them. That's all for this branch. */ if ((int)*tcode >= OP_BRA || *tcode == OP_ASSERT) { if (!set_start_bits(tcode, start_bits, caseless, utf8, cd)) return false; try_next = false; } else switch(*tcode) { default: return false; /* Skip over callout */ case OP_CALLOUT: tcode += 2; break; /* Skip over extended extraction bracket number */ case OP_BRANUMBER: tcode += 3; break; /* Skip over lookbehind and negative lookahead assertions */ case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: do tcode += GET(tcode, 1); while (*tcode == OP_ALT); tcode += 1+LINK_SIZE; break; /* Skip over an option setting, changing the caseless flag */ case OP_OPT: caseless = (tcode[1] & PCRE_CASELESS) != 0; tcode += 2; break; /* BRAZERO does the bracket, but carries on. */ case OP_BRAZERO: case OP_BRAMINZERO: if (!set_start_bits(++tcode, start_bits, caseless, utf8, cd)) return false; dummy = 1; do tcode += GET(tcode,1); while (*tcode == OP_ALT); tcode += 1+LINK_SIZE; break; /* Single-char * or ? sets the bit and tries the next item */ case OP_STAR: case OP_MINSTAR: case OP_QUERY: case OP_MINQUERY: set_bit(start_bits, tcode[1], caseless, cd); tcode += 2; break; /* Single-char upto sets the bit and tries the next */ case OP_UPTO: case OP_MINUPTO: set_bit(start_bits, tcode[3], caseless, cd); tcode += 4; break; /* At least one single char sets the bit and stops */ case OP_EXACT: /* Fall through */ tcode++; case OP_CHARS: /* Fall through */ tcode++; case OP_PLUS: case OP_MINPLUS: set_bit(start_bits, tcode[1], caseless, cd); try_next = false; break; /* Single character type sets the bits and stops */ case OP_NOT_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_digit]; try_next = false; break; case OP_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_digit]; try_next = false; break; case OP_NOT_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_space]; try_next = false; break; case OP_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_space]; try_next = false; break; case OP_NOT_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_word]; try_next = false; break; case OP_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_word]; try_next = false; break; /* One or more character type fudges the pointer and restarts, knowing it will hit a single character type and stop there. */ case OP_TYPEPLUS: case OP_TYPEMINPLUS: tcode++; break; case OP_TYPEEXACT: tcode += 3; break; /* Zero or more repeats of character types set the bits and then try again. */ case OP_TYPEUPTO: case OP_TYPEMINUPTO: tcode += 2; /* Fall through */ case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEQUERY: case OP_TYPEMINQUERY: switch(tcode[1]) { case OP_NOT_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_digit]; break; case OP_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_digit]; break; case OP_NOT_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_space]; break; case OP_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_space]; break; case OP_NOT_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_word]; break; case OP_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_word]; break; } tcode += 2; break; /* Character class where all the information is in a bit map: set the bits and either carry on or not, according to the repeat count. If it was a negative class, and we are operating with UTF-8 characters, any byte with the top-bit set is a potentially valid starter because it may start a character with a value > 255. (This is sub-optimal in that the character may be in the range 128-255, and those characters might be unwanted, but that's as far as we go for the moment.) */ case OP_NCLASS: if (utf8) memset(start_bits+16, 0xff, 16); /* Fall through */ case OP_CLASS: { tcode++; for (c = 0; c < 32; c++) start_bits[c] |= tcode[c]; tcode += 32; switch (*tcode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: tcode++; break; case OP_CRRANGE: case OP_CRMINRANGE: if (((tcode[1] << 8) + tcode[2]) == 0) tcode += 5; else try_next = false; break; default: try_next = false; break; } } break; /* End of bitmap class handling */ } /* End of switch */ } /* End of try_next loop */ code += GET(code, 1); /* Advance to next branch */ } while (*code == OP_ALT); return true; } /************************************************* * Study a compiled expression * *************************************************/ /* This function is handed a compiled expression that it must study to produce information that will speed up the matching. It returns a pcre_extra block which then gets handed back to pcre_exec(). Arguments: re points to the compiled expression options contains option bits errorptr points to where to place error messages; set NULL unless error Returns: pointer to a pcre_extra block, with study_data filled in and the appropriate flag set; NULL on error or if no optimization possible */ pcre_extra * pcre_study(const pcre *external_re, int options, const char **errorptr) { uschar start_bits[32]; pcre_extra *extra; pcre_study_data *study; const real_pcre *re = (const real_pcre *)external_re; uschar *code = (uschar *)re + sizeof(real_pcre) + (re->name_count * re->name_entry_size); compile_data compile_block; *errorptr = NULL; if (re == NULL || re->magic_number != MAGIC_NUMBER) { *errorptr = "argument is not a compiled regular expression"; return NULL; } if ((options & ~PUBLIC_STUDY_OPTIONS) != 0) { *errorptr = "unknown or incorrect option bit(s) set"; return NULL; } /* For an anchored pattern, or an unanchored pattern that has a first char, or a multiline pattern that matches only at "line starts", no further processing at present. */ if ((re->options & (PCRE_ANCHORED|PCRE_FIRSTSET|PCRE_STARTLINE)) != 0) return NULL; /* Set the character tables in the block which is passed around */ compile_block.lcc = re->tables + lcc_offset; compile_block.fcc = re->tables + fcc_offset; compile_block.cbits = re->tables + cbits_offset; compile_block.ctypes = re->tables + ctypes_offset; /* See if we can find a fixed set of initial characters for the pattern. */ memset(start_bits, 0, 32 * sizeof(uschar)); if (!set_start_bits(code, start_bits, (re->options & PCRE_CASELESS) != 0, (re->options & PCRE_UTF8) != 0, &compile_block)) return NULL; /* Get a pcre_extra block and a pcre_study_data block. The study data is put in the latter, which is pointed to by the former, which may also get additional data set later by the calling program. At the moment, the size of pcre_study_data is fixed. We nevertheless save it in a field for returning via the pcre_fullinfo() function so that if it becomes variable in the future, we don't have to change that code. */ extra = static_cast(malloc(sizeof(pcre_extra) + sizeof(pcre_study_data))); if (extra == NULL) { *errorptr = "failed to get memory"; return NULL; } // Hmm. study = reinterpret_cast(reinterpret_cast(extra) + sizeof(pcre_extra)); extra->flags = PCRE_EXTRA_STUDY_DATA; extra->study_data = study; study->size = sizeof(pcre_study_data); study->options = PCRE_STUDY_MAPPED; memcpy(study->start_bits, start_bits, sizeof(start_bits)); return extra; } /* End of study.c */ /* pcre.c */ #define DPRINTF(p) /*nothing*/ /* Maximum number of items on the nested bracket stacks at compile time. This applies to the nesting of all kinds of parentheses. It does not limit un-nested, non-capturing parentheses. This number can be made bigger if necessary - it is used to dimension one int and one unsigned char vector at compile time. */ #define BRASTACK_SIZE 200 /* Maximum number of ints of offset to save on the stack for recursive calls. If the offset vector is bigger, malloc is used. This should be a multiple of 3, because the offset vector is always a multiple of 3 long. */ #define REC_STACK_SAVE_MAX 30 /* The number of bytes in a literal character string above which we can't add any more is set at 250 in order to allow for UTF-8 characters. (In theory it could be 255 when UTF-8 support is excluded, but that means that some of the test output would be different, which just complicates things.) */ #define MAXLIT 250 /* The maximum remaining length of subject we are prepared to search for a req_byte match. */ #define REQ_BYTE_MAX 1000 /* Table of sizes for the fixed-length opcodes. It's defined in a macro so that the definition is next to the definition of the opcodes in internal.h. */ static const uschar OP_lengths[] = { OP_LENGTHS }; /* Min and max values for the common repeats; for the maxima, 0 => infinity */ static const char rep_min[] = { 0, 0, 1, 1, 0, 0 }; static const char rep_max[] = { 0, 0, 0, 0, 1, 1 }; /* Table for handling escaped characters in the range '0'-'z'. Positive returns are simple data values; negative values are for special things like \d and so on. Zero means further processing is needed (for things like \x), or the escape is invalid. */ static const short int escapes[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ '@', -ESC_A, -ESC_B, -ESC_C, -ESC_D, -ESC_E, 0, -ESC_G, /* @ - G */ 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ 0, -ESC_Q, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ 0, 0, -ESC_Z, '[', '\\', ']', '^', '_', /* X - _ */ '`', 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, /* ` - g */ 0, 0, 0, 0, 0, 0, ESC_n, 0, /* h - o */ 0, 0, ESC_r, -ESC_s, ESC_tee, 0, 0, -ESC_w, /* p - w */ 0, 0, -ESC_z /* x - z */ }; /* Tables of names of POSIX character classes and their lengths. The list is terminated by a zero length entry. The first three must be alpha, upper, lower, as this is assumed for handling case independence. */ static const char *const posix_names[] = { "alpha", "lower", "upper", "alnum", "ascii", "blank", "cntrl", "digit", "graph", "print", "punct", "space", "word", "xdigit" }; static const uschar posix_name_lengths[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; /* Table of class bit maps for each POSIX class; up to three may be combined to form the class. The table for [:blank:] is dynamically modified to remove the vertical space characters. */ static const int posix_class_maps[] = { cbit_lower, cbit_upper, -1, /* alpha */ cbit_lower, -1, -1, /* lower */ cbit_upper, -1, -1, /* upper */ cbit_digit, cbit_lower, cbit_upper, /* alnum */ cbit_print, cbit_cntrl, -1, /* ascii */ cbit_space, -1, -1, /* blank - a GNU extension */ cbit_cntrl, -1, -1, /* cntrl */ cbit_digit, -1, -1, /* digit */ cbit_graph, -1, -1, /* graph */ cbit_print, -1, -1, /* print */ cbit_punct, -1, -1, /* punct */ cbit_space, -1, -1, /* space */ cbit_word, -1, -1, /* word - a Perl extension */ cbit_xdigit,-1, -1 /* xdigit */ }; /* Table to identify digits and hex digits. This is used when compiling patterns. Note that the tables in chartables are dependent on the locale, and may mark arbitrary characters as digits - but the PCRE compiling code expects to handle only 0-9, a-z, and A-Z as digits when compiling. That is why we have a private table here. It costs 256 bytes, but it is a lot faster than doing character value tests (at least in some simple cases I timed), and in some applications one wants PCRE to compile efficiently as well as match efficiently. For convenience, we use the same bit definitions as in chartables: 0x04 decimal digit 0x08 hexadecimal digit Then we can use ctype_digit and ctype_xdigit in the code. */ static const unsigned char digitab[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - ' */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ( - / */ 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 */ 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, /* 8 - ? */ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* @ - G */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H - O */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* P - W */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* X - _ */ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* ` - g */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h - o */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p - w */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* x -127 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ /* Definition to allow mutual recursion */ static bool compile_regex(int, int, int *, uschar **, const uschar **, const char **, bool, int, int *, int *, branch_chain *, compile_data *); /* Structure for building a chain of data that actually lives on the stack, for holding the values of the subject pointer at the start of each subpattern, so as to detect when an empty string has been matched by a subpattern - to break infinite loops. */ typedef struct eptrblock { struct eptrblock *epb_prev; const uschar *epb_saved_eptr; } eptrblock; /* Flag bits for the match() function */ #define match_condassert 0x01 /* Called to check a condition assertion */ #define match_isgroup 0x02 /* Set if start of bracketed group */ /* Non-error returns from the match() function. Error returns are externally defined PCRE_ERROR_xxx codes, which are all negative. */ #define MATCH_MATCH 1 #define MATCH_NOMATCH 0 /************************************************* * Global variables * *************************************************/ /* PCRE is thread-clean and doesn't use any global variables in the normal sense. However, it calls memory allocation and free functions via the four indirections below, and it can optionally do callouts. These values can be changed by the caller, but are shared between all threads. However, when compiling for Virtual Pascal, things are done differently (see pcre.in). */ static int (*pcre_callout)(pcre_callout_block *) = NULL; /************************************************* * Macros and tables for character handling * *************************************************/ #define GETCHAR(c, eptr) c = *eptr; #define GETCHARINC(c, eptr) c = *eptr++; #define GETCHARINCTEST(c, eptr) c = *eptr++; #define GETCHARLEN(c, eptr, len) c = *eptr; #define BACKCHAR(eptr) /************************************************* * Handle escapes * *************************************************/ /* This function is called when a \ has been encountered. It either returns a positive value for a simple escape such as \n, or a negative value which encodes one of the more complicated things such as \d. When UTF-8 is enabled, a positive value greater than 255 may be returned. On entry, ptr is pointing at the \. On exit, it is on the final character of the escape sequence. Arguments: ptrptr points to the pattern position pointer errorptr points to the pointer to the error message bracount number of previous extracting brackets options the options bits isclass true if inside a character class Returns: zero or positive => a data character negative => a special escape sequence on error, errorptr is set */ static int check_escape(const uschar **ptrptr, const char **errorptr, int bracount, int options, bool isclass) { const uschar *ptr = *ptrptr; int c, i; /* If backslash is at the end of the pattern, it's an error. */ c = *(++ptr); if (c == 0) *errorptr = ERR1; /* Non-alphamerics are literals. For digits or letters, do an initial lookup in a table. A non-zero result is something that can be returned immediately. Otherwise further processing may be required. */ else if (c < '0' || c > 'z') {} /* Not alphameric */ else if ((i = escapes[c - '0']) != 0) c = i; /* Escapes that need further processing, or are illegal. */ else { const uschar *oldptr; switch (c) { /* A number of Perl escapes are not handled by PCRE. We give an explicit error. */ case 'l': case 'L': case 'N': case 'p': case 'P': case 'u': case 'U': case 'X': *errorptr = ERR37; break; /* The handling of escape sequences consisting of a string of digits starting with one that is not zero is not straightforward. By experiment, the way Perl works seems to be as follows: Outside a character class, the digits are read as a decimal number. If the number is less than 10, or if there are that many previous extracting left brackets, then it is a back reference. Otherwise, up to three octal digits are read to form an escaped byte. Thus \123 is likely to be octal 123 (cf \0123, which is octal 012 followed by the literal 3). If the octal value is greater than 377, the least significant 8 bits are taken. Inside a character class, \ followed by a digit is always an octal number. */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!isclass) { oldptr = ptr; c -= '0'; while ((digitab[ptr[1]] & ctype_digit) != 0) c = c * 10 + *(++ptr) - '0'; if (c < 10 || c <= bracount) { c = -(ESC_REF + c); break; } ptr = oldptr; /* Put the pointer back and fall through */ } /* Handle an octal number following \. If the first digit is 8 or 9, Perl generates a binary zero byte and treats the digit as a following literal. Thus we have to pull back the pointer by one. */ if ((c = *ptr) >= '8') { ptr--; c = 0; break; } /* \0 always starts an octal number, but we may drop through to here with a larger first octal digit. */ case '0': c -= '0'; while(i++ < 2 && ptr[1] >= '0' && ptr[1] <= '7') c = c * 8 + *(++ptr) - '0'; c &= 255; /* Take least significant 8 bits */ break; /* \x is complicated when UTF-8 is enabled. \x{ddd} is a character number which can be greater than 0xff, but only if the ddd are hex digits. */ case 'x': /* Read just a single hex char */ c = 0; while (i++ < 2 && (digitab[ptr[1]] & ctype_xdigit) != 0) { int cc; /* Some compilers don't like ++ */ cc = *(++ptr); /* in initializers */ if (cc >= 'a') cc -= 32; /* Convert to upper case */ c = c * 16 + cc - ((cc < 'A')? '0' : ('A' - 10)); } break; /* Other special escapes not starting with a digit are straightforward */ case 'c': c = *(++ptr); if (c == 0) { *errorptr = ERR2; return 0; } /* A letter is upper-cased; then the 0x40 bit is flipped. This coding is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */ if (c >= 'a' && c <= 'z') c -= 32; c ^= 0x40; break; /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any other alphameric following \ is an error if PCRE_EXTRA was set; otherwise, for Perl compatibility, it is a literal. This code looks a bit odd, but there used to be some cases other than the default, and there may be again in future, so I haven't "optimized" it. */ default: if ((options & PCRE_EXTRA) != 0) { *errorptr = ERR3; } break; } } *ptrptr = ptr; return c; } /************************************************* * Check for counted repeat * *************************************************/ /* This function is called when a '{' is encountered in a place where it might start a quantifier. It looks ahead to see if it really is a quantifier or not. It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} where the ddds are digits. Arguments: p pointer to the first char after '{' Returns: true or false */ static bool is_counted_repeat(const uschar *p) { if ((digitab[*p++] & ctype_digit) == 0) return false; while ((digitab[*p] & ctype_digit) != 0) p++; if (*p == '}') return true; if (*p++ != ',') return false; if (*p == '}') return true; if ((digitab[*p++] & ctype_digit) == 0) return false; while ((digitab[*p] & ctype_digit) != 0) p++; return (*p == '}'); } /************************************************* * Read repeat counts * *************************************************/ /* Read an item of the form {n,m} and return the values. This is called only after is_counted_repeat() has confirmed that a repeat-count quantifier exists, so the syntax is guaranteed to be correct, but we need to check the values. Arguments: p pointer to first char after '{' minp pointer to int for min maxp pointer to int for max returned as -1 if no max errorptr points to pointer to error message Returns: pointer to '}' on success; current ptr on error, with errorptr set */ static const uschar * read_repeat_counts(const uschar *p, int *minp, int *maxp, const char **errorptr) { int min = 0; int max = -1; while ((digitab[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0'; if (*p == '}') max = min; else { if (*(++p) != '}') { max = 0; while((digitab[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0'; if (max < min) { *errorptr = ERR4; return p; } } } /* Do paranoid checks, then fill in the required variables, and pass back the pointer to the terminating '}'. */ if (min < 0 || 65535 < min || max < -1 || 65535 < max) *errorptr = ERR5; else { *minp = min; *maxp = max; } return p; } /************************************************* * Find first significant op code * *************************************************/ /* This is called by several functions that scan a compiled expression looking for a fixed first character, or an anchoring op code etc. It skips over things that do not influence this. For some calls, a change of option is important. Arguments: code pointer to the start of the group options pointer to external options optbit the option bit whose changing is significant, or zero if none are Returns: pointer to the first significant opcode */ static const uschar* first_significant_code(const uschar *code, int *options, int optbit) { for (;;) { switch ((int)*code) { case OP_OPT: if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit)) *options = (int)code[1]; code += 2; break; case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: do code += GET(code, 1); while (*code == OP_ALT); /* Fall through */ case OP_CALLOUT: case OP_CREF: case OP_BRANUMBER: case OP_WORD_BOUNDARY: case OP_NOT_WORD_BOUNDARY: code += OP_lengths[*code]; break; default: return code; } } /* Control never reaches here */ } /************************************************* * Find the fixed length of a pattern * *************************************************/ /* Scan a pattern and compute the fixed length of subject that will match it, if the length is fixed. This is needed for dealing with backward assertions. In UTF8 mode, the result is in characters rather than bytes. Arguments: code points to the start of the pattern (the bracket) options the compiling options Returns: the fixed length, or -1 if there is no fixed length, or -2 if \C was encountered */ static int find_fixedlength(uschar *code, int options) { int length = -1; register int branchlength = 0; register uschar *cc = code + 1 + LINK_SIZE; /* Scan along the opcodes for this branch. If we get to the end of the branch, check the length against that of the other branches. */ for (;;) { int d; register int op = *cc; if (op >= OP_BRA) op = OP_BRA; switch (op) { case OP_BRA: case OP_ONCE: case OP_COND: d = find_fixedlength(cc, options); if (d < 0) return d; branchlength += d; do cc += GET(cc, 1); while (*cc == OP_ALT); cc += 1 + LINK_SIZE; break; /* Reached end of a branch; if it's a ket it is the end of a nested call. If it's ALT it is an alternation in a nested call. If it is END it's the end of the outer call. All can be handled by the same code. */ case OP_ALT: case OP_KET: case OP_KETRMAX: case OP_KETRMIN: case OP_END: if (length < 0) length = branchlength; else if (length != branchlength) return -1; if (*cc != OP_ALT) return length; cc += 1 + LINK_SIZE; branchlength = 0; break; /* Skip over assertive subpatterns */ case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: do cc += GET(cc, 1); while (*cc == OP_ALT); /* Fall through */ /* Skip over things that don't match chars */ case OP_REVERSE: case OP_BRANUMBER: case OP_CREF: case OP_OPT: case OP_CALLOUT: case OP_SOD: case OP_SOM: case OP_EOD: case OP_EODN: case OP_CIRC: case OP_DOLL: case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: cc += OP_lengths[*cc]; break; /* Handle char strings. In UTF-8 mode we must count characters, not bytes. This requires a scan of the string, unfortunately. We assume valid UTF-8 strings, so all we do is reduce the length by one for every byte whose bits are 10xxxxxx. */ case OP_CHARS: branchlength += *(++cc); cc += *cc + 1; break; /* Handle exact repetitions. The count is already in characters, but we need to skip over a multibyte character in UTF8 mode. */ case OP_EXACT: branchlength += GET2(cc,1); cc += 4; break; case OP_TYPEEXACT: branchlength += GET2(cc,1); cc += 4; break; /* Handle single-char matchers */ case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: case OP_ANY: branchlength++; cc++; break; /* The single-byte matcher isn't allowed */ case OP_ANYBYTE: return -2; /* Check a class for variable quantification */ case OP_CLASS: case OP_NCLASS: cc += 33; switch (*cc) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: return -1; case OP_CRRANGE: case OP_CRMINRANGE: if (GET2(cc,1) != GET2(cc,3)) return -1; branchlength += GET2(cc,1); cc += 5; break; default: branchlength++; } break; /* Anything else is variable length */ default: return -1; } } /* Control never gets here */ } /************************************************* * Scan compiled regex for numbered bracket * *************************************************/ /* This little function scans through a compiled pattern until it finds a capturing bracket with the given number. Arguments: code points to start of expression utf8 true in UTF-8 mode number the required bracket number Returns: pointer to the opcode for the bracket, or NULL if not found */ static const uschar * find_bracket(const uschar *code, int number) { for (;;) { register int c = *code; if (c == OP_END) return NULL; else if (c == OP_CHARS) code += code[1] + OP_lengths[c]; else if (c > OP_BRA) { int n = c - OP_BRA; if (n > EXTRACT_BASIC_MAX) n = GET2(code, 2+LINK_SIZE); if (n == number) return (uschar *)code; code += OP_lengths[OP_BRA]; } else { code += OP_lengths[c]; } } } /************************************************* * Scan compiled regex for recursion reference * *************************************************/ /* This little function scans through a compiled pattern until it finds an instance of OP_RECURSE. Arguments: code points to start of expression utf8 true in UTF-8 mode Returns: pointer to the opcode for OP_RECURSE, or NULL if not found */ static const uschar * find_recurse(const uschar *code, bool utf8) { utf8 = utf8; /* Stop pedantic compilers complaining */ for (;;) { register int c = *code; if (c == OP_END) return NULL; else if (c == OP_RECURSE) return code; else if (c == OP_CHARS) code += code[1] + OP_lengths[c]; else if (c > OP_BRA) { code += OP_lengths[OP_BRA]; } else { code += OP_lengths[c]; } } } /************************************************* * Scan compiled branch for non-emptiness * *************************************************/ /* This function scans through a branch of a compiled pattern to see whether it can match the empty string or not. It is called only from could_be_empty() below. Note that first_significant_code() skips over assertions. If we hit an unclosed bracket, we return "empty" - this means we've struck an inner bracket whose current branch will already have been scanned. Arguments: code points to start of search endcode points to where to stop utf8 true if in UTF8 mode Returns: true if what is matched could be empty */ static bool could_be_empty_branch(const uschar *code, const uschar *endcode, bool utf8) { register int c; for (code = first_significant_code(code + 1 + LINK_SIZE, NULL, 0); code < endcode; code = first_significant_code(code + OP_lengths[c], NULL, 0)) { const uschar *ccode; c = *code; if (c >= OP_BRA) { bool empty_branch; if (GET(code, 1) == 0) return true; /* Hit unclosed bracket */ /* Scan a closed bracket */ empty_branch = false; do { if (!empty_branch && could_be_empty_branch(code, endcode, utf8)) empty_branch = true; code += GET(code, 1); } while (*code == OP_ALT); if (!empty_branch) return false; /* All branches are non-empty */ code += 1 + LINK_SIZE; c = *code; } else switch (c) { /* Check for quantifiers after a class */ case OP_CLASS: case OP_NCLASS: ccode = code + 33; switch (*ccode) { case OP_CRSTAR: /* These could be empty; continue */ case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: break; default: /* Non-repeat => class must match */ case OP_CRPLUS: /* These repeats aren't empty */ case OP_CRMINPLUS: return false; case OP_CRRANGE: case OP_CRMINRANGE: if (GET2(ccode, 1) > 0) return false; /* Minimum > 0 */ break; } break; /* Opcodes that must match a character */ case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: case OP_ANY: case OP_ANYBYTE: case OP_CHARS: case OP_NOT: case OP_PLUS: case OP_MINPLUS: case OP_EXACT: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTEXACT: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEEXACT: return false; /* End of branch */ case OP_KET: case OP_KETRMAX: case OP_KETRMIN: case OP_ALT: return true; } } return true; } /************************************************* * Scan compiled regex for non-emptiness * *************************************************/ /* This function is called to check for left recursive calls. We want to check the current branch of the current pattern to see if it could match the empty string. If it could, we must look outwards for branches at other levels, stopping when we pass beyond the bracket which is the subject of the recursion. Arguments: code points to start of the recursion endcode points to where to stop (current RECURSE item) bcptr points to the chain of current (unclosed) branch starts utf8 true if in UTF-8 mode Returns: true if what is matched could be empty */ static bool could_be_empty(const uschar *code, const uschar *endcode, branch_chain *bcptr, bool utf8) { while (bcptr != NULL && bcptr->current >= code) { if (!could_be_empty_branch(bcptr->current, endcode, utf8)) return false; bcptr = bcptr->outer; } return true; } /************************************************* * Check for POSIX class syntax * *************************************************/ /* This function is called when the sequence "[:" or "[." or "[=" is encountered in a character class. It checks whether this is followed by an optional ^ and then a sequence of letters, terminated by a matching ":]" or ".]" or "=]". Argument: ptr pointer to the initial [ endptr where to return the end pointer cd pointer to compile data Returns: true or false */ static bool check_posix_syntax(const uschar *ptr, const uschar **endptr, compile_data *cd) { int terminator; /* Don't combine these lines; the Solaris cc */ terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ if (*(++ptr) == '^') ptr++; while ((cd->ctypes[*ptr] & ctype_letter) != 0) ptr++; if (*ptr == terminator && ptr[1] == ']') { *endptr = ptr; return true; } return false; } /************************************************* * Check POSIX class name * *************************************************/ /* This function is called to check the name given in a POSIX-style class entry such as [:alnum:]. Arguments: ptr points to the first letter len the length of the name Returns: a value representing the name, or -1 if unknown */ static int check_posix_name(const uschar *ptr, int len) { register int yield = 0; while (posix_name_lengths[yield] != 0) { if (len == posix_name_lengths[yield] && strncmp((const char *)ptr, posix_names[yield], len) == 0) return yield; yield++; } return -1; } /************************************************* * Adjust OP_RECURSE items in repeated group * *************************************************/ /* OP_RECURSE items contain an offset from the start of the regex to the group that is referenced. This means that groups can be replicated for fixed repetition simply by copying (because the recursion is allowed to refer to earlier groups that are outside the current group). However, when a group is optional (i.e. the minimum quantifier is zero), OP_BRAZERO is inserted before it, after it has been compiled. This means that any OP_RECURSE items within it that refer to the group itself or any contained groups have to have their offsets adjusted. That is the job of this function. Before it is called, the partially compiled regex must be temporarily terminated with OP_END. Arguments: group points to the start of the group adjust the amount by which the group is to be moved utf8 true in UTF-8 mode cd contains pointers to tables etc. Returns: nothing */ static void adjust_recurse(uschar *group, int adjust, bool utf8, compile_data *cd) { uschar *ptr = group; while ((ptr = (uschar *)find_recurse(ptr, utf8)) != NULL) { int offset = GET(ptr, 1); if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust); ptr += 1 + LINK_SIZE; } } /************************************************* * Compile one branch * *************************************************/ /* Scan the pattern, compiling it into the code vector. If the options are changed during the branch, the pointer is used to change the external options bits. Arguments: optionsptr pointer to the option bits brackets points to number of extracting brackets used code points to the pointer to the current code point ptrptr points to the current pattern pointer errorptr points to pointer to error message firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) reqbyteptr set to the last literal character required, else < 0 bcptr points to current branch chain cd contains pointers to tables etc. Returns: true on success false, with *errorptr set on error */ static bool compile_branch(int *optionsptr, int *brackets, uschar **codeptr, const uschar **ptrptr, const char **errorptr, int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, compile_data *cd) { int repeat_type, op_type; int repeat_min = 0, repeat_max = 0; /* To please picky compilers */ int bravalue = 0; int length; int greedy_default, greedy_non_default; int firstbyte, reqbyte; int zeroreqbyte, zerofirstbyte; int req_caseopt, reqvary, tempreqvary; int condcount = 0; int options = *optionsptr; register int c; register uschar *code = *codeptr; uschar *tempcode; bool inescq = false; bool groupsetfirstbyte = false; const uschar *ptr = *ptrptr; const uschar *tempptr; uschar *previous = NULL; uschar classa[32]; bool utf8 = false; /* Set up the default and non-default settings for greediness */ greedy_default = ((options & PCRE_UNGREEDY) != 0); greedy_non_default = greedy_default ^ 1; /* Initialize no first char, no required char. REQ_UNSET means "no char matching encountered yet". It gets changed to REQ_NONE if we hit something that matches a non-fixed char first char; reqbyte just remains unset if we never find one. When we hit a repeat whose minimum is zero, we may have to adjust these values to take the zero repeat into account. This is implemented by setting them to zerofirstbyte and zeroreqbyte when such a repeat is encountered. The individual item types that can be repeated set these backoff variables appropriately. */ firstbyte = reqbyte = zerofirstbyte = zeroreqbyte = REQ_UNSET; /* The variable req_caseopt contains either the REQ_CASELESS value or zero, according to the current setting of the caseless flag. REQ_CASELESS is a bit value > 255. It is added into the firstbyte or reqbyte variables to record the case status of the value. */ req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; /* Switch on next character until the end of the branch */ for (;; ptr++) { bool negate_class; bool possessive_quantifier; int class_charcount; int class_lastchar; int newoptions; int recno; int skipbytes; int subreqbyte; int subfirstbyte; c = *ptr; if (inescq && c != 0) goto NORMAL_CHAR; if ((options & PCRE_EXTENDED) != 0) { if ((cd->ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != NEWLINE) ; if (c != 0) continue; /* Else fall through to handle end of string */ } } switch(c) { /* The branch terminates at end of string, |, or ). */ case 0: case '|': case ')': *firstbyteptr = firstbyte; *reqbyteptr = reqbyte; *codeptr = code; *ptrptr = ptr; return true; /* Handle single-character metacharacters. In multiline mode, ^ disables the setting of any following char as a first character. */ case '^': if ((options & PCRE_MULTILINE) != 0) { if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; } previous = NULL; *code++ = OP_CIRC; break; case '$': previous = NULL; *code++ = OP_DOLL; break; /* There can never be a first char if '.' is first, whatever happens about repeats. The value of reqbyte doesn't change either. */ case '.': if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; zerofirstbyte = firstbyte; zeroreqbyte = reqbyte; previous = code; *code++ = OP_ANY; break; /* Character classes. If the included characters are all < 255 in value, we build a 32-byte bitmap of the permitted characters, except in the special case where there is only one such character. For negated classes, we build the map as usual, then invert it at the end. However, we use a different opcode so that data characters > 255 can be handled correctly. If the class contains characters outside the 0-255 range, a different opcode is compiled. It may optionally have a bit map for characters < 256, but those above are are explicitly listed afterwards. A flag byte tells whether the bitmap is present, and whether this is a negated class or not. */ case '[': previous = code; /* PCRE supports POSIX class stuff inside a class. Perl gives an error if they are encountered at the top level, so we'll do that too. */ if ((ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && check_posix_syntax(ptr, &tempptr, cd)) { *errorptr = (ptr[1] == ':')? ERR13 : ERR31; goto FAILED; } /* If the first character is '^', set the negation flag and skip it. */ if ((c = *(++ptr)) == '^') { negate_class = true; c = *(++ptr); } else { negate_class = false; } /* Keep a count of chars with values < 256 so that we can optimize the case of just a single character (as long as it's < 256). For higher valued UTF-8 characters, we don't yet do any optimization. */ class_charcount = 0; class_lastchar = -1; /* Initialize the 32-char bit map to all zeros. We have to build the map in a temporary bit of store, in case the class contains only 1 character (< 256), because in that case the compiled code doesn't use the bit map. */ memset(classa, 0, 32 * sizeof(uschar)); /* Process characters until ] is reached. By writing this as a "do" it means that an initial ] is taken as a data character. The first pass through the regex checked the overall syntax, so we don't need to be very strict here. At the start of the loop, c contains the first byte of the character. */ do { /* Inside \Q...\E everything is literal except \E */ if (inescq) { if (c == '\\' && ptr[1] == 'E') { inescq = false; ptr++; continue; } else goto LONE_SINGLE_CHARACTER; } /* Handle POSIX class names. Perl allows a negation extension of the form [:^name:]. A square bracket that doesn't match the syntax is treated as a literal. We also recognize the POSIX constructions [.ch.] and [=ch=] ("collating elements") and fault them, as Perl 5.6 and 5.8 do. */ if (c == '[' && (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && check_posix_syntax(ptr, &tempptr, cd)) { bool local_negate = false; int posix_class, i; register const uschar *cbits = cd->cbits; if (ptr[1] != ':') { *errorptr = ERR31; goto FAILED; } ptr += 2; if (*ptr == '^') { local_negate = true; ptr++; } posix_class = check_posix_name(ptr, tempptr - ptr); if (posix_class < 0) { *errorptr = ERR30; goto FAILED; } /* If matching is caseless, upper and lower are converted to alpha. This relies on the fact that the class table starts with alpha, lower, upper as the first 3 entries. */ if ((options & PCRE_CASELESS) != 0 && posix_class <= 2) posix_class = 0; /* Or into the map we are building up to 3 of the static class tables, or their negations. The [:blank:] class sets up the same chars as the [:space:] class (all white space). We remove the vertical white space chars afterwards. */ posix_class *= 3; for (i = 0; i < 3; i++) { bool blankclass = strncmp((char *)ptr, "blank", 5) == 0; int taboffset = posix_class_maps[posix_class + i]; if (taboffset < 0) break; if (local_negate) { for (c = 0; c < 32; c++) classa[c] |= ~cbits[c+taboffset]; if (blankclass) classa[1] |= 0x3c; } else { for (c = 0; c < 32; c++) classa[c] |= cbits[c+taboffset]; if (blankclass) classa[1] &= ~0x3c; } } ptr = tempptr + 1; class_charcount = 10; /* Set > 1; assumes more than 1 per class */ continue; /* End of POSIX syntax handling */ } /* Backslash may introduce a single character, or it may introduce one of the specials, which just set a flag. Escaped items are checked for validity in the pre-compiling pass. The sequence \b is a special case. Inside a class (and only there) it is treated as backspace. Elsewhere it marks a word boundary. Other escapes have preset maps ready to or into the one we are building. We assume they have more than one character in them, so set class_charcount bigger than one. */ if (c == '\\') { c = check_escape(&ptr, errorptr, *brackets, options, true); if (-c == ESC_b) c = '\b'; /* \b is backslash in a class */ if (-c == ESC_Q) /* Handle start of quoted string */ { if (ptr[1] == '\\' && ptr[2] == 'E') { ptr += 2; /* avoid empty string */ } else inescq = true; continue; } else if (c < 0) { register const uschar *cbits = cd->cbits; class_charcount = 10; /* Greater than 1 is what matters */ switch (-c) { case ESC_d: for (c = 0; c < 32; c++) classa[c] |= cbits[c+cbit_digit]; continue; case ESC_D: for (c = 0; c < 32; c++) classa[c] |= ~cbits[c+cbit_digit]; continue; case ESC_w: for (c = 0; c < 32; c++) classa[c] |= cbits[c+cbit_word]; continue; case ESC_W: for (c = 0; c < 32; c++) classa[c] |= ~cbits[c+cbit_word]; continue; case ESC_s: for (c = 0; c < 32; c++) classa[c] |= cbits[c+cbit_space]; classa[1] &= ~0x08; /* Perl 5.004 onwards omits VT from \s */ continue; case ESC_S: for (c = 0; c < 32; c++) classa[c] |= ~cbits[c+cbit_space]; classa[1] |= 0x08; /* Perl 5.004 onwards omits VT from \s */ continue; /* Unrecognized escapes are faulted if PCRE is running in its strict mode. By default, for compatibility with Perl, they are treated as literals. */ default: if ((options & PCRE_EXTRA) != 0) { *errorptr = ERR7; goto FAILED; } c = *ptr; /* The final character */ } } /* Fall through if we have a single character (c >= 0). This may be > 256 in UTF-8 mode. */ } /* End of backslash handling */ /* A single character may be followed by '-' to form a range. However, Perl does not permit ']' to be the end of the range. A '-' character here is treated as a literal. */ if (ptr[1] == '-' && ptr[2] != ']') { int d; ptr += 2; d = *ptr; /* The second part of a range can be a single-character escape, but not any of the other escapes. Perl 5.6 treats a hyphen as a literal in such circumstances. */ if (d == '\\') { const uschar *oldptr = ptr; d = check_escape(&ptr, errorptr, *brackets, options, true); /* \b is backslash; any other special means the '-' was literal */ if (d < 0) { if (d == -ESC_b) d = '\b'; else { ptr = oldptr - 2; goto LONE_SINGLE_CHARACTER; /* A few lines below */ } } } /* Check that the two values are in the correct order */ if (d < c) { *errorptr = ERR8; goto FAILED; } /* If d is greater than 255, we can't just use the bit map, so set up for the UTF-8 supporting class type. If we are not caseless, we can just set up a single range. If we are caseless, the characters < 256 are handled with a bitmap, in order to get the case-insensitive handling. */ /* We use the bit map if the range is entirely < 255, or if part of it is < 255 and matching is caseless. */ for (; c <= d; c++) { classa[c/8] |= (1 << (c&7)); if ((options & PCRE_CASELESS) != 0) { int uc = cd->fcc[c]; /* flip case */ classa[uc/8] |= (1 << (uc&7)); } class_charcount++; /* in case a one-char range */ class_lastchar = c; } continue; /* Go get the next char in the class */ } /* Handle a lone single character - we can get here for a normal non-escape char, or after \ that introduces a single character. */ LONE_SINGLE_CHARACTER: /* Handle a single-byte character */ { classa[c/8] |= (1 << (c&7)); if ((options & PCRE_CASELESS) != 0) { c = cd->fcc[c]; /* flip case */ classa[c/8] |= (1 << (c&7)); } class_charcount++; class_lastchar = c; } } /* Loop until ']' reached; the check for end of string happens inside the loop. This "while" is the end of the "do" above. */ while ((c = *(++ptr)) != ']' || inescq); /* If class_charcount is 1, we saw precisely one character with a value < 256. In UTF-8 mode, we can optimize if there were no characters >= 256 and the one character is < 128. In non-UTF-8 mode we can always optimize. The optimization throws away the bit map. We turn the item into a 1-character OP_CHARS if it's positive, or OP_NOT if it's negative. Note that OP_NOT does not support multibyte characters. In the positive case, it can cause firstbyte to be set. Otherwise, there can be no first char if this item is first, whatever repeat count may follow. In the case of reqbyte, save the previous value for reinstating. */ if (class_charcount == 1) { zeroreqbyte = reqbyte; if (negate_class) { if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; zerofirstbyte = firstbyte; *code++ = OP_NOT; } else { if (firstbyte == REQ_UNSET) { zerofirstbyte = REQ_NONE; firstbyte = class_lastchar | req_caseopt; } else { zerofirstbyte = firstbyte; reqbyte = class_lastchar | req_caseopt | cd->req_varyopt; } *code++ = OP_CHARS; *code++ = 1; } *code++ = static_cast(class_lastchar); break; /* End of class handling */ } /* End of 1-byte optimization */ /* Otherwise, if this is the first thing in the branch, there can be no first char setting, whatever the repeat count. Any reqbyte setting must remain unchanged after any kind of repeat. */ if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; zerofirstbyte = firstbyte; zeroreqbyte = reqbyte; /* If there are characters with values > 255, we have to compile an extended class, with its own opcode. If there are no characters < 256, we can omit the bitmap. */ /* If there are no characters > 255, negate the 32-byte map if necessary, and copy it into the code vector. If this is the first thing in the branch, there can be no first char setting, whatever the repeat count. Any reqbyte setting must remain unchanged after any kind of repeat. */ if (negate_class) { *code++ = OP_NCLASS; for (c = 0; c < 32; c++) code[c] = static_cast(~classa[c]); } else { *code++ = OP_CLASS; memcpy(code, classa, 32); } code += 32; break; /* Various kinds of repeat */ case '{': if (!is_counted_repeat(ptr+1)) goto NORMAL_CHAR; ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorptr); if (*errorptr != NULL) goto FAILED; goto REPEAT; case '*': repeat_min = 0; repeat_max = -1; goto REPEAT; case '+': repeat_min = 1; repeat_max = -1; goto REPEAT; case '?': repeat_min = 0; repeat_max = 1; REPEAT: if (previous == NULL) { *errorptr = ERR9; goto FAILED; } if (repeat_min == 0) { firstbyte = zerofirstbyte; /* Adjust for zero repeat */ reqbyte = zeroreqbyte; /* Ditto */ } /* Remember whether this is a variable length repeat */ reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY; op_type = 0; /* Default single-char op codes */ possessive_quantifier = false; /* Default not possessive quantifier */ /* Save start of previous item, in case we have to move it up to make space for an inserted OP_ONCE for the additional '+' extension. */ tempcode = previous; /* If the next character is '+', we have a possessive quantifier. This implies greediness, whatever the setting of the PCRE_UNGREEDY option. If the next character is '?' this is a minimizing repeat, by default, but if PCRE_UNGREEDY is set, it works the other way round. We change the repeat type to the non-default. */ if (ptr[1] == '+') { repeat_type = 0; /* Force greedy */ possessive_quantifier = true; ptr++; } else if (ptr[1] == '?') { repeat_type = greedy_non_default; ptr++; } else repeat_type = greedy_default; /* If previous was a recursion, we need to wrap it inside brackets so that it can be replicated if necessary. */ if (*previous == OP_RECURSE) { memmove(previous + 1 + LINK_SIZE, previous, 1 + LINK_SIZE); code += 1 + LINK_SIZE; *previous = OP_BRA; PUT(previous, 1, code - previous); *code = OP_KET; PUT(code, 1, code - previous); code += 1 + LINK_SIZE; } /* If previous was a string of characters, chop off the last one and use it as the subject of the repeat. If there was only one character, we can abolish the previous item altogether. If a one-char item has a minumum of more than one, ensure that it is set in reqbyte - it might not be if a sequence such as x{3} is the first thing in a branch because the x will have gone into firstbyte instead. */ if (*previous == OP_CHARS) { /* Deal with UTF-8 characters that take up more than one byte. It's easier to write this out separately than try to macrify it. Use c to hold the length of the character in bytes, plus 0x80 to flag that it's a length rather than a small character. */ /* Handle the case of a single byte - either with no UTF8 support, or with UTF-8 disabled, or for a UTF-8 character < 128. */ { c = *(--code); if (code == previous + 2) /* There was only one character */ { code = previous; /* Abolish the previous item */ if (repeat_min > 1) reqbyte = c | req_caseopt | cd->req_varyopt; } else { previous[1]--; /* adjust length */ tempcode = code; /* Adjust position to be moved for '+' */ } } goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ } /* If previous was a single negated character ([^a] or similar), we use one of the special opcodes, replacing it. The code is shared with single- character repeats by setting opt_type to add a suitable offset into repeat_type. OP_NOT is currently used only for single-byte chars. */ else if (*previous == OP_NOT) { op_type = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ c = previous[1]; code = previous; goto OUTPUT_SINGLE_REPEAT; } /* If previous was a character type match (\d or similar), abolish it and create a suitable repeat item. The code is shared with single-character repeats by setting op_type to add a suitable offset into repeat_type. */ else if (*previous < OP_EODN) { op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ c = *previous; code = previous; OUTPUT_SINGLE_REPEAT: /* If the maximum is zero then the minimum must also be zero; Perl allows this case, so we do too - by simply omitting the item altogether. */ if (repeat_max == 0) goto END_REPEAT; /* Combine the op_type with the repeat_type */ repeat_type += op_type; /* A minimum of zero is handled either as the special case * or ?, or as an UPTO, with the maximum given. */ if (repeat_min == 0) { if (repeat_max == -1) *code++ = static_cast(OP_STAR + repeat_type); else if (repeat_max == 1) *code++ = static_cast(OP_QUERY + repeat_type); else { *code++ = static_cast(OP_UPTO + repeat_type); PUT2INC(code, 0, repeat_max); } } /* The case {1,} is handled as the special case + */ else if (repeat_min == 1 && repeat_max == -1) *code++ = static_cast(OP_PLUS + repeat_type); /* The case {n,n} is just an EXACT, while the general case {n,m} is handled as an EXACT followed by an UPTO. An EXACT of 1 is optimized. */ else { if (repeat_min != 1) { *code++ = static_cast(OP_EXACT + op_type); /* NB EXACT doesn't have repeat_type */ PUT2INC(code, 0, repeat_min); } /* If the mininum is 1 and the previous item was a character string, we either have to put back the item that got cancelled if the string length was 1, or add the character back onto the end of a longer string. For a character type nothing need be done; it will just get put back naturally. Note that the final character is always going to get added below, so we leave code ready for its insertion. */ else if (*previous == OP_CHARS) { if (code == previous) code += 2; else /* In UTF-8 mode, a multibyte char has its length in c, with the 0x80 bit set as a flag. The length will always be between 2 and 6. */ previous[1]++; } /* For a single negated character we also have to put back the item that got cancelled. At present this applies only to single byte characters in any mode. */ else if (*previous == OP_NOT) code++; /* If the maximum is unlimited, insert an OP_STAR. Before doing so, we have to insert the character for the previous code. In UTF-8 mode, long characters have their length in c, with the 0x80 bit as a flag. */ if (repeat_max < 0) { *code++ = static_cast(c); *code++ = static_cast(OP_STAR + repeat_type); } /* Else insert an UPTO if the max is greater than the min, again preceded by the character, for the previously inserted code. */ else if (repeat_max != repeat_min) { *code++ = static_cast(c); repeat_max -= repeat_min; *code++ = static_cast(OP_UPTO + repeat_type); PUT2INC(code, 0, repeat_max); } } /* The character or character type itself comes last in all cases. */ *code++ = static_cast(c); } /* If previous was a character class or a back reference, we put the repeat stuff after it, but just skip the item if the repeat was {0,0}. */ else if (*previous == OP_CLASS || *previous == OP_NCLASS || *previous == OP_REF) { if (repeat_max == 0) { code = previous; goto END_REPEAT; } if (repeat_min == 0 && repeat_max == -1) *code++ = static_cast(OP_CRSTAR + repeat_type); else if (repeat_min == 1 && repeat_max == -1) *code++ = static_cast(OP_CRPLUS + repeat_type); else if (repeat_min == 0 && repeat_max == 1) *code++ = static_cast(OP_CRQUERY + repeat_type); else { *code++ = static_cast(OP_CRRANGE + repeat_type); PUT2INC(code, 0, repeat_min); if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */ PUT2INC(code, 0, repeat_max); } } /* If previous was a bracket group, we may have to replicate it in certain cases. */ else if (*previous >= OP_BRA || *previous == OP_ONCE || *previous == OP_COND) { register int i; int ketoffset = 0; int len = code - previous; uschar *bralink = NULL; /* If the maximum repeat count is unlimited, find the end of the bracket by scanning through from the start, and compute the offset back to it from the current code pointer. There may be an OP_OPT setting following the final KET, so we can't find the end just by going back from the code pointer. */ if (repeat_max == -1) { register uschar *ket = previous; do ket += GET(ket, 1); while (*ket != OP_KET); ketoffset = code - ket; } /* The case of a zero minimum is special because of the need to stick OP_BRAZERO in front of it, and because the group appears once in the data, whereas in other cases it appears the minimum number of times. For this reason, it is simplest to treat this case separately, as otherwise the code gets far too messy. There are several special subcases when the minimum is zero. */ if (repeat_min == 0) { /* If the maximum is also zero, we just omit the group from the output altogether. */ if (repeat_max == 0) { code = previous; goto END_REPEAT; } /* If the maximum is 1 or unlimited, we just have to stick in the BRAZERO and do no more at this point. However, we do need to adjust any OP_RECURSE calls inside the group that refer to the group itself or any internal group, because the offset is from the start of the whole regex. Temporarily terminate the pattern while doing this. */ if (repeat_max <= 1) { *code = OP_END; adjust_recurse(previous, 1, utf8, cd); memmove(previous+1, previous, len); code++; *previous++ = static_cast(OP_BRAZERO + repeat_type); } /* If the maximum is greater than 1 and limited, we have to replicate in a nested fashion, sticking OP_BRAZERO before each set of brackets. The first one has to be handled carefully because it's the original copy, which has to be moved up. The remainder can be handled by code that is common with the non-zero minimum case below. We have to adjust the value or repeat_max, since one less copy is required. Once again, we may have to adjust any OP_RECURSE calls inside the group. */ else { int offset; *code = OP_END; adjust_recurse(previous, 2 + LINK_SIZE, utf8, cd); memmove(previous + 2 + LINK_SIZE, previous, len); code += 2 + LINK_SIZE; *previous++ = static_cast(OP_BRAZERO + repeat_type); *previous++ = OP_BRA; /* We chain together the bracket offset fields that have to be filled in later when the ends of the brackets are reached. */ offset = (bralink == NULL)? 0 : previous - bralink; bralink = previous; PUTINC(previous, 0, offset); } repeat_max--; } /* If the minimum is greater than zero, replicate the group as many times as necessary, and adjust the maximum to the number of subsequent copies that we need. If we set a first char from the group, and didn't set a required char, copy the latter from the former. */ else { if (repeat_min > 1) { if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte; for (i = 1; i < repeat_min; i++) { memcpy(code, previous, len); code += len; } } if (repeat_max > 0) repeat_max -= repeat_min; } /* This code is common to both the zero and non-zero minimum cases. If the maximum is limited, it replicates the group in a nested fashion, remembering the bracket starts on a stack. In the case of a zero minimum, the first one was set up above. In all cases the repeat_max now specifies the number of additional copies needed. */ if (repeat_max >= 0) { for (i = repeat_max - 1; i >= 0; i--) { *code++ = static_cast(OP_BRAZERO + repeat_type); /* All but the final copy start a new nesting, maintaining the chain of brackets outstanding. */ if (i != 0) { int offset; *code++ = OP_BRA; offset = (bralink == NULL)? 0 : code - bralink; bralink = code; PUTINC(code, 0, offset); } memcpy(code, previous, len); code += len; } /* Now chain through the pending brackets, and fill in their length fields (which are holding the chain links pro tem). */ while (bralink != NULL) { int oldlinkoffset; int offset = code - bralink + 1; uschar *bra = code - offset; oldlinkoffset = GET(bra, 1); bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; *code++ = OP_KET; PUTINC(code, 0, offset); PUT(bra, 1, offset); } } /* If the maximum is unlimited, set a repeater in the final copy. We can't just offset backwards from the current code point, because we don't know if there's been an options resetting after the ket. The correct offset was computed above. */ else code[-ketoffset] = static_cast(OP_KETRMAX + repeat_type); } /* Else there's some kind of shambles */ else { *errorptr = ERR11; goto FAILED; } /* If the character following a repeat is '+', we wrap the entire repeated item inside OP_ONCE brackets. This is just syntactic sugar, taken from Sun's Java package. The repeated item starts at tempcode, not at previous, which might be the first part of a string whose (former) last char we repeated. However, we don't support '+' after a greediness '?'. */ if (possessive_quantifier) { int len = code - tempcode; memmove(tempcode + 1+LINK_SIZE, tempcode, len); code += 1 + LINK_SIZE; len += 1 + LINK_SIZE; tempcode[0] = OP_ONCE; *code++ = OP_KET; PUTINC(code, 0, len); PUT(tempcode, 1, len); } /* In all case we no longer have a previous item. We also set the "follows varying string" flag for subsequently encountered reqbytes if it isn't already set and we have just passed a varying length item. */ END_REPEAT: previous = NULL; cd->req_varyopt |= reqvary; break; /* Start of nested bracket sub-expression, or comment or lookahead or lookbehind or option setting or condition. First deal with special things that can come after a bracket; all are introduced by ?, and the appearance of any of them means that this is not a referencing group. They were checked for validity in the first pass over the string, so we don't have to check for syntax errors here. */ case '(': newoptions = options; skipbytes = 0; if (*(++ptr) == '?') { int set, unset; int *optset; switch (*(++ptr)) { case '#': /* Comment; skip to ket */ ptr++; while (*ptr != ')') ptr++; continue; case ':': /* Non-extracting bracket */ bravalue = OP_BRA; ptr++; break; case '(': bravalue = OP_COND; /* Conditional group */ /* Condition to test for recursion */ if (ptr[1] == 'R') { code[1+LINK_SIZE] = OP_CREF; PUT2(code, 2+LINK_SIZE, CREF_RECURSE); skipbytes = 3; ptr += 3; } /* Condition to test for a numbered subpattern match. We know that if a digit follows ( then there will just be digits until ) because the syntax was checked in the first pass. */ else if ((digitab[ptr[1]] && ctype_digit) != 0) { int condref; /* Don't amalgamate; some compilers */ condref = *(++ptr) - '0'; /* grumble at autoincrement in declaration */ while (*(++ptr) != ')') condref = condref*10 + *ptr - '0'; if (condref == 0) { *errorptr = ERR35; goto FAILED; } ptr++; code[1+LINK_SIZE] = OP_CREF; PUT2(code, 2+LINK_SIZE, condref); skipbytes = 3; } /* For conditions that are assertions, we just fall through, having set bravalue above. */ break; case '=': /* Positive lookahead */ bravalue = OP_ASSERT; ptr++; break; case '!': /* Negative lookahead */ bravalue = OP_ASSERT_NOT; ptr++; break; case '<': /* Lookbehinds */ switch (*(++ptr)) { case '=': /* Positive lookbehind */ bravalue = OP_ASSERTBACK; ptr++; break; case '!': /* Negative lookbehind */ bravalue = OP_ASSERTBACK_NOT; ptr++; break; } break; case '>': /* One-time brackets */ bravalue = OP_ONCE; ptr++; break; case 'C': /* Callout - may be followed by digits */ *code++ = OP_CALLOUT; { int n = 0; while ((digitab[*(++ptr)] & ctype_digit) != 0) n = n * 10 + *ptr - '0'; if (n > 255) { *errorptr = ERR38; goto FAILED; } *code++ = static_cast(n); } previous = NULL; continue; case 'P': /* Named subpattern handling */ if (*(++ptr) == '<') /* Definition */ { int i, namelen; uschar *slot = cd->name_table; const uschar *name; /* Don't amalgamate; some compilers */ name = ++ptr; /* grumble at autoincrement in declaration */ while (*ptr++ != '>'); namelen = ptr - name - 1; for (i = 0; i < cd->names_found; i++) { int crc = memcmp(name, slot+2, namelen); if (crc == 0) { if (slot[2+namelen] == 0) { *errorptr = ERR43; goto FAILED; } crc = -1; /* Current name is substring */ } if (crc < 0) { memmove(slot + cd->name_entry_size, slot, (cd->names_found - i) * cd->name_entry_size); break; } slot += cd->name_entry_size; } PUT2(slot, 0, *brackets + 1); memcpy(slot + 2, name, namelen); slot[2+namelen] = 0; cd->names_found++; goto NUMBERED_GROUP; } if (*ptr == '=' || *ptr == '>') /* Reference or recursion */ { int i, namelen; int type = *ptr++; const uschar *name = ptr; uschar *slot = cd->name_table; while (*ptr != ')') ptr++; namelen = ptr - name; for (i = 0; i < cd->names_found; i++) { if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break; slot += cd->name_entry_size; } if (i >= cd->names_found) { *errorptr = ERR15; goto FAILED; } recno = GET2(slot, 0); if (type == '>') goto HANDLE_RECURSION; /* A few lines below */ /* Back reference */ previous = code; *code++ = OP_REF; PUT2INC(code, 0, recno); cd->backref_map |= (recno < 32)? (1 << recno) : 1; if (recno > cd->top_backref) cd->top_backref = recno; continue; } /* Should never happen */ break; case 'R': /* Pattern recursion */ ptr++; /* Same as (?0) */ /* Fall through */ /* Recursion or "subroutine" call */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { const uschar *called; recno = 0; while((digitab[*ptr] & ctype_digit) != 0) recno = recno * 10 + *ptr++ - '0'; /* Come here from code above that handles a named recursion */ HANDLE_RECURSION: previous = code; /* Find the bracket that is being referenced. Temporarily end the regex in case it doesn't exist. */ *code = OP_END; called = (recno == 0)? cd->start_code : find_bracket(cd->start_code, recno); if (called == NULL) { *errorptr = ERR15; goto FAILED; } /* If the subpattern is still open, this is a recursive call. We check to see if this is a left recursion that could loop for ever, and diagnose that case. */ if (GET(called, 1) == 0 && could_be_empty(called, code, bcptr, utf8)) { *errorptr = ERR40; goto FAILED; } /* Insert the recursion/subroutine item */ *code = OP_RECURSE; PUT(code, 1, called - cd->start_code); code += 1 + LINK_SIZE; } continue; /* Character after (? not specially recognized */ default: /* Option setting */ set = unset = 0; optset = &set; while (*ptr != ')' && *ptr != ':') { switch (*ptr++) { case '-': optset = &unset; break; case 'i': *optset |= PCRE_CASELESS; break; case 'm': *optset |= PCRE_MULTILINE; break; case 's': *optset |= PCRE_DOTALL; break; case 'x': *optset |= PCRE_EXTENDED; break; case 'U': *optset |= PCRE_UNGREEDY; break; case 'X': *optset |= PCRE_EXTRA; break; } } /* Set up the changed option bits, but don't change anything yet. */ newoptions = (options | set) & (~unset); /* If the options ended with ')' this is not the start of a nested group with option changes, so the options change at this level. Compile code to change the ims options if this setting actually changes any of them. We also pass the new setting back so that it can be put at the start of any following branches, and when this group ends (if we are in a group), a resetting item can be compiled. Note that if this item is right at the start of the pattern, the options will have been abstracted and made global, so there will be no change to compile. */ if (*ptr == ')') { if ((options & PCRE_IMS) != (newoptions & PCRE_IMS)) { *code++ = OP_OPT; *code++ = static_cast(newoptions & PCRE_IMS); } /* Change options at this level, and pass them back for use in subsequent branches. Reset the greedy defaults and the case value for firstbyte and reqbyte. */ *optionsptr = options = newoptions; greedy_default = ((newoptions & PCRE_UNGREEDY) != 0); greedy_non_default = greedy_default ^ 1; req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; previous = NULL; /* This item can't be repeated */ continue; /* It is complete */ } /* If the options ended with ':' we are heading into a nested group with possible change of options. Such groups are non-capturing and are not assertions of any kind. All we need to do is skip over the ':'; the newoptions value is handled below. */ bravalue = OP_BRA; ptr++; } } /* If PCRE_NO_AUTO_CAPTURE is set, all unadorned brackets become non-capturing and behave like (?:...) brackets */ else if ((options & PCRE_NO_AUTO_CAPTURE) != 0) { bravalue = OP_BRA; } /* Else we have a referencing group; adjust the opcode. If the bracket number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and arrange for the true number to follow later, in an OP_BRANUMBER item. */ else { NUMBERED_GROUP: if (++(*brackets) > EXTRACT_BASIC_MAX) { bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; code[1+LINK_SIZE] = OP_BRANUMBER; PUT2(code, 2+LINK_SIZE, *brackets); skipbytes = 3; } else bravalue = OP_BRA + *brackets; } /* Process nested bracketed re. Assertions may not be repeated, but other kinds can be. We copy code into a non-register variable in order to be able to pass its address because some compilers complain otherwise. Pass in a new setting for the ims options if they have changed. */ previous = (bravalue >= OP_ONCE)? code : NULL; *code = static_cast(bravalue); tempcode = code; tempreqvary = cd->req_varyopt; /* Save value before bracket */ if (!compile_regex( newoptions, /* The complete new option state */ options & PCRE_IMS, /* The previous ims option state */ brackets, /* Extracting bracket count */ &tempcode, /* Where to put code (updated) */ &ptr, /* Input pointer (updated) */ errorptr, /* Where to put an error message */ (bravalue == OP_ASSERTBACK || bravalue == OP_ASSERTBACK_NOT), /* true if back assert */ skipbytes, /* Skip over OP_COND/OP_BRANUMBER */ &subfirstbyte, /* For possible first char */ &subreqbyte, /* For possible last char */ bcptr, /* Current branch chain */ cd)) /* Tables block */ goto FAILED; /* At the end of compiling, code is still pointing to the start of the group, while tempcode has been updated to point past the end of the group and any option resetting that may follow it. The pattern pointer (ptr) is on the bracket. */ /* If this is a conditional bracket, check that there are no more than two branches in the group. */ else if (bravalue == OP_COND) { uschar *tc = code; condcount = 0; do { condcount++; tc += GET(tc,1); } while (*tc != OP_KET); if (condcount > 2) { *errorptr = ERR27; goto FAILED; } /* If there is just one branch, we must not make use of its firstbyte or reqbyte, because this is equivalent to an empty second branch. */ if (condcount == 1) subfirstbyte = subreqbyte = REQ_NONE; } /* Handle updating of the required and first characters. Update for normal brackets of all kinds, and conditions with two branches (see code above). If the bracket is followed by a quantifier with zero repeat, we have to back off. Hence the definition of zeroreqbyte and zerofirstbyte outside the main loop so that they can be accessed for the back off. */ zeroreqbyte = reqbyte; zerofirstbyte = firstbyte; groupsetfirstbyte = false; if (bravalue >= OP_BRA || bravalue == OP_ONCE || bravalue == OP_COND) { /* If we have not yet set a firstbyte in this branch, take it from the subpattern, remembering that it was set here so that a repeat of more than one can replicate it as reqbyte if necessary. If the subpattern has no firstbyte, set "none" for the whole branch. In both cases, a zero repeat forces firstbyte to "none". */ if (firstbyte == REQ_UNSET) { if (subfirstbyte >= 0) { firstbyte = subfirstbyte; groupsetfirstbyte = true; } else firstbyte = REQ_NONE; zerofirstbyte = REQ_NONE; } /* If firstbyte was previously set, convert the subpattern's firstbyte into reqbyte if there wasn't one, using the vary flag that was in existence beforehand. */ else if (subfirstbyte >= 0 && subreqbyte < 0) subreqbyte = subfirstbyte | tempreqvary; /* If the subpattern set a required byte (or set a first byte that isn't really the first byte - see above), set it. */ if (subreqbyte >= 0) reqbyte = subreqbyte; } /* For a forward assertion, we take the reqbyte, if set. This can be helpful if the pattern that follows the assertion doesn't set a different char. For example, it's useful for /(?=abcde).+/. We can't set firstbyte for an assertion, however because it leads to incorrect effect for patterns such as /(?=a)a.+/ when the "real" "a" would then become a reqbyte instead of a firstbyte. This is overcome by a scan at the end if there's no firstbyte, looking for an asserted first char. */ else if (bravalue == OP_ASSERT && subreqbyte >= 0) reqbyte = subreqbyte; /* Now update the main code pointer to the end of the group. */ code = tempcode; /* Error if hit end of pattern */ if (*ptr != ')') { *errorptr = ERR14; goto FAILED; } break; /* Check \ for being a real metacharacter; if not, fall through and handle it as a data character at the start of a string. Escape items are checked for validity in the pre-compiling pass. */ case '\\': tempptr = ptr; c = check_escape(&ptr, errorptr, *brackets, options, false); /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values are arranged to be the negation of the corresponding OP_values. For the back references, the values are ESC_REF plus the reference number. Only back references and those types that consume a character may be repeated. We can test for values between ESC_b and ESC_Z for the latter; this may have to change if any new ones are ever created. */ if (c < 0) { if (-c == ESC_Q) /* Handle start of quoted string */ { if (ptr[1] == '\\' && ptr[2] == 'E') ptr += 2; /* avoid empty string */ else inescq = true; continue; } /* For metasequences that actually match a character, we disable the setting of a first character if it hasn't already been set. */ if (firstbyte == REQ_UNSET && -c > ESC_b && -c < ESC_Z) firstbyte = REQ_NONE; /* Set values to reset to if this is followed by a zero repeat. */ zerofirstbyte = firstbyte; zeroreqbyte = reqbyte; /* Back references are handled specially */ if (-c >= ESC_REF) { int number = -c - ESC_REF; previous = code; *code++ = OP_REF; PUT2INC(code, 0, number); } else { previous = (-c > ESC_b && -c < ESC_Z)? code : NULL; *code++ = static_cast(-c); } continue; } /* Data character: reset and fall through */ ptr = tempptr; c = '\\'; /* Handle a run of data characters until a metacharacter is encountered. The first character is guaranteed not to be whitespace or # when the extended flag is set. */ NORMAL_CHAR: default: previous = code; *code = OP_CHARS; code += 2; length = 0; do { /* If in \Q...\E, check for the end; if not, we always have a literal */ if (inescq) { if (c == '\\' && ptr[1] == 'E') { inescq = false; ptr++; } else { *code++ = static_cast(c); length++; } continue; } /* Skip white space and comments for /x patterns */ if ((options & PCRE_EXTENDED) != 0) { if ((cd->ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != NEWLINE) ; if (c == 0) break; continue; } } /* Backslash may introduce a data char or a metacharacter. Escaped items are checked for validity in the pre-compiling pass. Stop the string before a metaitem. */ if (c == '\\') { tempptr = ptr; c = check_escape(&ptr, errorptr, *brackets, options, false); if (c < 0) { ptr = tempptr; break; } /* If a character is > 127 in UTF-8 mode, we have to turn it into two or more bytes in the UTF-8 encoding. */ } /* Ordinary character or single-char escape */ *code++ = static_cast(c); length++; } /* This "while" is the end of the "do" above. */ while (length < MAXLIT && (cd->ctypes[c = *(++ptr)] & ctype_meta) == 0); /* Update the first and last requirements. These are always bytes, even in UTF-8 mode. However, there is a special case to be considered when there are only one or two characters. Because this gets messy in UTF-8 mode, the code is kept separate. When we get here "length" contains the number of bytes. */ /* This is the code for non-UTF-8 operation, either without UTF-8 support, or when UTF-8 is not enabled. */ { /* firstbyte was not previously set; take it from this string */ if (firstbyte == REQ_UNSET) { if (length == 1) { zerofirstbyte = REQ_NONE; firstbyte = previous[2] | req_caseopt; zeroreqbyte = reqbyte; } else { zerofirstbyte = firstbyte = previous[2] | req_caseopt; zeroreqbyte = (length > 2)? (code[-2] | req_caseopt | cd->req_varyopt) : reqbyte; reqbyte = code[-1] | req_caseopt | cd->req_varyopt; } } /* firstbyte was previously set */ else { zerofirstbyte = firstbyte; zeroreqbyte = (length == 1)? reqbyte : code[-2] | req_caseopt | cd->req_varyopt; reqbyte = code[-1] | req_caseopt | cd->req_varyopt; } } /* Set the length in the data vector, and advance to the next state. */ previous[1] = static_cast(length); if (length < MAXLIT) ptr--; break; } } /* end of big loop */ /* Control never reaches here by falling through, only by a goto for all the error states. Pass back the position in the pattern so that it can be displayed to the user for diagnosing the error. */ FAILED: *ptrptr = ptr; return false; } /************************************************* * Compile sequence of alternatives * *************************************************/ /* On entry, ptr is pointing past the bracket character, but on return it points to the closing bracket, or vertical bar, or end of string. The code variable is pointing at the byte into which the BRA operator has been stored. If the ims options are changed at the start (for a (?ims: group) or during any branch, we need to insert an OP_OPT item at the start of every following branch to ensure they get set correctly at run time, and also pass the new options into every subsequent branch compile. Argument: options option bits, including any changes for this subpattern oldims previous settings of ims option bits brackets -> int containing the number of extracting brackets used codeptr -> the address of the current code pointer ptrptr -> the address of the current pattern pointer errorptr -> pointer to error message lookbehind true if this is a lookbehind assertion skipbytes skip this many bytes at start (for OP_COND, OP_BRANUMBER) firstbyteptr place to put the first required character, or a negative number reqbyteptr place to put the last required character, or a negative number bcptr pointer to the chain of currently open branches cd points to the data block with tables pointers etc. Returns: true on success */ static bool compile_regex(int options, int oldims, int *brackets, uschar **codeptr, const uschar **ptrptr, const char **errorptr, bool lookbehind, int skipbytes, int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, compile_data *cd) { const uschar *ptr = *ptrptr; uschar *code = *codeptr; uschar *last_branch = code; uschar *start_bracket = code; uschar *reverse_count = NULL; int firstbyte, reqbyte; int branchfirstbyte, branchreqbyte; branch_chain bc; bc.outer = bcptr; bc.current = code; firstbyte = reqbyte = REQ_UNSET; /* Offset is set zero to mark that this bracket is still open */ PUT(code, 1, 0); code += 1 + LINK_SIZE + skipbytes; /* Loop for each alternative branch */ for (;!MuxAlarm.bAlarmed;) { /* Handle a change of ims options at the start of the branch */ if ((options & PCRE_IMS) != oldims) { *code++ = OP_OPT; *code++ = static_cast(options & PCRE_IMS); } /* Set up dummy OP_REVERSE if lookbehind assertion */ if (lookbehind) { *code++ = OP_REVERSE; reverse_count = code; PUTINC(code, 0, 0); } /* Now compile the branch */ if (!compile_branch(&options, brackets, &code, &ptr, errorptr, &branchfirstbyte, &branchreqbyte, &bc, cd)) { *ptrptr = ptr; return false; } /* If this is the first branch, the firstbyte and reqbyte values for the branch become the values for the regex. */ if (*last_branch != OP_ALT) { firstbyte = branchfirstbyte; reqbyte = branchreqbyte; } /* If this is not the first branch, the first char and reqbyte have to match the values from all the previous branches, except that if the previous value for reqbyte didn't have REQ_VARY set, it can still match, and we set REQ_VARY for the regex. */ else { /* If we previously had a firstbyte, but it doesn't match the new branch, we have to abandon the firstbyte for the regex, but if there was previously no reqbyte, it takes on the value of the old firstbyte. */ if (firstbyte >= 0 && firstbyte != branchfirstbyte) { if (reqbyte < 0) reqbyte = firstbyte; firstbyte = REQ_NONE; } /* If we (now or from before) have no firstbyte, a firstbyte from the branch becomes a reqbyte if there isn't a branch reqbyte. */ if (firstbyte < 0 && branchfirstbyte >= 0 && branchreqbyte < 0) branchreqbyte = branchfirstbyte; /* Now ensure that the reqbytes match */ if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY)) reqbyte = REQ_NONE; else reqbyte |= branchreqbyte; /* To "or" REQ_VARY */ } /* If lookbehind, check that this branch matches a fixed-length string, and put the length into the OP_REVERSE item. Temporarily mark the end of the branch with OP_END. */ if (lookbehind) { int length; *code = OP_END; length = find_fixedlength(last_branch, options); DPRINTF(("fixed length = %d\n", length)); if (length < 0) { *errorptr = (length == -2)? ERR36 : ERR25; *ptrptr = ptr; return false; } PUT(reverse_count, 0, length); } /* Reached end of expression, either ')' or end of pattern. Go back through the alternative branches and reverse the chain of offsets, with the field in the BRA item now becoming an offset to the first alternative. If there are no alternatives, it points to the end of the group. The length in the terminating ket is always the length of the whole bracketed item. If any of the ims options were changed inside the group, compile a resetting op-code following, except at the very end of the pattern. Return leaving the pointer at the terminating char. */ if (*ptr != '|') { int length = code - last_branch; do { int prev_length = GET(last_branch, 1); PUT(last_branch, 1, length); length = prev_length; last_branch -= length; } while (length > 0); /* Fill in the ket */ *code = OP_KET; PUT(code, 1, code - start_bracket); code += 1 + LINK_SIZE; /* Resetting option if needed */ if ((options & PCRE_IMS) != oldims && *ptr == ')') { *code++ = OP_OPT; *code++ = static_cast(oldims); } /* Set values to pass back */ *codeptr = code; *ptrptr = ptr; *firstbyteptr = firstbyte; *reqbyteptr = reqbyte; return true; } /* Another branch follows; insert an "or" node. Its length field points back to the previous branch while the bracket remains open. At the end the chain is reversed. It's done like this so that the start of the bracket has a zero offset until it is closed, making it possible to detect recursion. */ *code = OP_ALT; PUT(code, 1, code - last_branch); bc.current = last_branch = code; code += 1 + LINK_SIZE; ptr++; } return false; } /************************************************* * Check for anchored expression * *************************************************/ /* Try to find out if this is an anchored regular expression. Consider each alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then it's anchored. However, if this is a multiline pattern, then only OP_SOD counts, since OP_CIRC can match in the middle. We can also consider a regex to be anchored if OP_SOM starts all its branches. This is the code for \G, which means "match at start of match position, taking into account the match offset". A branch is also implicitly anchored if it starts with .* and DOTALL is set, because that will try the rest of the pattern at all possible matching points, so there is no point trying again.... er .... .... except when the .* appears inside capturing parentheses, and there is a subsequent back reference to those parentheses. We haven't enough information to catch that case precisely. At first, the best we could do was to detect when .* was in capturing brackets and the highest back reference was greater than or equal to that level. However, by keeping a bitmap of the first 31 back references, we can catch some of the more common cases more precisely. Arguments: code points to start of expression (the bracket) options points to the options setting bracket_map a bitmap of which brackets we are inside while testing; this handles up to substring 31; after that we just have to take the less precise approach backref_map the back reference bitmap Returns: true or false */ static bool is_anchored(register const uschar *code, int *options, unsigned int bracket_map, unsigned int backref_map) { do { const uschar *scode = first_significant_code(code + 1+LINK_SIZE, options, PCRE_MULTILINE); register int op = *scode; /* Capturing brackets */ if (op > OP_BRA) { int new_map; op -= OP_BRA; if (op > EXTRACT_BASIC_MAX) op = GET2(scode, 2+LINK_SIZE); new_map = bracket_map | ((op < 32)? (1 << op) : 1); if (!is_anchored(scode, options, new_map, backref_map)) return false; } /* Other brackets */ else if (op == OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) { if (!is_anchored(scode, options, bracket_map, backref_map)) return false; } /* .* is not anchored unless DOTALL is set and it isn't in brackets that are or may be referenced. */ else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) && (*options & PCRE_DOTALL) != 0) { if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return false; } /* Check for explicit anchoring */ else if (op != OP_SOD && op != OP_SOM && ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC)) return false; code += GET(code, 1); } while (*code == OP_ALT); /* Loop for each alternative */ return true; } /************************************************* * Check for starting with ^ or .* * *************************************************/ /* This is called to find out if every branch starts with ^ or .* so that "first char" processing can be done to speed things up in multiline matching and for non-DOTALL patterns that start with .* (which must start at the beginning or after \n). As in the case of is_anchored() (see above), we have to take account of back references to capturing brackets that contain .* because in that case we can't make the assumption. Arguments: code points to start of expression (the bracket) bracket_map a bitmap of which brackets we are inside while testing; this handles up to substring 31; after that we just have to take the less precise approach backref_map the back reference bitmap Returns: true or false */ static bool is_startline(const uschar *code, unsigned int bracket_map, unsigned int backref_map) { do { const uschar *scode = first_significant_code(code + 1+LINK_SIZE, NULL, 0); register int op = *scode; /* Capturing brackets */ if (op > OP_BRA) { int new_map; op -= OP_BRA; if (op > EXTRACT_BASIC_MAX) op = GET2(scode, 2+LINK_SIZE); new_map = bracket_map | ((op < 32)? (1 << op) : 1); if (!is_startline(scode, new_map, backref_map)) return false; } /* Other brackets */ else if (op == OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) { if (!is_startline(scode, bracket_map, backref_map)) return false; } /* .* is not anchored unless DOTALL is set and it isn't in brackets that may be referenced. */ else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) { if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return false; } /* Check for explicit circumflex */ else if (op != OP_CIRC) return false; code += GET(code, 1); } while (*code == OP_ALT); /* Loop for each alternative */ return true; } /************************************************* * Check for asserted fixed first char * *************************************************/ /* During compilation, the "first char" settings from forward assertions are discarded, because they can cause conflicts with actual literals that follow. However, if we end up without a first char setting for an unanchored pattern, it is worth scanning the regex to see if there is an initial asserted first char. If all branches start with the same asserted char, or with a bracket all of whose alternatives start with the same asserted char (recurse ad lib), then we return that char, otherwise -1. Arguments: code points to start of expression (the bracket) options pointer to the options (used to check casing changes) inassert true if in an assertion Returns: -1 or the fixed first char */ static int find_firstassertedchar(const uschar *code, int *options, bool inassert) { register int c = -1; do { int d; const uschar *scode = first_significant_code(code + 1+LINK_SIZE, options, PCRE_CASELESS); register int op = *scode; if (op >= OP_BRA) op = OP_BRA; switch(op) { default: return -1; case OP_BRA: case OP_ASSERT: case OP_ONCE: case OP_COND: if ((d = find_firstassertedchar(scode, options, op == OP_ASSERT)) < 0) return -1; if (c < 0) c = d; else if (c != d) return -1; break; case OP_EXACT: /* Fall through */ scode++; case OP_CHARS: /* Fall through */ scode++; case OP_PLUS: case OP_MINPLUS: if (!inassert) return -1; if (c < 0) { c = scode[1]; if ((*options & PCRE_CASELESS) != 0) c |= REQ_CASELESS; } else if (c != scode[1]) return -1; break; } code += GET(code, 1); } while (*code == OP_ALT); return c; } /************************************************* * Compile a Regular Expression * *************************************************/ /* This function takes a string and returns a pointer to a block of store holding a compiled version of the expression. Arguments: pattern the regular expression options various option bits errorptr pointer to pointer to error text erroroffset ptr offset in pattern where error was detected tables pointer to character tables or NULL Returns: pointer to compiled data block, or NULL on error, with errorptr and erroroffset set */ pcre * pcre_compile(const char *pattern, int options, const char **errorptr, int *erroroffset, const unsigned char *tables) { real_pcre *re; int length = 1 + LINK_SIZE; /* For initial BRA plus length */ int runlength; int c, firstbyte, reqbyte; int bracount = 0; int branch_extra = 0; int branch_newextra; int item_count = -1; int name_count = 0; int max_name_size = 0; bool inescq = false; unsigned int brastackptr = 0; size_t size; uschar *code; const uschar *codestart; const uschar *ptr; compile_data compile_block; int brastack[BRASTACK_SIZE]; uschar bralenstack[BRASTACK_SIZE]; /* We can't pass back an error message if errorptr is NULL; I guess the best we can do is just return NULL. */ if (errorptr == NULL) return NULL; *errorptr = NULL; /* However, we can give a message for this error */ if (erroroffset == NULL) { *errorptr = ERR16; return NULL; } *erroroffset = 0; /* Can't support UTF8 unless PCRE has been compiled to include the code. */ if ((options & PCRE_UTF8) != 0) { *errorptr = ERR32; return NULL; } if ((options & ~PUBLIC_OPTIONS) != 0) { *errorptr = ERR17; return NULL; } /* Set up pointers to the individual character tables */ if (tables == NULL) tables = pcre_default_tables; compile_block.lcc = tables + lcc_offset; compile_block.fcc = tables + fcc_offset; compile_block.cbits = tables + cbits_offset; compile_block.ctypes = tables + ctypes_offset; /* Maximum back reference and backref bitmap. This is updated for numeric references during the first pass, but for named references during the actual compile pass. The bitmap records up to 31 back references to help in deciding whether (.*) can be treated as anchored or not. */ compile_block.top_backref = 0; compile_block.backref_map = 0; /* Reflect pattern for debugging output */ DPRINTF(("------------------------------------------------------------------\n")); DPRINTF(("%s\n", pattern)); /* The first thing to do is to make a pass over the pattern to compute the amount of store required to hold the compiled code. This does not have to be perfect as long as errors are overestimates. At the same time we can detect any flag settings right at the start, and extract them. Make an attempt to correct for any counted white space if an "extended" flag setting appears late in the pattern. We can't be so clever for #-comments. */ ptr = (const uschar *)(pattern - 1); while ((c = *(++ptr)) != 0) { int min, max; #if defined(WIN32) && (_MSC_VER == 1200) && defined(_M_IX86) && !defined(__INTEL_COMPILER) // The addition of 'volatile' works around a bug in Version 12.0 of // Microsoft's Visual C/C++ compiler (part of Visual Studio 6.0). Without // volatile, class_optcount is calculated properly, but the compiler // clobbers the EAX register before tests it as class_optcount. // // This is not a problem with the Intel Compiler. // volatile int class_optcount; #else int class_optcount; #endif int bracket_length; int duplength; /* If we are inside a \Q...\E sequence, all chars are literal */ if (inescq) goto NORMAL_CHAR; /* Otherwise, first check for ignored whitespace and comments */ if ((options & PCRE_EXTENDED) != 0) { if ((compile_block.ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != NEWLINE) ; if (c == 0) break; continue; } } item_count++; /* Is zero for the first non-comment item */ switch(c) { /* A backslashed item may be an escaped "normal" character or a character type. For a "normal" character, put the pointers and character back so that tests for whitespace etc. in the input are done correctly. */ case '\\': { const uschar *save_ptr = ptr; c = check_escape(&ptr, errorptr, bracount, options, false); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if (c >= 0) { ptr = save_ptr; c = '\\'; goto NORMAL_CHAR; } } /* If \Q, enter "literal" mode */ if (-c == ESC_Q) { inescq = true; continue; } /* Other escapes need one byte, and are of length one for repeats */ length++; /* A back reference needs an additional 2 bytes, plus either one or 5 bytes for a repeat. We also need to keep the value of the highest back reference. */ if (c <= -ESC_REF) { int refnum = -c - ESC_REF; compile_block.backref_map |= (refnum < 32)? (1 << refnum) : 1; if (refnum > compile_block.top_backref) compile_block.top_backref = refnum; length += 2; /* For single back reference */ if (ptr[1] == '{' && is_counted_repeat(ptr+2)) { ptr = read_repeat_counts(ptr+2, &min, &max, errorptr); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if ((min == 0 && (max == 1 || max == -1)) || (min == 1 && max == -1)) length++; else length += 5; if (ptr[1] == '?') ptr++; } } continue; case '^': /* Single-byte metacharacters */ case '.': case '$': length++; continue; case '*': /* These repeats won't be after brackets; */ case '+': /* those are handled separately */ case '?': length++; goto POSESSIVE; /* A few lines below */ /* This covers the cases of braced repeats after a single char, metachar, class, or back reference. */ case '{': if (!is_counted_repeat(ptr+1)) goto NORMAL_CHAR; ptr = read_repeat_counts(ptr+1, &min, &max, errorptr); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; /* These special cases just insert one extra opcode */ if ((min == 0 && (max == 1 || max == -1)) || (min == 1 && max == -1)) length++; /* These cases might insert additional copies of a preceding character. */ else { /* Not UTF-8 mode: all characters are one byte */ { if (min != 1) { length--; /* Uncount the original char or metachar */ if (min > 0) length += 4; } length += (max > 0)? 4 : 2; } } if (ptr[1] == '?') ptr++; /* Needs no extra length */ POSESSIVE: /* Test for possessive quantifier */ if (ptr[1] == '+') { ptr++; length += 2 + 2*LINK_SIZE; /* Allow for atomic brackets */ } continue; /* An alternation contains an offset to the next branch or ket. If any ims options changed in the previous branch(es), and/or if we are in a lookbehind assertion, extra space will be needed at the start of the branch. This is handled by branch_extra. */ case '|': length += 1 + LINK_SIZE + branch_extra; continue; /* A character class uses 33 characters provided that all the character values are less than 256. Otherwise, it uses a bit map for low valued characters, and individual items for others. Don't worry about character types that aren't allowed in classes - they'll get picked up during the compile. A character class that contains only one single-byte character uses 2 or 3 bytes, depending on whether it is negated or not. Notice this where we can. (In UTF-8 mode we can do this only for chars < 128.) */ case '[': class_optcount = 0; if (*(++ptr) == '^') ptr++; /* Written as a "do" so that an initial ']' is taken as data */ if (*ptr != 0) do { /* Inside \Q...\E everything is literal except \E */ if (inescq) { if (*ptr != '\\' || ptr[1] != 'E') goto NON_SPECIAL_CHARACTER; inescq = false; ptr += 1; continue; } /* Outside \Q...\E, check for escapes */ if (*ptr == '\\') { int ch = check_escape(&ptr, errorptr, bracount, options, true); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; /* \b is backspace inside a class */ if (-ch == ESC_b) ch = '\b'; /* \Q enters quoting mode */ if (-ch == ESC_Q) { inescq = true; continue; } /* Handle escapes that turn into characters */ if (ch >= 0) { class_optcount++; /* for possible optimization */ } else class_optcount = 10; /* \d, \s etc; make sure > 1 */ } /* Check the syntax for POSIX stuff. The bits we actually handle are checked during the real compile phase. */ else if (*ptr == '[' && check_posix_syntax(ptr, &ptr, &compile_block)) { ptr++; class_optcount = 10; /* Make sure > 1 */ } /* Anything else just increments the possible optimization count. If there are wide characters, we are going to have to use an XCLASS. */ else { NON_SPECIAL_CHARACTER: class_optcount++; } } while (*(++ptr) != 0 && (inescq || *ptr != ']')); /* Concludes "do" above */ if (*ptr == 0) /* Missing terminating ']' */ { *errorptr = ERR6; goto PCRE_ERROR_RETURN; } /* We can optimize when there was only one optimizable character. Repeats for positive and negated single one-byte chars are handled by the general code. Here, we handle repeats for the class opcodes. */ if (class_optcount == 1) length += 3; else { length += 33; /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier, we also need extra for wrapping the whole thing in a sub-pattern. */ if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2)) { ptr = read_repeat_counts(ptr+2, &min, &max, errorptr); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if ((min == 0 && (max == 1 || max == -1)) || (min == 1 && max == -1)) length++; else length += 5; if (ptr[1] == '+') { ptr++; length += 2 + 2*LINK_SIZE; } else if (ptr[1] == '?') ptr++; } } continue; /* Brackets may be genuine groups or special things */ case '(': branch_newextra = 0; bracket_length = 1 + LINK_SIZE; /* Handle special forms of bracket, which all start (? */ if (ptr[1] == '?') { int set, unset; int *optset; switch (c = ptr[2]) { /* Skip over comments entirely */ case '#': ptr += 3; while (*ptr != 0 && *ptr != ')') ptr++; if (*ptr == 0) { *errorptr = ERR18; goto PCRE_ERROR_RETURN; } continue; /* Non-referencing groups and lookaheads just move the pointer on, and then behave like a non-special bracket, except that they don't increment the count of extracting brackets. Ditto for the "once only" bracket, which is in Perl from version 5.005. */ case ':': case '=': case '!': case '>': ptr += 2; break; /* (?R) specifies a recursive call to the regex, which is an extension to provide the facility which can be obtained by (?p{perl-code}) in Perl 5.6. In Perl 5.8 this has become (??{perl-code}). From PCRE 4.00, items such as (?3) specify subroutine-like "calls" to the appropriate numbered brackets. This includes both recursive and non-recursive calls. (?R) is now synonymous with (?0). */ case 'R': ptr++; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ptr += 2; if (c != 'R') while ((digitab[*(++ptr)] & ctype_digit) != 0); if (*ptr != ')') { *errorptr = ERR29; goto PCRE_ERROR_RETURN; } length += 1 + LINK_SIZE; /* If this item is quantified, it will get wrapped inside brackets so as to use the code for quantified brackets. We jump down and use the code that handles this for real brackets. */ if (ptr[1] == '+' || ptr[1] == '*' || ptr[1] == '?' || ptr[1] == '{') { length += 2 + 2 * LINK_SIZE; /* to make bracketed */ duplength = 5 + 3 * LINK_SIZE; goto HANDLE_QUANTIFIED_BRACKETS; } continue; /* (?C) is an extension which provides "callout" - to provide a bit of the functionality of the Perl (?{...}) feature. An optional number may follow (default is zero). */ case 'C': ptr += 2; while ((digitab[*(++ptr)] & ctype_digit) != 0); if (*ptr != ')') { *errorptr = ERR39; goto PCRE_ERROR_RETURN; } length += 2; continue; /* Named subpatterns are an extension copied from Python */ case 'P': ptr += 3; if (*ptr == '<') { const uschar *p; /* Don't amalgamate; some compilers */ p = ++ptr; /* grumble at autoincrement in declaration */ while ((compile_block.ctypes[*ptr] & ctype_word) != 0) ptr++; if (*ptr != '>') { *errorptr = ERR42; goto PCRE_ERROR_RETURN; } name_count++; if (ptr - p > max_name_size) max_name_size = (ptr - p); break; } if (*ptr == '=' || *ptr == '>') { while ((compile_block.ctypes[*(++ptr)] & ctype_word) != 0); if (*ptr != ')') { *errorptr = ERR42; goto PCRE_ERROR_RETURN; } break; } /* Unknown character after (?P */ *errorptr = ERR41; goto PCRE_ERROR_RETURN; /* Lookbehinds are in Perl from version 5.005 */ case '<': ptr += 3; if (*ptr == '=' || *ptr == '!') { branch_newextra = 1 + LINK_SIZE; length += 1 + LINK_SIZE; /* For the first branch */ break; } *errorptr = ERR24; goto PCRE_ERROR_RETURN; /* Conditionals are in Perl from version 5.005. The bracket must either be followed by a number (for bracket reference) or by an assertion group, or (a PCRE extension) by 'R' for a recursion test. */ case '(': if (ptr[3] == 'R' && ptr[4] == ')') { ptr += 4; length += 3; } else if ((digitab[ptr[3]] & ctype_digit) != 0) { ptr += 4; length += 3; while ((digitab[*ptr] & ctype_digit) != 0) ptr++; if (*ptr != ')') { *errorptr = ERR26; goto PCRE_ERROR_RETURN; } } else /* An assertion must follow */ { ptr++; /* Can treat like ':' as far as spacing is concerned */ if (ptr[2] != '?' || (ptr[3] != '=' && ptr[3] != '!' && ptr[3] != '<') ) { ptr += 2; /* To get right offset in message */ *errorptr = ERR28; goto PCRE_ERROR_RETURN; } } break; /* Else loop checking valid options until ) is met. Anything else is an error. If we are without any brackets, i.e. at top level, the settings act as if specified in the options, so massage the options immediately. This is for backward compatibility with Perl 5.004. */ default: set = unset = 0; optset = &set; ptr += 2; for (;; ptr++) { c = *ptr; switch (c) { case 'i': *optset |= PCRE_CASELESS; continue; case 'm': *optset |= PCRE_MULTILINE; continue; case 's': *optset |= PCRE_DOTALL; continue; case 'x': *optset |= PCRE_EXTENDED; continue; case 'X': *optset |= PCRE_EXTRA; continue; case 'U': *optset |= PCRE_UNGREEDY; continue; case '-': optset = &unset; continue; /* A termination by ')' indicates an options-setting-only item; if this is at the very start of the pattern (indicated by item_count being zero), we use it to set the global options. This is helpful when analyzing the pattern for first characters, etc. Otherwise nothing is done here and it is handled during the compiling process. [Historical note: Up to Perl 5.8, options settings at top level were always global settings, wherever they appeared in the pattern. That is, they were equivalent to an external setting. From 5.8 onwards, they apply only to what follows (which is what you might expect).] */ case ')': if (item_count == 0) { options = (options | set) & (~unset); set = unset = 0; /* To save length */ item_count--; /* To allow for several */ } /* Fall through */ /* A termination by ':' indicates the start of a nested group with the given options set. This is again handled at compile time, but we must allow for compiled space if any of the ims options are set. We also have to allow for resetting space at the end of the group, which is why 4 is added to the length and not just 2. If there are several changes of options within the same group, this will lead to an over-estimate on the length, but this shouldn't matter very much. We also have to allow for resetting options at the start of any alternations, which we do by setting branch_newextra to 2. Finally, we record whether the case-dependent flag ever changes within the regex. This is used by the "required character" code. */ case ':': if (((set|unset) & PCRE_IMS) != 0) { length += 4; branch_newextra = 2; if (((set|unset) & PCRE_CASELESS) != 0) options |= PCRE_ICHANGED; } goto END_OPTIONS; /* Unrecognized option character */ default: *errorptr = ERR12; goto PCRE_ERROR_RETURN; } } /* If we hit a closing bracket, that's it - this is a freestanding option-setting. We need to ensure that branch_extra is updated if necessary. The only values branch_newextra can have here are 0 or 2. If the value is 2, then branch_extra must either be 2 or 5, depending on whether this is a lookbehind group or not. */ END_OPTIONS: if (c == ')') { if (branch_newextra == 2 && (branch_extra == 0 || branch_extra == 1+LINK_SIZE)) branch_extra += branch_newextra; continue; } /* If options were terminated by ':' control comes here. Fall through to handle the group below. */ } } /* Extracting brackets must be counted so we can process escapes in a Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need an additional 3 bytes of store per extracting bracket. However, if PCRE_NO_AUTO)CAPTURE is set, unadorned brackets become non-capturing, so we must leave the count alone (it will aways be zero). */ else if ((options & PCRE_NO_AUTO_CAPTURE) == 0) { bracount++; if (bracount > EXTRACT_BASIC_MAX) bracket_length += 3; } /* Save length for computing whole length at end if there's a repeat that requires duplication of the group. Also save the current value of branch_extra, and start the new group with the new value. If non-zero, this will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ if (brastackptr >= sizeof(brastack)/sizeof(int)) { *errorptr = ERR19; goto PCRE_ERROR_RETURN; } bralenstack[brastackptr] = static_cast(branch_extra); branch_extra = branch_newextra; brastack[brastackptr++] = length; length += bracket_length; continue; /* Handle ket. Look for subsequent max/min; for certain sets of values we have to replicate this bracket up to that many times. If brastackptr is 0 this is an unmatched bracket which will generate an error, but take care not to try to access brastack[-1] when computing the length and restoring the branch_extra value. */ case ')': length += 1 + LINK_SIZE; if (brastackptr > 0) { duplength = length - brastack[--brastackptr]; branch_extra = bralenstack[brastackptr]; } else duplength = 0; /* The following code is also used when a recursion such as (?3) is followed by a quantifier, because in that case, it has to be wrapped inside brackets so that the quantifier works. The value of duplength must be set before arrival. */ HANDLE_QUANTIFIED_BRACKETS: /* Leave ptr at the final char; for read_repeat_counts this happens automatically; for the others we need an increment. */ if ((c = ptr[1]) == '{' && is_counted_repeat(ptr+2)) { ptr = read_repeat_counts(ptr+2, &min, &max, errorptr); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; } else if (c == '*') { min = 0; max = -1; ptr++; } else if (c == '+') { min = 1; max = -1; ptr++; } else if (c == '?') { min = 0; max = 1; ptr++; } else { min = 1; max = 1; } /* If the minimum is zero, we have to allow for an OP_BRAZERO before the group, and if the maximum is greater than zero, we have to replicate maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting bracket set. */ if (min == 0) { length++; if (max > 0) length += (max - 1) * (duplength + 3 + 2*LINK_SIZE); } /* When the minimum is greater than zero, we have to replicate up to minval-1 times, with no additions required in the copies. Then, if there is a limited maximum we have to replicate up to maxval-1 times allowing for a BRAZERO item before each optional copy and nesting brackets for all but one of the optional copies. */ else { length += (min - 1) * duplength; if (max > min) /* Need this test as max=-1 means no limit */ length += (max - min) * (duplength + 3 + 2*LINK_SIZE) - (2 + 2*LINK_SIZE); } /* Allow space for once brackets for "possessive quantifier" */ if (ptr[1] == '+') { ptr++; length += 2 + 2*LINK_SIZE; } continue; /* Non-special character. For a run of such characters the length required is the number of characters + 2, except that the maximum run length is MAXLIT. We won't get a skipped space or a non-data escape or the start of a # comment as the first character, so the length can't be zero. */ NORMAL_CHAR: default: length += 2; runlength = 0; do { /* If in a \Q...\E sequence, check for end; otherwise it's a literal */ if (inescq) { if (c == '\\' && ptr[1] == 'E') { inescq = false; ptr++; } else runlength++; continue; } /* Skip whitespace and comments for /x */ if ((options & PCRE_EXTENDED) != 0) { if ((compile_block.ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != NEWLINE) ; continue; } } /* Backslash may introduce a data char or a metacharacter; stop the string before the latter. */ if (c == '\\') { const uschar *saveptr = ptr; c = check_escape(&ptr, errorptr, bracount, options, false); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if (c < 0) { ptr = saveptr; break; } /* In UTF-8 mode, add on the number of additional bytes needed to encode this character, and save the total length in case this is a final char that is repeated. */ } /* Ordinary character or single-char escape */ runlength++; } /* This "while" is the end of the "do" above. */ while (runlength < MAXLIT && (compile_block.ctypes[c = *(++ptr)] & ctype_meta) == 0); /* If we hit a meta-character, back off to point to it */ if (runlength < MAXLIT) ptr--; /* If the last char in the string is a UTF-8 multibyte character, we must set lastcharlength correctly. If it was specified as an escape, this will already have been done above. However, we also have to support in-line UTF-8 characters, so check backwards from where we are. */ length += runlength; continue; } } length += 2 + LINK_SIZE; /* For final KET and END */ if (length > MAX_PATTERN_SIZE) { *errorptr = ERR20; return NULL; } /* Compute the size of data block needed and get it, either from malloc or externally provided function. */ size = length + sizeof(real_pcre) + name_count * (max_name_size + 3); re = static_cast(malloc(size)); if (re == NULL) { *errorptr = ERR21; return NULL; } /* Put in the magic number, and save the size, options, and table pointer */ re->magic_number = MAGIC_NUMBER; re->size = size; re->options = options; re->tables = tables; re->name_entry_size = static_cast(max_name_size + 3); re->name_count = static_cast(name_count); /* The starting points of the name/number translation table and of the code are passed around in the compile data block. */ compile_block.names_found = 0; compile_block.name_entry_size = max_name_size + 3; compile_block.name_table = (uschar *)re + sizeof(real_pcre); codestart = compile_block.name_table + re->name_entry_size * re->name_count; compile_block.start_code = codestart; compile_block.req_varyopt = 0; /* Set up a starting, non-extracting bracket, then compile the expression. On error, *errorptr will be set non-NULL, so we don't need to look at the result of the function here. */ ptr = (const uschar *)pattern; code = (uschar *)codestart; *code = OP_BRA; bracount = 0; (void)compile_regex(options, options & PCRE_IMS, &bracount, &code, &ptr, errorptr, false, 0, &firstbyte, &reqbyte, NULL, &compile_block); re->top_bracket = static_cast(bracount); re->top_backref = static_cast(compile_block.top_backref); /* If not reached end of pattern on success, there's an excess bracket. */ if (*errorptr == NULL && *ptr != 0) *errorptr = ERR22; /* Fill in the terminating state and check for disastrous overflow, but if debugging, leave the test till after things are printed out. */ *code++ = OP_END; if (code - codestart > length) *errorptr = ERR23; /* Give an error if there's back reference to a non-existent capturing subpattern. */ if (re->top_backref > re->top_bracket) *errorptr = ERR15; /* Failed to compile, or error while post-processing */ if (*errorptr != NULL) { free(re); PCRE_ERROR_RETURN: *erroroffset = ptr - (const uschar *)pattern; return NULL; } /* If the anchored option was not passed, set the flag if we can determine that the pattern is anchored by virtue of ^ characters or \A or anything else (such as starting with .* when DOTALL is set). Otherwise, if we know what the first character has to be, save it, because that speeds up unanchored matches no end. If not, see if we can set the PCRE_STARTLINE flag. This is helpful for multiline matches when all branches start with ^. and also when all branches start with .* for non-DOTALL matches. */ if ((options & PCRE_ANCHORED) == 0) { int temp_options = options; if (is_anchored(codestart, &temp_options, 0, compile_block.backref_map)) re->options |= PCRE_ANCHORED; else { if (firstbyte < 0) firstbyte = find_firstassertedchar(codestart, &temp_options, false); if (firstbyte >= 0) /* Remove caseless flag for non-caseable chars */ { int ch = firstbyte & 255; re->first_byte = static_cast(((firstbyte & REQ_CASELESS) != 0 && compile_block.fcc[ch] == ch)? ch : firstbyte); re->options |= PCRE_FIRSTSET; } else if (is_startline(codestart, 0, compile_block.backref_map)) re->options |= PCRE_STARTLINE; } } /* For an anchored pattern, we use the "required byte" only if it follows a variable length item in the regex. Remove the caseless flag for non-caseable chars. */ if (reqbyte >= 0 && ((re->options & PCRE_ANCHORED) == 0 || (reqbyte & REQ_VARY) != 0)) { int ch = reqbyte & 255; re->req_byte = static_cast(((reqbyte & REQ_CASELESS) != 0 && compile_block.fcc[ch] == ch)? (reqbyte & ~REQ_CASELESS) : reqbyte); re->options |= PCRE_REQCHSET; } return (pcre *)re; } /************************************************* * Match a back-reference * *************************************************/ /* If a back reference hasn't been set, the length that is passed is greater than the number of characters left in the string, so the match fails. Arguments: offset index into the offset vector eptr points into the subject length length to be matched md points to match data block ims the ims flags Returns: true if matched */ static bool match_ref ( int offset, register const uschar *eptr, int length, match_data *md, unsigned long int ims ) { const uschar *p = md->start_subject + md->offset_vector[offset]; /* Always fail if not enough characters left */ if (length > md->end_subject - eptr) { return false; } /* Separate the caselesss case for speed */ if ((ims & PCRE_CASELESS) != 0) { while (length-- > 0) { if (md->lcc[*p] != md->lcc[*eptr]) { p++; eptr++; return false; } p++; eptr++; } } else { while (length-- > 0) { if (*p != *eptr) { p++; eptr++; return false; } p++; eptr++; } } return true; } /*************************************************************************** **************************************************************************** RECURSION IN THE match() FUNCTION The match() function is highly recursive. Some regular expressions can cause it to recurse thousands of times. I was writing for Unix, so I just let it call itself recursively. This uses the stack for saving everything that has to be saved for a recursive call. On Unix, the stack can be large, and this works fine. It turns out that on non-Unix systems there are problems with programs that use a lot of stack. (This despite the fact that every last chip has oodles of memory these days, and techniques for extending the stack have been known for decades.) So.... There is a fudge, triggered by defining NO_RECURSE, which avoids recursive calls by keeping local variables that need to be preserved in blocks of memory obtained from malloc instead instead of on the stack. Macros are used to achieve this so that the actual code doesn't look very different to what it always used to. **************************************************************************** ***************************************************************************/ /* These versions of the macros use the stack, as normal */ #define REGISTER register #define RMATCH(rx,ra,rb,rc,rd,re,rf,rg) rx = match(ra,rb,rc,rd,re,rf,rg) #define RRETURN(ra) return ra /*************************************************************************** ***************************************************************************/ /************************************************* * Match from current position * *************************************************/ /* On entry ecode points to the first opcode, and eptr to the first character in the subject string, while eptrb holds the value of eptr at the start of the last bracketed group - used for breaking infinite loops matching zero-length strings. This function is called recursively in many circumstances. Whenever it returns a negative (error) response, the outer incarnation must also return the same response. Performance note: It might be tempting to extract commonly used fields from the md structure (e.g. utf8, end_subject) into individual variables to improve performance. Tests using gcc on a SPARC disproved this; in the first case, it made performance worse. Arguments: eptr pointer in subject ecode position in code offset_top current top pointer md pointer to "static" info for the match ims current /i, /m, and /s options eptrb pointer to chain of blocks containing eptr at start of brackets - for testing for empty matches flags can contain match_condassert - this is an assertion condition match_isgroup - this is the start of a bracketed group Returns: MATCH_MATCH if matched ) these values are >= 0 MATCH_NOMATCH if failed to match ) a negative PCRE_ERROR_xxx value if aborted by an error condition (e.g. stopped by recursion limit) */ static int match(REGISTER const uschar *eptr, REGISTER const uschar *ecode, int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb, int flags) { /* These variables do not need to be preserved over recursion in this function, so they can be ordinary variables in all cases. Mark them with "register" because they are used a lot in loops. */ register int rrc; /* Returns from recursive calls */ register int i; /* Used for loops not involving calls to RMATCH() */ register int c; /* Character values not kept over RMATCH() calls */ /* When recursion is not being used, all "local" variables that have to be preserved over calls to RMATCH() are part of a "frame" which is obtained from heap storage. Set up the top-level frame here; others are obtained from the heap whenever RMATCH() does a "recursion". See the macro definitions above. */ #define fi i #define fc c const uschar *callpat; /* Many of these variables are used ony */ /* small blocks of the code. My normal */ const uschar *data; /* style of coding would have declared */ /* them within each of those blocks. */ const uschar *next; /* However, in order to accommodate the */ const uschar *pp; /* version of this code that uses an */ const uschar *prev; /* external "stack" implemented on the */ const uschar *saved_eptr; /* heap, it is easier to declare them */ /* all here, so the declarations can */ recursion_info new_recursive; /* be cut out in a block. The only */ /* declarations within blocks below are */ bool cur_is_word; /* for variables that do not have to */ bool condition; /* be preserved over a recursive call */ bool minimize; /* to RMATCH(). */ bool prev_is_word; unsigned long int original_ims; int ctype; int length; int max; int min; int number; int offset; int op; int save_capture_last; int save_offset1, save_offset2, save_offset3; int stacksave[REC_STACK_SAVE_MAX]; eptrblock newptrb; /* OK, now we can get on with the real code of the function. Recursion is specified by the macros RMATCH and RRETURN. When NO_RECURSE is *not* defined, these just turn into a recursive call to match() and a "return", respectively. However, RMATCH isn't like a function call because it's quite a complicated macro. It has to be used in one particular way. This shouldn't, however, impact performance when true recursion is being used. */ if (md->match_call_count++ >= md->match_limit) RRETURN(PCRE_ERROR_MATCHLIMIT); original_ims = ims; /* Save for resetting on ')' */ /* At the start of a bracketed group, add the current subject pointer to the stack of such pointers, to be re-instated at the end of the group when we hit the closing ket. When match() is called in other circumstances, we don't add to this stack. */ if ((flags & match_isgroup) != 0) { newptrb.epb_prev = eptrb; newptrb.epb_saved_eptr = eptr; eptrb = &newptrb; } /* Now start processing the operations. */ for (;!MuxAlarm.bAlarmed;) { op = *ecode; minimize = false; /* Opening capturing bracket. If there is space in the offset vector, save the current subject position in the working slot at the top of the vector. We mustn't change the current values of the data slot, because they may be set from a previous iteration of this group, and be referred to by a reference inside the group. If the bracket fails to match, we need to restore this value and also the values of the final offsets, in case they were set by a previous iteration of the same bracket. If there isn't enough space in the offset vector, treat this as if it were a non-capturing bracket. Don't worry about setting the flag for the error case here; that is handled in the code for KET. */ if (op > OP_BRA) { number = op - OP_BRA; /* For extended extraction brackets (large number), we have to fish out the number from a dummy opcode at the start. */ if (number > EXTRACT_BASIC_MAX) number = GET2(ecode, 2+LINK_SIZE); offset = number << 1; if (offset < md->offset_max) { save_offset1 = md->offset_vector[offset]; save_offset2 = md->offset_vector[offset+1]; save_offset3 = md->offset_vector[md->offset_end - number]; save_capture_last = md->capture_last; DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3)); md->offset_vector[md->offset_end - number] = eptr - md->start_subject; do { RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, match_isgroup); if (rrc != MATCH_NOMATCH) RRETURN(rrc); md->capture_last = save_capture_last; ecode += GET(ecode, 1); } while (*ecode == OP_ALT); DPRINTF(("bracket %d failed\n", number)); md->offset_vector[offset] = save_offset1; md->offset_vector[offset+1] = save_offset2; md->offset_vector[md->offset_end - number] = save_offset3; RRETURN(MATCH_NOMATCH); } /* Insufficient room for saving captured contents */ else op = OP_BRA; } /* Other types of node can be handled by a switch */ switch(op) { case OP_BRA: /* Non-capturing bracket: optimized */ DPRINTF(("start bracket 0\n")); do { RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, match_isgroup); if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += GET(ecode, 1); } while (*ecode == OP_ALT); DPRINTF(("bracket 0 failed\n")); RRETURN(MATCH_NOMATCH); /* Conditional group: compilation checked that there are no more than two branches. If the condition is false, skipping the first branch takes us past the end if there is only one branch, but that's OK because that is exactly what going to the ket would do. */ case OP_COND: if (ecode[LINK_SIZE+1] == OP_CREF) /* Condition extract or recurse test */ { offset = GET2(ecode, LINK_SIZE+2) << 1; /* Doubled ref number */ condition = (offset == CREF_RECURSE * 2)? (md->recursive != NULL) : (offset < offset_top && md->offset_vector[offset] >= 0); RMATCH(rrc, eptr, ecode + (condition? (LINK_SIZE + 4) : (LINK_SIZE + 1 + GET(ecode, 1))), offset_top, md, ims, eptrb, match_isgroup); RRETURN(rrc); } /* The condition is an assertion. Call match() to evaluate it - setting the final argument true causes it to stop at the end of an assertion. */ else { RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, match_condassert | match_isgroup); if (rrc == MATCH_MATCH) { ecode += 1 + LINK_SIZE + GET(ecode, LINK_SIZE+2); while (*ecode == OP_ALT) ecode += GET(ecode, 1); } else if (rrc != MATCH_NOMATCH) { RRETURN(rrc); /* Need braces because of following else */ } else ecode += GET(ecode, 1); RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, match_isgroup); RRETURN(rrc); } /* Control never reaches here */ /* Skip over conditional reference or large extraction number data if encountered. */ case OP_CREF: case OP_BRANUMBER: ecode += 3; break; /* End of the pattern. If we are in a recursion, we should restore the offsets appropriately and continue from after the call. */ case OP_END: if (md->recursive != NULL && md->recursive->group_num == 0) { recursion_info *rec = md->recursive; DPRINTF(("Hit the end in a (?0) recursion\n")); md->recursive = rec->prevrec; memmove(md->offset_vector, rec->offset_save, rec->saved_max * sizeof(int)); md->start_match = rec->save_start; ims = original_ims; ecode = rec->after_call; break; } /* Otherwise, if PCRE_NOTEMPTY is set, fail if we have matched an empty string - backtracking will then try other alternatives, if any. */ if (md->notempty && eptr == md->start_match) RRETURN(MATCH_NOMATCH); md->end_match_ptr = eptr; /* Record where we ended */ md->end_offset_top = offset_top; /* and how many extracts were taken */ RRETURN(MATCH_MATCH); /* Change option settings */ case OP_OPT: ims = ecode[1]; ecode += 2; DPRINTF(("ims set to %02lx\n", ims)); break; /* Assertion brackets. Check the alternative branches in turn - the matching won't pass the KET for an assertion. If any one branch matches, the assertion is true. Lookbehind assertions have an OP_REVERSE item at the start of each branch to move the current point backwards, so the code at this level is identical to the lookahead case. */ case OP_ASSERT: case OP_ASSERTBACK: do { RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, match_isgroup); if (rrc == MATCH_MATCH) break; if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += GET(ecode, 1); } while (*ecode == OP_ALT); if (*ecode == OP_KET) RRETURN(MATCH_NOMATCH); /* If checking an assertion for a condition, return MATCH_MATCH. */ if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH); /* Continue from after the assertion, updating the offsets high water mark, since extracts may have been taken during the assertion. */ do ecode += GET(ecode,1); while (*ecode == OP_ALT); ecode += 1 + LINK_SIZE; offset_top = md->end_offset_top; continue; /* Negative assertion: all branches must fail to match */ case OP_ASSERT_NOT: case OP_ASSERTBACK_NOT: do { RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, match_isgroup); if (rrc == MATCH_MATCH) RRETURN(MATCH_NOMATCH); if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += GET(ecode,1); } while (*ecode == OP_ALT); if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH); ecode += 1 + LINK_SIZE; continue; /* Move the subject pointer back. This occurs only at the start of each branch of a lookbehind assertion. If we are too close to the start to move back, this match function fails. When working with UTF-8 we move back a number of characters, not bytes. */ case OP_REVERSE: /* No UTF-8 support, or not in UTF-8 mode: count is byte count */ { eptr -= GET(ecode,1); if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH); } /* Skip to next op code */ ecode += 1 + LINK_SIZE; break; /* The callout item calls an external function, if one is provided, passing details of the match so far. This is mainly for debugging, though the function is able to force a failure. */ case OP_CALLOUT: if (pcre_callout != NULL) { pcre_callout_block cb; cb.version = 0; /* Version 0 of the callout block */ cb.callout_number = ecode[1]; cb.offset_vector = md->offset_vector; cb.subject = (const char *)md->start_subject; cb.subject_length = md->end_subject - md->start_subject; cb.start_match = md->start_match - md->start_subject; cb.current_position = eptr - md->start_subject; cb.capture_top = offset_top/2; cb.capture_last = md->capture_last; cb.callout_data = md->callout_data; if ((rrc = (*pcre_callout)(&cb)) > 0) RRETURN(MATCH_NOMATCH); if (rrc < 0) RRETURN(rrc); } ecode += 2; break; /* Recursion either matches the current regex, or some subexpression. The offset data is the offset to the starting bracket from the start of the whole pattern. (This is so that it works from duplicated subpatterns.) If there are any capturing brackets started but not finished, we have to save their starting points and reinstate them after the recursion. However, we don't know how many such there are (offset_top records the completed total) so we just have to save all the potential data. There may be up to 65535 such values, which is too large to put on the stack, but using malloc for small numbers seems expensive. As a compromise, the stack is used when there are no more than REC_STACK_SAVE_MAX values to store; otherwise malloc is used. A problem is what to do if the malloc fails ... there is no way of returning to the top level with an error. Save the top REC_STACK_SAVE_MAX values on the stack, and accept that the rest may be wrong. There are also other values that have to be saved. We use a chained sequence of blocks that actually live on the stack. Thanks to Robin Houston for the original version of this logic. */ case OP_RECURSE: { callpat = md->start_code + GET(ecode, 1); new_recursive.group_num = *callpat - OP_BRA; /* For extended extraction brackets (large number), we have to fish out the number from a dummy opcode at the start. */ if (new_recursive.group_num > EXTRACT_BASIC_MAX) new_recursive.group_num = GET2(callpat, 2+LINK_SIZE); /* Add to "recursing stack" */ new_recursive.prevrec = md->recursive; md->recursive = &new_recursive; /* Find where to continue from afterwards */ ecode += 1 + LINK_SIZE; new_recursive.after_call = ecode; /* Now save the offset data. */ new_recursive.saved_max = md->offset_end; if (new_recursive.saved_max <= REC_STACK_SAVE_MAX) new_recursive.offset_save = stacksave; else { new_recursive.offset_save = static_cast(malloc(new_recursive.saved_max * sizeof(int))); if (new_recursive.offset_save == NULL) RRETURN(PCRE_ERROR_NOMEMORY); } memcpy(new_recursive.offset_save, md->offset_vector, new_recursive.saved_max * sizeof(int)); new_recursive.save_start = md->start_match; md->start_match = eptr; /* OK, now we can do the recursion. For each top-level alternative we restore the offset and recursion data. */ DPRINTF(("Recursing into group %d\n", new_recursive.group_num)); do { RMATCH(rrc, eptr, callpat + 1 + LINK_SIZE, offset_top, md, ims, eptrb, match_isgroup); if (rrc == MATCH_MATCH) { md->recursive = new_recursive.prevrec; if (new_recursive.offset_save != stacksave) free(new_recursive.offset_save); RRETURN(MATCH_MATCH); } else if (rrc != MATCH_NOMATCH) RRETURN(rrc); md->recursive = &new_recursive; memcpy(md->offset_vector, new_recursive.offset_save, new_recursive.saved_max * sizeof(int)); callpat += GET(callpat, 1); } while (*callpat == OP_ALT); DPRINTF(("Recursion didn't match\n")); md->recursive = new_recursive.prevrec; if (new_recursive.offset_save != stacksave) free(new_recursive.offset_save); RRETURN(MATCH_NOMATCH); } /* Control never reaches here */ /* "Once" brackets are like assertion brackets except that after a match, the point in the subject string is not moved back. Thus there can never be a move back into the brackets. Friedl calls these "atomic" subpatterns. Check the alternative branches in turn - the matching won't pass the KET for this kind of subpattern. If any one branch matches, we carry on as at the end of a normal bracket, leaving the subject pointer. */ case OP_ONCE: { prev = ecode; saved_eptr = eptr; do { RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, match_isgroup); if (rrc == MATCH_MATCH) break; if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += GET(ecode,1); } while (*ecode == OP_ALT); /* If hit the end of the group (which could be repeated), fail */ if (*ecode != OP_ONCE && *ecode != OP_ALT) RRETURN(MATCH_NOMATCH); /* Continue as from after the assertion, updating the offsets high water mark, since extracts may have been taken. */ do ecode += GET(ecode,1); while (*ecode == OP_ALT); offset_top = md->end_offset_top; eptr = md->end_match_ptr; /* For a non-repeating ket, just continue at this level. This also happens for a repeating ket if no characters were matched in the group. This is the forcible breaking of infinite loops as implemented in Perl 5.005. If there is an options reset, it will get obeyed in the normal course of events. */ if (*ecode == OP_KET || eptr == saved_eptr) { ecode += 1+LINK_SIZE; break; } /* The repeating kets try the rest of the pattern or restart from the preceding bracket, in the appropriate order. We need to reset any options that changed within the bracket before re-running it, so check the next opcode. */ if (ecode[1+LINK_SIZE] == OP_OPT) { ims = (ims & ~PCRE_IMS) | ecode[4]; DPRINTF(("ims set to %02lx at group repeat\n", ims)); } if (*ecode == OP_KETRMIN) { RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup); if (rrc != MATCH_NOMATCH) RRETURN(rrc); } else /* OP_KETRMAX */ { RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup); if (rrc != MATCH_NOMATCH) RRETURN(rrc); RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); } } RRETURN(MATCH_NOMATCH); /* An alternation is the end of a branch; scan along to find the end of the bracketed group and go to there. */ case OP_ALT: do ecode += GET(ecode,1); while (*ecode == OP_ALT); break; /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating that it may occur zero times. It may repeat infinitely, or not at all - i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper repeat limits are compiled as a number of copies, with the optional ones preceded by BRAZERO or BRAMINZERO. */ case OP_BRAZERO: { next = ecode+1; RMATCH(rrc, eptr, next, offset_top, md, ims, eptrb, match_isgroup); if (rrc != MATCH_NOMATCH) RRETURN(rrc); do next += GET(next,1); while (*next == OP_ALT); ecode = next + 1+LINK_SIZE; } break; case OP_BRAMINZERO: { next = ecode+1; do next += GET(next,1); while (*next == OP_ALT); RMATCH(rrc, eptr, next + 1+LINK_SIZE, offset_top, md, ims, eptrb, match_isgroup); if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode++; } break; /* End of a group, repeated or non-repeating. If we are at the end of an assertion "group", stop matching and return MATCH_MATCH, but record the current high water mark for use by positive assertions. Do this also for the "once" (not-backup up) groups. */ case OP_KET: case OP_KETRMIN: case OP_KETRMAX: { prev = ecode - GET(ecode, 1); saved_eptr = eptrb->epb_saved_eptr; /* Back up the stack of bracket start pointers. */ eptrb = eptrb->epb_prev; if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT || *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT || *prev == OP_ONCE) { md->end_match_ptr = eptr; /* For ONCE */ md->end_offset_top = offset_top; RRETURN(MATCH_MATCH); } /* In all other cases except a conditional group we have to check the group number back at the start and if necessary complete handling an extraction by setting the offsets and bumping the high water mark. */ if (*prev != OP_COND) { number = *prev - OP_BRA; /* For extended extraction brackets (large number), we have to fish out the number from a dummy opcode at the start. */ if (number > EXTRACT_BASIC_MAX) number = GET2(prev, 2+LINK_SIZE); offset = number << 1; /* Test for a numbered group. This includes groups called as a result of recursion. Note that whole-pattern recursion is coded as a recurse into group 0, so it won't be picked up here. Instead, we catch it when the OP_END is reached. */ if (number > 0) { md->capture_last = number; if (offset >= md->offset_max) md->offset_overflow = true; else { md->offset_vector[offset] = md->offset_vector[md->offset_end - number]; md->offset_vector[offset+1] = eptr - md->start_subject; if (offset_top <= offset) offset_top = offset + 2; } /* Handle a recursively called group. Restore the offsets appropriately and continue from after the call. */ if (md->recursive != NULL && md->recursive->group_num == number) { recursion_info *rec = md->recursive; DPRINTF(("Recursion (%d) succeeded - continuing\n", number)); md->recursive = rec->prevrec; md->start_match = rec->save_start; memcpy(md->offset_vector, rec->offset_save, rec->saved_max * sizeof(int)); ecode = rec->after_call; ims = original_ims; break; } } } /* Reset the value of the ims flags, in case they got changed during the group. */ ims = original_ims; DPRINTF(("ims reset to %02lx\n", ims)); /* For a non-repeating ket, just continue at this level. This also happens for a repeating ket if no characters were matched in the group. This is the forcible breaking of infinite loops as implemented in Perl 5.005. If there is an options reset, it will get obeyed in the normal course of events. */ if (*ecode == OP_KET || eptr == saved_eptr) { ecode += 1 + LINK_SIZE; break; } /* The repeating kets try the rest of the pattern or restart from the preceding bracket, in the appropriate order. */ if (*ecode == OP_KETRMIN) { RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup); if (rrc != MATCH_NOMATCH) RRETURN(rrc); } else /* OP_KETRMAX */ { RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup); if (rrc != MATCH_NOMATCH) RRETURN(rrc); RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); } } RRETURN(MATCH_NOMATCH); /* Start of subject unless notbol, or after internal newline if multiline */ case OP_CIRC: if (md->notbol && eptr == md->start_subject) RRETURN(MATCH_NOMATCH); if ((ims & PCRE_MULTILINE) != 0) { if (eptr != md->start_subject && eptr[-1] != NEWLINE) RRETURN(MATCH_NOMATCH); ecode++; break; } /* ... else fall through */ /* Start of subject assertion */ case OP_SOD: if (eptr != md->start_subject) RRETURN(MATCH_NOMATCH); ecode++; break; /* Start of match assertion */ case OP_SOM: if (eptr != md->start_subject + md->start_offset) RRETURN(MATCH_NOMATCH); ecode++; break; /* Assert before internal newline if multiline, or before a terminating newline unless endonly is set, else end of subject unless noteol is set. */ case OP_DOLL: if ((ims & PCRE_MULTILINE) != 0) { if (eptr < md->end_subject) { if (*eptr != NEWLINE) RRETURN(MATCH_NOMATCH); } else { if (md->noteol) RRETURN(MATCH_NOMATCH); } ecode++; break; } else { if (md->noteol) RRETURN(MATCH_NOMATCH); if (!md->endonly) { if (eptr < md->end_subject - 1 || (eptr == md->end_subject - 1 && *eptr != NEWLINE)) RRETURN(MATCH_NOMATCH); ecode++; break; } } /* ... else fall through */ /* End of subject assertion (\z) */ case OP_EOD: if (eptr < md->end_subject) RRETURN(MATCH_NOMATCH); ecode++; break; /* End of subject or ending \n assertion (\Z) */ case OP_EODN: if (eptr < md->end_subject - 1 || (eptr == md->end_subject - 1 && *eptr != NEWLINE)) RRETURN(MATCH_NOMATCH); ecode++; break; /* Word boundary assertions */ case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: { /* Find out if the previous and current characters are "word" characters. It takes a bit more work in UTF-8 mode. Characters > 255 are assumed to be "non-word" characters. */ /* More streamlined when not in UTF-8 mode */ { prev_is_word = (eptr != md->start_subject) && ((md->ctypes[eptr[-1]] & ctype_word) != 0); cur_is_word = (eptr < md->end_subject) && ((md->ctypes[*eptr] & ctype_word) != 0); } /* Now see if the situation is what we want */ if ((*ecode++ == OP_WORD_BOUNDARY)? cur_is_word == prev_is_word : cur_is_word != prev_is_word) RRETURN(MATCH_NOMATCH); } break; /* Match a single character type; inline for speed */ case OP_ANY: if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == NEWLINE) RRETURN(MATCH_NOMATCH); if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH); ecode++; break; /* Match a single byte, even in UTF-8 mode. This opcode really does match any byte, even newline, independent of the setting of PCRE_DOTALL. */ case OP_ANYBYTE: if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_NOT_DIGIT: if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); GETCHARINCTEST(c, eptr); if ( (md->ctypes[c] & ctype_digit) != 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_DIGIT: if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); GETCHARINCTEST(c, eptr); if ( (md->ctypes[c] & ctype_digit) == 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_NOT_WHITESPACE: if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); GETCHARINCTEST(c, eptr); if ( (md->ctypes[c] & ctype_space) != 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_WHITESPACE: if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); GETCHARINCTEST(c, eptr); if ( (md->ctypes[c] & ctype_space) == 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_NOT_WORDCHAR: if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); GETCHARINCTEST(c, eptr); if ( (md->ctypes[c] & ctype_word) != 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_WORDCHAR: if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); GETCHARINCTEST(c, eptr); if ( (md->ctypes[c] & ctype_word) == 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; /* Match a back reference, possibly repeatedly. Look past the end of the item to see if there is repeat information following. The code is similar to that for character classes, but repeated for efficiency. Then obey similar code to character type repeats - written out again for speed. However, if the referenced string is the empty string, always treat it as matched, any number of times (otherwise there could be infinite loops). */ case OP_REF: { offset = GET2(ecode, 1) << 1; /* Doubled ref number */ ecode += 3; /* Advance past item */ /* If the reference is unset, set the length to be longer than the amount of subject left; this ensures that every attempt at a match fails. We can't just fail here, because of the possibility of quantifiers with zero minima. */ length = (offset >= offset_top || md->offset_vector[offset] < 0)? md->end_subject - eptr + 1 : md->offset_vector[offset+1] - md->offset_vector[offset]; /* Set up for repetition, or handle the non-repeated case */ switch (*ecode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: c = *ecode++ - OP_CRSTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; break; case OP_CRRANGE: case OP_CRMINRANGE: minimize = (*ecode == OP_CRMINRANGE); min = GET2(ecode, 1); max = GET2(ecode, 3); if (max == 0) max = INT_MAX; ecode += 5; break; default: /* No repeat follows */ if (!match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH); eptr += length; continue; /* With the main loop */ } /* If the length of the reference is zero, just continue with the main loop. */ if (length == 0) continue; /* First, ensure the minimum number of matches are present. We get back the length of the reference string explicitly rather than passing the address of eptr, so that eptr can be a register variable. */ for (i = 1; i <= min; i++) { if (!match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH); eptr += length; } /* If min = max, continue at the same level without recursion. They are not both allowed to be zero. */ if (min == max) continue; /* If minimizing, keep trying and advancing the pointer */ if (minimize) { for (fi = min;; fi++) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max || !match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH); eptr += length; } /* Control never gets here */ } /* If maximizing, find the longest string and work backwards */ else { pp = eptr; for (i = min; i < max; i++) { if (!match_ref(offset, eptr, length, md, ims)) break; eptr += length; } while (eptr >= pp) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr -= length; } RRETURN(MATCH_NOMATCH); } } /* Control never gets here */ /* Match a bit-mapped character class, possibly repeatedly. This op code is used when all the characters in the class have values in the range 0-255. The only difference between OP_CLASS and OP_NCLASS occurs when a data character outside the range is encountered. First, look past the end of the item to see if there is repeat information following. Then obey similar code to character type repeats - written out again for speed. */ case OP_NCLASS: case OP_CLASS: { data = ecode + 1; /* Save for matching */ ecode += 33; /* Advance past the item */ switch (*ecode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: c = *ecode++ - OP_CRSTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; break; case OP_CRRANGE: case OP_CRMINRANGE: minimize = (*ecode == OP_CRMINRANGE); min = GET2(ecode, 1); max = GET2(ecode, 3); if (max == 0) max = INT_MAX; ecode += 5; break; default: /* No repeat follows */ min = max = 1; break; } /* First, ensure the minimum number of matches are present. */ /* Not UTF-8 mode */ { for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); c = *eptr++; if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); } } /* If max == min we can continue with the main loop without the need to recurse. */ if (min == max) continue; /* If minimizing, keep testing the rest of the expression and advancing the pointer while it matches the class. */ if (minimize) { /* Not UTF-8 mode */ { for (fi = min;; fi++) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); c = *eptr++; if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); } } /* Control never gets here */ } /* If maximizing, find the longest possible run, then work backwards. */ else { pp = eptr; /* Not UTF-8 mode */ { for (i = min; i < max; i++) { if (eptr >= md->end_subject) break; c = *eptr; if ((data[c/8] & (1 << (c&7))) == 0) break; eptr++; } while (eptr >= pp) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); eptr--; if (rrc != MATCH_NOMATCH) RRETURN(rrc); } } RRETURN(MATCH_NOMATCH); } } /* Control never gets here */ /* Match an extended character class. This opcode is encountered only in UTF-8 mode, because that's the only time it is compiled. */ /* Match a run of characters */ case OP_CHARS: { register int slen = ecode[1]; ecode += 2; if (slen > md->end_subject - eptr) { RRETURN(MATCH_NOMATCH); } if ((ims & PCRE_CASELESS) != 0) { while (slen-- > 0) { if (md->lcc[*ecode] != md->lcc[*eptr]) { ecode++; eptr++; RRETURN(MATCH_NOMATCH); } ecode++; eptr++; } } else { while (slen-- > 0) { if (*ecode != *eptr) { ecode++; eptr++; RRETURN(MATCH_NOMATCH); } ecode++; eptr++; } } } break; /* Match a single character repeatedly; different opcodes share code. */ case OP_EXACT: min = max = GET2(ecode, 1); ecode += 3; goto REPEATCHAR; case OP_UPTO: case OP_MINUPTO: min = 0; max = GET2(ecode, 1); minimize = *ecode == OP_MINUPTO; ecode += 3; goto REPEATCHAR; case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: c = *ecode++ - OP_STAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single-character matches. We can give up quickly if there are fewer than the minimum number of characters left in the subject. */ REPEATCHAR: /* When not in UTF-8 mode, load a single-byte character. */ { if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); fc = *ecode++; } /* The value of fc at this point is always less than 256, though we may or may not be in UTF-8 mode. The code is duplicated for the caseless and caseful cases, for speed, since matching characters is likely to be quite common. First, ensure the minimum number of matches are present. If min = max, continue at the same level without recursing. Otherwise, if minimizing, keep trying the rest of the expression and advancing one matching character if failing, up to the maximum. Alternatively, if maximizing, find the maximum number of characters and work backwards. */ DPRINTF(("matching %c{%d,%d} against subject %.*s\n", fc, min, max, max, eptr)); if ((ims & PCRE_CASELESS) != 0) { fc = md->lcc[fc]; for (i = 1; i <= min; i++) if (fc != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); if (min == max) continue; if (minimize) { for (fi = min;; fi++) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max || eptr >= md->end_subject || fc != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ } else { pp = eptr; for (i = min; i < max; i++) { if (eptr >= md->end_subject || fc != md->lcc[*eptr]) break; eptr++; } while (eptr >= pp) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); eptr--; if (rrc != MATCH_NOMATCH) RRETURN(rrc); } RRETURN(MATCH_NOMATCH); } /* Control never gets here */ } /* Caseful comparisons (includes all multi-byte characters) */ else { for (i = 1; i <= min; i++) if (fc != *eptr++) RRETURN(MATCH_NOMATCH); if (min == max) continue; if (minimize) { for (fi = min;; fi++) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max || eptr >= md->end_subject || fc != *eptr++) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ } else { pp = eptr; for (i = min; i < max; i++) { if (eptr >= md->end_subject || fc != *eptr) break; eptr++; } while (eptr >= pp) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); eptr--; if (rrc != MATCH_NOMATCH) RRETURN(rrc); } RRETURN(MATCH_NOMATCH); } } /* Control never gets here */ /* Match a negated single one-byte character. The character we are checking can be multibyte. */ case OP_NOT: if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); ecode++; GETCHARINCTEST(c, eptr); if ((ims & PCRE_CASELESS) != 0) { c = md->lcc[c]; if (md->lcc[*ecode++] == c) RRETURN(MATCH_NOMATCH); } else { if (*ecode++ == c) RRETURN(MATCH_NOMATCH); } break; /* Match a negated single one-byte character repeatedly. This is almost a repeat of the code for a repeated single character, but I haven't found a nice way of commoning these up that doesn't require a test of the positive/negative option for each character match. Maybe that wouldn't add very much to the time taken, but character matching *is* what this is all about... */ case OP_NOTEXACT: min = max = GET2(ecode, 1); ecode += 3; goto REPEATNOTCHAR; case OP_NOTUPTO: case OP_NOTMINUPTO: min = 0; max = GET2(ecode, 1); minimize = *ecode == OP_NOTMINUPTO; ecode += 3; goto REPEATNOTCHAR; case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: c = *ecode++ - OP_NOTSTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single-character (less than 255) matches. We can give up quickly if there are fewer than the minimum number of characters left in the subject. */ REPEATNOTCHAR: if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); fc = *ecode++; /* The code is duplicated for the caseless and caseful cases, for speed, since matching characters is likely to be quite common. First, ensure the minimum number of matches are present. If min = max, continue at the same level without recursing. Otherwise, if minimizing, keep trying the rest of the expression and advancing one matching character if failing, up to the maximum. Alternatively, if maximizing, find the maximum number of characters and work backwards. */ DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", fc, min, max, max, eptr)); if ((ims & PCRE_CASELESS) != 0) { fc = md->lcc[fc]; /* Not UTF-8 mode */ { for (i = 1; i <= min; i++) if (fc == md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); } if (min == max) continue; if (minimize) { /* Not UTF-8 mode */ { for (fi = min;; fi++) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max || eptr >= md->end_subject || fc == md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); } } /* Control never gets here */ } /* Maximize case */ else { pp = eptr; /* Not UTF-8 mode */ { for (i = min; i < max; i++) { if (eptr >= md->end_subject || fc == md->lcc[*eptr]) break; eptr++; } while (eptr >= pp) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; } } RRETURN(MATCH_NOMATCH); } /* Control never gets here */ } /* Caseful comparisons */ else { /* Not UTF-8 mode */ { for (i = 1; i <= min; i++) if (fc == *eptr++) RRETURN(MATCH_NOMATCH); } if (min == max) continue; if (minimize) { /* Not UTF-8 mode */ { for (fi = min;; fi++) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max || eptr >= md->end_subject || fc == *eptr++) RRETURN(MATCH_NOMATCH); } } /* Control never gets here */ } /* Maximize case */ else { pp = eptr; /* Not UTF-8 mode */ { for (i = min; i < max; i++) { if (eptr >= md->end_subject || fc == *eptr) break; eptr++; } while (eptr >= pp) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; } } RRETURN(MATCH_NOMATCH); } } /* Control never gets here */ /* Match a single character type repeatedly; several different opcodes share code. This is very similar to the code for single characters, but we repeat it in the interests of efficiency. */ case OP_TYPEEXACT: min = max = GET2(ecode, 1); minimize = true; ecode += 3; goto REPEATTYPE; case OP_TYPEUPTO: case OP_TYPEMINUPTO: min = 0; max = GET2(ecode, 1); minimize = *ecode == OP_TYPEMINUPTO; ecode += 3; goto REPEATTYPE; case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: c = *ecode++ - OP_TYPESTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single character type matches. Note that in UTF-8 mode, '.' matches a character of any length, but for the other character types, the valid characters are all one-byte long. */ REPEATTYPE: ctype = *ecode++; /* Code for the character type */ /* First, ensure the minimum number of matches are present. Use inline code for maximizing the speed, and do the type test once at the start (i.e. keep it out of the loop). Also we can test that there are at least the minimum number of bytes before we start. This isn't as effective in UTF-8 mode, but it does no harm. Separate the UTF-8 code completely as that is tidier. */ if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); if (min > 0) { /* Code for the non-UTF-8 case for minimum matching */ switch(ctype) { case OP_ANY: if ((ims & PCRE_DOTALL) == 0) { for (i = 1; i <= min; i++) if (*eptr++ == NEWLINE) RRETURN(MATCH_NOMATCH); } else eptr += min; break; case OP_ANYBYTE: eptr += min; break; case OP_NOT_DIGIT: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); break; case OP_DIGIT: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); break; case OP_NOT_WHITESPACE: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); break; case OP_WHITESPACE: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); break; case OP_NOT_WORDCHAR: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); break; case OP_WORDCHAR: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_word) == 0) RRETURN(MATCH_NOMATCH); break; } } /* If min = max, continue at the same level without recursing */ if (min == max) continue; /* If minimizing, we have to test the rest of the pattern before each subsequent match. Again, separate the UTF-8 case for speed. */ if (minimize) { /* Not UTF-8 mode */ { for (fi = min;; fi++) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); c = *eptr++; switch(ctype) { case OP_ANY: if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) RRETURN(MATCH_NOMATCH); break; case OP_ANYBYTE: break; case OP_NOT_DIGIT: if ((md->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); break; case OP_DIGIT: if ((md->ctypes[c] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); break; case OP_NOT_WHITESPACE: if ((md->ctypes[c] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); break; case OP_WHITESPACE: if ((md->ctypes[c] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); break; case OP_NOT_WORDCHAR: if ((md->ctypes[c] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); break; case OP_WORDCHAR: if ((md->ctypes[c] & ctype_word) == 0) RRETURN(MATCH_NOMATCH); break; } } } /* Control never gets here */ } /* If maximizing it is worth using inline code for speed, doing the type test once at the start (i.e. keep it out of the loop). Again, keep the UTF-8 stuff separate. */ else { pp = eptr; /* Not UTF-8 mode */ { switch(ctype) { case OP_ANY: if ((ims & PCRE_DOTALL) == 0) { for (i = min; i < max; i++) { if (eptr >= md->end_subject || *eptr == NEWLINE) break; eptr++; } break; } /* For DOTALL case, fall through and treat as \C */ case OP_ANYBYTE: c = max - min; if (c > md->end_subject - eptr) c = md->end_subject - eptr; eptr += c; break; case OP_NOT_DIGIT: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0) break; eptr++; } break; case OP_DIGIT: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0) break; eptr++; } break; case OP_NOT_WHITESPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0) break; eptr++; } break; case OP_WHITESPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0) break; eptr++; } break; case OP_NOT_WORDCHAR: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0) break; eptr++; } break; case OP_WORDCHAR: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0) break; eptr++; } break; } /* eptr is now past the end of the maximum run */ while (eptr >= pp) { RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); eptr--; if (rrc != MATCH_NOMATCH) RRETURN(rrc); } } /* Get here if we can't make it match with any permitted repetitions */ RRETURN(MATCH_NOMATCH); } /* Control never gets here */ /* There's been some horrible disaster. Since all codes > OP_BRA are for capturing brackets, and there shouldn't be any gaps between 0 and OP_BRA, arrival here can only mean there is something seriously wrong in the code above or the OP_xxx definitions. */ default: DPRINTF(("Unknown opcode %d\n", *ecode)); RRETURN(PCRE_ERROR_UNKNOWN_NODE); } /* Do not stick any code in here without much thought; it is assumed that "continue" in the code above comes out to here to repeat the main loop. */ } /* End of main loop */ RRETURN(MATCH_NOMATCH); } /*************************************************************************** **************************************************************************** RECURSION IN THE match() FUNCTION Undefine all the macros that were defined above to handle this. */ /* These two are defined as macros in both cases */ #undef fc #undef fi /*************************************************************************** ***************************************************************************/ /************************************************* * Execute a Regular Expression * *************************************************/ /* This function applies a compiled re to a subject string and picks out portions of the string if it matches. Two elements in the vector are set for each substring: the offsets to the start and end of the substring. Arguments: external_re points to the compiled expression extra_data points to extra data or is NULL subject points to the subject string length length of subject string (may contain binary zeros) start_offset where to start in the subject string options option bits offsets points to a vector of ints to be filled in with offsets offsetcount the number of elements in the vector Returns: > 0 => success; value is the number of elements filled in = 0 => success, but offsets is not big enough -1 => failed to match < -1 => some kind of unexpected problem */ int pcre_exec(const pcre *external_re, const pcre_extra *extra_data, const char *subject, int length, int start_offset, int options, int *offsets, int offsetcount) { int rc, resetcount, ocount; int first_byte = -1; int req_byte = -1; int req_byte2 = -1; unsigned long int ims = 0; bool using_temporary_offsets = false; bool anchored; bool startline; bool first_byte_caseless = false; bool req_byte_caseless = false; match_data match_block; const uschar *start_bits = NULL; const uschar *start_match = (const uschar *)subject + start_offset; const uschar *end_subject; const uschar *req_byte_ptr = start_match - 1; const pcre_study_data *study; const real_pcre *re = (const real_pcre *)external_re; /* Plausibility checks */ if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION; if (re == NULL || subject == NULL || (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; /* Fish out the optional data from the extra_data structure, first setting the default values. */ study = NULL; match_block.match_limit = MATCH_LIMIT; match_block.callout_data = NULL; if (extra_data != NULL) { register unsigned int flags = extra_data->flags; if ((flags & PCRE_EXTRA_STUDY_DATA) != 0) study = (const pcre_study_data *)extra_data->study_data; if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0) match_block.match_limit = extra_data->match_limit; if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0) match_block.callout_data = extra_data->callout_data; } /* Now we have re supposedly pointing to the regex */ if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; anchored = ((re->options | options) & PCRE_ANCHORED) != 0; startline = (re->options & PCRE_STARTLINE) != 0; match_block.start_code = (const uschar *)re + sizeof(real_pcre) + re->name_count * re->name_entry_size; match_block.start_subject = (const uschar *)subject; match_block.start_offset = start_offset; match_block.end_subject = match_block.start_subject + length; end_subject = match_block.end_subject; match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; match_block.utf8 = (re->options & PCRE_UTF8) != 0; match_block.notbol = (options & PCRE_NOTBOL) != 0; match_block.noteol = (options & PCRE_NOTEOL) != 0; match_block.notempty = (options & PCRE_NOTEMPTY) != 0; match_block.recursive = NULL; /* No recursion at top level */ match_block.lcc = re->tables + lcc_offset; match_block.ctypes = re->tables + ctypes_offset; /* Check a UTF-8 string if required. Unfortunately there's no way of passing back the character offset. */ /* The ims options can vary during the matching as a result of the presence of (?ims) items in the pattern. They are kept in a local variable so that restoring at the exit of a group is easy. */ ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL); /* If the expression has got more back references than the offsets supplied can hold, we get a temporary bit of working store to use during the matching. Otherwise, we can use the vector supplied, rounding down its size to a multiple of 3. */ ocount = offsetcount - (offsetcount % 3); if (re->top_backref > 0 && re->top_backref >= ocount/3) { ocount = re->top_backref * 3 + 3; match_block.offset_vector = static_cast(malloc(ocount * sizeof(int))); if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY; using_temporary_offsets = true; DPRINTF(("Got memory to hold back references\n")); } else match_block.offset_vector = offsets; match_block.offset_end = ocount; match_block.offset_max = (2*ocount)/3; match_block.offset_overflow = false; match_block.capture_last = -1; /* Compute the minimum number of offsets that we need to reset each time. Doing this makes a huge difference to execution time when there aren't many brackets in the pattern. */ resetcount = 2 + re->top_bracket * 2; if (resetcount > offsetcount) resetcount = ocount; /* Reset the working variable associated with each extraction. These should never be used unless previously set, but they get saved and restored, and so we initialize them to avoid reading uninitialized locations. */ if (match_block.offset_vector != NULL) { register int *iptr = match_block.offset_vector + ocount; register int *iend = iptr - resetcount/2 + 1; while (--iptr >= iend) *iptr = -1; } /* Set up the first character to match, if available. The first_byte value is never set for an anchored regular expression, but the anchoring may be forced at run time, so we have to test for anchoring. The first char may be unset for an unanchored pattern, of course. If there's no first char and the pattern was studied, there may be a bitmap of possible first characters. */ if (!anchored) { if ((re->options & PCRE_FIRSTSET) != 0) { first_byte = re->first_byte & 255; if ((first_byte_caseless = ((re->first_byte & REQ_CASELESS) != 0)) == true) first_byte = match_block.lcc[first_byte]; } else if (!startline && study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0) start_bits = study->start_bits; } /* For anchored or unanchored matches, there may be a "last known required character" set. */ if ((re->options & PCRE_REQCHSET) != 0) { req_byte = re->req_byte & 255; req_byte_caseless = (re->req_byte & REQ_CASELESS) != 0; req_byte2 = (re->tables + fcc_offset)[req_byte]; /* case flipped */ } /* Loop for handling unanchored repeated matching attempts; for anchored regexs the loop runs just once. */ do { register int *iptr = match_block.offset_vector; register int *iend = iptr + resetcount; /* Reset the maximum number of extractions we might see. */ while (iptr < iend) *iptr++ = -1; /* Advance to a unique first char if possible */ if (first_byte >= 0) { if (first_byte_caseless) while (start_match < end_subject && match_block.lcc[*start_match] != first_byte) start_match++; else while (start_match < end_subject && *start_match != first_byte) start_match++; } /* Or to just after \n for a multiline match if possible */ else if (startline) { if (start_match > match_block.start_subject + start_offset) { while (start_match < end_subject && start_match[-1] != NEWLINE) start_match++; } } /* Or to a non-unique first char after study */ else if (start_bits != NULL) { while (start_match < end_subject) { register int c = *start_match; if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; else break; } } /* If req_byte is set, we know that that character must appear in the subject for the match to succeed. If the first character is set, req_byte must be later in the subject; otherwise the test starts at the match point. This optimization can save a huge amount of backtracking in patterns with nested unlimited repeats that aren't going to match. Writing separate code for cased/caseless versions makes it go faster, as does using an autoincrement and backing off on a match. HOWEVER: when the subject string is very, very long, searching to its end can take a long time, and give bad performance on quite ordinary patterns. This showed up when somebody was matching /^C/ on a 32-megabyte string... so we don't do this when the string is sufficiently long. */ if (req_byte >= 0 && end_subject - start_match < REQ_BYTE_MAX) { register const uschar *p = start_match + ((first_byte >= 0)? 1 : 0); /* We don't need to repeat the search if we haven't yet reached the place we found it at last time. */ if (p > req_byte_ptr) { if (req_byte_caseless) { while (p < end_subject) { register int pp = *p++; if (pp == req_byte || pp == req_byte2) { p--; break; } } } else { while (p < end_subject) { if (*p++ == req_byte) { p--; break; } } } /* If we can't find the required character, break the matching loop */ if (p >= end_subject) break; /* If we have found the required character, save the point where we found it, so that we don't search again next time round the loop if the start hasn't passed this character yet. */ req_byte_ptr = p; } } /* When a match occurs, substrings will be set for all internal extractions; we just need to set up the whole thing as substring 0 before returning. If there were too many extractions, set the return code to zero. In the case where we had to get some local store to hold offsets for backreferences, copy those back references that we can. In this case there need not be overflow if certain parts of the pattern were not used. */ match_block.start_match = start_match; match_block.match_call_count = 0; rc = match(start_match, match_block.start_code, 2, &match_block, ims, NULL, match_isgroup); if (rc == MATCH_NOMATCH) { start_match++; continue; } if (rc != MATCH_MATCH) { DPRINTF((">>>> error: returning %d\n", rc)); return rc; } /* We have a match! Copy the offset information from temporary store if necessary */ if (using_temporary_offsets) { if (offsetcount >= 4) { memcpy(offsets + 2, match_block.offset_vector + 2, (offsetcount - 2) * sizeof(int)); DPRINTF(("Copied offsets from temporary memory\n")); } if (match_block.end_offset_top > offsetcount) match_block.offset_overflow = true; DPRINTF(("Freeing temporary memory\n")); free(match_block.offset_vector); } rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2; if (offsetcount < 2) rc = 0; else { offsets[0] = start_match - match_block.start_subject; offsets[1] = match_block.end_match_ptr - match_block.start_subject; } DPRINTF((">>>> returning %d\n", rc)); return rc; } /* This "while" is the end of the "do" above */ while (!anchored && start_match <= end_subject); if (using_temporary_offsets) { DPRINTF(("Freeing temporary memory\n")); free(match_block.offset_vector); } DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n")); return PCRE_ERROR_NOMATCH; } /* End of pcre.c */ mux2.6/src/unsplit.cpp0000600000175000017500000000131211025753746014775 0ustar sdennissdennis// unsplit.cpp -- Filter for re-combining continuation lines. // // $Id: unsplit.cpp 8 2006-09-05 01:55:58Z brazilofmux $ // #include "copyright.h" #include #include int main(int argc, char *argv[]) { int c, numcr; while ((c = getchar()) != EOF) { if (c == '\\') { numcr = 0; do { c = getchar(); if (c == '\n') numcr++; } while ((c != EOF) && isspace(c)); if (numcr > 1) { putchar('\n'); } ungetc(c, stdin); } else { putchar(c); } } return 0; } mux2.6/src/mguests.cpp0000600000175000017500000002710411025753746014775 0ustar sdennissdennis// mguests.cpp -- Multiguest code originally ported from DarkZone. // Multiguest code rewritten by Matthew J. Leavitt (zenty). // Idea for @list guest from Ashen-Shugar and the great team of RhostMUSH // // $Id: mguests.cpp 3433 2008-03-31 04:22:09Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include #include "attrs.h" #include "mguests.h" #include "powers.h" #include "comsys.h" #define GUEST_HYSTERESIS 20 CGuests Guest; CGuests::CGuests(void) { Guests = NULL; nGuests = 0; nMaxGuests = 0; } CGuests::~CGuests(void) { if (Guests) { MEMFREE(Guests); Guests = NULL; nGuests = 0; nMaxGuests = 0; } } void CGuests::StartUp(void) { if ( !Good_obj(mudconf.guest_char) || mudconf.number_guests <= 0) { // The guest system is effectively disabled. // return; } // SizeGuests(mudconf.min_guests); // Search the Database for Guest chars and snag em. // dbref thing; DO_WHOLE_DB(thing) { if ( Guest(thing) && isPlayer(thing)) { SizeGuests(nGuests+1); Guests[nGuests] = thing; nGuests++; } } // Create the Minimum # of guests. // for (; nGuests < mudconf.min_guests; nGuests++) { SizeGuests(nGuests+1); Guests[nGuests] = MakeGuestChar(); // If we couldn't create guest character, break out and let later // functions handle it. // if (Guests[nGuests] == NOTHING) { break; } } } void CGuests::SizeGuests(int nMin) { // We must have at least nMin, but if nMin is sufficiently below // nMaxGuests, we can also shrink. // if (nMin < nGuests) { nMin = nGuests; } if ( nMaxGuests <= nMin + GUEST_HYSTERESIS && nMin <= nMaxGuests) { return; } dbref *newGuests = (dbref *)MEMALLOC(nMin * sizeof(dbref)); ISOUTOFMEMORY(newGuests); if (Guests) { memcpy(newGuests, Guests, nGuests * sizeof(dbref)); MEMFREE(Guests); Guests = NULL; } Guests = newGuests; nMaxGuests = nMin; } const char *CGuests::Create(DESC *d) { // We don't have a main guest character, break out. // if (!Good_obj(mudconf.guest_char)) { return NULL; } // If we have a guest character, let's use it // int i; for (i = 0; i < nGuests; i++) { dbref guest_player = Guests[i]; // If we have something in the list that isn't a guest, lets // just drop it and make a new one. // if ( !Good_obj(guest_player) || !isPlayer(guest_player) || !Guest(guest_player)) { guest_player = Guests[i] = MakeGuestChar(); if (guest_player == NOTHING) { return NULL; } else { return Name(guest_player); } } if (!Connected(guest_player)) { // Lets try to grab our own name, if we don't have it. // mux_sprintf(name, sizeof(name), "%s%d", mudconf.guest_prefix, i+1); dbref j = lookup_player(GOD, name, false); if (j == NOTHING) { delete_player_name(guest_player, Name(guest_player)); s_Name(guest_player, name); add_player_name(guest_player, Name(guest_player)); } else { // Release comsys and @mail state. // ReleaseAllResources(guest_player); AddToGuestChannel(guest_player); } // Copy flags from guest prototype. // db[guest_player].fs = db[mudconf.guest_char].fs; // Strip flags, enforce PLAYER type. // FLAG aClearFlags[3]; FLAG aSetFlags[3]; aClearFlags[FLAG_WORD1] = WIZARD | TYPE_MASK | mudconf.stripped_flags.word[FLAG_WORD1]; aClearFlags[FLAG_WORD2] = mudconf.stripped_flags.word[FLAG_WORD2]; aClearFlags[FLAG_WORD3] = mudconf.stripped_flags.word[FLAG_WORD3]; aSetFlags[FLAG_WORD1] = TYPE_PLAYER; aSetFlags[FLAG_WORD2] = 0; aSetFlags[FLAG_WORD3] = 0; SetClearFlags(guest_player, aClearFlags, aSetFlags); // Make sure they're a guest. // s_Guest(guest_player); move_object(guest_player, mudconf.start_room); s_Pennies(guest_player, Pennies(mudconf.guest_char)); s_Zone(guest_player, Zone(mudconf.guest_char)); s_Parent(guest_player, Parent(mudconf.guest_char)); // Wipe the attributes. // WipeAttrs(guest_player); ChangePassword(guest_player, GUEST_PASSWORD); // Copy them back. // atr_cpy(guest_player, mudconf.guest_char, true); return Name(guest_player); } } if (nGuests >= mudconf.number_guests) { queue_string(d, "Sorry, All guests are currently busy. Try again later.\n"); return NULL; } dbref newGuest = MakeGuestChar(); if (newGuest == NOTHING) { queue_string(d, "GAME: Error creating guest, please try again later.\n"); return NULL; } SizeGuests(nGuests+1); Guests[nGuests] = newGuest; nGuests++; return Name(newGuest); } void CGuests::CleanUp(void) { // Verify that our existing pool of guests are reasonable. Replace any // unreasonable dbrefs. // int nPool = nGuests; if (mudconf.min_guests < nGuests) { nPool = mudconf.min_guests; } int i; for (i = 0; i < nPool; i++) { if ( !Good_obj(Guests[i]) || !isPlayer(Guests[i]) || !Guest(Guests[i])) { Guests[i] = MakeGuestChar(); } } if (nGuests <= mudconf.min_guests) { return; } // We have more than the minimum number of guests in the pool. Let's // see if there are any guests beyond that minimum number that we can // trim out of the pool. // PASS 1: Move connected guests to the beginning of the list. // int itmp; int currGuest = mudconf.min_guests; for (i = mudconf.min_guests; i < nGuests; i++) { if (Connected(Guests[i])) { if (i > currGuest) { itmp = Guests[currGuest]; Guests[currGuest] = Guests[i]; Guests[i] = itmp; } currGuest++; } } // PASS 2: Destroy unconnected guests. // itmp = nGuests; for (i = mudconf.min_guests; i < itmp;i++) { if (!Connected(Guests[i])) { if (Good_obj(Guests[i])) { DestroyGuestChar(Guests[i]); } nGuests--; } } SizeGuests(nGuests); } dbref CGuests::MakeGuestChar(void) { // Search for the first available name. // int i; dbref player; bool bFound = false; for (i = 0; i < mudconf.number_guests;i++) { mux_sprintf(name, sizeof(name), "%s%d", mudconf.guest_prefix, i + 1); player = lookup_player(GOD, name, false); if (player == NOTHING) { bFound = true; break; } } if (!bFound) { return NOTHING; } // Make the player. // const char *pmsg; player = create_player(name, (char *)GUEST_PASSWORD, mudconf.guest_nuker, false, &pmsg); // No Player Created?? Return error. // if (player == NOTHING) { log_text("GUEST: failed in create_player" ENDLINE); return NOTHING; } // Lets make the player a guest, move it into the starting room, // don't let it be a wizard, and setup other basics. // AddToGuestChannel(player); s_Guest(player); move_object(player, mudconf.start_room); // Copy flags from guest prototype and restore the player type. // FLAGSET f = db[mudconf.guest_char].fs; f.word[FLAG_WORD1] |= TYPE_PLAYER; db[player].fs = f; // Strip flags. // FLAG aClearFlags[3]; aClearFlags[FLAG_WORD1] = WIZARD | mudconf.stripped_flags.word[FLAG_WORD1]; aClearFlags[FLAG_WORD2] = mudconf.stripped_flags.word[FLAG_WORD2]; aClearFlags[FLAG_WORD3] = mudconf.stripped_flags.word[FLAG_WORD3]; SetClearFlags(player, aClearFlags, NULL); s_Pennies(player, Pennies(mudconf.guest_char)); s_Zone(player, Zone(mudconf.guest_char)); s_Parent(player, Parent(mudconf.guest_char)); // Copy the attributes. // atr_cpy(player, mudconf.guest_char, true); // Lock em! // do_lock(player, player, player, A_LOCK, 2, tprintf("#%d", player), (char *)"=me"); do_lock(player, player, player, A_LENTER, 2, tprintf("#%d", player), (char *)"=me"); // return em! // return player; } void CGuests::DestroyGuestChar(dbref guest) { // Don't destroy anything not a guest. // if (!Guest(guest)) { return; } // Make sure the nuker is ok. // if ( !Wizard(mudconf.guest_nuker) || !Good_obj(mudconf.guest_nuker)) { mudconf.guest_nuker = GOD; } // Destroy it! // destroy_player(mudconf.guest_nuker, guest); } void CGuests::WipeAttrs(dbref guest) { olist_push(); int atr; char *as; for (atr = atr_head(guest, &as); atr; atr = atr_next(&as)) { ATTR *ap = atr_num(atr); if (ap) { // Get the attr and make sure we can modify it. // if (bCanSetAttr(GOD, guest, ap)) { atr_clr(guest, ap->number); } } } olist_pop(); } bool CGuests::CheckGuest(dbref player) { int i; for (i = 0; i < nGuests; i++) { if (Guests[i] == player) { return true; } } return false; } // @list guests, thanks Rhost for the idea! // void CGuests::ListAll(dbref player) { notify(player, "--------------------------- Current Guests Listing ---------------------------"); notify(player, "*Guest # : Name dbref Status Last Site"); notify(player, "------------------------------------------------------------------------------");\ char *buff = alloc_lbuf("CGuests-ListAll"); int i; char *LastSite=alloc_lbuf("CGuests-LastSite"); for (i = 0; i < nGuests; i++) { dbref aowner; int aflags; atr_get_str(LastSite, Guests[i], A_LASTSITE, &aowner, &aflags); mux_sprintf(buff, LBUF_SIZE, "%sGuest %-3d: %-15s #%-5d %-10s %s", (i #include #include "attrs.h" #include "command.h" #include "functions.h" #include "comsys.h" #include "file_c.h" #include "mguests.h" #include "muxcli.h" #include "pcre.h" #include "powers.h" #include "help.h" #ifdef REALITY_LVLS #include "levels.h" #endif // REALITY_LVLS #if defined(FIRANMUX) #include MYSQL *mush_database = NULL; #endif // FIRANMUX void do_dump(dbref executor, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); #ifndef WIN32 if (mudstate.dumping) { notify(executor, "Dumping in progress. Try again later."); return; } #endif notify(executor, "Dumping..."); fork_and_dump(key); } // print out stuff into error file // void report(void) { STARTLOG(LOG_BUGS, "BUG", "INFO"); log_text("Command: '"); log_text(mudstate.debug_cmd); log_text("'"); ENDLOG; if (Good_obj(mudstate.curr_executor)) { STARTLOG(LOG_BUGS, "BUG", "INFO"); log_text("Player: "); log_name_and_loc(mudstate.curr_executor); if ( mudstate.curr_enactor != mudstate.curr_executor && Good_obj(mudstate.curr_enactor)) { log_text(" Enactor: "); log_name_and_loc(mudstate.curr_enactor); } ENDLOG; } } /* ---------------------------------------------------------------------- * regexp_match: Load a regular expression match and insert it into * registers. */ bool regexp_match ( char *pattern, char *str, int case_opt, char *args[], int nargs ) { int matches; int i; const char *errptr; int erroffset; /* * Load the regexp pattern. This allocates memory which must be * later freed. A free() of the regexp does free all structures * under it. */ pcre *re; if ( MuxAlarm.bAlarmed || (re = pcre_compile(pattern, case_opt, &errptr, &erroffset, NULL)) == NULL) { /* * This is a matching error. We have an error message in * regexp_errbuf that we can ignore, since we're doing * command-matching. */ return false; } // To capture N substrings, you need space for 3(N+1) offsets in the // offset vector. We'll allow 2N-1 substrings and possibly ignore some. // const int ovecsize = 6 * nargs; int *ovec = new int[ovecsize]; /* * Now we try to match the pattern. The relevant fields will * automatically be filled in by this. */ matches = pcre_exec(re, NULL, str, static_cast(strlen(str)), 0, 0, ovec, ovecsize); if (matches < 0) { delete [] ovec; MEMFREE(re); return false; } if (matches == 0) { // There were too many substring matches. See docs for // pcre_copy_substring(). // matches = ovecsize / 3; } /* * Now we fill in our args vector. Note that in regexp matching, * 0 is the entire string matched, and the parenthesized strings * go from 1 to 9. We DO PRESERVE THIS PARADIGM, for consistency * with other languages. */ for (i = 0; i < nargs; ++i) { args[i] = alloc_lbuf("regexp_match"); if (pcre_copy_substring(str, ovec, matches, i, args[i], LBUF_SIZE) < 0) { free_lbuf(args[i]); args[i] = NULL; } } delete [] ovec; MEMFREE(re); return true; } /* ---------------------------------------------------------------------- * atr_match: Check attribute list for wild card matches and queue them. */ static int atr_match1 ( dbref thing, dbref parent, dbref player, char type, char *str, char *raw_str, int check_exclude, int hash_insert ) { // See if we can do it. Silently fail if we can't. // if (!could_doit(player, parent, A_LUSE)) { return -1; } int match = 0; if ( ( AMATCH_CMD == type && mudstate.bfNoCommands.IsSet(parent)) || ( AMATCH_LISTEN == type && mudstate.bfNoListens.IsSet(parent))) { // We may need to process the hash_insert to support exclusion of // this parent's $-commands before we return no matches. // if (hash_insert) { // Because we know this object contains no commands, there is no // need to look at the attribute values. // char *as; atr_push(); for (int atr = atr_head(parent, &as); atr; atr = atr_next(&as)) { ATTR *ap = atr_num(atr); if ( ap && 0 == (ap->flags & AF_NOPROG) && ( !check_exclude || ( 0 == (ap->flags & AF_PRIVATE) && !hashfindLEN(&(ap->number), sizeof(ap->number), &mudstate.parent_htab)))) { hashaddLEN(&(ap->number), sizeof(ap->number), &atr, &mudstate.parent_htab); } } atr_pop(); } return match; } bool bFoundCommands = false; bool bFoundListens = false; char *as; atr_push(); for (int atr = atr_head(parent, &as); atr; atr = atr_next(&as)) { ATTR *ap = atr_num(atr); // Never check NOPROG attributes. // if ( !ap || (ap->flags & AF_NOPROG)) { continue; } // We need to grab the attribute even before we know whether we'll use // it or not in order to maintain cached knowledge about ^-Commands // and $-Commands. // dbref aowner; int aflags; char buff[LBUF_SIZE]; atr_get_str(buff, parent, atr, &aowner, &aflags); char *s = NULL; if ( 0 == (aflags & AF_NOPROG) && ( AMATCH_CMD == buff[0] || AMATCH_LISTEN == buff[0])) { s = strchr(buff+1, ':'); if (s) { if (AMATCH_CMD == buff[0]) { bFoundCommands = true; } else { bFoundListens = true; } } } // If we aren't the bottom level, check if we saw this attr // before. Also exclude it if the attribute type is PRIVATE. // if ( check_exclude && ( (ap->flags & AF_PRIVATE) || (aflags & AF_PRIVATE) || hashfindLEN(&(ap->number), sizeof(ap->number), &mudstate.parent_htab))) { continue; } // If we aren't the top level, remember this attr so we // exclude it from now on. // if (hash_insert) { hashaddLEN(&(ap->number), sizeof(ap->number), &atr, &mudstate.parent_htab); } if (aflags & AF_NOPROG) { continue; } // Check for the leadin character after excluding the attrib. // This lets non-command attribs on the child block commands // on the parent. // if (buff[0] != type) { continue; } // Was there a ':'? // if (!s) { continue; } *s++ = '\0'; char *args[NUM_ENV_VARS]; if ( ( 0 != (aflags & AF_REGEXP) && regexp_match(buff + 1, (aflags & AF_NOPARSE) ? raw_str : str, ((aflags & AF_CASE) ? 0 : PCRE_CASELESS), args, NUM_ENV_VARS)) || ( 0 == (aflags & AF_REGEXP) && wild(buff + 1, (aflags & AF_NOPARSE) ? raw_str : str, args, NUM_ENV_VARS))) { match = 1; CLinearTimeAbsolute lta; wait_que(thing, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, s, NUM_ENV_VARS, args, mudstate.global_regs); for (int i = 0; i < NUM_ENV_VARS; i++) { if (args[i]) { free_lbuf(args[i]); } } } } atr_pop(); if (bFoundCommands) { mudstate.bfNoCommands.Clear(parent); mudstate.bfCommands.Set(parent); } else { mudstate.bfCommands.Clear(parent); mudstate.bfNoCommands.Set(parent); } if (bFoundListens) { mudstate.bfNoListens.Clear(parent); mudstate.bfListens.Set(parent); } else { mudstate.bfListens.Clear(parent); mudstate.bfNoListens.Set(parent); } return match; } bool atr_match ( dbref thing, dbref player, char type, char *str, char *raw_str, bool check_parents ) { int lev, result; bool exclude, insert; dbref parent; // If thing is halted or we are matching $-commands on a NO_COMMAND // object, don't check anything // if ( Halted(thing) || ( AMATCH_CMD == type && No_Command(thing))) { return false; } // If we're matching ^-commands, strip ANSI // if (AMATCH_LISTEN == type) { // Remember, strip_ansi returns a pointer to a static buffer // within itself. // size_t junk; str = strip_ansi(str, &junk); } // If not checking parents, just check the thing // bool match = false; if (!check_parents) { return (atr_match1(thing, thing, player, type, str, raw_str, false, false) > 0); } // Check parents, ignoring halted objects // exclude = false; insert = true; hashflush(&mudstate.parent_htab); ITER_PARENTS(thing, parent, lev) { if (!Good_obj(Parent(parent))) { insert = false; } result = atr_match1(thing, parent, player, type, str, raw_str, exclude, insert); if (result > 0) { match = true; } else if (result < 0) { return match; } exclude = true; } return match; } /* --------------------------------------------------------------------------- * notify_check: notifies the object #target of the message msg, and * optionally notify the contents, neighbors, and location also. */ static bool check_filter(dbref object, dbref player, int filter, const char *msg_arg) { int aflags; dbref aowner; char *buf = atr_pget(object, filter, &aowner, &aflags); if (!*buf) { free_lbuf(buf); return true; } // Strip ANSI from msg. // char *msg = alloc_lbuf("check_filter.msg"); char *mp = msg; size_t nmsg; char *msg_stripped = strip_ansi(msg_arg, &nmsg); safe_copy_buf(msg_stripped, nmsg, msg, &mp); *mp = '\0'; reg_ref **preserve = NULL; preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); char *nbuf = alloc_lbuf("check_filter"); char *dp = nbuf; char *str = buf; mux_exec(nbuf, &dp, object, player, player, AttrTrace(aflags, EV_FIGNORE|EV_EVAL|EV_TOP), &str, NULL, 0); *dp = '\0'; dp = nbuf; free_lbuf(buf); restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); preserve = NULL; if (!(aflags & AF_REGEXP)) { do { char *cp = parse_to(&dp, ',', EV_STRIP_CURLY); mudstate.wild_invk_ctr = 0; if ( MuxAlarm.bAlarmed || quick_wild(cp, msg)) { free_lbuf(nbuf); free_lbuf(msg); return false; } } while (dp != NULL); } else { int case_opt = (aflags & AF_CASE) ? 0 : PCRE_CASELESS; do { int erroffset; const char *errptr; char *cp = parse_to(&dp, ',', EV_STRIP_CURLY); pcre *re; if ( !MuxAlarm.bAlarmed && (re = pcre_compile(cp, case_opt, &errptr, &erroffset, NULL)) != NULL) { const int ovecsize = 33; int ovec[ovecsize]; int matches = pcre_exec(re, NULL, msg, static_cast(strlen(msg)), 0, 0, ovec, ovecsize); if (0 <= matches) { MEMFREE(re); free_lbuf(nbuf); free_lbuf(msg); return false; } MEMFREE(re); } } while (dp != NULL); } free_lbuf(nbuf); free_lbuf(msg); return true; } static char *add_prefix(dbref object, dbref player, int prefix, const char *msg, const char *dflt) { int aflags; dbref aowner; char *buf, *nbuf, *cp, *str; buf = atr_pget(object, prefix, &aowner, &aflags); if (!*buf) { cp = buf; safe_str(dflt, buf, &cp); } else { reg_ref **preserve = NULL; preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); nbuf = cp = alloc_lbuf("add_prefix"); str = buf; mux_exec(nbuf, &cp, object, player, player, AttrTrace(aflags, EV_FIGNORE|EV_EVAL|EV_TOP), &str, NULL, 0); free_lbuf(buf); restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); buf = nbuf; } if (cp != buf) { safe_chr(' ', buf, &cp); } safe_str(msg, buf, &cp); *cp = '\0'; return buf; } static char *dflt_from_msg(dbref sender, dbref sendloc) { char *tp, *tbuff; tp = tbuff = alloc_lbuf("notify_check.fwdlist"); safe_str("From ", tbuff, &tp); if (Good_obj(sendloc)) { safe_str(Moniker(sendloc), tbuff, &tp); } else { safe_str(Moniker(sender), tbuff, &tp); } safe_chr(',', tbuff, &tp); *tp = '\0'; return tbuff; } /* Do HTML escaping, converting < to <, etc. 'dest' needs to be * allocated & freed by the caller. * * If you're using this to append to a string, you can pass in the * safe_{str|chr} (char **) so we can just do the append directly, * saving you an alloc_lbuf()...free_lbuf(). If you want us to append * from the start of 'dest', just pass in a 0 for 'destp'. * * Returns 0 if the copy succeeded, 1 if it failed. */ bool html_escape(const char *src, char *dest, char **destp) { const char *msg_orig; bool ret = false; if (destp == 0) { char *temp = dest; destp = &temp; } for (msg_orig = src; msg_orig && *msg_orig && !ret; msg_orig++) { char *p = *destp; switch (*msg_orig) { case '<': safe_str("<", dest, destp); break; case '>': safe_str(">", dest, destp); break; case '&': safe_str("&", dest, destp); break; case '\"': safe_str(""", dest, destp); break; default: safe_chr(*msg_orig, dest, destp); break; } // For <>&\, this may cause an extra loop around before it figures out that we are // out of buffer, but no harm is done in this, and the common case is a single character. // if (p == *destp) { ret = true; } } **destp = 0; return ret; } void notify_check(dbref target, dbref sender, const char *msg, int key) { // If speaker is invalid or message is empty, just exit. // if ( !Good_obj(target) || !msg || !*msg) { return; } #ifdef WOD_REALMS if ((key & MSG_OOC) == 0) { if ((key & MSG_SAYPOSE) != 0) { if (REALM_DO_HIDDEN_FROM_YOU == DoThingToThingVisibility(target, sender, ACTION_IS_TALKING)) { return; } } else { if (REALM_DO_HIDDEN_FROM_YOU == DoThingToThingVisibility(target, sender, ACTION_IS_MOVING)) { return; } } } #endif // WOD_REALMS // Enforce a recursion limit // mudstate.ntfy_nest_lev++; if (mudconf.ntfy_nest_lim <= mudstate.ntfy_nest_lev) { mudstate.ntfy_nest_lev--; return; } char *msg_ns, *mp, *tbuff, *tp, *buff; char *args[NUM_ENV_VARS]; dbref aowner, recip, obj; int i, nargs, aflags; FWDLIST *fp; // If we want NOSPOOF output, generate it. It is only needed if we are // sending the message to the target object. // if (key & MSG_ME) { mp = msg_ns = alloc_lbuf("notify_check"); if ( Nospoof(target) && target != sender && target != mudstate.curr_enactor && target != mudstate.curr_executor) { // I'd really like to use tprintf here but I can't because the // caller may have. notify(target, tprintf(...)) is quite common // in the code. // tbuff = alloc_sbuf("notify_check.nospoof"); safe_chr('[', msg_ns, &mp); safe_str(Moniker(sender), msg_ns, &mp); mux_sprintf(tbuff, SBUF_SIZE, "(#%d)", sender); safe_str(tbuff, msg_ns, &mp); if (sender != Owner(sender)) { safe_chr('{', msg_ns, &mp); safe_str(Moniker(Owner(sender)), msg_ns, &mp); safe_chr('}', msg_ns, &mp); } if (sender != mudstate.curr_enactor) { mux_sprintf(tbuff, SBUF_SIZE, "<-(#%d)", mudstate.curr_enactor); safe_str(tbuff, msg_ns, &mp); } safe_str("] ", msg_ns, &mp); free_sbuf(tbuff); } safe_str(msg, msg_ns, &mp); *mp = '\0'; } else { msg_ns = NULL; } // msg contains the raw message, msg_ns contains the NOSPOOFed msg. // bool check_listens = !Halted(target); switch (Typeof(target)) { case TYPE_PLAYER: if (key & MSG_ME) { if (key & MSG_HTML) { raw_notify_html(target, msg_ns); } else { if (Html(target)) { char *msg_ns_escaped; msg_ns_escaped = alloc_lbuf("notify_check_escape"); html_escape(msg_ns, msg_ns_escaped, 0); raw_notify(target, msg_ns_escaped); free_lbuf(msg_ns_escaped); } else { raw_notify(target, msg_ns); } } } if (!mudconf.player_listen) { check_listens = false; } // FALLTHROUGH case TYPE_THING: case TYPE_ROOM: // If we're in a pipe, objects can receive raw_notify if // they're not a player. (players were already notified // above. // if ( mudstate.inpipe && !isPlayer(target)) { raw_notify(target, msg_ns); } // Forward puppet message if it is for me. // bool has_neighbors = Has_location(target); dbref targetloc = where_is(target); bool is_audible = Audible(target); if ( (key & MSG_ME) && Puppet(target) && (target != Owner(target)) && ( (key & MSG_PUP_ALWAYS) || ( targetloc != Location(Owner(target)) && targetloc != Owner(target)))) { tp = tbuff = alloc_lbuf("notify_check.puppet"); safe_str(Moniker(target), tbuff, &tp); safe_str("> ", tbuff, &tp); safe_str(msg_ns, tbuff, &tp); *tp = '\0'; raw_notify(Owner(target), tbuff); free_lbuf(tbuff); } // Check for @Listen match if it will be useful. // bool pass_listen = false; nargs = 0; if ( check_listens && (key & (MSG_ME | MSG_INV_L)) && H_Listen(target)) { tp = atr_get(target, A_LISTEN, &aowner, &aflags); if (*tp && wild(tp, (char *)msg, args, NUM_ENV_VARS)) { for (nargs = NUM_ENV_VARS; nargs && (!args[nargs - 1] || !(*args[nargs - 1])); nargs--) { ; // Nothing } pass_listen = true; } free_lbuf(tp); } // If we matched the @listen or are monitoring, check the // USE lock. // bool pass_uselock = false; if ( (key & MSG_ME) && check_listens && ( pass_listen || Monitor(target))) { pass_uselock = could_doit(sender, target, A_LUSE); } // Process AxHEAR if we pass LISTEN, USElock and it's for me. // if ( (key & MSG_ME) && pass_listen && pass_uselock && mudstate.nHearNest <= 2) { mudstate.nHearNest++; if (sender != target) { did_it(sender, target, 0, NULL, 0, NULL, A_AHEAR, 0, args, nargs); } else { did_it(sender, target, 0, NULL, 0, NULL, A_AMHEAR, 0, args, nargs); } did_it(sender, target, 0, NULL, 0, NULL, A_AAHEAR, 0, args, nargs); mudstate.nHearNest--; } // Get rid of match arguments. We don't need them anymore. // if (pass_listen) { for (i = 0; i < nargs; i++) { if (args[i] != NULL) { free_lbuf(args[i]); } } } // Process ^-listens if for me, MONITOR, and we pass USElock. // if ( (key & MSG_ME) && pass_uselock && sender != target && Monitor(target)) { atr_match(target, sender, AMATCH_LISTEN, (char *)msg, (char *)msg, false); } // Deliver message to forwardlist members. // if ( (key & MSG_FWDLIST) && is_audible && check_filter(target, sender, A_FILTER, msg)) { tbuff = dflt_from_msg(sender, target); buff = add_prefix(target, sender, A_PREFIX, msg, tbuff); free_lbuf(tbuff); fp = fwdlist_get(target); if (fp) { for (i = 0; i < fp->count; i++) { recip = fp->data[i]; if ( !Good_obj(recip) || recip == target) { continue; } notify_check(recip, sender, buff, MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE); } } free_lbuf(buff); } // Deliver message through audible exits. // if (key & MSG_INV_EXITS) { DOLIST(obj, Exits(target)) { recip = Location(obj); if ( Audible(obj) && ( recip != target && check_filter(obj, sender, A_FILTER, msg))) { buff = add_prefix(obj, target, A_PREFIX, msg, "From a distance,"); notify_check(recip, sender, buff, MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE); free_lbuf(buff); } } } // Deliver message through neighboring audible exits. // if ( has_neighbors && ( (key & MSG_NBR_EXITS) || ( (key & MSG_NBR_EXITS_A) && is_audible))) { // If from inside, we have to add the prefix string of // the container. // if (key & MSG_S_INSIDE) { tbuff = dflt_from_msg(sender, target); buff = add_prefix(target, sender, A_PREFIX, msg, tbuff); free_lbuf(tbuff); } else { buff = (char *)msg; } DOLIST(obj, Exits(Location(target))) { recip = Location(obj); if ( Good_obj(recip) && Audible(obj) && recip != targetloc && recip != target && check_filter(obj, sender, A_FILTER, msg)) { tbuff = add_prefix(obj, target, A_PREFIX, buff, "From a distance,"); notify_check(recip, sender, tbuff, MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE); free_lbuf(tbuff); } } if (key & MSG_S_INSIDE) { free_lbuf(buff); } } // Deliver message to contents. // if ( ( (key & MSG_INV) || ( (key & MSG_INV_L) && pass_listen)) && check_filter(target, sender, A_INFILTER, msg)) { // Don't prefix the message if we were given the MSG_NOPREFIX key. // if (key & MSG_S_OUTSIDE) { buff = add_prefix(target, sender, A_INPREFIX, msg, ""); } else { buff = (char *)msg; } DOLIST(obj, Contents(target)) { if (obj != target) { notify_check(obj, sender, buff, MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE | key & MSG_HTML); } } if (key & MSG_S_OUTSIDE) { free_lbuf(buff); } } // Deliver message to neighbors. // if ( has_neighbors && ( (key & MSG_NBR) || ( (key & MSG_NBR_A) && is_audible && check_filter(target, sender, A_FILTER, msg)))) { if (key & MSG_S_INSIDE) { tbuff = dflt_from_msg(sender, target); buff = add_prefix(target, sender, A_PREFIX, msg, ""); free_lbuf(tbuff); } else { buff = (char *)msg; } DOLIST(obj, Contents(targetloc)) { if ( obj != target && obj != targetloc) { notify_check(obj, sender, buff, MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE); } } if (key & MSG_S_INSIDE) { free_lbuf(buff); } } // Deliver message to container. // if ( has_neighbors && ( (key & MSG_LOC) || ( (key & MSG_LOC_A) && is_audible && check_filter(target, sender, A_FILTER, msg)))) { if (key & MSG_S_INSIDE) { tbuff = dflt_from_msg(sender, target); buff = add_prefix(target, sender, A_PREFIX, msg, tbuff); free_lbuf(tbuff); } else { buff = (char *)msg; } notify_check(targetloc, sender, buff, MSG_ME | MSG_F_UP | MSG_S_INSIDE); if (key & MSG_S_INSIDE) { free_lbuf(buff); } } } if (msg_ns) { free_lbuf(msg_ns); } mudstate.ntfy_nest_lev--; } void notify_except(dbref loc, dbref player, dbref exception, const char *msg, int key) { dbref first; if (loc != exception) { notify_check(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A | key)); } DOLIST(first, Contents(loc)) { if (first != exception) { notify_check(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE | key)); } } } void notify_except2(dbref loc, dbref player, dbref exc1, dbref exc2, const char *msg) { dbref first; if ( loc != exc1 && loc != exc2) { notify_check(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A)); } DOLIST(first, Contents(loc)) { if ( first != exc1 && first != exc2) { notify_check(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE)); } } } /* ---------------------------------------------------------------------- * Reporting of CPU information. */ static void report_timecheck ( dbref player, bool yes_screen, bool yes_log, bool yes_clear ) { int thing, obj_counted; CLinearTimeDelta ltdPeriod, ltdTotal; CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); ltdPeriod = ltaNow - mudstate.cpu_count_from; if ( yes_log && (LOG_TIMEUSE & mudconf.log_options)) { start_log("OBJ", "CPU"); log_name(player); log_text(" checks object time use over "); log_number(ltdPeriod.ReturnSeconds()); log_text(" seconds" ENDLINE); } else { yes_log = false; STARTLOG(LOG_ALWAYS, "WIZ", "TIMECHECK"); log_name(player); log_text(" checks object time use over "); log_number(ltdPeriod.ReturnSeconds()); log_text(" seconds"); ENDLOG; } obj_counted = 0; ltdTotal.Set100ns(0); // Step through the db. Care only about the ones that are nonzero. // DO_WHOLE_DB(thing) { CLinearTimeDelta <d = db[thing].cpu_time_used; if (ltd.Return100ns()) { ltdTotal += ltd; long used_msecs = ltd.ReturnMilliseconds(); obj_counted++; if (yes_log) { Log.tinyprintf("#%d\t%ld" ENDLINE, thing, used_msecs); } if (yes_screen) { raw_notify(player, tprintf("#%d\t%ld", thing, used_msecs)); } if (yes_clear) { ltd.Set100ns(0); } } } long lTotal = ltdTotal.ReturnMilliseconds(); long lPeriod = ltdPeriod.ReturnSeconds(); if (yes_screen) { raw_notify(player, tprintf("Counted %d objects using %ld msecs over %d seconds.", obj_counted, lTotal, lPeriod)); } if (yes_log) { Log.tinyprintf("Counted %d objects using %ld msecs over %d seconds.", obj_counted, lTotal, lPeriod); end_log(); } if (yes_clear) { mudstate.cpu_count_from = ltaNow; } } void do_timecheck(dbref executor, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); bool yes_screen, yes_log, yes_clear; yes_screen = yes_log = yes_clear = false; if (key == 0) { // No switches, default to printing to screen and clearing counters. // yes_screen = true; yes_clear = true; } else { if (key & TIMECHK_RESET) { yes_clear = true; } if (key & TIMECHK_SCREEN) { yes_screen = true; } if (key & TIMECHK_LOG) { yes_log = true; } } report_timecheck(executor, yes_screen, yes_log, yes_clear); } void do_shutdown ( dbref executor, dbref caller, dbref enactor, int eval, int key, char *message ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); if (!Can_SiteAdmin(executor)) { notify(executor, NOPERM_MESSAGE); return; } raw_broadcast(0, "GAME: Shutdown by %s", Moniker(Owner(executor))); STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN"); log_text("Shutdown by "); log_name(executor); ENDLOG; STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN"); log_text("Shutdown status: "); log_text(message); ENDLOG; int fd; if (mux_open(&fd, mudconf.status_file, O_RDWR|O_CREAT|O_TRUNC|O_BINARY)) { mux_write(fd, message, static_cast(strlen(message))); mux_write(fd, ENDLINE, sizeof(ENDLINE)-1); DebugTotalFiles++; if (mux_close(fd) == 0) { DebugTotalFiles--; } } // Do we perform a normal or an emergency shutdown? Normal // shutdown is handled by exiting the main loop in shovechars, // emergency shutdown is done here. // if (key & SHUTDN_PANIC) { // Close down the network interface. // emergency_shutdown(); local_presync_database(); // Close the attribute text db and dump the header db. // #ifndef MEMORY_BASED // Save cached modified attribute list // al_store(); #endif // MEMORY_BASED pcache_sync(); SYNC; CLOSE; STARTLOG(LOG_ALWAYS, "DMP", "PANIC"); log_text("Panic dump: "); log_text(mudconf.crashdb); ENDLOG; dump_database_internal(DUMP_I_PANIC); STARTLOG(LOG_ALWAYS, "DMP", "DONE"); log_text("Panic dump complete: "); log_text(mudconf.crashdb); ENDLOG; } // Set up for normal shutdown. // mudstate.shutdown_flag = true; } // There are several types of dumps: // // Type 0 - Normal mudstate.dumping controlled // Type 1 - Panic uncontrolled but only one of these happening at a time. // Type 2 - Restart mudstate.dumping controlled. // Type 3 - FLAT mudstate.dumping controlled. // Type 4 - signal uncontrolled and if we fault twice, the game ends -- // see check_panicking. // // When changing this function and to keep forking dumps safe, keep in mind // that the following combinations can be occuring at the same time. Don't // touch each other's files. // // Type 0 and 2 are allowed to touch each other's files. Type 1 and 4 should not // touch files used in Type 0 or Type 2. // typedef struct { char **ppszOutputBase; const char *szOutputSuffix; bool bUseTemporary; int fType; const char *pszErrorMessage; } DUMP_PROCEDURE; static DUMP_PROCEDURE DumpProcedures[NUM_DUMP_TYPES] = { { 0, "" , false, 0, "" }, // 0 -- Handled specially. { &mudconf.crashdb, "" , false, UNLOAD_VERSION | UNLOAD_FLAGS, "Opening crash file" }, // 1 { &mudconf.indb, "" , true, OUTPUT_VERSION | OUTPUT_FLAGS, "Opening input file" }, // 2 { &mudconf.indb, ".FLAT" , false, UNLOAD_VERSION | UNLOAD_FLAGS, "Opening flatfile" }, // 3 { &mudconf.indb, ".SIG" , false, UNLOAD_VERSION | UNLOAD_FLAGS, "Opening signalled flatfile"} // 4 }; #ifdef WIN32 #define POPEN_READ_OP "rb" #define POPEN_WRITE_OP "wb" #else // WIN32 #define POPEN_READ_OP "r" #define POPEN_WRITE_OP "w" #endif // WIN32 void dump_database_internal(int dump_type) { char tmpfile[SIZEOF_PATHNAME+32]; char outfn[SIZEOF_PATHNAME+32]; char prevfile[SIZEOF_PATHNAME+32]; FILE *f; if ( dump_type < 0 || NUM_DUMP_TYPES <= dump_type) { return; } bool bPotentialConflicts = false; #ifndef WIN32 // If we are already dumping for some reason, and suddenly get a type 1 or // type 4 dump, basically don't touch mail and comsys files. The other // dump will take care of them as well as can be expected for now, and if // we try to, we'll just step on them. // if ( mudstate.dumping && ( dump_type == DUMP_I_PANIC || dump_type == DUMP_I_SIGNAL)) { bPotentialConflicts = true; } #endif // Call the local dump function only if another dump is not already // in progress. // local_dump_database(dump_type); if (0 < dump_type) { DUMP_PROCEDURE *dp = &DumpProcedures[dump_type]; bool bOpen; mux_sprintf(outfn, sizeof(outfn), "%s%s", *(dp->ppszOutputBase), dp->szOutputSuffix); if (dp->bUseTemporary) { mux_sprintf(tmpfile, sizeof(tmpfile), "%s.#%d#", outfn, mudstate.epoch); RemoveFile(tmpfile); bOpen = mux_fopen(&f, tmpfile, "wb"); } else { RemoveFile(outfn); bOpen = mux_fopen(&f, outfn, "wb"); } if (bOpen) { DebugTotalFiles++; setvbuf(f, NULL, _IOFBF, 16384); db_write(f, F_MUX, dp->fType); if (fclose(f) == 0) { DebugTotalFiles--; } if (dp->bUseTemporary) { ReplaceFile(tmpfile, outfn); } } else { log_perror("DMP", "FAIL", dp->pszErrorMessage, outfn); } if (!bPotentialConflicts) { if (mudconf.have_mailer) { if (mux_fopen(&f, mudconf.mail_db, "wb")) { DebugTotalFiles++; dump_mail(f); if (fclose(f) == 0) { DebugTotalFiles--; } } } if (mudconf.have_comsys) { save_comsys(mudconf.comsys_db); } } return; } // Nuke our predecessor // if (mudconf.compress_db) { mux_sprintf(prevfile, sizeof(prevfile), "%s.prev.gz", mudconf.outdb); mux_sprintf(tmpfile, sizeof(tmpfile), "%s.#%d#.gz", mudconf.outdb, mudstate.epoch - 1); RemoveFile(tmpfile); mux_sprintf(tmpfile, sizeof(tmpfile), "%s.#%d#.gz", mudconf.outdb, mudstate.epoch); mux_sprintf(outfn, sizeof(outfn), "%s.gz", mudconf.outdb); f = popen(tprintf("%s > %s", mudconf.compress, tmpfile), POPEN_WRITE_OP); if (f) { DebugTotalFiles++; setvbuf(f, NULL, _IOFBF, 16384); db_write(f, F_MUX, OUTPUT_VERSION | OUTPUT_FLAGS); if (pclose(f) != -1) { DebugTotalFiles--; } ReplaceFile(outfn, prevfile); if (ReplaceFile(tmpfile, outfn) < 0) { log_perror("SAV", "FAIL", "Renaming output file to DB file", tmpfile); } } else { log_perror("SAV", "FAIL", "Opening", tmpfile); } } else { mux_sprintf(prevfile, sizeof(prevfile), "%s.prev", mudconf.outdb); mux_sprintf(tmpfile, sizeof(tmpfile), "%s.#%d#", mudconf.outdb, mudstate.epoch - 1); RemoveFile(tmpfile); mux_sprintf(tmpfile, sizeof(tmpfile), "%s.#%d#", mudconf.outdb, mudstate.epoch); if (mux_fopen(&f, tmpfile, "wb")) { DebugTotalFiles++; setvbuf(f, NULL, _IOFBF, 16384); db_write(f, F_MUX, OUTPUT_VERSION | OUTPUT_FLAGS); if (fclose(f) == 0) { DebugTotalFiles--; } ReplaceFile(mudconf.outdb, prevfile); if (ReplaceFile(tmpfile, mudconf.outdb) < 0) { log_perror("SAV", "FAIL", "Renaming output file to DB file", tmpfile); } } else { log_perror("SAV", "FAIL", "Opening", tmpfile); } } if (mudconf.have_mailer) { if (mux_fopen(&f, mudconf.mail_db, "wb")) { DebugTotalFiles++; dump_mail(f); if (fclose(f) == 0) { DebugTotalFiles--; } } } if (mudconf.have_comsys) { save_comsys(mudconf.comsys_db); } } static void dump_database(void) { char *buff; mudstate.epoch++; #ifndef WIN32 if (mudstate.dumping) { STARTLOG(LOG_DBSAVES, "DMP", "DUMP"); log_text("Waiting on previously-forked child before dumping... "); ENDLOG; while (mudstate.dumping) { // We have a forked dump in progress, so we will wait until the // child exits. // MuxAlarm.Sleep(time_1s); } } mudstate.dumping = true; mudstate.dumped = 0; #endif buff = alloc_mbuf("dump_database"); mux_sprintf(buff, MBUF_SIZE, "%s.#%d#", mudconf.outdb, mudstate.epoch); STARTLOG(LOG_DBSAVES, "DMP", "DUMP"); log_text("Dumping: "); log_text(buff); ENDLOG; local_presync_database(); #ifndef MEMORY_BASED // Save cached modified attribute list // al_store(); #endif // MEMORY_BASED pcache_sync(); dump_database_internal(DUMP_I_NORMAL); SYNC; STARTLOG(LOG_DBSAVES, "DMP", "DONE") log_text("Dump complete: "); log_text(buff); ENDLOG; free_mbuf(buff); #ifndef WIN32 // This doesn't matter. We are about the stop the game. However, // leave it in. // mudstate.dumping = false; local_dump_complete_signal(); #endif } void fork_and_dump(int key) { #ifndef WIN32 static volatile bool bRequestAccepted = false; // fork_and_dump is never called with mudstate.dumping true, but we'll // ensure that assertion now. // if ( bRequestAccepted || mudstate.dumping) { return; } bRequestAccepted = true; #endif // If no options were given, then it means DUMP_TEXT+DUMP_STRUCT. // if (key == 0) { key = DUMP_TEXT+DUMP_STRUCT; } if (*mudconf.dump_msg) { raw_broadcast(0, "%s", mudconf.dump_msg); } check_mail_expiration(); char *buff = alloc_lbuf("fork_and_dump"); if (key & (DUMP_TEXT|DUMP_STRUCT)) { STARTLOG(LOG_DBSAVES, "DMP", "CHKPT"); if (key & DUMP_TEXT) { log_text("SYNCing"); if (key & DUMP_STRUCT) { log_text(" and "); } } if (key & DUMP_STRUCT) { mudstate.epoch++; mux_sprintf(buff, LBUF_SIZE, "%s.#%d#", mudconf.outdb, mudstate.epoch); log_text("Checkpointing: "); log_text(buff); } ENDLOG; } if (key & DUMP_FLATFILE) { STARTLOG(LOG_DBSAVES, "DMP", "FLAT"); log_text("Creating flatfile: "); mux_sprintf(buff, LBUF_SIZE, "%s.FLAT", mudconf.outdb); log_text(buff); ENDLOG; } free_lbuf(buff); local_presync_database(); #ifndef MEMORY_BASED // Save cached modified attribute list // al_store(); #endif // MEMORY_BASED pcache_sync(); SYNC; #ifndef WIN32 mudstate.write_protect = true; int child = 0; bool bChildExists = false; mudstate.dumping = true; mudstate.dumped = 0; bool bAttemptFork = mudconf.fork_dump; #if !defined(HAVE_PREAD) \ || !defined(HAVE_PWRITE) if (key & DUMP_FLATFILE) { // Don't attempt a fork()'ed @dump/flat without pread()/pwrite() // support. // bAttemptFork = false; } #endif // !HAVE_PREAD !HAVE_PWRITE #endif // WIN32 if (key & (DUMP_STRUCT|DUMP_FLATFILE)) { #ifndef WIN32 if (bAttemptFork) { child = fork(); } if (child == 0) { // If we don't clear this alarm, the child will eventually receive a // SIG_PROF. // MuxAlarm.Clear(); #endif if (key & DUMP_STRUCT) { dump_database_internal(DUMP_I_NORMAL); } if (key & DUMP_FLATFILE) { dump_database_internal(DUMP_I_FLAT); } #ifndef WIN32 if (mudconf.fork_dump) { _exit(0); } } else if (child < 0) { log_perror("DMP", "FORK", NULL, "fork()"); } else { mudstate.dumper = child; if (mudstate.dumper == mudstate.dumped) { // The child process executed and exited before fork() returned // to the parent process. Without a process id, the parent's // SIGCHLD handler could not be certain that the pid of the // exiting process would match the pid of this child. // // At the this point, we can be sure, however, there's // nothing much left to do. // // See SIGCHLD handler in bsd.cpp. // mudstate.dumper = 0; mudstate.dumped = 0; } else { bChildExists = true; } } #endif } #ifndef WIN32 mudstate.write_protect = false; if (!bChildExists) { // We have the ability to fork children, but we are not configured to // use it; or, we tried to fork a child and failed; or, we didn't // need to dump the structure or a flatfile; or, the child has finished // dumping already. // mudstate.dumper = 0; mudstate.dumping = false; local_dump_complete_signal(); } bRequestAccepted = false; #endif if (*mudconf.postdump_msg) { raw_broadcast(0, "%s", mudconf.postdump_msg); } } #define LOAD_GAME_SUCCESS 0 #define LOAD_GAME_NO_INPUT_DB (-1) #define LOAD_GAME_CANNOT_OPEN (-2) #define LOAD_GAME_LOADING_PROBLEM (-3) #ifdef MEMORY_BASED static int load_game(void) #else // MEMORY_BASED static int load_game(int ccPageFile) #endif // MEMORY_BASED { FILE *f = NULL; char infile[SIZEOF_PATHNAME+8]; struct stat statbuf; int db_format, db_version, db_flags; bool compressed = false; if (mudconf.compress_db) { mux_sprintf(infile, sizeof(infile), "%s.gz", mudconf.indb); if (stat(infile, &statbuf) == 0) { f = popen(tprintf(" %s < %s", mudconf.uncompress, infile), POPEN_READ_OP); if (f != NULL) { DebugTotalFiles++; compressed = true; } } } if (!compressed) { mux_strncpy(infile, mudconf.indb, sizeof(infile)-1); if (stat(infile, &statbuf) != 0) { // Indicate that we couldn't load because the input db didn't // exist. // return LOAD_GAME_NO_INPUT_DB; } if (!mux_fopen(&f, infile, "rb")) { return LOAD_GAME_CANNOT_OPEN; } DebugTotalFiles++; setvbuf(f, NULL, _IOFBF, 16384); } // Ok, read it in. // STARTLOG(LOG_STARTUP, "INI", "LOAD") log_text("Loading: "); log_text(infile); ENDLOG if (db_read(f, &db_format, &db_version, &db_flags) < 0) { // Everything is not ok. // if (compressed) { if (pclose(f) != -1) { DebugTotalFiles--; } } else { if (fclose(f) == 0) { DebugTotalFiles--; } } f = 0; STARTLOG(LOG_ALWAYS, "INI", "FATAL") log_text("Error loading "); log_text(infile); ENDLOG return LOAD_GAME_LOADING_PROBLEM; } // Everything is ok. // if (compressed) { if (pclose(f) != -1) { DebugTotalFiles--; } } else { if (fclose(f) == 0) { DebugTotalFiles--; } } f = 0; #ifndef MEMORY_BASED if (db_flags & V_DATABASE) { // It loaded an output file. // if (ccPageFile == HF_OPEN_STATUS_NEW) { STARTLOG(LOG_STARTUP, "INI", "LOAD"); log_text("Attributes are not present in either the input file or the attribute database."); ENDLOG; } } else { // It loaded a flatfile. // if (ccPageFile == HF_OPEN_STATUS_OLD) { STARTLOG(LOG_STARTUP, "INI", "LOAD"); log_text("Attributes present in both the input file and the attribute database."); ENDLOG; } } #endif // !MEMORY_BASED if (mudconf.have_comsys) { load_comsys(mudconf.comsys_db); } if (mudconf.have_mailer) { if (mux_fopen(&f, mudconf.mail_db, "rb")) { DebugTotalFiles++; setvbuf(f, NULL, _IOFBF, 16384); Log.tinyprintf("LOADING: %s" ENDLINE, mudconf.mail_db); load_mail(f); Log.tinyprintf("LOADING: %s (done)" ENDLINE, mudconf.mail_db); if (fclose(f) == 0) { DebugTotalFiles--; } f = 0; } } STARTLOG(LOG_STARTUP, "INI", "LOAD"); log_text("Load complete."); ENDLOG; return LOAD_GAME_SUCCESS; } /* * match a list of things, using the no_command flag * * This seems to be always called with type == AMATCH_CMD... * So the fact that ansi_strip is done within atr_match only * brings about a if () performance hit... * */ bool list_check ( dbref thing, dbref player, char type, char *str, char *raw_str, bool check_parent ) { bool bMatch = false; int limit = mudstate.db_top; while (NOTHING != thing) { #ifdef REALITY_LVLS if ((thing != player) && (!(No_Command(thing))) && IsReal(thing, player)) #else if ( thing != player && !No_Command(thing)) #endif // REALITY_LVLS { bMatch |= atr_match(thing, player, type, str, raw_str, check_parent); } // Non-authoritative test of circular reference. // dbref next; if ( thing == (next = Next(thing)) || --limit < 0 || MuxAlarm.bAlarmed) { break; } thing = next; } return bMatch; } bool Hearer(dbref thing) { if ( mudstate.inpipe && thing == mudstate.poutobj) { return true; } if ( Connected(thing) || Puppet(thing) || H_Listen(thing)) { return true; } if (Monitor(thing)) { if (mudstate.bfListens.IsSet(thing)) { return true; } else if (mudstate.bfNoListens.IsSet(thing)) { return false; } else { bool bFoundCommands = false; char *buff = alloc_lbuf("Hearer"); char *as; atr_push(); for (int atr = atr_head(thing, &as); atr; atr = atr_next(&as)) { ATTR *ap = atr_num(atr); if ( !ap || (ap->flags & AF_NOPROG)) { continue; } int aflags; dbref aowner; atr_get_str(buff, thing, atr, &aowner, &aflags); if (aflags & AF_NOPROG) { continue; } char *s = NULL; if ( AMATCH_CMD == buff[0] || AMATCH_LISTEN == buff[0]) { s = strchr(buff+1, ':'); if (s) { if (AMATCH_CMD == buff[0]) { bFoundCommands = true; } else { free_lbuf(buff); atr_pop(); mudstate.bfListens.Set(thing); return true; } } } } free_lbuf(buff); atr_pop(); mudstate.bfNoListens.Set(thing); if (bFoundCommands) { mudstate.bfNoCommands.Clear(thing); mudstate.bfCommands.Set(thing); } else { mudstate.bfCommands.Clear(thing); mudstate.bfNoCommands.Set(thing); } } } return false; } void do_readcache(dbref executor, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); helpindex_load(executor); fcache_load(executor); } static void process_preload(void) { dbref thing, parent, aowner; int aflags, lev; char *tstr; tstr = alloc_lbuf("process_preload.string"); DO_WHOLE_DB(thing) { // Ignore GOING objects. // if (Going(thing)) { continue; } scheduler.RunTasks(10); // Look for a STARTUP attribute in parents. // if (mudconf.run_startup) { ITER_PARENTS(thing, parent, lev) { if (H_Startup(thing)) { did_it(Owner(thing), thing, 0, NULL, 0, NULL, A_STARTUP, 0, NULL, 0); // Process queue entries as we add them. // scheduler.RunTasks(10); break; } } } // Look for a FORWARDLIST attribute. // if (H_Fwdlist(thing)) { atr_get_str(tstr, thing, A_FORWARDLIST, &aowner, &aflags); if (*tstr) { FWDLIST *fp = fwdlist_load(GOD, tstr); if (NULL != fp) { fwdlist_set(thing, fp); if (fp->data) { delete [] fp->data; } delete fp; fp = NULL; } } } } free_lbuf(tstr); } #ifndef MEMORY_BASED /* * --------------------------------------------------------------------------- * * info: display info about the file being read or written. */ static void info(int fmt, int flags, int ver) { const char *cp; if (fmt == F_MUX) { cp = "MUX"; } else { cp = "*unknown*"; } Log.tinyprintf("%s version %d:", cp, ver); if ( ver < MIN_SUPPORTED_VERSION || MAX_SUPPORTED_VERSION < ver) { Log.WriteString(" Unsupported version"); exit(1); } else if ( ( ( 1 == ver || 2 == ver) && (flags & MANDFLAGS_V2) != MANDFLAGS_V2) || ( 3 == ver && (flags & MANDFLAGS_V3) != MANDFLAGS_V3)) { Log.WriteString(" Unsupported flags"); exit(1); } if (flags & V_DATABASE) Log.WriteString(" Database"); if (flags & V_ATRNAME) Log.WriteString(" AtrName"); if (flags & V_ATRKEY) Log.WriteString(" AtrKey"); if (flags & V_ATRMONEY) Log.WriteString(" AtrMoney"); Log.WriteString(ENDLINE); } static const char *standalone_infile = NULL; static const char *standalone_outfile = NULL; static const char *standalone_basename = NULL; static bool standalone_check = false; static bool standalone_load = false; static bool standalone_unload = false; static void dbconvert(void) { int setflags, clrflags, ver; int db_ver, db_format, db_flags; Log.SetBasename("-"); Log.StartLogging(); SeedRandomNumberGenerator(); pool_init(POOL_LBUF, LBUF_SIZE); pool_init(POOL_MBUF, MBUF_SIZE); pool_init(POOL_SBUF, SBUF_SIZE); pool_init(POOL_BOOL, sizeof(struct boolexp)); cf_init(); // Decide what conversions to do and how to format the output file. // setflags = clrflags = ver = 0; bool do_redirect = false; bool do_write = true; if (standalone_check) { do_write = false; } if (standalone_load) { clrflags = 0xffffffff; setflags = OUTPUT_FLAGS; ver = OUTPUT_VERSION; do_redirect = true; } else if (standalone_unload) { clrflags = 0xffffffff; setflags = UNLOAD_FLAGS; ver = UNLOAD_VERSION; } // Open the database // init_attrtab(); char dirfile[SIZEOF_PATHNAME]; char *dirfile_c = dirfile; safe_copy_str(standalone_basename, dirfile, &dirfile_c, (SIZEOF_PATHNAME-1)); safe_copy_str(".dir", dirfile, &dirfile_c, (SIZEOF_PATHNAME-1)); *dirfile_c = '\0'; char pagfile[SIZEOF_PATHNAME]; char *pagfile_c = pagfile; safe_copy_str(standalone_basename, pagfile, &pagfile_c, (SIZEOF_PATHNAME-1)); safe_copy_str(".pag", pagfile, &pagfile_c, (SIZEOF_PATHNAME-1)); *pagfile_c = '\0'; int cc = init_dbfile(dirfile, pagfile, 650); if (cc == HF_OPEN_STATUS_ERROR) { Log.tinyprintf("Can't open database in (%s, %s) files\n", dirfile, pagfile); exit(1); } else if (cc == HF_OPEN_STATUS_OLD) { if (setflags == OUTPUT_FLAGS) { Log.tinyprintf("Would overwrite existing database (%s, %s)\n", dirfile, pagfile); CLOSE; exit(1); } } else if (cc == HF_OPEN_STATUS_NEW) { if (setflags == UNLOAD_FLAGS) { Log.tinyprintf("Database (%s, %s) is empty.\n", dirfile, pagfile); CLOSE; exit(1); } } FILE *fpIn; if (!mux_fopen(&fpIn, standalone_infile, "rb")) { exit(1); } // Go do it. // if (do_redirect) { cache_redirect(); } setvbuf(fpIn, NULL, _IOFBF, 16384); if (db_read(fpIn, &db_format, &db_ver, &db_flags) < 0) { cache_cleanup(); exit(1); } if (do_redirect) { cache_pass2(); } Log.WriteString("Input: "); info(db_format, db_flags, db_ver); if (standalone_check) { do_dbck(NOTHING, NOTHING, NOTHING, DBCK_FULL); } fclose(fpIn); if (do_write) { FILE *fpOut; if (!mux_fopen(&fpOut, standalone_outfile, "wb")) { exit(1); } db_flags = (db_flags & ~clrflags) | setflags; if (db_format != F_MUX) { db_ver = 3; } if (ver != 0) { db_ver = ver; } Log.WriteString("Output: "); info(F_MUX, db_flags, db_ver); setvbuf(fpOut, NULL, _IOFBF, 16384); #ifndef MEMORY_BASED // Save cached modified attribute list // al_store(); #endif // MEMORY_BASED db_write(fpOut, F_MUX, db_ver | db_flags); fclose(fpOut); } CLOSE; db_free(); exit(0); } #endif // MEMORY_BASED static void write_pidfile(const char *pFilename) { FILE *fp; if (mux_fopen(&fp, pFilename, "wb")) { fprintf(fp, "%d" ENDLINE, game_pid); fclose(fp); } else { STARTLOG(LOG_ALWAYS, "PID", "FAIL"); Log.tinyprintf("Failed to write pidfile %s\n", pFilename); ENDLOG; } } #ifdef FIRANMUX static void init_sql(void) { if ('\0' != mudconf.sql_server[0]) { STARTLOG(LOG_STARTUP,"SQL","CONN"); log_text("Connecting: "); log_text(mudconf.sql_database); log_text("@"); log_text(mudconf.sql_server); log_text(" as "); log_text(mudconf.sql_user); ENDLOG; mush_database = mysql_init(NULL); if (mush_database) { if (mysql_real_connect(mush_database,mudconf.sql_server, mudconf.sql_user, mudconf.sql_password, mudconf.sql_database, 0, NULL, 0)) { STARTLOG(LOG_STARTUP,"SQL","CONN"); log_text("Connected to MySQL"); ENDLOG; } else { STARTLOG(LOG_STARTUP,"SQL","CONN"); log_text("Unable to connect"); ENDLOG; mysql_close(mush_database); mush_database = NULL; } } else { STARTLOG(LOG_STARTUP,"SQL","CONN"); log_text("MySQL Library unavailable"); ENDLOG; } } } #endif // FIRANMUX long DebugTotalFiles = 3; long DebugTotalSockets = 0; #ifdef WIN32 long DebugTotalThreads = 1; long DebugTotalSemaphores = 0; #endif #ifdef MEMORY_ACCOUNTING long DebugTotalMemory = 0; #endif #define CLI_DO_CONFIG_FILE CLI_USER+0 #define CLI_DO_MINIMAL CLI_USER+1 #define CLI_DO_VERSION CLI_USER+2 #define CLI_DO_USAGE CLI_USER+3 #define CLI_DO_INFILE CLI_USER+4 #define CLI_DO_OUTFILE CLI_USER+5 #define CLI_DO_CHECK CLI_USER+6 #define CLI_DO_LOAD CLI_USER+7 #define CLI_DO_UNLOAD CLI_USER+8 #define CLI_DO_BASENAME CLI_USER+9 #define CLI_DO_PID_FILE CLI_USER+10 #define CLI_DO_ERRORPATH CLI_USER+11 #define CLI_DO_SELECT CLI_USER+12 static bool bMinDB = false; static bool bSyntaxError = false; static const char *conffile = NULL; static bool bVersion = false; static const char *pErrorBasename = ""; static bool bServerOption = false; #ifdef MEMORY_BASED #define NUM_CLI_OPTIONS 7 #else #define NUM_CLI_OPTIONS 13 #endif static CLI_OptionEntry OptionTable[NUM_CLI_OPTIONS] = { { "c", CLI_REQUIRED, CLI_DO_CONFIG_FILE }, { "s", CLI_NONE, CLI_DO_MINIMAL }, { "v", CLI_NONE, CLI_DO_VERSION }, { "h", CLI_NONE, CLI_DO_USAGE }, #ifndef MEMORY_BASED { "i", CLI_REQUIRED, CLI_DO_INFILE }, { "o", CLI_REQUIRED, CLI_DO_OUTFILE }, { "k", CLI_NONE, CLI_DO_CHECK }, { "l", CLI_NONE, CLI_DO_LOAD }, { "u", CLI_NONE, CLI_DO_UNLOAD }, { "d", CLI_REQUIRED, CLI_DO_BASENAME }, #endif // MEMORY_BASED #ifdef WIN32 { "n", CLI_NONE, CLI_DO_SELECT }, #endif // WIN32 { "p", CLI_REQUIRED, CLI_DO_PID_FILE }, { "e", CLI_REQUIRED, CLI_DO_ERRORPATH } }; static void CLI_CallBack(CLI_OptionEntry *p, const char *pValue) { if (p) { switch (p->m_Unique) { case CLI_DO_PID_FILE: bServerOption = true; mudconf.pid_file = pValue; break; case CLI_DO_CONFIG_FILE: bServerOption = true; conffile = pValue; break; case CLI_DO_MINIMAL: bServerOption = true; bMinDB = true; break; case CLI_DO_VERSION: bServerOption = true; bVersion = true; break; case CLI_DO_ERRORPATH: bServerOption = true; pErrorBasename = pValue; break; #ifdef WIN32 case CLI_DO_SELECT: bUseCompletionPorts = false; break; #endif // WIN32 #ifndef MEMORY_BASED case CLI_DO_INFILE: mudstate.bStandAlone = true; standalone_infile = pValue; break; case CLI_DO_OUTFILE: mudstate.bStandAlone = true; standalone_outfile = pValue; break; case CLI_DO_CHECK: mudstate.bStandAlone = true; standalone_check = true; break; case CLI_DO_LOAD: mudstate.bStandAlone = true; standalone_load = true; break; case CLI_DO_UNLOAD: mudstate.bStandAlone = true; standalone_unload = true; break; case CLI_DO_BASENAME: mudstate.bStandAlone = true; standalone_basename = pValue; break; #endif case CLI_DO_USAGE: default: bSyntaxError = true; break; } } else { bSyntaxError = true; } } #if defined(__INTEL_COMPILER) && defined(_M_IX86) #define CPU_FD_ID 0x00200000UL #define CPUID_0 0 // GenuineIntel // #define INTEL_MFGSTR0 'uneG' #define INTEL_MFGSTR1 'letn' #define INTEL_MFGSTR2 'Ieni' // AuthenticAMD // #define AMD_MFGSTR0 'htuA' #define AMD_MFGSTR1 'DMAc' #define AMD_MFGSTR2 'itne' #define CPUID_1 1 #define CPU_STEPPING(x) ((x ) & 0x00000000F) #define CPU_MODEL(x) ((x >> 4) & 0x00000000F) #define CPU_FAMILY(x) ((x >> 8) & 0x00000000F) #define CPU_TYPE(x) ((x >> 12) & 0x00000000F) #define CPU_EXTMODEL(x) ((x >> 16) & 0x00000000F) #define CPU_EXTFAMILY(x) ((x >> 20) & 0x00000000F) #define CPU_FEATURE_MMX 0x00800000UL #define CPU_FEATURE_FSXR 0x01000000UL #define CPU_FEATURE_SSE 0x02000000UL #define CPU_FEATURE_SSE2 0x04000000UL #define CPU_MSR_SSE3 0x00000001UL // Indicators. // // OLDOS tags indicate that the CPU supports SSE[n], but the operating system // will throw an exception when they are used. // // #define CPU_TYPE_UNSPECIALIZED 0x00000001UL #define CPU_TYPE_FAMILY_5 0x00000002UL #define CPU_TYPE_FAMILY_6 0x00000004UL #define CPU_TYPE_FAMILY_5_MMX 0x00000008UL #define CPU_TYPE_FAMILY_6_MMX 0x00000010UL #define CPU_TYPE_FAMILY_6_MMX_FSXR 0x00000020UL #define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE_OLDOS 0x00000040UL #define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE 0x00000080UL #define CPU_TYPE_FAMILY_F_SSE2_OLDOS 0x00000100UL #define CPU_TYPE_FAMILY_F_SSE2 0x00000200UL #define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE2 0x00000400UL #define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE3 0x00000800UL #define CPU_TYPE_FAMILY_F_SSE3 0x00000800UL static void cpu_init(void) { UINT32 dwCPUID; // Determine whether CPUID instruction is supported. // __asm { // Obtain a copy of the flags register. // pushfd pop eax mov dwCPUID,eax // Attempt to flip the ID bit. // xor eax,CPU_FD_ID push eax popfd // Obtain a second copy of the flags register. // pushfd pop eax xor dwCPUID,eax } // If the ID bit didn't toggle, the CPUID instruction is not supported. // if (CPU_FD_ID != dwCPUID) { // CPUID instruction is not supported. // __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED; return; } UINT32 dwHighest; UINT32 dwMfgStr0; UINT32 dwMfgStr1; UINT32 dwMfgStr2; // CPUID is supported. // __asm { mov eax,CPUID_0 cpuid mov dwHighest,eax mov dwMfgStr0,ebx mov dwMfgStr1,ecx mov dwMfgStr2,edx } if (0 == dwHighest) { // We can't decipher anything with only CPUID (EAX=$0) available. // __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED; return; } typedef enum { Intel = 0, AMD } CPUMaker; CPUMaker maker; if ( INTEL_MFGSTR0 == dwMfgStr0 && INTEL_MFGSTR1 == dwMfgStr1 && INTEL_MFGSTR2 == dwMfgStr2) { maker = Intel; } else if ( AMD_MFGSTR0 == dwMfgStr0 && AMD_MFGSTR1 == dwMfgStr1 && AMD_MFGSTR2 == dwMfgStr2) { maker = AMD; } else { // It's not Intel or AMD. // __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED; return; } UINT32 dwSignature; UINT32 dwBrand; UINT32 dwMSR; UINT32 dwFeatures; __asm { mov eax,CPUID_1 cpuid mov dwSignature,eax mov dwBrand,ebx mov dwMSR,ecx mov dwFeatures,edx } (void)(dwBrand); // Develop 'Effective' Family and Model. // UINT32 dwEffFamily; if (CPU_FAMILY(dwSignature) == 0xF) { dwEffFamily = CPU_FAMILY(dwSignature) + CPU_EXTFAMILY(dwSignature); } else { dwEffFamily = CPU_FAMILY(dwSignature); } UINT32 dwEffModel; if (CPU_MODEL(dwSignature) == 0xF) { dwEffModel = CPU_MODEL(dwSignature) + (CPU_EXTMODEL(dwSignature) << 4); } else { dwEffModel = CPU_MODEL(dwSignature); } #define ADVF_MMX 0x00000001UL #define ADVF_FSXR 0x00000002UL #define ADVF_SSE 0x00000004UL #define ADVF_SSE2 0x00000008UL #define ADVF_SSE3 0x00000010UL UINT32 dwAdvFeatures = 0; // Decode the features the chips claim to possess. // if (dwFeatures & CPU_FEATURE_MMX) { dwAdvFeatures |= ADVF_MMX; } if (dwFeatures & CPU_FEATURE_FSXR) { dwAdvFeatures |= ADVF_FSXR; } if (dwFeatures & CPU_FEATURE_SSE) { dwAdvFeatures |= ADVF_SSE; } if (dwFeatures & CPU_FEATURE_SSE2) { dwAdvFeatures |= ADVF_SSE2; } if ( dwEffFamily <= 5 && dwMSR & CPU_MSR_SSE3) { dwAdvFeatures |= ADVF_SSE3; } // Test whether operating system will allow use of these extensions. // UINT32 dwUseable = dwAdvFeatures; if (dwUseable & ADVF_MMX) { try { __asm { // Let's try a MMX instruction. // emms } } catch (...) { dwUseable &= ~(ADVF_MMX|ADVF_SSE|ADVF_SSE2|ADVF_SSE3); } } if (dwUseable & ADVF_SSE) { try { __asm { // Let's try a SSE instruction. // xorps xmm0, xmm0 } } catch (...) { dwUseable &= ~(ADVF_SSE|ADVF_SSE2|ADVF_SSE3); } } if (dwUseable & ADVF_SSE2) { try { __asm { // Let's try a SSE2 instruction. // xorpd xmm0, xmm0 } } catch (...) { dwUseable &= ~(ADVF_SSE2|ADVF_SSE3); } } if (dwUseable & ADVF_SSE3) { try { __asm { // Let's try a SSE3 instruction. // haddpd xmm1,xmm2 } } catch (...) { dwUseable &= ~(ADVF_SSE3); } } // Map tested features to an indicator for CPU dispatching. // if (dwEffFamily <= 4) { __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED; } else if (5 == dwEffFamily) { if (dwUseable & ADVF_MMX) { __intel_cpu_indicator = CPU_TYPE_FAMILY_5_MMX; } else { __intel_cpu_indicator = CPU_TYPE_FAMILY_5; } } else { if (dwUseable & ADVF_MMX) { if (dwUseable & ADVF_FSXR) { if (dwUseable & ADVF_SSE) { if (dwUseable & ADVF_SSE2) { if (dwUseable & ADVF_SSE3) { if (dwEffFamily < 15) { __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR_SSE3; } else { __intel_cpu_indicator = CPU_TYPE_FAMILY_F_SSE3; } } else { if (dwEffFamily < 15) { __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR_SSE2; } else { __intel_cpu_indicator = CPU_TYPE_FAMILY_F_SSE2; } } } else { __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR_SSE; } } else { __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR; } } else { __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX; } } else { __intel_cpu_indicator = CPU_TYPE_FAMILY_6; } } // Report findings to the log. // fprintf(stderr, "cpu_init: %s, Family %u, Model %u, %s%s%s%s%s" ENDLINE, (Intel == maker ? "Intel" : (AMD == maker ? "AMD" : "Unknown")), dwEffFamily, dwEffModel, (dwUseable & ADVF_MMX) ? "MMX " : "", (dwUseable & ADVF_FSXR) ? "FSXR ": "", (dwUseable & ADVF_SSE) ? "SSE ": "", (dwUseable & ADVF_SSE2) ? "SSE2 ": "", (dwUseable & ADVF_SSE3) ? "SSE3 ": ""); if (dwUseable != dwAdvFeatures) { UINT32 dw = dwAdvFeatures & (~dwUseable); fprintf(stderr, "cpu_init: %s%s%s%s%s unsupported by OS." ENDLINE, (dw & ADVF_MMX) ? "MMX ": "", (dw & ADVF_FSXR) ? "FSXR ": "", (dw & ADVF_SSE) ? "SSE ": "", (dw & ADVF_SSE2) ? "SSE2 ": "", (dw & ADVF_SSE3) ? "SSE3 ": ""); } } #endif // __INTEL_COMPILER #define DBCONVERT_NAME1 "dbconvert" #define DBCONVERT_NAME2 "dbconvert.exe" int DCL_CDECL main(int argc, char *argv[]) { #if defined(__INTEL_COMPILER) && defined(_M_IX86) cpu_init(); #endif build_version(); // Look for dbconvert[.exe] in the program name. // size_t nProg = strlen(argv[0]); const char *pProg = argv[0] + nProg - 1; while ( nProg && ( mux_isalpha(*pProg) || *pProg == '.')) { nProg--; pProg--; } pProg++; mudstate.bStandAlone = false; if ( mux_stricmp(pProg, DBCONVERT_NAME1) == 0 || mux_stricmp(pProg, DBCONVERT_NAME2) == 0) { mudstate.bStandAlone = true; } mudconf.pid_file = "netmux.pid"; // Parse the command line // CLI_Process(argc, argv, OptionTable, sizeof(OptionTable)/sizeof(CLI_OptionEntry), CLI_CallBack); #ifndef MEMORY_BASED if (mudstate.bStandAlone) { int n = 0; if (standalone_check) { n++; } if (standalone_load) { n++; } if (standalone_unload) { n++; } if ( !standalone_basename || !standalone_infile || !standalone_outfile || n != 1 || bServerOption) { bSyntaxError = true; } else { dbconvert(); return 0; } } else #endif // MEMORY_BASED if (bVersion) { fprintf(stderr, "Version: %s" ENDLINE, mudstate.version); return 1; } if ( bSyntaxError || conffile == NULL || !bServerOption) { fprintf(stderr, "Version: %s" ENDLINE, mudstate.version); if (mudstate.bStandAlone) { fprintf(stderr, "Usage: %s -d -i [-o ] [-l|-u|-k]" ENDLINE, pProg); fprintf(stderr, " -d Basename." ENDLINE); fprintf(stderr, " -i Input file." ENDLINE); fprintf(stderr, " -k Check." ENDLINE); fprintf(stderr, " -l Load." ENDLINE); fprintf(stderr, " -o Output file." ENDLINE); fprintf(stderr, " -u Unload." ENDLINE); } else { fprintf(stderr, "Usage: %s [-c ] [-p ] [-h] [-s] [-v]" ENDLINE, pProg); fprintf(stderr, " -c Specify configuration file." ENDLINE); fprintf(stderr, " -e Specify logfile basename (or '-' for stderr)." ENDLINE); fprintf(stderr, " -h Display this help." ENDLINE); fprintf(stderr, " -p Specify process ID file." ENDLINE); fprintf(stderr, " -s Start with a minimal database." ENDLINE); #ifdef WIN32 fprintf(stderr, " -n Disable use of NT I/O Completion Ports." ENDLINE); #endif // WIN32 fprintf(stderr, " -v Display version string." ENDLINE ENDLINE); } return 1; } mudstate.bStandAlone = false; FLOAT_Initialize(); TIME_Initialize(); SeedRandomNumberGenerator(); Log.SetBasename(pErrorBasename); Log.StartLogging(); game_pid = mux_getpid(); write_pidfile(mudconf.pid_file); BuildSignalNamesTable(); #ifdef MEMORY_ACCOUNTING extern CHashFile hfAllocData; extern CHashFile hfIdentData; extern bool bMemAccountingInitialized; hfAllocData.Open("svdptrs.dir", "svdptrs.pag", 40); hfIdentData.Open("svdlines.dir", "svdlines.pag", 40); bMemAccountingInitialized = true; #endif #ifdef WIN32 hGameProcess = GetCurrentProcess(); // Get a handle to the kernel32 DLL // HINSTANCE hInstKernel32 = LoadLibrary("kernel32"); if (!hInstKernel32) { Log.WriteString("LoadLibrary of kernel32 failed. Cannot use completion ports." ENDLINE); bUseCompletionPorts = false; } else { if (bUseCompletionPorts) { // Find the entry point for CancelIO so we can use it. This is done // dynamically because Windows 95/98 doesn't have a CancelIO entry // point. If it were done at load time, it would always fail on // Windows 95/98...even though we don't use it or depend on it in // that case. // fpCancelIo = (FCANCELIO *)GetProcAddress(hInstKernel32, "CancelIo"); if (NULL == fpCancelIo) { Log.WriteString("GetProcAddress of _CancelIo failed." ENDLINE); bUseCompletionPorts = false; } } fpGetProcessTimes = (FGETPROCESSTIMES *)GetProcAddress(hInstKernel32, "GetProcessTimes"); if (NULL == fpGetProcessTimes) { // We can work with or without GetProcessTimes(). // Log.WriteString("GetProcAddress of GetProcessTimes failed, but that's OK." ENDLINE); } } if (bUseCompletionPorts) { Log.WriteString("Using NT I/O Completion Ports for networking." ENDLINE); } else { Log.WriteString("Using select() for networking." ENDLINE); } // Initialize WinSock. // WORD wVersionRequested = MAKEWORD(2,2); WSADATA wsaData; if (WSAStartup(wVersionRequested, &wsaData) != 0) { Log.WriteString("ERROR: Could not initialize WinSock." ENDLINE); return 101; } if ( LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { // We can't run on this version of WinSock. // Log.tinyprintf("INFO: WinSock v%d.%d instead of v2.2." ENDLINE, LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); //WSACleanup(); //return 102; } if (!bCryptoAPI) { Log.WriteString("Crypto API unavailable.\r\n"); } #endif // WIN32 mudstate.start_time.GetLocal(); mudstate.cpu_count_from.GetUTC(); pool_init(POOL_LBUF, LBUF_SIZE); pool_init(POOL_MBUF, MBUF_SIZE); pool_init(POOL_SBUF, SBUF_SIZE); pool_init(POOL_BOOL, sizeof(struct boolexp)); pool_init(POOL_DESC, sizeof(DESC)); pool_init(POOL_QENTRY, sizeof(BQUE)); pool_init(POOL_LBUFREF, sizeof(lbuf_ref)); pool_init(POOL_REGREF, sizeof(reg_ref)); tcache_init(); pcache_init(); cf_init(); #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) init_rlimit(); #endif // HAVE_SETRLIMIT RLIMIT_NOFILE init_cmdtab(); init_logout_cmdtab(); init_flagtab(); init_powertab(); init_functab(); init_attrtab(); init_version(); mudconf.config_file = StringClone(conffile); mudconf.log_dir = StringClone(pErrorBasename); cf_read(); #if defined(FIRANMUX) init_sql(); #endif // FIRANMUX fcache_init(); helpindex_init(); #ifdef MEMORY_BASED db_free(); #else // MEMORY_BASED if (bMinDB) { RemoveFile(mudconf.game_dir); RemoveFile(mudconf.game_pag); } int ccPageFile = init_dbfile(mudconf.game_dir, mudconf.game_pag, mudconf.cache_pages); if (HF_OPEN_STATUS_ERROR == ccPageFile) { STARTLOG(LOG_ALWAYS, "INI", "LOAD"); log_text("Couldn't load text database: "); log_text(mudconf.game_dir); log_text(mudconf.game_pag); ENDLOG; return 2; } #endif // MEMORY_BASED mudstate.record_players = 0; if (bMinDB) { db_make_minimal(); } else { #ifdef MEMORY_BASED int ccInFile = load_game(); #else // MEMORY_BASED int ccInFile = load_game(ccPageFile); #endif // MEMORY_BASED if (LOAD_GAME_NO_INPUT_DB == ccInFile) { // The input file didn't exist. // #ifndef MEMORY_BASED if (HF_OPEN_STATUS_NEW == ccPageFile) { // Since the .db file didn't exist, and the .pag/.dir files // were newly created, just create a minimal DB. // #endif // !MEMORY_BASED db_make_minimal(); ccInFile = LOAD_GAME_SUCCESS; #ifndef MEMORY_BASED } #endif // !MEMORY_BASED } if (ccInFile != LOAD_GAME_SUCCESS) { STARTLOG(LOG_ALWAYS, "INI", "LOAD") log_text("Couldn't load: "); log_text(mudconf.indb); ENDLOG return 2; } } set_signals(); Guest.StartUp(); // Do a consistency check and set up the freelist // do_dbck(NOTHING, NOTHING, NOTHING, 0); // Reset all the hash stats // hashreset(&mudstate.command_htab); hashreset(&mudstate.channel_htab); hashreset(&mudstate.mail_htab); hashreset(&mudstate.logout_cmd_htab); hashreset(&mudstate.func_htab); hashreset(&mudstate.flags_htab); hashreset(&mudstate.attr_name_htab); hashreset(&mudstate.player_htab); hashreset(&mudstate.fwdlist_htab); hashreset(&mudstate.desc_htab); ValidateConfigurationDbrefs(); process_preload(); #ifndef WIN32 load_restart_db(); if (!mudstate.restarting) #endif // !WIN32 { if (fclose(stdout) == 0) { DebugTotalFiles--; } if (fclose(stdin) == 0) { DebugTotalFiles--; } } SetupPorts(&nMainGamePorts, aMainGamePorts, &mudconf.ports); boot_slave(GOD, GOD, GOD, 0); #ifdef QUERY_SLAVE boot_sqlslave(GOD, GOD, GOD, 0); #endif // QUERY_SLAVE // All intialization should be complete, allow the local // extensions to configure themselves. // local_startup(); init_timer(); #ifdef WIN32 if (bUseCompletionPorts) { process_output = process_outputNT; shovecharsNT(nMainGamePorts, aMainGamePorts); } else { process_output = process_output9x; shovechars9x(nMainGamePorts, aMainGamePorts); } #else // WIN32 shovechars(nMainGamePorts, aMainGamePorts); #endif // WIN32 #ifdef FIRANMUX if (mush_database) { mysql_close(mush_database); mush_database = NULL; STARTLOG(LOG_STARTUP,"SQL","DISC"); log_text("SQL shut down"); ENDLOG; } #endif // FIRANMUX close_sockets(false, "Going down - Bye"); dump_database(); // All shutdown, barring logfiles, should be done, shutdown the // local extensions. // local_shutdown(); CLOSE; #ifndef WIN32 CleanUpSlaveSocket(); CleanUpSlaveProcess(); #endif #ifdef QUERY_SLAVE CleanUpSQLSlaveSocket(); CleanUpSQLSlaveProcess(); #endif // Go ahead and explicitly free the memory for these things so // that it's easy to spot unintentional memory leaks. // int i; for (i = 0; i < mudstate.nHelpDesc; i++) { helpindex_clean(i); } db_free(); #ifdef WIN32 // Critical section not needed any more. // if (bUseCompletionPorts) { DeleteCriticalSection(&csDescriptorList); } WSACleanup(); #endif // WIN32 return 0; } #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) void init_rlimit(void) { struct rlimit *rlp; rlp = (struct rlimit *)alloc_lbuf("rlimit"); if (getrlimit(RLIMIT_NOFILE, rlp)) { log_perror("RLM", "FAIL", NULL, "getrlimit()"); free_lbuf(rlp); return; } rlp->rlim_cur = rlp->rlim_max; if (setrlimit(RLIMIT_NOFILE, rlp)) { log_perror("RLM", "FAIL", NULL, "setrlimit()"); } free_lbuf(rlp); } #endif // HAVE_SETRLIMIT RLIMIT_NOFILE bool mux_fopen(FILE **pFile, const char *filename, const char *mode) { if (pFile) { *pFile = NULL; if ( NULL != filename && NULL != mode) { #if defined(WIN32) && !defined(__INTEL_COMPILER) && (_MSC_VER >= 1400) // 1400 is Visual C++ 2005 // return (fopen_s(pFile, filename, mode) == 0); #else *pFile = fopen(filename, mode); if (NULL != *pFile) { return true; } #endif // WIN32 } } return false; } bool mux_open(int *pfh, const char *filename, int oflag) { if (NULL != pfh) { *pfh = MUX_OPEN_INVALID_HANDLE_VALUE; if (NULL != filename) { #if defined(WIN32) && !defined(__INTEL_COMPILER) && (_MSC_VER >= 1400) // 1400 is Visual C++ 2005 // return (_sopen_s(pfh, filename, oflag, _SH_DENYNO, _S_IREAD|_S_IWRITE) == 0); #elif defined(win32) *pfh = _open(filename, oflag, _S_IREAD|_S_IWRITE); return (0 <= *pfh); #else *pfh = open(filename, oflag, 0600); return (0 <= *pfh); #endif } } return false; } const char *mux_strerror(int errnum) { #if defined(WIN32) && !defined(__INTEL_COMPILER) && (_MSC_VER >= 1400) // 1400 is Visual C++ 2005 // static char buffer[80]; strerror_s(buffer, sizeof(buffer), errnum); return buffer; #else return strerror(errnum); #endif } mux2.6/src/sha1.cpp0000600000175000017500000000765511025753746014153 0ustar sdennissdennis#include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "sha1.h" void SHA1_Init(SHA1_CONTEXT *p) { p->H[0] = 0x67452301; p->H[1] = 0xEFCDAB89; p->H[2] = 0x98BADCFE; p->H[3] = 0x10325476; p->H[4] = 0xC3D2E1F0; p->nTotal = 0; p->nblock = 0; } #ifdef WIN32 #define ROTL(d,n) _lrotl(d,n) #else // WIN32 #define ROTL(d,n) (((d) << (n)) | ((d) >> (32-(n)))) #endif // WIN32 #define Ch(x,y,z) (((x) & (y)) ^ (~(x) & (z))) #define Parity(x,y,z) ((x) ^ (y) ^ (z)) #define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) static void SHA1_HashBlock(SHA1_CONTEXT *p) { int t; UINT32 W[80]; // Prepare Message Schedule, {W sub t}. // int j; for (t = 0, j = 0; t <= 15; t++, j += 4) { W[t] = (p->block[j ] << 24) | (p->block[j+1] << 16) | (p->block[j+2] << 8) | (p->block[j+3] ); } for (t = 16; t <= 79; t++) { W[t] = ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1); } UINT32 a = p->H[0]; UINT32 b = p->H[1]; UINT32 c = p->H[2]; UINT32 d = p->H[3]; UINT32 e = p->H[4]; UINT32 T; for (t = 0; t <= 19; t++) { T = ROTL(a,5) + Ch(b,c,d) + e + 0x5A827999 + W[t]; e = d; d = c; c = ROTL(b,30); b = a; a = T; } for (t = 20; t <= 39; t++) { T = ROTL(a,5) + Parity(b,c,d) + e + 0x6ED9EBA1 + W[t]; e = d; d = c; c = ROTL(b,30); b = a; a = T; } for (t = 40; t <= 59; t++) { T = ROTL(a,5) + Maj(b,c,d) + e + 0x8F1BBCDC + W[t]; e = d; d = c; c = ROTL(b,30); b = a; a = T; } for (t = 60; t <= 79; t++) { T = ROTL(a,5) + Parity(b,c,d) + e + 0xCA62C1D6 + W[t]; e = d; d = c; c = ROTL(b,30); b = a; a = T; } p->H[0] += a; p->H[1] += b; p->H[2] += c; p->H[3] += d; p->H[4] += e; } void SHA1_Compute(SHA1_CONTEXT *p, size_t n, const char *buf) { while (n) { size_t m = sizeof(p->block) - p->nblock; if (n < m) { m = n; } memcpy(p->block + p->nblock, buf, m); buf += m; n -= m; p->nblock += m; p->nTotal += m; if (p->nblock == sizeof(p->block)) { SHA1_HashBlock(p); p->nblock = 0; } } } void SHA1_Final(SHA1_CONTEXT *p) { p->block[p->nblock++] = 0x80; if (sizeof(p->block) - sizeof(UINT64) <= p->nblock) { memset(p->block + p->nblock, 0, sizeof(p->block) - p->nblock); SHA1_HashBlock(p); memset(p->block, 0, sizeof(p->block) - sizeof(UINT64)); } else { memset(p->block + p->nblock, 0, sizeof(p->block) - p->nblock - sizeof(UINT64)); } p->nTotal *= 8; p->block[sizeof(p->block) - 8] = static_cast((p->nTotal >> 56) & 0xFF); p->block[sizeof(p->block) - 7] = static_cast((p->nTotal >> 48) & 0xFF); p->block[sizeof(p->block) - 6] = static_cast((p->nTotal >> 40) & 0xFF); p->block[sizeof(p->block) - 5] = static_cast((p->nTotal >> 32) & 0xFF); p->block[sizeof(p->block) - 4] = static_cast((p->nTotal >> 24) & 0xFF); p->block[sizeof(p->block) - 3] = static_cast((p->nTotal >> 16) & 0xFF); p->block[sizeof(p->block) - 2] = static_cast((p->nTotal >> 8) & 0xFF); p->block[sizeof(p->block) - 1] = static_cast((p->nTotal ) & 0xFF); SHA1_HashBlock(p); } #if 0 //#define TEST_STRING "abc" #define TEST_STRING "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" int main(int argc, char *argv[]) { char buffer[] = TEST_STRING; SHA1_CONTEXT shac; SHA1_Init(&shac); SHA1_Compute(&shac, strlen(TEST_STRING), buffer); SHA1_Final(&shac); int i; for (i = 0; i < 5; i++) { printf("%08X", shac.H[i]); } return 1; } #endif mux2.6/src/match.cpp0000600000175000017500000003267611025753746014414 0ustar sdennissdennis// match.cpp -- Routines for parsing arguments. // // $Id: match.cpp 492 2006-11-30 17:12:25Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "powers.h" #ifdef REALITY_LVLS #include "levels.h" #endif // REALITY_LVLS const char *NOMATCH_MESSAGE = "I don't see that here."; const char *AMBIGUOUS_MESSAGE = "I don't know which one you mean!"; const char *NOPERM_MESSAGE = "Permission denied."; const char *FUNC_FAIL_MESSAGE = "#-1"; const char *FUNC_NOMATCH_MESSAGE = "#-1 NO MATCH"; const char *OUT_OF_RANGE = "#-1 OUT OF RANGE"; const char *FUNC_NOT_FOUND = "#-1 NOT FOUND"; const char *FUNC_AMBIGUOUS = "#-2 AMBIGUOUS"; const char *FUNC_NOPERM_MESSAGE = "#-1 PERMISSION DENIED"; #define CON_LOCAL 0x01 // Match is near me. #define CON_TYPE 0x02 // Match is of requested type. #define CON_LOCK 0x04 // I pass the lock on match. #define CON_COMPLETE 0x08 // Name given is the full name. #define CON_TOKEN 0x10 // Name is a special token. #define CON_DBREF 0x20 // Name is a dbref. static MSTATE md; static void promote_match(dbref what, int confidence) { #ifdef REALITY_LVLS // Check is the object is visible. // if( Good_obj(what) && (confidence & CON_LOCAL) && !IsReal(md.player, what) && what != Location(md.player)) { return; } #endif // REALITY_LVLS // Check for type and locks, if requested. // if (md.pref_type != NOTYPE) { if ( Good_obj(what) && Typeof(what) == md.pref_type) { confidence |= CON_TYPE; } } if (md.check_keys) { MSTATE save_md; save_match_state(&save_md); if ( Good_obj(what) && could_doit(md.player, what, A_LOCK)) { confidence |= CON_LOCK; } restore_match_state(&save_md); } // If nothing matched, take it. // if (md.count == 0) { md.match = what; md.confidence = confidence; md.count = 1; return; } // If confidence is lower, ignore. // if (confidence < md.confidence) { return; } // If confidence is higher, replace. // if (confidence > md.confidence) { md.match = what; md.confidence = confidence; md.count = 1; return; } // Equal confidence, pick randomly. // md.count++; if (RandomINT32(1,md.count) == 1) { md.match = what; } return; } /* * --------------------------------------------------------------------------- * * This function removes repeated spaces from the template to which object * * names are being matched. It also removes inital and terminal spaces. */ static char *munge_space_for_match(char *name) { static char buffer[LBUF_SIZE]; char *p = name; char *q = buffer; if (p) { // Remove Initial spaces. // while (mux_isspace(*p)) { p++; } while (*p) { while ( *p && !mux_isspace(*p)) { safe_chr(*p, buffer, &q); p++; } while (mux_isspace(*p)) { p++; } if (*p) { safe_chr(' ', buffer, &q); } } } // Remove terminal spaces and terminate string. // *q = '\0'; return buffer; } void match_player(void) { if (md.confidence >= CON_DBREF) { return; } if (Good_obj(md.absolute_form) && isPlayer(md.absolute_form)) { promote_match(md.absolute_form, CON_DBREF); return; } if (*md.string == LOOKUP_TOKEN) { char *p; for (p = md.string + 1; mux_isspace(*p); p++) { ; // Nothing. } dbref match = lookup_player(NOTHING, p, true); if (Good_obj(match)) { promote_match(match, CON_TOKEN); } } } /* * returns nnn if name = #nnn, else NOTHING */ static dbref absolute_name(bool bNeedPound) { char *mname = md.string; if (bNeedPound) { if (*mname != NUMBER_TOKEN) { return NOTHING; } mname++; } if (*mname) { dbref match = parse_dbref(mname); if (Good_obj(match)) { return match; } } return NOTHING; } void match_absolute(void) { if (md.confidence >= CON_DBREF) { return; } if (Good_obj(md.absolute_form)) { promote_match(md.absolute_form, CON_DBREF); } } static void match_numeric(void) { if (md.confidence >= CON_DBREF) { return; } dbref match = absolute_name(false); if (Good_obj(match)) { promote_match(match, CON_DBREF); } } void match_me(void) { if (md.confidence >= CON_DBREF) { return; } if ( Good_obj(md.absolute_form) && md.absolute_form == md.player) { promote_match(md.player, CON_DBREF | CON_LOCAL); return; } if (!string_compare(md.string, "me")) { promote_match(md.player, CON_TOKEN | CON_LOCAL); } return; } static void match_home(void) { if (md.confidence >= CON_DBREF) { return; } if (!string_compare(md.string, "home")) { promote_match(HOME, CON_TOKEN); } return; } void match_here(void) { if (md.confidence >= CON_DBREF) { return; } if ( Good_obj(md.player) && Has_location(md.player)) { dbref loc = Location(md.player); if (Good_obj(loc)) { if (loc == md.absolute_form) { promote_match(loc, CON_DBREF | CON_LOCAL); } else if (!string_compare(md.string, "here")) { promote_match(loc, CON_TOKEN | CON_LOCAL); } else if (!string_compare(md.string, PureName(loc))) { promote_match(loc, CON_COMPLETE | CON_LOCAL); } } } } static void match_list(dbref first, int local) { if (md.confidence >= CON_DBREF) { return; } DOLIST(first, first) { if (first == md.absolute_form) { promote_match(first, CON_DBREF | local); return; } /* * Warning: make sure there are no other calls to Name() in * promote_match or its called subroutines; they * would overwrite Name()'s static buffer which is * needed by string_match(). */ const char *namebuf = PureName(first); if (!string_compare(namebuf, md.string)) { promote_match(first, CON_COMPLETE | local); } else if (string_match(namebuf, md.string)) { promote_match(first, local); } } } void match_possession(void) { if (md.confidence >= CON_DBREF) { return; } if (Good_obj(md.player) && Has_contents(md.player)) { match_list(Contents(md.player), CON_LOCAL); } } void match_neighbor(void) { if (md.confidence >= CON_DBREF) { return; } if ( Good_obj(md.player) && Has_location(md.player)) { dbref loc = Location(md.player); if (Good_obj(loc)) { match_list(Contents(loc), CON_LOCAL); } } } static bool match_exit_internal(dbref loc, dbref baseloc, int local) { if ( !Good_obj(loc) || !Has_exits(loc)) { return true; } dbref exit; bool result = false; int key; DOLIST(exit, Exits(loc)) { if (exit == md.absolute_form) { key = 0; if (Examinable(md.player, loc)) { key |= VE_LOC_XAM; } if (Dark(loc)) { key |= VE_LOC_DARK; } if (Dark(baseloc)) { key |= VE_BASE_DARK; } if (exit_visible(exit, md.player, key)) { promote_match(exit, CON_DBREF | local); return true; } } if (matches_exit_from_list(md.string, PureName(exit))) { promote_match(exit, CON_COMPLETE | local); result = true; } } return result; } void match_exit(void) { if (md.confidence >= CON_DBREF) { return; } dbref loc = Location(md.player); if ( Good_obj(md.player) && Has_location(md.player)) { (void)match_exit_internal(loc, loc, CON_LOCAL); } } void match_exit_with_parents(void) { if (md.confidence >= CON_DBREF) { return; } if ( Good_obj(md.player) && Has_location(md.player)) { dbref parent; int lev; dbref loc = Location(md.player); ITER_PARENTS(loc, parent, lev) { if (match_exit_internal(parent, loc, CON_LOCAL)) { break; } } } } void match_carried_exit(void) { if (md.confidence >= CON_DBREF) { return; } if ( Good_obj(md.player) && Has_exits(md.player)) { (void)match_exit_internal(md.player, md.player, CON_LOCAL); } } void match_carried_exit_with_parents(void) { if (md.confidence >= CON_DBREF) { return; } if ( Good_obj(md.player) && Has_exits(md.player)) { dbref parent; int lev; ITER_PARENTS(md.player, parent, lev) { if (match_exit_internal(parent, md.player, CON_LOCAL)) { break; } } } } void match_master_exit(void) { if (md.confidence >= CON_DBREF) { return; } if ( Good_obj(md.player) && Has_exits(md.player)) { (void)match_exit_internal(mudconf.master_room, mudconf.master_room, 0); } } void match_zone_exit(void) { if (md.confidence >= CON_DBREF) { return; } if ( Good_obj(md.player) && Has_exits(md.player)) { (void)match_exit_internal(Zone(md.player), Zone(md.player), 0); } } void match_everything(int key) { /* * Try matching me, then here, then absolute, then player FIRST, since * this will hit most cases. STOP if we get something, since those are * exact matches. */ match_me(); match_here(); match_absolute(); if (key & MAT_NUMERIC) { match_numeric(); } if (key & MAT_HOME) { match_home(); } match_player(); if (md.confidence >= CON_TOKEN) { return; } if (!(key & MAT_NO_EXITS)) { if (key & MAT_EXIT_PARENTS) { match_carried_exit_with_parents(); match_exit_with_parents(); } else { match_carried_exit(); match_exit(); } } match_neighbor(); match_possession(); } dbref match_result(void) { switch (md.count) { case 0: return NOTHING; case 1: return md.match; default: #if defined(FIRANMUX) return md.match; #else return AMBIGUOUS; #endif // FIRANMUX } } // Use this if you don't care about ambiguity. // dbref last_match_result(void) { return md.match; } dbref match_status(dbref player, dbref match) { switch (match) { case NOTHING: notify(player, NOMATCH_MESSAGE); return NOTHING; case AMBIGUOUS: notify(player, AMBIGUOUS_MESSAGE); return NOTHING; case NOPERM: notify(player, NOPERM_MESSAGE); return NOTHING; } return match; } dbref noisy_match_result(void) { return match_status(md.player, match_result()); } void save_match_state(MSTATE *mstate) { mstate->confidence = md.confidence; mstate->count = md.count; mstate->pref_type = md.pref_type; mstate->check_keys = md.check_keys; mstate->absolute_form = md.absolute_form; mstate->match = md.match; mstate->player = md.player; mstate->string = alloc_lbuf("save_match_state"); mux_strncpy(mstate->string, md.string, LBUF_SIZE-1); } void restore_match_state(MSTATE *mstate) { md.confidence = mstate->confidence; md.count = mstate->count; md.pref_type = mstate->pref_type; md.check_keys = mstate->check_keys; md.absolute_form = mstate->absolute_form; md.match = mstate->match; md.player = mstate->player; mux_strncpy(md.string, mstate->string, LBUF_SIZE-1); free_lbuf(mstate->string); } void init_match(dbref player, const char *name, int type) { md.confidence = -1; md.count = 0; md.check_keys = false; md.pref_type = type; md.match = NOTHING; md.player = player; md.string = munge_space_for_match((char *)name); md.absolute_form = absolute_name(true); } void init_match_check_keys(dbref player, const char *name, int type) { init_match(player, name, type); md.check_keys = true; } dbref match_thing(dbref player, char *name) { init_match(player, name, NOTYPE); match_everything(MAT_EXIT_PARENTS); return noisy_match_result(); } dbref match_thing_quiet(dbref player, char *name) { init_match(player, name, NOTYPE); match_everything(MAT_EXIT_PARENTS); return match_result(); } void safe_match_result(dbref it, char *buff, char **bufc) { if (it == AMBIGUOUS) { safe_ambiguous(buff, bufc); } else { safe_notfound(buff, bufc); } } mux2.6/src/vattr.cpp0000600000175000017500000005075211025753746014453 0ustar sdennissdennis// vattr.cpp -- Manages the user-defined attributes. // // $Id: vattr.cpp 8 2006-09-05 01:55:58Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "functions.h" #include "vattr.h" static char *store_string(char *); // Allocate space for strings in lumps this big. // #define STRINGBLOCK 1000 // Current block we're putting stuff in // static char *stringblock = (char *)NULL; // High water mark. // static size_t stringblock_hwm = 0; ATTR *vattr_find_LEN(const char *pAttrName, size_t nAttrName) { UINT32 nHash = HASH_ProcessBuffer(0, pAttrName, nAttrName); CHashTable *pht = &mudstate.vattr_name_htab; UINT32 iDir = pht->FindFirstKey(nHash); while (iDir != HF_FIND_END) { HP_HEAPLENGTH nRecord; int anum; pht->Copy(iDir, &nRecord, &anum); ATTR *va = (ATTR *)anum_table[anum]; if (strcmp(pAttrName, va->name) == 0) { return va; } iDir = pht->FindNextKey(iDir, nHash); } return NULL; } ATTR *vattr_alloc_LEN(char *pName, size_t nName, int flags) { int number = mudstate.attr_next++; anum_extend(number); return vattr_define_LEN(pName, nName, number, flags); } ATTR *vattr_define_LEN(char *pName, size_t nName, int number, int flags) { ATTR *vp = vattr_find_LEN(pName, nName); if (vp) { return vp; } vp = (ATTR *)MEMALLOC(sizeof(ATTR)); if (vp) { // NOTE: By using store_string, the only way to release the // memory associated with a user attribute name is to @restart // the game. // vp->name = store_string(pName); vp->flags = flags; vp->number = number; // This entry cannot already be in the hash table because we've checked it // above with vattr_find_LEN. // UINT32 nHash = HASH_ProcessBuffer(0, pName, nName); mudstate.vattr_name_htab.Insert(sizeof(number), nHash, &number); anum_extend(vp->number); anum_set(vp->number, (ATTR *) vp); } else { ISOUTOFMEMORY(vp); } return vp; } // There are five data structures which must remain mutually consistent: The // attr_name_htab, vattr_name_htab, the anum_table, the A_LIST for every // object, and the attribute database. // static void dbclean_CheckANHtoAT(dbref executor) { notify(executor, "1. Checking (v)attr_name_htabs to anum_table mapping..."); // This test traverses the attr_name_htab/vattr_name_htab and verifies // that the corresponding anum_table entry exists and is valid. // int nAttributes = 0; int nPredefined = 0; int nUserDefined = 0; int nOutOfBounds = 0; int nInvalid = 0; for (ATTR *pa = (ATTR *)hash_firstentry(&mudstate.attr_name_htab); pa; pa = (ATTR *)hash_nextentry(&mudstate.attr_name_htab)) { nAttributes++; int iAttr = pa->number; if (iAttr <= 0 || iAttr > anum_alc_top) { nOutOfBounds++; } else { if (iAttr < A_USER_START) { nPredefined++; } else { nInvalid++; } ATTR *pb = (ATTR *) anum_get(iAttr); if (pb != pa) { nInvalid++; } } } for (ATTR *va = vattr_first(); va; va = vattr_next(va)) { nAttributes++; int iAttr = va->number; if (iAttr <= 0 || iAttr > anum_alc_top) { nOutOfBounds++; } else { if (iAttr < A_USER_START) { nInvalid++; } else { nUserDefined++; } ATTR *vb = (ATTR *) anum_get(iAttr); if (vb != va) { nInvalid++; } } } notify(executor, tprintf(" Total Attributes: %d", nAttributes)); notify(executor, tprintf(" Predefined: %d", nPredefined)); notify(executor, tprintf(" User Defined: %d", nUserDefined)); notify(executor, tprintf(" Index Out of Bounds: %d", nOutOfBounds)); notify(executor, tprintf(" Inconsistent: %d", nInvalid)); notify(executor, " Done."); } static void dbclean_CheckATtoANH(dbref executor) { notify(executor, "2. Checking anum_table to vattr_name_htab mapping..."); // This test traverses the anum_table and verifies that the corresponding attr_name_htab and // vattr_name_htab entries exist and are valid. // int nAttributes = 0; int nPredefined = 0; int nUserDefined = 0; int nInvalid = 0; int nEmpty = 0; for (int iAttr = 1; iAttr <= anum_alc_top; iAttr++) { if (iAttr < A_USER_START) { ATTR *pa = (ATTR *) anum_get(iAttr); if (pa) { nPredefined++; nAttributes++; // Convert name to upper case. // char Buffer[SBUF_SIZE]; mux_strncpy(Buffer, pa->name, SBUF_SIZE-1); mux_strupr(Buffer); // Fetch the attribute structure pointer -- which should match the one // from the corresponding table entry. // ATTR *pb = (ATTR *) hashfindLEN(Buffer, strlen(Buffer), &mudstate.attr_name_htab); if (pb != pa) { nInvalid++; } } else { nEmpty++; } } else { ATTR *va = (ATTR *) anum_get(iAttr); if (va) { nUserDefined++; nAttributes++; ATTR *vb = vattr_find_LEN(va->name, strlen(va->name)); if (vb != va) { nInvalid++; } } else { nEmpty++; } } } notify(executor, tprintf(" Total Attributes: %d", nAttributes)); notify(executor, tprintf(" Predefined: %d", nPredefined)); notify(executor, tprintf(" User Defined: %d", nUserDefined)); notify(executor, tprintf(" Empty: %d", nEmpty)); notify(executor, tprintf(" Inconsistent: %d", nInvalid)); notify(executor, " Done."); } static void dbclean_CheckALISTtoAT(dbref executor) { notify(executor, "3. Checking ALIST to anum_table mapping..."); // Traverse every attribute on every object and make sure that attribute is // represented in the attribute table. // dbref iObject; int nInvalid = 0; int nDangle = 0; int nALIST = 0; atr_push(); DO_WHOLE_DB(iObject) { char *as; for (int iAttr = atr_head(iObject, &as); iAttr; iAttr = atr_next(&as)) { if (iAttr <= 0) { nInvalid++; } else if (iAttr < A_USER_START) { ATTR *pa = (ATTR *) anum_get(iAttr); if (pa == NULL) { nInvalid++; } } else if (iAttr <= anum_alc_top) { ATTR *va = (ATTR *) anum_get(iAttr); if (va == NULL) { // We can try to fix this one. // const char *pRecord = atr_get_raw(iObject, iAttr); if (pRecord) { // If the attribute exists in the DB, then the easiest thing to do // is add a dummy attribute name. Note: The following attribute // is already in Canonical form, otherwise, we would need to // call MakeCanonicalAttributeName. // char *p = tprintf("DANGLINGATTR-%08d", iAttr); vattr_define_LEN(p, strlen(p), iAttr, 0); nDangle++; } else { // Otherwise, the easiest thing to do is remove it from the ALIST. // atr_clr(iObject, iAttr); nALIST++; } } } else { nInvalid++; } } } notify(executor, tprintf(" Invalid: %d", nInvalid)); notify(executor, tprintf(" DANGLINGATTR-99999999 added: %d", nDangle)); notify(executor, tprintf(" ALIST prunes: %d", nALIST)); atr_pop(); } static void dbclean_CheckALISTtoDB(dbref executor) { notify(executor, "4. Checking ALIST against attribute DB on disk..."); // Traverse every attribute on every object and make sure that attribute is // represented attribute database. // dbref iObject; int nInvalid = 0; int nMissing = 0; atr_push(); DO_WHOLE_DB(iObject) { char *as; for (int iAttr = atr_head(iObject, &as); iAttr; iAttr = atr_next(&as)) { if (iAttr <= 0) { nInvalid++; } else if (iAttr <= anum_alc_top) { const char *pRecord = atr_get_raw(iObject, iAttr); if (!pRecord) { // The contents are gone. The easiest thing to do is remove it from the ALIST. // atr_clr(iObject, iAttr); nMissing++; } } else { nInvalid++; } } } notify(executor, tprintf(" Invalid: %d", nInvalid)); notify(executor, tprintf(" DB prunes: %d", nMissing)); atr_pop(); } static void dbclean_IntegrityChecking(dbref executor) { dbclean_CheckANHtoAT(executor); dbclean_CheckATtoANH(executor); dbclean_CheckALISTtoAT(executor); dbclean_CheckALISTtoDB(executor); } static int dbclean_RemoveStaleAttributeNames(void) { ATTR *va; // Clear every valid attribute's AF_ISUSED flag // int iAttr; for (iAttr = A_USER_START; iAttr <= anum_alc_top; iAttr++) { va = (ATTR *) anum_get(iAttr); if (va != NULL) { va->flags &= ~AF_ISUSED; } } // Traverse every attribute on every object and mark it's attribute as AF_ISUSED. // dbref iObject; atr_push(); DO_WHOLE_DB(iObject) { char *as; for (int atr = atr_head(iObject, &as); atr; atr = atr_next(&as)) { if (atr >= A_USER_START) { va = (ATTR *) anum_get(atr); if (va != NULL) { va->flags |= AF_ISUSED; } } } } atr_pop(); // Traverse the attribute table again and remove the ones that aren't AF_ISUSED, // and count how many vattributes -are- used. // int cVAttributes = 0; for (iAttr = A_USER_START; iAttr <= anum_alc_top; iAttr++) { va = (ATTR *) anum_get(iAttr); if (va != NULL) { if ((AF_ISUSED & (va->flags)) != AF_ISUSED) { anum_set(iAttr, NULL); // Delete from hashtable. // UINT32 nHash = HASH_ProcessBuffer(0, va->name, strlen(va->name)); CHashTable *pht = &mudstate.vattr_name_htab; UINT32 iDir = pht->FindFirstKey(nHash); while (iDir != HF_FIND_END) { HP_HEAPLENGTH nRecord; int anum; pht->Copy(iDir, &nRecord, &anum); if (iAttr == anum) { pht->Remove(iDir); } iDir = pht->FindNextKey(iDir, nHash); } MEMFREE(va); va = NULL; } else { cVAttributes++; va->flags &= ~AF_ISUSED; } } } return cVAttributes; } static void dbclean_RenumberAttributes(int cVAttributes) { ATTR *va; // Now that all the stale attribute entries have been removed, we can // begin the interesting task of renumbering the attributes that remain. // The range [A_USER_START, A_USER_START+cVAttributes] will be left // alone. The range (A_USER_START+cVAttribute, anum_alc_top] can be // reallocated from the first range. To create this mapping from old // attribute numbers to new ones, we need the following table: // int iMapStart = A_USER_START+cVAttributes+1; int iMapEnd = anum_alc_top; int nMap = iMapEnd - iMapStart + 1; int *aMap = (int *)MEMALLOC(sizeof(int) * nMap); ISOUTOFMEMORY(aMap); int iSweep = A_USER_START; memset(aMap, 0, sizeof(int) * nMap); for (int i = nMap - 1; i >= 0 && iSweep < iMapStart; i--) { int iAttr = iMapStart + i; va = (ATTR *) anum_get(iAttr); if (va != NULL) { while (anum_get(iSweep)) { iSweep++; } int iAllocated = iSweep++; aMap[i] = iAllocated; // Change vattr_name_htab mapping as well to point to // iAllocated instead of iAttr. // UINT32 nHash = HASH_ProcessBuffer(0, va->name, strlen(va->name)); CHashTable *pht = &mudstate.vattr_name_htab; UINT32 iDir = pht->FindFirstKey(nHash); while (iDir != HF_FIND_END) { HP_HEAPLENGTH nRecord; int anum; pht->Copy(iDir, &nRecord, &anum); if (anum == iAttr) { pht->Update(iDir, sizeof(int), &iAllocated); break; } iDir = pht->FindNextKey(iDir, nHash); } va->number = iAllocated; anum_set(iAllocated, (ATTR *)va); anum_set(iAttr, NULL); mudstate.attr_next = iAttr; } } // aMap contains a unique map from old, high-numbered attribute // entries to new, low-numbered, empty attribute entries. We can // traverse all the attributes on all the objects again and look for // attributes numbers in the range [iMapStart, iMapEnd]. FETCHing // them out of the database using the old attribute number, STOREing // them in the database using the new attribute number, and // TM_DELETEing them under the old attributes number. // atr_push(); dbref iObject; DO_WHOLE_DB(iObject) { char *as; for ( int iAttr = atr_head(iObject, &as); iAttr; iAttr = atr_next(&as) ) { if (iMapStart <= iAttr && iAttr <= iMapEnd) { int iNew = aMap[iAttr-iMapStart]; if (iNew) { dbref iOwner; int iFlag; char *pRecord = atr_get(iObject, iAttr, &iOwner, &iFlag); atr_add_raw(iObject, iNew, pRecord); free_lbuf(pRecord); atr_add_raw(iObject, iAttr, NULL); } } } } // Traverse entire @addcommand data structure. // int nKeyLength; char *pKeyName; CMDENT *old; for (old = (CMDENT *)hash_firstkey(&mudstate.command_htab, &nKeyLength, &pKeyName); old != NULL; old = (CMDENT *)hash_nextkey(&mudstate.command_htab, &nKeyLength, &pKeyName)) { if (old && (old->callseq & CS_ADDED)) { pKeyName[nKeyLength] = '\0'; ADDENT *nextp; for (nextp = old->addent; nextp != NULL; nextp = nextp->next) { if (strcmp(pKeyName, nextp->name) != 0) { continue; } int iAttr = nextp->atr; if (iMapStart <= iAttr && iAttr <= iMapEnd) { int iNew = aMap[iAttr-iMapStart]; if (iNew) { nextp->atr = iNew; } } } } } // Traverse entire @function data structure. // UFUN *ufp2; for (ufp2 = ufun_head; ufp2; ufp2 = ufp2->next) { int iAttr = ufp2->atr; if (iMapStart <= iAttr && iAttr <= iMapEnd) { int iNew = aMap[iAttr-iMapStart]; if (iNew) { ufp2->atr = iNew; } } } atr_pop(); MEMFREE(aMap); aMap = NULL; } void do_dbclean(dbref executor, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); #ifndef WIN32 if (mudstate.dumping) { notify(executor, "Dumping in progress. Try again later."); return; } #endif // !WIN32 #ifndef MEMORY_BASED // Save cached modified attribute list // al_store(); #endif // MEMORY_BASED pcache_sync(); notify(executor, "Checking Integrity of the attribute data structures..."); dbclean_IntegrityChecking(executor); notify(executor, "Removing stale attributes names..."); int cVAttributes = dbclean_RemoveStaleAttributeNames(); notify(executor, "Renumbering and compacting attribute numbers..."); dbclean_RenumberAttributes(cVAttributes); notify(executor, tprintf("Next Attribute number to allocate: %d", mudstate.attr_next)); notify(executor, "Checking Integrity of the attribute data structures..."); dbclean_IntegrityChecking(executor); notify(executor, "@dbclean completed.."); } void vattr_delete_LEN(char *pName, size_t nName) { // Delete from hashtable. // UINT32 nHash = HASH_ProcessBuffer(0, pName, nName); CHashTable *pht = &mudstate.vattr_name_htab; UINT32 iDir = pht->FindFirstKey(nHash); while (iDir != HF_FIND_END) { HP_HEAPLENGTH nRecord; int anum; pht->Copy(iDir, &nRecord, &anum); if (strcmp(pName, anum_table[anum]->name) == 0) { ATTR *vp = (ATTR *)anum_table[anum]; anum_set(anum, NULL); pht->Remove(iDir); MEMFREE(vp); vp = NULL; } iDir = pht->FindNextKey(iDir, nHash); } } ATTR *vattr_rename_LEN(char *pOldName, size_t nOldName, char *pNewName, size_t nNewName) { // Find and Delete old name from hashtable. // UINT32 nHash = HASH_ProcessBuffer(0, pOldName, nOldName); CHashTable *pht = &mudstate.vattr_name_htab; UINT32 iDir = pht->FindFirstKey(nHash); while (iDir != HF_FIND_END) { HP_HEAPLENGTH nRecord; int anum; pht->Copy(iDir, &nRecord, &anum); ATTR *vp = (ATTR *)anum_table[anum]; if (strcmp(pOldName, vp->name) == 0) { pht->Remove(iDir); // Add in new name. After the Insert call, iDir is no longer // valid, so don't write code that uses it. // vp->name = store_string(pNewName); nHash = HASH_ProcessBuffer(0, pNewName, nNewName); pht->Insert(sizeof(int), nHash, &anum); return (ATTR *)anum_table[anum]; } iDir = pht->FindNextKey(iDir, nHash); } return NULL; } ATTR *vattr_first(void) { HP_HEAPLENGTH nRecord; int anum; UINT32 iDir = mudstate.vattr_name_htab.FindFirst(&nRecord, &anum); if (iDir != HF_FIND_END) { return (ATTR *)anum_table[anum]; } return NULL; } ATTR *vattr_next(ATTR *vp) { if (vp == NULL) return vattr_first(); HP_HEAPLENGTH nRecord; int anum; UINT32 iDir = mudstate.vattr_name_htab.FindNext(&nRecord, &anum); if (iDir != HF_FIND_END) { return (ATTR *)anum_table[anum]; } return NULL; } // Some goop for efficiently storing strings we expect to keep forever. There // is no freeing mechanism. // static char *store_string(char *str) { size_t nSize = strlen(str) + 1; // If we have no block, or there's not enough room left in the // current one, get a new one. // if ( !stringblock || (STRINGBLOCK - stringblock_hwm) < nSize) { // NOTE: These allocations are -never- freed, and this is // intentional. // stringblock = (char *)MEMALLOC(STRINGBLOCK); ISOUTOFMEMORY(stringblock); stringblock_hwm = 0; } char *ret = stringblock + stringblock_hwm; memcpy(ret, str, nSize); stringblock_hwm += nSize; return ret; } mux2.6/src/eval.cpp0000600000175000017500000021724011025753746014237 0ustar sdennissdennis// eval.cpp -- Command evaluation and cracking. // // $Id: eval.cpp 2720 2007-10-28 01:15:01Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "ansi.h" #include "attrs.h" #include "functions.h" //----------------------------------------------------------------------------- // parse_to: Split a line at a character, obeying nesting. The line is // destructively modified (a null is inserted where the delimiter was found) // dstr is modified to point to the char after the delimiter, and the function // return value points to the found string (space compressed if specified). If // we ran off the end of the string without finding the delimiter, dstr is // returned as NULL. // static char *parse_to_cleanup( int eval, int first, char *cstr, char *rstr, char *zstr, char *strFirewall) { if ( ( mudconf.space_compress || (eval & EV_STRIP_TS)) && !(eval & EV_NO_COMPRESS) && !first && strFirewall < cstr && cstr[-1] == ' ') { zstr--; } if ( (eval & EV_STRIP_AROUND) && *rstr == '{' && strFirewall < zstr && zstr[-1] == '}') { rstr++; if ( ( mudconf.space_compress && !(eval & EV_NO_COMPRESS)) || (eval & EV_STRIP_LS)) { while (mux_isspace(*rstr)) { rstr++; } } rstr[-1] = '\0'; zstr--; if ( ( mudconf.space_compress && !(eval & EV_NO_COMPRESS)) || (eval & EV_STRIP_TS)) { while ( strFirewall < zstr && mux_isspace(zstr[-1])) { zstr--; } } *zstr = '\0'; } *zstr = '\0'; return rstr; } /*! \brief Accesses the isSpecial_ tables with proper typecast. * * \param table indicates which table: \c L1, \c L2, \c L3, or \c L4. * \param c character being looked up. * \return lvalue of table entry. */ #define isSpecial(table, c) isSpecial_##table[(unsigned char)(c)] // During parsing, this table may be modified for a particular terminating delimeter. // The table is always restored it's original state. // // 0 means mundane character. // 1 is 0x20 ' ' delim overridable (only done by parse_to, not parse_to_lite) // 2 is 0x5B '[' delim overridable // 3 is 0x28 '(' delim overridable // 4 is 0x25 '%', 0x5C '\\', or 0x1B ESC not overridable. // 5 is 0x29 ')' or 0x5D ']' not overridable. // 6 is 0x7B '{' not overridable. // 7 is 0x00 '\0' not overridable. // 8 is the client-specific terminator. // // A code 4 or above means that the client-specified delim cannot override it. // A code 8 is temporary. // static int isSpecial_L3[256] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, // 0x10-0x1F 0, 0, 0, 0, 0, 4, 0, 0, 3, 5, 0, 0, 0, 0, 0, 0, // 0x20-0x2F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x30-0x3F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x40-0x4F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 5, 0, 0, // 0x50-0x5F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x6F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, // 0x70-0x7F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0-0xAF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0-0xBF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0-0xCF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0-0xDF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0-0xEF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF0-0xFF }; static const char isSpecial_L4[256] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // 0x10-0x1F 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x30-0x3F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x40-0x4F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 0x50-0x5F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x6F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, // 0x70-0x7F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0-0xAF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0-0xBF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0-0xCF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0-0xDF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0-0xEF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF0-0xFF }; // Characters that are valid q-registers, and their offsets in the register // array. -1 for invalid registers. // const signed char mux_RegisterSet[256] = { -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0x00-0x0F -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0x10-0x1F -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0x20-0x2F 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, // 0x30-0x3F -1,10,11,12,13,14,15,16, 17,18,19,20,21,22,23,24, // 0x40-0x4F 25,26,27,28,29,30,31,32, 33,34,35,-1,-1,-1,-1,-1, // 0x50-0x5F -1,10,11,12,13,14,15,16, 17,18,19,20,21,22,23,24, // 0x60-0x6F 25,26,27,28,29,30,31,32, 33,34,35,-1,-1,-1,-1,-1, // 0x70-0x7F -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0x80-0x8F -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0x90-0x9F -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0xA0-0xAF -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0xB0-0xBF -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0xC0-0xCF -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0xD0-0xDF -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0xE0-0xEF -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1 // 0xF0-0xFF }; // Stephen: Some silly compilers don't handle aliased pointers well. For these // compilers, we can't change this to just '*zstr++ = *cstr++'. However all // up-to-date compilers that I know about handle this correctly. // #if 1 #define NEXTCHAR *zstr++ = *cstr++; #else #define NEXTCHAR \ if (cstr == zstr) \ { \ cstr++; \ zstr++; \ } \ else \ { \ *zstr++ = *cstr++; \ } #endif char *parse_to(char **dstr, char delim, int eval) { #define stacklim 32 char stack[stacklim]; char *rstr, *cstr, *zstr, *strFirewall; int sp, tp, bracketlev; if ( dstr == NULL || *dstr == NULL) { return NULL; } if (**dstr == '\0') { rstr = *dstr; *dstr = NULL; return rstr; } sp = 0; bool first = true; strFirewall = rstr = *dstr; if ( ( mudconf.space_compress || (eval & EV_STRIP_LS)) && !(eval & EV_NO_COMPRESS)) { while (mux_isspace(*rstr)) { rstr++; } *dstr = rstr; } zstr = cstr = rstr; int iOriginalCode = isSpecial(L3, delim); isSpecial(L3, ' ') = 1; // Spaces are special. if (iOriginalCode <= 3) { // We can override this code. // isSpecial(L3, delim) = 8; } for (;;) { int iCode = isSpecial(L3, *cstr); TryAgain: if (iCode == 0) { // Mundane characters and not the delimiter we are looking for. // first = false; do { NEXTCHAR iCode = isSpecial(L3, *cstr); } while (iCode == 0); } if (iCode <= 4) { // 1 is 0x20 ' ' delim overridable // 2 is 0x5B '[' delim overridable // 3 is 0x28 '(' delim overridable // 4 is 0x25 '%', 0x5C '\\', or 0x1B ESC not overridable. // if (iCode <= 2) { // 1 is 0x20 ' ' delim overridable // 2 is 0x5B '[' delim overridable // if (iCode == 1) { // space // if ( mudconf.space_compress && !(eval & EV_NO_COMPRESS)) { if (first) { rstr++; } else if ( strFirewall < cstr && cstr[-1] == ' ') { zstr--; } } NEXTCHAR } else { // '[' // first = false; if (sp < stacklim) { stack[sp++] = ']'; } NEXTCHAR } } else { // 3 is 0x28 '(' delim overridable // 4 is 0x25 '%', 0x5C '\\', or 0x1B ESC not overridable. // if (iCode == 3) { first = false; if (sp < stacklim) { stack[sp++] = ')'; } NEXTCHAR } else { // %, \, and ESC escapes. // first = false; NEXTCHAR if (*cstr) { NEXTCHAR } } } } else { // 5 is 0x29 ')' or 0x5D ']' not overridable. // 6 is 0x7B '{' not overridable. // 7 is 0x00 '\0' not overridable. // 8 is the client-specific terminator. // if (iCode <= 6) { // 5 is 0x29 ')' or 0x5D ']' not overridable. // 6 is 0x7B '{' not overridable. // if (iCode == 5) { // ) and ] // for (tp = sp - 1; tp >= 0 && stack[tp] != *cstr; tp--) { ; // Nothing. } // If we hit something on the stack, unwind to it. Otherwise (it's // not on stack), if it's our delim we are done, and we convert the // delim to a null and return a ptr to the char after the null. If // it's not our delimiter, skip over it normally. // if (tp >= 0) { sp = tp; } else if (*cstr == delim) { rstr = parse_to_cleanup(eval, first, cstr, rstr, zstr, strFirewall); *dstr = ++cstr; isSpecial(L3, delim) = iOriginalCode; isSpecial(L3, ' ') = 0; // Spaces no longer special return rstr; } first = false; NEXTCHAR } else { // { // bracketlev = 1; if (eval & EV_STRIP_CURLY) { cstr++; } else { NEXTCHAR; } for (;;) { int iCodeL4 = isSpecial(L4, *cstr); if (iCodeL4 == 0) { // Mudane Characters // do { NEXTCHAR iCodeL4 = isSpecial(L4, *cstr); } while (iCodeL4 == 0); } if (iCodeL4 == 1) { // %, \, and ESC escapes. // if (cstr[1]) { NEXTCHAR } } else if (iCodeL4 == 2) { // '{' // bracketlev++; } else if (iCodeL4 == 3) { // '}' // bracketlev--; if (bracketlev <= 0) { break; } } else { // '\0' // break; } NEXTCHAR } if (bracketlev == 0) { if (eval & EV_STRIP_CURLY) { cstr++; } else { NEXTCHAR } } first = false; } } else { // 7 is 0x00 '\0' not overridable. // 8 is the client-specific terminator. // if (iCode == 7) { // '\0' - End of string. // isSpecial(L3, delim) = iOriginalCode; isSpecial(L3, ' ') = 0; // Spaces no longer special break; } else { // Client-Specific terminator // if (sp == 0) { rstr = parse_to_cleanup(eval, first, cstr, rstr, zstr, strFirewall); *dstr = ++cstr; isSpecial(L3, delim) = iOriginalCode; isSpecial(L3, ' ') = 0; // Spaces no longer special return rstr; } // At this point, we need to process the iOriginalCode. // iCode = iOriginalCode; goto TryAgain; } } } } rstr = parse_to_cleanup(eval, first, cstr, rstr, zstr, strFirewall); *dstr = NULL; return rstr; } // This version parse_to is less destructive. It only null-terminates the source // It doesn't process escapes. It's useful with mux_exec which will be copying // the characters to another buffer anyway and is more than able to perform the // escapes and trimming. // static char *parse_to_lite(char **dstr, char delim1, char delim2, size_t *nLen, int *iWhichDelim) { #define stacklim 32 char stack[stacklim]; char *rstr, *cstr; int sp, tp, bracketlev; if ( dstr == NULL || *dstr == NULL) { *nLen = 0; return NULL; } if (**dstr == '\0') { rstr = *dstr; *dstr = NULL; *nLen = 0; return rstr; } sp = 0; cstr = rstr = *dstr; int iOriginalCode1 = isSpecial(L3, delim1); int iOriginalCode2 = isSpecial(L3, delim2); if (iOriginalCode1 <= 3) { // We can override this code. // isSpecial(L3, delim1) = 8; } if (iOriginalCode2 <= 3) { // We can override this code. // isSpecial(L3, delim2) = 8; } for (;;) { int iCode = isSpecial(L3, *cstr); TryAgain: if (iCode == 0) { // Mundane characters and not the delimiter we are looking for. // do { cstr++; iCode = isSpecial(L3, *cstr); } while (iCode == 0); } if (iCode <= 4) { // 2 is 0x5B '[' delim overridable // 3 is 0x28 '(' delim overridable // 4 is 0x25 '%' or 0x5C '\\' not overridable. // if (iCode <= 3) { // 2 is 0x5B '[' delim overridable // 3 is 0x28 '(' delim overridable // if (sp < stacklim) { static char matcher[2] = { ']', ')'}; stack[sp++] = matcher[iCode-2]; } cstr++; } else { // 4 is 0x25 '%' or 0x5C '\\' not overridable. // cstr++; if (*cstr) { cstr++; } } } else { // 5 is 0x29 ')' or 0x5D ']' not overridable. // 6 is 0x7B '{' not overridable. // 7 is 0x00 '\0' not overridable. // 8 is the client-specific terminator. // if (iCode <= 6) { // 5 is 0x29 ')' or 0x5D ']' not overridable. // 6 is 0x7B '{' not overridable. // if (iCode == 5) { // ) and ] // for (tp = sp - 1; tp >= 0 && stack[tp] != *cstr; tp--) { ; // Nothing. } // If we hit something on the stack, unwind to it. Otherwise (it's // not on stack), if it's our delim we are done, and we convert the // delim to a null and return a ptr to the char after the null. If // it's not our delimiter, skip over it normally. // if (0 <= tp) { sp = tp; } else if ( *cstr == delim1 || *cstr == delim2) { if (*cstr == delim1) { *iWhichDelim = 1; } else { *iWhichDelim = 2; } *cstr = '\0'; *nLen = (cstr - rstr); *dstr = ++cstr; isSpecial(L3, delim1) = iOriginalCode1; isSpecial(L3, delim2) = iOriginalCode2; return rstr; } cstr++; } else { // { // bracketlev = 1; cstr++; for (;;) { int iCodeL4 = isSpecial(L4, *cstr); if (iCodeL4 == 0) { // Mudane Characters // do { cstr++; iCodeL4 = isSpecial(L4, *cstr); } while (iCodeL4 == 0); } if (iCodeL4 == 1) { // '\\' or '%' // if (cstr[1]) { cstr++; } } else if (iCodeL4 == 2) { // '{' // bracketlev++; } else if (iCodeL4 == 3) { // '}' // bracketlev--; if (bracketlev <= 0) { break; } } else { // '\0' // break; } cstr++; } if (bracketlev == 0) { cstr++; } } } else { // 7 is 0x00 '\0' not overridable. // 8 is the client-specific terminator. // if (iCode == 7) { // '\0' - End of string. // isSpecial(L3, delim1) = iOriginalCode1; isSpecial(L3, delim2) = iOriginalCode2; break; } else { // Client-Specific terminator // if (sp == 0) { if (*cstr == delim1) { *iWhichDelim = 1; } else { *iWhichDelim = 2; } *cstr = '\0'; *nLen = (cstr - rstr); *dstr = ++cstr; isSpecial(L3, delim1) = iOriginalCode1; isSpecial(L3, delim2) = iOriginalCode2; return rstr; } // At this point, we need to process the iOriginalCode. // if (*cstr == delim1) { iCode = iOriginalCode1; } else { iCode = iOriginalCode2; } goto TryAgain; } } } } *iWhichDelim = 0; *cstr = '\0'; *nLen = (cstr - rstr); *dstr = NULL; return rstr; } //----------------------------------------------------------------------------- // parse_arglist: Parse a line into an argument list contained in lbufs. A // pointer is returned to whatever follows the final delimiter. If the arglist // is unterminated, a NULL is returned. The original arglist is destructively // modified. // char *parse_arglist( dbref executor, dbref caller, dbref enactor, char *dstr, char delim, int eval, char *fargs[], dbref nfargs, char *cargs[], dbref ncargs, int *nArgsParsed ) { char *rstr, *tstr, *bp, *str; int arg, peval; if (dstr == NULL) { *nArgsParsed = 0; return NULL; } size_t nLen; int iWhichDelim; rstr = parse_to_lite(&dstr, delim, '\0', &nLen, &iWhichDelim); arg = 0; peval = (eval & ~EV_EVAL); while ( arg < nfargs && rstr) { if (arg < nfargs - 1) { tstr = parse_to(&rstr, ',', peval); } else { tstr = parse_to(&rstr, '\0', peval); } bp = fargs[arg] = alloc_lbuf("parse_arglist"); if (eval & EV_EVAL) { str = tstr; mux_exec(fargs[arg], &bp, executor, caller, enactor, eval | EV_FCHECK, &str, cargs, ncargs); *bp = '\0'; } else { mux_strncpy(fargs[arg], tstr, LBUF_SIZE-1); } arg++; } *nArgsParsed = arg; return dstr; } static char *parse_arglist_lite( dbref executor, dbref caller, dbref enactor, char *dstr, char delim, int eval, char *fargs[], dbref nfargs, char *cargs[], dbref ncargs, int *nArgsParsed) { UNUSED_PARAMETER(delim); char *tstr, *bp, *str; if (dstr == NULL) { *nArgsParsed = 0; return NULL; } size_t nLen; int peval = eval; if (eval & EV_EVAL) { peval = eval | EV_FCHECK; } else { peval = ((eval & ~EV_FCHECK)|EV_NOFCHECK); } int arg = 0; int iWhichDelim = 0; while ( arg < nfargs && dstr && iWhichDelim != 2) { if (arg < nfargs - 1) { tstr = parse_to_lite(&dstr, ',', ')', &nLen, &iWhichDelim); } else { tstr = parse_to_lite(&dstr, '\0', ')', &nLen, &iWhichDelim); } if ( iWhichDelim == 2 && arg == 0 && tstr[0] == '\0') { break; } bp = fargs[arg] = alloc_lbuf("parse_arglist"); str = tstr; mux_exec(fargs[arg], &bp, executor, caller, enactor, peval, &str, cargs, ncargs); *bp = '\0'; arg++; } *nArgsParsed = arg; return dstr; } //----------------------------------------------------------------------------- // exec: Process a command line, evaluating function calls and %-substitutions. // int get_gender(dbref player) { dbref aowner; int aflags; char *atr_gotten = atr_pget(player, A_SEX, &aowner, &aflags); char first = atr_gotten[0]; free_lbuf(atr_gotten); switch (mux_tolower(first)) { case 'p': return 4; case 'm': return 3; case 'f': case 'w': return 2; } return 1; } //--------------------------------------------------------------------------- // Trace cache routines. // typedef struct tcache_ent TCENT; static struct tcache_ent { dbref player; char *orig; char *result; struct tcache_ent *next; } *tcache_head; static bool tcache_top; static int tcache_count; void tcache_init(void) { tcache_head = NULL; tcache_top = true; tcache_count = 0; } static bool tcache_empty(void) { if (tcache_top) { tcache_top = false; tcache_count = 0; return true; } return false; } static void tcache_add(dbref player, char *orig, char *result) { if (strcmp(orig, result)) { tcache_count++; if (tcache_count <= mudconf.trace_limit) { TCENT *xp = (TCENT *) alloc_sbuf("tcache_add.sbuf"); char *tp = alloc_lbuf("tcache_add.lbuf"); size_t nvw; ANSI_TruncateToField(result, LBUF_SIZE, tp, LBUF_SIZE, &nvw, ANSI_ENDGOAL_NORMAL); xp->result = tp; xp->player = player; xp->orig = orig; xp->next = tcache_head; tcache_head = xp; } else { free_lbuf(orig); } } else { free_lbuf(orig); } } static void tcache_finish(void) { while (tcache_head != NULL) { TCENT *xp = tcache_head; tcache_head = xp->next; notify(Owner(xp->player), tprintf("%s(#%d)} '%s' -> '%s'", Name(xp->player), xp->player, xp->orig, xp->result)); free_lbuf(xp->orig); free_lbuf(xp->result); free_sbuf(xp); } tcache_top = true; tcache_count = 0; } const char *ColorTable[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10-0x1F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x30-0x3F 0, 0, ANSI_BBLUE, ANSI_BCYAN, // 0x40-0x43 0, 0, 0, ANSI_BGREEN, // 0x44-0x47 0, 0, 0, 0, // 0x48-0x4B 0, ANSI_BMAGENTA, 0, 0, // 0x4B-0x4F 0, 0, ANSI_BRED, 0, // 0x50-0x53 0, 0, 0, ANSI_BWHITE, // 0x54-0x57 ANSI_BBLACK, ANSI_BYELLOW, 0, 0, // 0x58-0x5B 0, 0, 0, 0, // 0x5B-0x5F 0, 0, ANSI_BLUE, ANSI_CYAN, // 0x60-0x63 0, 0, ANSI_BLINK, ANSI_GREEN, // 0x64-0x67 ANSI_HILITE, ANSI_INVERSE, 0, 0, // 0x68-0x6B 0, ANSI_MAGENTA, ANSI_NORMAL, 0, // 0x6C-0x6F 0, 0, ANSI_RED, 0, // 0x70-0x73 0, ANSI_UNDER, 0, ANSI_WHITE, // 0x74-0x77 ANSI_BLACK, ANSI_YELLOW, 0, 0, // 0x78-0x7B 0, 0, 0, 0, // 0x7B-0x7F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0-0xAF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0-0xBF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0-0xCF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0-0xDF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0-0xEF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF0-0xFF }; static bool isSpecial_L1[256] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // 0x10-0x1F 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x30-0x3F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x40-0x4F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // 0x50-0x5F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x6F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // 0x70-0x7F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0-0xAF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0-0xBF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0-0xCF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0-0xDF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0-0xEF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF0-0xFF }; static const unsigned char isSpecial_L2[256] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10-0x1F 0, 4, 0, 3, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 21, 0, 0, // 0x30-0x3F 20,145, 7, 6, 0, 0, 0, 0, 0, 0, 0, 0, 9,147,140,144, // 0x40-0x4F 143,130, 5,142, 8, 0,138, 0, 6, 0, 0, 0, 0, 0, 0, 0, // 0x50-0x5F 20, 17, 7, 6, 0, 0, 0, 0, 0, 0, 0, 0, 9, 19, 12, 16, // 0x60-0x6F 15, 2, 5, 14, 8, 0, 10, 0, 6, 0, 0, 0, 13, 0, 0, 0, // 0x70-0x7F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0-0xAF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0-0xBF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0-0xCF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0-0xDF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0-0xEF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF0-0xFF }; #define PTRS_PER_FRAME ((LBUF_SIZE - sizeof(char *) - sizeof(int))/sizeof(char *)) typedef struct tag_ptrsframe { int nptrs; char *ptrs[PTRS_PER_FRAME]; struct tag_ptrsframe *next; } PtrsFrame; static PtrsFrame *pPtrsFrame = NULL; char **PushPointers(int nNeeded) { if ( !pPtrsFrame || pPtrsFrame->nptrs < nNeeded) { PtrsFrame *p = (PtrsFrame *)alloc_lbuf("PushPointers"); p->next = pPtrsFrame; p->nptrs = PTRS_PER_FRAME; pPtrsFrame = p; } pPtrsFrame->nptrs -= nNeeded; return pPtrsFrame->ptrs + pPtrsFrame->nptrs; } void PopPointers(char **p, int nNeeded) { UNUSED_PARAMETER(p); if (pPtrsFrame->nptrs == PTRS_PER_FRAME) { PtrsFrame *q = pPtrsFrame->next; free_lbuf((char *)pPtrsFrame); pPtrsFrame = q; } //mux_assert(p == pPtrsFrame->ptrs + pPtrsFrame->nptrs); pPtrsFrame->nptrs += nNeeded; } #define REFS_PER_FRAME ((LBUF_SIZE - sizeof(void *) - sizeof(int))/sizeof(void *)) typedef struct tag_refsframe { int nrefs; reg_ref *refs[REFS_PER_FRAME]; struct tag_refsframe *next; } RefsFrame; static RefsFrame *pRefsFrame = NULL; reg_ref **PushRegisters(int nNeeded) { if ( !pRefsFrame || pRefsFrame->nrefs < nNeeded) { RefsFrame *p = (RefsFrame *)alloc_lbuf("PushRegisters"); p->next = pRefsFrame; p->nrefs = REFS_PER_FRAME; pRefsFrame = p; } pRefsFrame->nrefs -= nNeeded; return pRefsFrame->refs + pRefsFrame->nrefs; } void PopRegisters(reg_ref **p, int nNeeded) { UNUSED_PARAMETER(p); if (pRefsFrame->nrefs == REFS_PER_FRAME) { RefsFrame *q = pRefsFrame->next; free_lbuf((char *)pRefsFrame); pRefsFrame = q; } //mux_assert(p == pRefsFrame->refs + pRefsFrame->nrefs); pRefsFrame->nrefs += nNeeded; } void mux_exec( char *buff, char **bufc, dbref executor, dbref caller, dbref enactor, int eval, char **dstr, char *cargs[], int ncargs) { if ( *dstr == NULL || **dstr == '\0' || MuxAlarm.bAlarmed) { return; } // Stack Limit checking with thanks to RhostMUSH. // if (mudconf.nStackLimit < mudstate.nStackNest) { mudstate.bStackLimitReached = true; return; } char *TempPtr; char *tstr, *tbuf, *start, *oldp, *savestr; const char *constbuf; char ch; char *realbuff = NULL, *realbp = NULL; dbref aowner; int nfargs, aflags, feval, i; size_t n; bool ansi = false; FUN *fp; UFUN *ufp; static const char *subj[5] = {"", "it", "she", "he", "they"}; static const char *poss[5] = {"", "its", "her", "his", "their"}; static const char *obj[5] = {"", "it", "her", "him", "them"}; static const char *absp[5] = {"", "its", "hers", "his", "theirs"}; // This is scratch buffer is used potentially on every invocation of // mux_exec. Do not assume that its contents are valid after you // execute any function that could re-enter mux_exec. // static char mux_scratch[LBUF_SIZE]; char *pdstr = *dstr; int at_space = 1; int gender = -1; bool is_trace = (Trace(executor) || (eval & EV_TRACE)) && !(eval & EV_NOTRACE); bool is_top = false; // Extend the buffer if we need to. // if (LBUF_SIZE - SBUF_SIZE < (*bufc) - buff) { realbuff = buff; realbp = *bufc; buff = (char *)MEMALLOC(LBUF_SIZE); ISOUTOFMEMORY(buff); *bufc = buff; } oldp = start = *bufc; // If we are tracing, save a copy of the starting buffer. // savestr = NULL; if (is_trace) { is_top = tcache_empty(); savestr = alloc_lbuf("exec.save"); mux_strncpy(savestr, pdstr, LBUF_SIZE-1); } // Save Parser Mode. // bool bSpaceIsSpecialSave = isSpecial(L1, ' '); bool bParenthesisIsSpecialSave = isSpecial(L1, '('); bool bBracketIsSpecialSave = isSpecial(L1, '['); // Setup New Parser Mode. // bool bSpaceIsSpecial = mudconf.space_compress && !(eval & EV_NO_COMPRESS); isSpecial(L1, ' ') = bSpaceIsSpecial; isSpecial(L1, '(') = (eval & EV_FCHECK) != 0; isSpecial(L1, '[') = (eval & EV_NOFCHECK) == 0; size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; for (;;) { // Handle mundane characters specially. There are usually a lot of them. // Just copy them. // if (!isSpecial(L1, *pdstr)) { char *p = pdstr + 1; while (!isSpecial(L1, *p++)) { ; // Nothing. } n = p - pdstr - 1; if (nBufferAvailable < n) { n = nBufferAvailable; } memcpy(*bufc, pdstr, n); nBufferAvailable -= n; *bufc += n; at_space = 0; pdstr = p - 1; } // At this point, **dstr must be one of the following characters: // // 0x00 0x20 0x25 0x28 0x5B 0x5C 0x7B // NULL SP % ( [ \ { // // Test softcode shows the following distribution: // // NULL occurs 116948 times // ( occurs 49567 times // % occurs 24553 times // [ occurs 7618 times // SP occurs 1323 times // if (*pdstr == '\0') { break; } else if (*pdstr == '(') { // *pdstr == '(' // // Arglist start. See if what precedes is a function. If so, // execute it if we should. // at_space = 0; // Load an sbuf with an lowercase version of the func name, and // see if the func exists. Trim trailing spaces from the name if // configured. // char *pEnd = *bufc - 1; if (mudconf.space_compress && (eval & EV_FMAND)) { while ( oldp <= pEnd && mux_isspace(*pEnd)) { pEnd--; } } // _strlwr(tbuf); // char *p2 = mux_scratch; for (char *p = oldp; p <= pEnd; p++) { *p2++ = mux_tolower(*p); } *p2 = '\0'; size_t ntbuf = p2 - mux_scratch; fp = (FUN *)hashfindLEN(mux_scratch, ntbuf, &mudstate.func_htab); // If not a builtin func, check for global func. // ufp = NULL; if (fp == NULL) { ufp = (UFUN *)hashfindLEN(mux_scratch, ntbuf, &mudstate.ufunc_htab); } // Do the right thing if it doesn't exist. // if (!fp && !ufp) { if (eval & EV_FMAND) { *bufc = oldp; safe_str("#-1 FUNCTION (", buff, bufc); safe_str(mux_scratch, buff, bufc); safe_str(") NOT FOUND", buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; break; } else if (nBufferAvailable) { *(*bufc)++ = '('; nBufferAvailable--; } } else { // Get the arglist and count the number of args. Neg # of args // means catenate subsequent args. // if (ufp) { nfargs = MAX_ARG; } else { nfargs = fp->maxArgsParsed; } tstr = pdstr; if ( fp && (fp->flags & FN_NOEVAL)) { feval = eval & ~(EV_EVAL|EV_TOP|EV_STRIP_CURLY); } else { feval = eval & ~EV_TOP; } char **fargs = PushPointers(MAX_ARG); pdstr = parse_arglist_lite(executor, caller, enactor, pdstr + 1, ')', feval, fargs, nfargs, cargs, ncargs, &nfargs); // If no closing delim, just insert the '(' and continue normally. // if (!pdstr) { pdstr = tstr; if (nBufferAvailable) { *(*bufc)++ = *pdstr; nBufferAvailable--; } } else { pdstr--; // If it's a user-defined function, perform it now. // mudstate.func_nest_lev++; mudstate.func_invk_ctr++; if (mudconf.func_nest_lim <= mudstate.func_nest_lev) { safe_str("#-1 FUNCTION RECURSION LIMIT EXCEEDED", buff, &oldp); } else if (mudconf.func_invk_lim <= mudstate.func_invk_ctr) { safe_str("#-1 FUNCTION INVOCATION LIMIT EXCEEDED", buff, &oldp); } else if (Going(executor)) { safe_str("#-1 BAD EXECUTOR", buff, &oldp); } else if (!check_access(executor, ufp ? ufp->perms : fp->perms)) { safe_noperm(buff, &oldp); } else if (MuxAlarm.bAlarmed) { safe_str("#-1 CPU LIMITED", buff, &oldp); } else if (ufp) { tstr = atr_get(ufp->obj, ufp->atr, &aowner, &aflags); if (ufp->flags & FN_PRIV) { i = ufp->obj; } else { i = executor; } TempPtr = tstr; reg_ref **preserve = NULL; if (ufp->flags & FN_PRES) { preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); } mux_exec(buff, &oldp, i, executor, enactor, AttrTrace(aflags, feval), &TempPtr, fargs, nfargs); if (ufp->flags & FN_PRES) { restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); preserve = NULL; } free_lbuf(tstr); } else { // If the number of args is right, perform the func. // Otherwise, return an error message. // if ( fp->minArgs <= nfargs && nfargs <= fp->maxArgs && !MuxAlarm.bAlarmed) { fp->fun(buff, &oldp, executor, caller, enactor, feval & EV_TRACE, fargs, nfargs, cargs, ncargs); } else { if (fp->minArgs == fp->maxArgs) { mux_sprintf(mux_scratch, sizeof(mux_scratch), "#-1 FUNCTION (%s) EXPECTS %d ARGUMENTS", fp->name, fp->minArgs); } else if (fp->minArgs + 1 == fp->maxArgs) { mux_sprintf(mux_scratch, sizeof(mux_scratch), "#-1 FUNCTION (%s) EXPECTS %d OR %d ARGUMENTS", fp->name, fp->minArgs, fp->maxArgs); } else if (MuxAlarm.bAlarmed) { mux_sprintf(mux_scratch, sizeof(mux_scratch), "#-1 CPU LIMITED"); } else { mux_sprintf(mux_scratch, sizeof(mux_scratch), "#-1 FUNCTION (%s) EXPECTS BETWEEN %d AND %d ARGUMENTS", fp->name, fp->minArgs, fp->maxArgs); } safe_str(mux_scratch, buff, &oldp); } } *bufc = oldp; nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; mudstate.func_nest_lev--; } // Return the space allocated for the arguments. // for (i = 0; i < nfargs; i++) { free_lbuf(fargs[i]); } PopPointers(fargs, MAX_ARG); fargs = NULL; } eval &= ~EV_FCHECK; isSpecial(L1, '(') = false; } else if (*pdstr == '%') { // Percent-replace start. Evaluate the chars following and // perform the appropriate substitution. // at_space = 0; if (!(eval & EV_EVAL)) { if (nBufferAvailable) { *(*bufc)++ = '%'; nBufferAvailable--; } pdstr++; if (nBufferAvailable) { *(*bufc)++ = *pdstr; nBufferAvailable--; } } else { pdstr++; ch = *pdstr; unsigned char cType_L2 = isSpecial(L2, ch); TempPtr = *bufc; int iCode = cType_L2 & 0x7F; if (iCode == 1) { // 30 31 32 33 34 35 36 37 38 39 // 0 1 2 3 4 5 6 7 8 9 // // Command argument number N. // i = ch - '0'; if ( i < ncargs && cargs[i]) { safe_str(cargs[i], buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } } else if (iCode == 2) { // 51 // Q // pdstr++; i = mux_RegisterSet[(unsigned char)*pdstr]; if ( 0 <= i && i < MAX_GLOBAL_REGS) { if ( mudstate.global_regs[i] && mudstate.global_regs[i]->reg_len > 0) { safe_copy_buf(mudstate.global_regs[i]->reg_ptr, mudstate.global_regs[i]->reg_len, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } } else if (*pdstr == '\0') { pdstr--; } } else if (iCode <= 4) { if (iCode == 3) { // 23 // # // // Enactor DB number. // mux_scratch[0] = '#'; n = mux_ltoa(enactor, mux_scratch+1); safe_copy_buf(mux_scratch, n+1, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } else if (iCode == 4) { // 21 // ! // // iCode == '!' // Executor DB number. // mux_scratch[0] = '#'; n = mux_ltoa(executor, mux_scratch+1); safe_copy_buf(mux_scratch, n+1, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } else { // iCode == 0 // // Just copy // if (nBufferAvailable) { *(*bufc)++ = ch; nBufferAvailable--; } } } else if (iCode <= 6) { if (iCode == 6) { // 43 58 // C X // // Color // const char *pColor = ColorTable[(unsigned char)pdstr[1]]; if (pColor) { pdstr++; ansi = true; safe_str(pColor, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } else if (pdstr[1] && nBufferAvailable) { *(*bufc)++ = *pdstr; nBufferAvailable--; } } else { // 52 // R // // Carriage return. // safe_copy_buf("\r\n", 2, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } } else if (iCode <= 8) { if (iCode == 7) { // 42 // B // // Blank. // if (nBufferAvailable) { *(*bufc)++ = ' '; nBufferAvailable--; } } else { // 54 // T // // Tab. // if (nBufferAvailable) { *(*bufc)++ = '\t'; nBufferAvailable--; } } } else if (iCode <= 10) { if (iCode == 9) { // 4C // L // // Enactor Location DB Ref // if (!(eval & EV_NO_LOCATION)) { mux_scratch[0] = '#'; n = mux_ltoa(where_is(enactor), mux_scratch+1); safe_copy_buf(mux_scratch, n+1, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } } else { // 56 // V // // Variable attribute. // pdstr++; if (mux_isazAZ(*pdstr)) { i = A_VA + mux_toupper(*pdstr) - 'A'; size_t nAttrGotten; atr_pget_str_LEN(mux_scratch, executor, i, &aowner, &aflags, &nAttrGotten); if (0 < nAttrGotten) { if (nAttrGotten > nBufferAvailable) { nAttrGotten = nBufferAvailable; } memcpy(*bufc, mux_scratch, nAttrGotten); *bufc += nAttrGotten; nBufferAvailable -= nAttrGotten; } } else if ('\0' == *pdstr) { pdstr--; } } } else if (iCode <= 14) { if (iCode <= 12) { if (iCode == 11) { // 25 // % // // Percent - a literal % // if (nBufferAvailable) { *(*bufc)++ = '%'; nBufferAvailable--; } } else { // 4E // N // // Enactor name // safe_str(Name(enactor), buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } } else { if (iCode == 13) { // 7C // | // // piped command output. // safe_str(mudstate.pout, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } else { // 53 // S // // Subjective pronoun. // if (gender < 0) { gender = get_gender(enactor); } if (!gender) { constbuf = Name(enactor); } else { constbuf = subj[gender]; } safe_str(constbuf, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } } } else { if (iCode <= 16) { if (iCode == 15) { // 50 // P // // Personal pronoun. // if (gender < 0) { gender = get_gender(enactor); } if (!gender) { safe_str(Name(enactor), buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; if (nBufferAvailable) { *(*bufc)++ = 's'; nBufferAvailable--; } } else { safe_str(poss[gender], buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } } else { // 4F // O // // Objective pronoun. // if (gender < 0) { gender = get_gender(enactor); } if (!gender) { constbuf = Name(enactor); } else { constbuf = obj[gender]; } safe_str(constbuf, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } } else if (iCode <= 18) { if (iCode == 17) { // 41 // A // // Absolute posessive. // Idea from Empedocles. // if (gender < 0) { gender = get_gender(enactor); } if (!gender) { safe_str(Name(enactor), buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; if (nBufferAvailable) { *(*bufc)++ = 's'; nBufferAvailable--; } } else { safe_str(absp[gender], buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } } else // if (iCode == 18) { // 00 // \0 // // All done. // pdstr--; } } else if (iCode <= 20) { if (iCode == 19) { // 4D // M // // Last command // safe_str(mudstate.curr_cmd, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } else { // 40 // @ // // Caller DB number. // mux_scratch[0] = '#'; n = mux_ltoa(caller, mux_scratch+1); safe_copy_buf(mux_scratch, n+1, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } } else // if (iCode == 21) { // 3D // = // // %= like v(attr). // pdstr++; if ('<' == pdstr[0]) { pdstr++; char *p2 = mux_scratch; while ( pdstr[0] && '>' != pdstr[0]) { safe_chr(pdstr[0], mux_scratch, &p2); pdstr++; } *p2 = '\0'; if ('>' == pdstr[0]) { if (mux_AttrNameInitialSet(mux_scratch[0])) { ATTR *ap = atr_str(mux_scratch); if (ap) { size_t nLen; tbuf = atr_pget_LEN(executor, ap->number, &aowner, &aflags, &nLen); if (See_attr(executor, executor, ap)) { safe_copy_buf(tbuf, nLen, buff, bufc); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; } free_lbuf(tbuf); } } } else { pdstr--; } } else if ('\0' == pdstr[0]) { pdstr--; } } } // For some escape letters, if the escape letter // was upper-case, then upper-case the first // letter of the value. // if (cType_L2 & 0x80) { *TempPtr = mux_toupper(*TempPtr); } } } else if (*pdstr == '[') { // Function start. Evaluate the contents of the square brackets // as a function. If no closing bracket, insert the '[' and // continue. // tstr = pdstr++; mudstate.nStackNest++; tbuf = parse_to_lite(&pdstr, ']', '\0', &n, &at_space); at_space = 0; if (pdstr == NULL) { if (nBufferAvailable) { *(*bufc)++ = '['; nBufferAvailable--; } pdstr = tstr; } else { mudstate.nStackNest--; TempPtr = tbuf; mux_exec(buff, bufc, executor, caller, enactor, (eval | EV_FCHECK | EV_FMAND) & ~EV_TOP, &TempPtr, cargs, ncargs); nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; pdstr--; } } // At this point, *pdstr must be one of the following characters: // // 0x20 0x5C 0x7B // SP \ { // else if (*pdstr == ' ') { // A space. Add a space if not compressing or if previous char was // not a space. // if (bSpaceIsSpecial && !at_space) { if (nBufferAvailable) { *(*bufc)++ = ' '; nBufferAvailable--; } at_space = 1; } } else if (*pdstr == '{') { // *pdstr == '{' // // Literal start. Insert everything up to the terminating '}' // without parsing. If no closing brace, insert the '{' and // continue. // tstr = pdstr++; mudstate.nStackNest++; tbuf = parse_to_lite(&pdstr, '}', '\0', &n, &at_space); at_space = 0; if (pdstr == NULL) { if (nBufferAvailable) { *(*bufc)++ = '{'; nBufferAvailable--; } pdstr = tstr; } else { mudstate.nStackNest--; if (!(eval & EV_STRIP_CURLY)) { if (nBufferAvailable) { *(*bufc)++ = '{'; nBufferAvailable--; } } if (eval & EV_EVAL) { // Preserve leading spaces (Felan) // if (*tbuf == ' ') { if (nBufferAvailable) { *(*bufc)++ = ' '; nBufferAvailable--; } tbuf++; } TempPtr = tbuf; mux_exec(buff, bufc, executor, caller, enactor, (eval & ~(EV_STRIP_CURLY | EV_FCHECK | EV_TOP)), &TempPtr, cargs, ncargs); } else { TempPtr = tbuf; mux_exec(buff, bufc, executor, caller, enactor, eval & ~EV_TOP, &TempPtr, cargs, ncargs); } nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; if (!(eval & EV_STRIP_CURLY)) { if (nBufferAvailable) { *(*bufc)++ = '}'; nBufferAvailable--; } } pdstr--; } } else if (*pdstr == '\\') { // *pdstr must be \. // // General escape. Add the following char without special // processing. // at_space = 0; pdstr++; if (*pdstr) { if (nBufferAvailable) { *(*bufc)++ = *pdstr; nBufferAvailable--; } } else { pdstr--; } } else { // *pdstr must be ESC. // at_space = 0; if (nBufferAvailable) { *(*bufc)++ = *pdstr; nBufferAvailable--; } pdstr++; if (*pdstr) { if (nBufferAvailable) { *(*bufc)++ = *pdstr; nBufferAvailable--; } } else { pdstr--; } } pdstr++; } // If we're eating spaces, and the last thing was a space, eat it up. // Complicated by the fact that at_space is initially true. So check to // see if we actually put something in the buffer, too. // if ( bSpaceIsSpecial && at_space && start != *bufc) { (*bufc)--; } **bufc = '\0'; // Collect and report trace information. // if (is_trace) { tcache_add(executor, savestr, start); if ( is_top || !mudconf.trace_topdown) { tcache_finish(); } if ( is_top && 0 < tcache_count - mudconf.trace_limit) { tbuf = alloc_mbuf("exec.trace_diag"); mux_sprintf(tbuf, MBUF_SIZE, "%d lines of trace output discarded.", tcache_count - mudconf.trace_limit); notify(executor, tbuf); free_mbuf(tbuf); } } if ( realbuff || ansi || (eval & EV_TOP)) { // We need to transfer and/or ANSI optimize the result. // static struct ANSI_In_Context aic; static struct ANSI_Out_Context aoc; ANSI_String_Out_Init(&aoc, mux_scratch, sizeof(mux_scratch), sizeof(mux_scratch), ANSI_ENDGOAL_NORMAL); if (realbuff) { *realbp = '\0'; ANSI_String_In_Init(&aic, realbuff, ANSI_ENDGOAL_NORMAL); ANSI_String_Copy(&aoc, &aic, sizeof(mux_scratch)); } ANSI_String_In_Init(&aic, buff, ANSI_ENDGOAL_NORMAL); ANSI_String_Copy(&aoc, &aic, sizeof(mux_scratch)); if (realbuff) { MEMFREE(buff); buff = realbuff; } size_t nVisualWidth; size_t nLen = ANSI_String_Finalize(&aoc, &nVisualWidth); memcpy(buff, mux_scratch, nLen+1); *bufc = buff + nLen; } *dstr = pdstr; // Restore Parser Mode. // isSpecial(L1, ' ') = bSpaceIsSpecialSave; isSpecial(L1, '(') = bParenthesisIsSpecialSave; isSpecial(L1, '[') = bBracketIsSpecialSave; } /* --------------------------------------------------------------------------- * save_global_regs, restore_global_regs: Save and restore the global * registers to protect them from various sorts of munging. */ void save_global_regs ( reg_ref *preserve[] ) { for (int i = 0; i < MAX_GLOBAL_REGS; i++) { if (mudstate.global_regs[i]) { RegAddRef(mudstate.global_regs[i]); } preserve[i] = mudstate.global_regs[i]; } } void save_and_clear_global_regs ( reg_ref *preserve[] ) { for (int i = 0; i < MAX_GLOBAL_REGS; i++) { preserve[i] = mudstate.global_regs[i]; mudstate.global_regs[i] = NULL; } } void restore_global_regs ( reg_ref *preserve[] ) { for (int i = 0; i < MAX_GLOBAL_REGS; i++) { if (mudstate.global_regs[i]) { RegRelease(mudstate.global_regs[i]); mudstate.global_regs[i] = NULL; } if (preserve[i]) { mudstate.global_regs[i] = preserve[i]; preserve[i] = NULL; } } } static lbuf_ref *last_lbufref = NULL; static size_t last_left = 0; static char *last_ptr = NULL; void RegAssign(reg_ref **regref, size_t nLength, const char *ptr) { if ( NULL == regref || NULL == ptr || LBUF_SIZE <= nLength) { return; } // Put any previous register value out of the way. // if (NULL != *regref) { RegRelease(*regref); *regref = NULL; } // Let go of the last lbuf if we can't use it. // size_t nSize = nLength + 1; if ( NULL != last_lbufref && last_left < nSize) { BufRelease(last_lbufref); last_lbufref = NULL; last_left = 0; last_ptr = NULL; } // Grab a new, fresh lbuf if we don't have one. // if (NULL == last_lbufref) { last_ptr = alloc_lbuf("RegAssign"); last_left = LBUF_SIZE; // Fill in new lbufref. // last_lbufref = alloc_lbufref("RegAssign"); last_lbufref->refcount = 1; last_lbufref->lbuf_ptr = last_ptr; } // Use last lbuf. // char *p = last_ptr; memcpy(last_ptr, ptr, nSize); last_ptr[nLength] = '\0'; last_ptr += nSize; last_left -= nSize; // Fill in new regref. // *regref = alloc_regref("RegAssign"); (*regref)->refcount = 1; (*regref)->lbuf = last_lbufref; (*regref)->reg_len = nLength; (*regref)->reg_ptr = p; BufAddRef(last_lbufref); } mux2.6/src/stringutil.cpp0000600000175000017500000055373011025753746015523 0ustar sdennissdennis/*! \file stringutil.cpp * String utility functions. * * $Id: stringutil.cpp 3691 2008-06-01 01:41:19Z brazilofmux $ * */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "ansi.h" #include "pcre.h" const bool mux_isprint[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 7 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, // 8 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, // 9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F }; const bool mux_isdigit[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; const bool mux_isxdigit[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; const bool mux_isazAZ[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; const bool mux_isalpha[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0 // F }; const bool mux_isalnum[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0 // F }; const bool mux_isupper[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; const bool mux_islower[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0 // F }; const bool mux_isspace[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; // The first character of an attribute name must be either alphabetic, // '_', '#', '.', or '~'. It's handled by the following table. // // Characters thereafter may be letters, numbers, and characters from // the set {'?!`/-_.@#$^&~=+<>()}. Lower-case letters are turned into // uppercase before being used, but lower-case letters are valid input. // bool mux_AttrNameInitialSet[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 5 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 7 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 // F }; bool mux_AttrNameSet[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 7 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Valid characters for an object name are all printable // characters except those from the set {=&|}. // const bool mux_ObjectNameSet[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, // 7 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, // 8 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, // 9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Valid characters for a player name are all alphanumeric plus // {`$_-.,'} plus SPACE depending on configuration. // bool mux_PlayerNameSet[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Characters which should be escaped for the secure() // function: '%$\[](){},;'. // const bool mux_issecure[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; // Characters which should be escaped for the escape() // function: '%\[]{};,()^$'. // const bool mux_isescape[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; const bool ANSI_TokenTerminatorTable[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 1, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 5 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; const unsigned char mux_hex2dec[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // 3 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; const unsigned char mux_toupper[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 1 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 2 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 3 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 4 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // 5 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 6 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // 7 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // 8 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x8A, 0x9B, 0x8C, 0x9D, 0x8E, 0x9F, // 9 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, // A 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, // B 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, // C 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, // D 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, // E 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xFF // F }; const unsigned char mux_tolower[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 1 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 2 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 3 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 4 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // 5 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 6 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // 7 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x9A, 0x8B, 0x9C, 0x8D, 0x9E, 0x8F, // 8 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0xFF, // 9 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, // A 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, // B 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, // C 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xD7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xDF, // D 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, // E 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF // F }; const unsigned char mux_StripAccents[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 1 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 2 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 3 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 4 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // 5 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 6 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // 7 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // 8 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, // 9 0xA0, 0x21, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0x22, 0xAC, 0xAD, 0xAE, 0xAF, // A 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0x22, 0xBC, 0xBD, 0xBE, 0x3F, // B 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, // C 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x59, 0x50, 0x42, // D 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xE6, 0x63, 0x65, 0x65, 0x65, 0x65, 0x69, 0x69, 0x69, 0x69, // E 0x6F, 0x6E, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0xF7, 0x6F, 0x75, 0x75, 0x75, 0x75, 0x79, 0x70, 0x79, // F }; // This will help decode UTF-8 sequences. // // 0xxxxxxx ==> 00000000-01111111 ==> 00-7F 1 byte sequence. // 10xxxxxx ==> 10000000-10111111 ==> 80-BF continue // 110xxxxx ==> 11000000-11011111 ==> C0-DF 2 byte sequence. // 1110xxxx ==> 11100000-11101111 ==> E0-EF 3 byte sequence. // 11110xxx ==> 11110000-11110111 ==> F0-F7 4 byte sequence. // 11111000-11111111 illegal // // Also, RFC 3629 specifies that 0xC0, 0xC1, and 0xF5-0xFF never // appear in a valid sequence. // // The first byte gives the length of a sequence (UTF8_SIZE1 - UTF8_SIZE4). // Bytes in the middle of a sequence map to UTF8_CONTINUE. Bytes which should // not appear map to UTF8_ILLEGAL. // const unsigned char utf8_FirstByte[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 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, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 8 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 9 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // A 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // B 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // D 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // E 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 // F }; // utf/tr_Color.txt // // 517 code points. // 5 states, 13 columns, 321 bytes // const unsigned char tr_color_itt[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const unsigned char tr_color_stt[5][13] = { { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 3, 4, 5}, { 5, 6, 7, 5, 5, 8, 9, 5, 10, 5, 5, 5, 5}, { 5, 11, 12, 13, 14, 15, 16, 17, 18, 5, 5, 5, 5}, { 5, 19, 20, 21, 22, 23, 24, 25, 26, 5, 5, 5, 5} }; // utf/tr_utf8_latin1.txt // // 1596 code points. // 74 states, 191 columns, 28524 bytes // #define TR_LATIN1_START_STATE (0) #define TR_LATIN1_ACCEPTING_STATES_START (74) const unsigned char tr_latin1_itt[256] = { 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 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, 0, 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, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 0, 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, 0, 0, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 0, 0, 0, 0, 175, 176, 177, 178, 0, 179, 180, 0, 0, 181, 0, 182, 0, 0, 0, 183, 184, 185, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 189, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const unsigned short tr_latin1_stt[74][191] = { { 137, 81, 82, 83, 84, 87, 101, 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, 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, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 23, 35, 54, 56, 62, 70}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 139, 171, 139, 171, 139, 171, 141, 173, 141, 173, 141, 173, 141, 173, 142, 174, 142, 174, 143, 175, 143, 175, 143, 175, 143, 175, 143, 175, 145, 177, 145, 177, 145, 177, 145, 177, 146, 178, 146, 178, 147, 179, 147, 179, 147, 179, 147, 179, 147, 137, 137, 137, 148, 180, 149, 181, 137, 150, 182, 150, 182, 150, 182, 150, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 182, 150, 182, 152, 184, 152, 184, 152, 184, 184, 137, 137, 153, 185, 153, 185, 153, 185, 137, 137, 156, 188, 156, 188, 156, 188, 157, 189, 157, 189, 157, 189, 157, 189, 158, 190, 158, 190, 158, 190, 159, 191, 159, 191, 159, 191, 159, 191, 159, 191, 159, 191, 161, 193, 163, 195, 329, 164, 196, 164, 196, 196, 196, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 172, 140, 140, 172, 137, 137, 137, 141, 173, 137, 142, 142, 174, 137, 137, 137, 137, 144, 205, 145, 137, 137, 137, 147, 149, 181, 182, 137, 137, 152, 184, 153, 153, 185, 137, 137, 154, 186, 137, 137, 137, 137, 137, 190, 158, 190, 158, 159, 191, 137, 160, 163, 195, 164, 196, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 107, 137, 137, 137, 137, 137, 137, 137, 137, 137, 139, 171, 147, 179, 153, 185, 159, 191, 159, 191, 159, 191, 159, 191, 159, 191, 137, 139, 171, 139, 171, 137, 304, 145, 177, 145, 177, 149, 181, 153, 185, 153, 185, 137, 137, 180, 137, 137, 137, 145, 177, 137, 137, 152, 184, 139, 171, 137, 304, 153, 185, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 139, 171, 139, 171, 143, 175, 143, 175, 147, 179, 147, 179, 153, 185, 153, 185, 156, 188, 156, 188, 159, 191, 159, 191, 157, 189, 158, 190, 137, 137, 146, 178, 152, 174, 137, 137, 164, 196, 139, 171, 143, 175, 153, 185, 153, 185, 153, 185, 153, 185, 163, 195, 182, 184, 190, 137, 137, 137, 139, 141, 173, 150, 158, 189, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 196, 137, 137, 140, 159, 137, 143, 175, 148, 180, 137, 187, 156, 188, 163, 195, 137, 137, 137, 172, 137, 173, 174, 174, 137, 137, 137, 137, 137, 137, 137, 137, 177, 137, 137, 137, 137, 137, 178, 137, 179, 137, 137, 182, 182, 182, 182, 137, 137, 183, 184, 184, 137, 137, 137, 137, 137, 137, 137, 137, 188, 188, 188, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 189, 137, 137, 137, 137, 137, 190, 191, 137, 192, 137, 137, 137, 137, 196, 196, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 180, 137, 137, 187, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 210, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 226, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 143, 137, 147, 137, 137, 137, 137, 137, 137, 147, 137, 137, 139, 137, 137, 137, 137, 137, 137, 137, 147, 137, 137, 137, 137, 137, 153, 137, 137, 137, 137, 159, 137, 137, 137, 137, 137, 137, 137, 137, 137, 143, 137, 137, 171, 137, 137, 137, 137, 137, 137, 137, 179, 137, 137, 137, 137, 137, 185, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 191, 137, 137, 137, 137, 137, 137, 137, 137, 137, 175, 137, 137, 137, 137, 137, 137, 175, 137, 179, 137, 137, 137, 137, 137, 137, 179, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 153, 185, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 146, 178, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 139, 171, 139, 171, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 147, 179, 147, 179, 153, 185, 137, 137, 137, 137, 143, 175, 159, 191, 159, 191, 159, 191, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 107, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 119, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 107, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 21, 137, 21, 137, 21, 137, 21, 137, 21, 137, 21, 137, 21, 137, 21, 137, 21, 137, 137, 137, 22, 137, 22, 17, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 24, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 25, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 17, 26, 137, 137, 137, 137, 27, 137, 22, 137, 137, 137, 137, 137, 22, 137, 137, 137, 137, 137, 137, 28, 29, 30, 137, 31, 32, 33, 34, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 247, 137, 137, 137, 137, 137, 137, 137, 137, 137, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 107, 137, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 139, 137, 137, 140, 141, 142, 282, 143, 143, 147, 148, 149, 150, 151, 152, 153, 153, 153, 153, 153, 137, 137, 153, 153, 154, 156, 156, 158, 159, 159, 159, 151, 160, 161, 164, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 179, 188, 191, 192, 137, 137, 137, 137, 137, 137, 172, 174, 176, 183, 184, 186, 188, 188, 189, 190, 196, 137, 137, 137, 137, 147, 137, 186, 159, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 172, 174, 176, 177, 181, 182, 183, 184, 186, 188, 189, 137, 192, 194, 196, 171, 137, 174, 175, 137, 137, 137, 179, 137, 137, 191, 137, 137, 173, 173, 314, 175, 176, 180, 177, 178, 179, 137, 179, 179, 180, 182, 182, 182, 183, 183, 184, 184, 184, 185, 137, 189, 137, 190, 191, 137, 191, 192, 192, 196, 196, 196, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 139, 171, 140, 172, 140, 172, 140, 172, 141, 173, 142, 174, 142, 174, 142, 174, 142, 174, 142, 174, 143, 175, 143, 175, 143, 175, 143, 175, 143, 175, 144, 176, 145, 177, 146, 178, 146, 178, 146, 178, 146, 178, 146, 178, 147, 179, 147, 179, 149, 181, 149, 181, 149, 181, 150, 182, 150, 182, 150, 182, 150, 182, 151, 183, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 151, 183, 151, 183, 152, 184, 152, 184, 152, 184, 152, 184, 153, 185, 153, 185, 153, 185, 153, 185, 154, 186, 154, 186, 156, 188, 156, 188, 156, 188, 156, 188, 157, 189, 157, 189, 157, 189, 157, 189, 157, 189, 158, 190, 158, 190, 158, 190, 158, 190, 159, 191, 159, 191, 159, 191, 159, 191, 159, 191, 160, 192, 160, 192, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 161, 193, 161, 193, 161, 193, 161, 193, 161, 193, 162, 194, 162, 194, 163, 195, 164, 196, 164, 196, 164, 196, 178, 190, 193, 195, 171, 137, 137, 137, 137, 137, 139, 171, 139, 171, 139, 171, 139, 171, 139, 171, 139, 171, 139, 171, 139, 171, 139, 171, 139, 171, 139, 171, 139, 171, 143, 175, 143, 175, 143, 175, 143, 175, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 143, 175, 143, 175, 143, 175, 143, 175, 147, 179, 147, 179, 153, 185, 153, 185, 153, 185, 153, 185, 153, 185, 153, 185, 153, 185, 153, 185, 153, 185, 153, 185, 153, 185, 153, 185, 159, 191, 159, 191, 159, 191, 159, 191, 159, 191, 159, 191, 159, 191, 163, 195, 163, 195, 163, 195, 163, 195, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 36, 37, 38, 137, 39, 137, 137, 137, 40, 137, 41, 137, 42, 137, 137, 137, 137, 43, 44, 45, 137, 137, 137, 137, 137, 137, 137, 137, 46, 47, 48, 137, 137, 137, 137, 137, 137, 137, 137, 137, 49, 137, 137, 50, 137, 137, 137, 137, 51, 52, 53, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 119, 119, 137, 224, 225, 137, 137, 137, 219, 220, 204, 204, 221, 222, 206, 206, 208, 209, 223, 137, 137, 137, 207, 137, 137, 137, 137, 137, 137, 137, 137, 137, 211, 137, 137, 137, 137, 137, 137, 137, 137, 213, 229, 137, 107, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 119, 137, 137, 137, 137, 107, 137, 137, 137, 137, 137, 137, 137, 137, 137, 119, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 122, 179, 137, 137, 126, 127, 128, 129, 130, 131, 137, 247, 137, 137, 137, 184, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 247, 137, 137, 137, 137, 171, 175, 185, 194, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 202, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 227, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 119, 137, 137, 121, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 116, 137, 137, 137, 137, 137, 137, 137, 137, 119, 137, 121, 137, 137, 137, 137, 137, 137, 119, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 246, 137, 137, 137, 137, 137, 137, 137, 137, 246, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 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, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 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, 122, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 122, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 116, 116, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 107, 107, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 213, 229, 137, 137, 137, 137, 137, 137, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 116, 116, 137, 137, 116, 116, 116, 116, 121, 137, 137, 116, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 116, 116, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 246, 246, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 147, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 179, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 150, 182, 150, 154, 156, 171, 190, 146, 178, 149, 181, 164, 196, 137, 137, 137, 137, 137, 137, 137, 192, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 153, 185, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 55, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 106, 118, 120, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 57, 58, 137, 137, 59, 60, 137, 61, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 107, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 107, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 119, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 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, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 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, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 236, 237, 246, 137, 240, 239, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 63, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 67, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 64, 65, 17, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 66, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 146, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 282, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 178, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 314, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 123, 124, 125, 126, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 68, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 69, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 123, 124, 125, 126, 127, 128, 129, 130, 131, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 71, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 72, 73, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 107, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 119, 137, 137, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137}, { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 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, 137, 137, 137, 137, 137, 137, 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, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137} }; // ANSI_lex - This function parses a string and returns two token types. // The type identifies the token type of length nLengthToken0. nLengthToken1 // may also be present and is a token of the -other- type. // int ANSI_lex(size_t nString, const char *pString, size_t *nLengthToken0, size_t *nLengthToken1) { *nLengthToken0 = 0; *nLengthToken1 = 0; const char *p = pString; for (;;) { // Look for an ESC_CHAR // p = strchr(p, ESC_CHAR); if (!p) { // This is the most common case by far. // *nLengthToken0 = nString; return TOKEN_TEXT_ANSI; } // We have an ESC_CHAR. Let's look at the next character. // if (p[1] != '[') { // Could be a '\0' or another non-'[' character. // Move the pointer to position ourselves over it. // And continue looking for an ESC_CHAR. // p = p + 1; continue; } // We found the beginning of an ANSI sequence. // Find the terminating character. // const char *q = p+2; while (ANSI_TokenTerminatorTable[(unsigned char)*q] == 0) { q++; } if (q[0] == '\0') { // There was no good terminator. Treat everything like text. // Also, we are at the end of the string, so just return. // *nLengthToken0 = q - pString; return TOKEN_TEXT_ANSI; } else { // We found an ANSI sequence. // if (p == pString) { // The ANSI sequence started it. // *nLengthToken0 = q - pString + 1; return TOKEN_ANSI; } else { // We have TEXT followed by an ANSI sequence. // *nLengthToken0 = p - pString; *nLengthToken1 = q - p + 1; return TOKEN_TEXT_ANSI; } } } } char *strip_ansi(const char *szString, size_t *pnString) { static char Buffer[LBUF_SIZE]; char *pBuffer = Buffer; const char *pString = szString; if (!pString) { if (pnString) { *pnString = 0; } *pBuffer = '\0'; return Buffer; } size_t nString = strlen(szString); while (nString) { size_t nTokenLength0; size_t nTokenLength1; int iType = ANSI_lex(nString, pString, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { memcpy(pBuffer, pString, nTokenLength0); pBuffer += nTokenLength0; size_t nSkipLength = nTokenLength0 + nTokenLength1; nString -= nSkipLength; pString += nSkipLength; } else { // TOKEN_ANSI // nString -= nTokenLength0; pString += nTokenLength0; } } if (pnString) { *pnString = pBuffer - Buffer; } *pBuffer = '\0'; return Buffer; } char *strip_accents(const char *szString, size_t *pnString) { static char Buffer[LBUF_SIZE]; char *pBuffer = Buffer; const char *pString = szString; if (pString) { while (*pString) { *pBuffer = mux_StripAccents(*pString); pBuffer++; pString++; } } if (pnString) { *pnString = pBuffer - Buffer; } *pBuffer = '\0'; return Buffer; } #define ANSI_COLOR_INDEX_BLACK 0 #define ANSI_COLOR_INDEX_RED 1 #define ANSI_COLOR_INDEX_GREEN 2 #define ANSI_COLOR_INDEX_YELLOW 3 #define ANSI_COLOR_INDEX_BLUE 4 #define ANSI_COLOR_INDEX_MAGENTA 5 #define ANSI_COLOR_INDEX_CYAN 6 #define ANSI_COLOR_INDEX_WHITE 7 #define ANSI_COLOR_INDEX_DEFAULT 8 static const ANSI_ColorState acsRestingStates[3] = { {true, false, false, false, false, ANSI_COLOR_INDEX_DEFAULT, ANSI_COLOR_INDEX_DEFAULT}, {false, false, false, false, false, ANSI_COLOR_INDEX_WHITE, ANSI_COLOR_INDEX_DEFAULT}, {true, false, false, false, false, ANSI_COLOR_INDEX_DEFAULT, ANSI_COLOR_INDEX_DEFAULT} }; static void ANSI_Parse_m(ANSI_ColorState *pacsCurrent, size_t nANSI, const char *pANSI) { // If the last character isn't an 'm', then it's an ANSI sequence we // don't support, yet. TODO: There should be a ANSI_Parse() function // that calls into this one -only- if there's an 'm', but since 'm' // is the only command this game understands at the moment, it's easier // to put the test here. // if (pANSI[nANSI-1] != 'm') { return; } // Process entire string and update the current color state structure. // while (nANSI) { // Process the next attribute phrase (terminated by ';' or 'm' // typically). // const char *p = pANSI; while (mux_isdigit(*p)) { p++; } size_t nLen = p - pANSI + 1; if (p[0] == 'm' || p[0] == ';') { // We have an attribute. // if (nLen == 2) { int iCode = pANSI[0] - '0'; switch (iCode) { case 0: // Normal. // *pacsCurrent = acsRestingStates[ANSI_ENDGOAL_NORMAL]; break; case 1: // High Intensity. // pacsCurrent->bHighlite = true; pacsCurrent->bNormal = false; break; case 2: // Low Intensity. // pacsCurrent->bHighlite = false; pacsCurrent->bNormal = false; break; case 4: // Underline. // pacsCurrent->bUnder = true; pacsCurrent->bNormal = false; break; case 5: // Blinking. // pacsCurrent->bBlink = true; pacsCurrent->bNormal = false; break; case 7: // Reverse Video // pacsCurrent->bInverse = true; pacsCurrent->bNormal = false; break; } } else if (nLen == 3) { int iCode0 = pANSI[0] - '0'; int iCode1 = pANSI[1] - '0'; if (iCode0 == 3) { // Foreground Color // if (iCode1 <= 7) { pacsCurrent->iForeground = iCode1; pacsCurrent->bNormal = false; } } else if (iCode0 == 4) { // Background Color // if (iCode1 <= 7) { pacsCurrent->iBackground = iCode1; pacsCurrent->bNormal = false; } } } } pANSI += nLen; nANSI -= nLen; } } // The following is really 30 (E[0mE[1mE[4mE[5mE[7mE[33mE[43m) but we are // being conservative. // #define ANSI_MAXIMUM_BINARY_TRANSITION_LENGTH 60 // Generate the minimal ANSI sequence that will transition from one color state // to another. // static char *ANSI_TransitionColorBinary ( ANSI_ColorState *acsCurrent, const ANSI_ColorState *pcsNext, size_t *nTransition, int iEndGoal ) { static char Buffer[ANSI_MAXIMUM_BINARY_TRANSITION_LENGTH+1]; if (memcmp(acsCurrent, pcsNext, sizeof(ANSI_ColorState)) == 0) { *nTransition = 0; Buffer[0] = '\0'; return Buffer; } ANSI_ColorState tmp = *acsCurrent; char *p = Buffer; if (pcsNext->bNormal) { // With NOBLEED, we can't stay in the normal mode. We must eventually // be on a white foreground. // pcsNext = &acsRestingStates[iEndGoal]; } // Do we need to go through the normal state? // if ( tmp.bHighlite && !pcsNext->bHighlite || tmp.bUnder && !pcsNext->bUnder || tmp.bBlink && !pcsNext->bBlink || tmp.bInverse && !pcsNext->bInverse || ( tmp.iBackground != ANSI_COLOR_INDEX_DEFAULT && pcsNext->iBackground == ANSI_COLOR_INDEX_DEFAULT) || ( tmp.iForeground != ANSI_COLOR_INDEX_DEFAULT && pcsNext->iForeground == ANSI_COLOR_INDEX_DEFAULT)) { memcpy(p, ANSI_NORMAL, sizeof(ANSI_NORMAL)-1); p += sizeof(ANSI_NORMAL)-1; tmp = acsRestingStates[ANSI_ENDGOAL_NORMAL]; } if (tmp.bHighlite != pcsNext->bHighlite) { memcpy(p, ANSI_HILITE, sizeof(ANSI_HILITE)-1); p += sizeof(ANSI_HILITE)-1; } if (tmp.bUnder != pcsNext->bUnder) { memcpy(p, ANSI_UNDER, sizeof(ANSI_UNDER)-1); p += sizeof(ANSI_UNDER)-1; } if (tmp.bBlink != pcsNext->bBlink) { memcpy(p, ANSI_BLINK, sizeof(ANSI_BLINK)-1); p += sizeof(ANSI_BLINK)-1; } if (tmp.bInverse != pcsNext->bInverse) { memcpy(p, ANSI_INVERSE, sizeof(ANSI_INVERSE)-1); p += sizeof(ANSI_INVERSE)-1; } if (tmp.iForeground != pcsNext->iForeground) { memcpy(p, ANSI_FOREGROUND, sizeof(ANSI_FOREGROUND)-1); p += sizeof(ANSI_FOREGROUND)-1; *p++ = static_cast(pcsNext->iForeground + '0'); *p++ = ANSI_ATTR_CMD; } if (tmp.iBackground != pcsNext->iBackground) { memcpy(p, ANSI_BACKGROUND, sizeof(ANSI_BACKGROUND)-1); p += sizeof(ANSI_BACKGROUND)-1; *p++ = static_cast(pcsNext->iBackground + '0'); *p++ = ANSI_ATTR_CMD; } *p = '\0'; *nTransition = p - Buffer; return Buffer; } // The following is really 21 (%xn%xh%xu%xi%xf%xR%xr) but we are being conservative // #define ANSI_MAXIMUM_ESCAPE_TRANSITION_LENGTH 42 // Generate the minimal MU ANSI %-sequence that will transition from one color state // to another. // static char *ANSI_TransitionColorEscape ( ANSI_ColorState *acsCurrent, ANSI_ColorState *acsNext, int *nTransition ) { static char Buffer[ANSI_MAXIMUM_ESCAPE_TRANSITION_LENGTH+1]; static const char cForegroundColors[9] = "xrgybmcw"; static const char cBackgroundColors[9] = "XRGYBMCW"; if (memcmp(acsCurrent, acsNext, sizeof(ANSI_ColorState)) == 0) { *nTransition = 0; Buffer[0] = '\0'; return Buffer; } ANSI_ColorState tmp = *acsCurrent; int i = 0; // Do we need to go through the normal state? // if ( tmp.bBlink && !acsNext->bBlink || tmp.bHighlite && !acsNext->bHighlite || tmp.bInverse && !acsNext->bInverse || tmp.bUnder && !acsNext->bUnder || ( tmp.iBackground != ANSI_COLOR_INDEX_DEFAULT && acsNext->iBackground == ANSI_COLOR_INDEX_DEFAULT) || ( tmp.iForeground != ANSI_COLOR_INDEX_DEFAULT && acsNext->iForeground == ANSI_COLOR_INDEX_DEFAULT)) { Buffer[i ] = '%'; Buffer[i+1] = 'x'; Buffer[i+2] = 'n'; i = i + 3; tmp = acsRestingStates[ANSI_ENDGOAL_NORMAL]; } if (tmp.bHighlite != acsNext->bHighlite) { Buffer[i ] = '%'; Buffer[i+1] = 'x'; Buffer[i+2] = 'h'; i = i + 3; } if (tmp.bUnder != acsNext->bUnder) { Buffer[i ] = '%'; Buffer[i+1] = 'x'; Buffer[i+2] = 'u'; i = i + 3; } if (tmp.bBlink != acsNext->bBlink) { Buffer[i ] = '%'; Buffer[i+1] = 'x'; Buffer[i+2] = 'f'; i = i + 3; } if (tmp.bInverse != acsNext->bInverse) { Buffer[i ] = '%'; Buffer[i+1] = 'x'; Buffer[i+2] = 'i'; i = i + 3; } if ( tmp.iForeground != acsNext->iForeground && acsNext->iForeground < ANSI_COLOR_INDEX_DEFAULT) { Buffer[i ] = '%'; Buffer[i+1] = 'x'; Buffer[i+2] = cForegroundColors[acsNext->iForeground]; i = i + 3; } if ( tmp.iBackground != acsNext->iBackground && acsNext->iBackground < ANSI_COLOR_INDEX_DEFAULT) { Buffer[i ] = '%'; Buffer[i+1] = 'x'; Buffer[i+2] = cBackgroundColors[acsNext->iBackground]; i = i + 3; } Buffer[i] = '\0'; *nTransition = i; return Buffer; } void ANSI_String_In_Init ( struct ANSI_In_Context *pacIn, const char *szString, int iEndGoal ) { pacIn->m_acs = acsRestingStates[iEndGoal]; pacIn->m_p = szString; pacIn->m_n = strlen(szString); } void ANSI_String_Out_Init ( struct ANSI_Out_Context *pacOut, char *pField, size_t nField, size_t vwMax, int iEndGoal ) { pacOut->m_acs = acsRestingStates[ANSI_ENDGOAL_NORMAL]; pacOut->m_bDone = false; pacOut->m_iEndGoal = iEndGoal; pacOut->m_n = 0; pacOut->m_nMax = nField; pacOut->m_p = pField; pacOut->m_vw = 0; pacOut->m_vwMax = vwMax; } void ANSI_String_Skip ( struct ANSI_In_Context *pacIn, size_t maxVisualWidth, size_t *pnVisualWidth ) { *pnVisualWidth = 0; while (pacIn->m_n) { size_t nTokenLength0; size_t nTokenLength1; int iType = ANSI_lex(pacIn->m_n, pacIn->m_p, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { // Process TEXT // size_t nTextToSkip = maxVisualWidth - *pnVisualWidth; if (nTokenLength0 > nTextToSkip) { // We have reached the limits of the field // *pnVisualWidth += nTextToSkip; pacIn->m_p += nTextToSkip; pacIn->m_n -= nTextToSkip; return; } pacIn->m_p += nTokenLength0; pacIn->m_n -= nTokenLength0; *pnVisualWidth += nTokenLength0; if (nTokenLength1) { // Process ANSI // ANSI_Parse_m(&(pacIn->m_acs), nTokenLength1, pacIn->m_p); pacIn->m_p += nTokenLength1; pacIn->m_n -= nTokenLength1; } } else { // Process ANSI // ANSI_Parse_m(&(pacIn->m_acs), nTokenLength0, pacIn->m_p); pacIn->m_n -= nTokenLength0; pacIn->m_p += nTokenLength0; } } } // TODO: Rework comment block. // // ANSI_String_Copy -- Copy characters into a buffer starting at // pField0 with maximum size of nField. Truncate the string if it would // overflow the buffer -or- if it would have a visual with of greater // than maxVisualWidth. Returns the number of ANSI-encoded characters // copied to. Also, the visual width produced by this is returned in // *pnVisualWidth. // // There are three ANSI color states that we deal with in this routine: // // 1. acsPrevious is the color state at the current end of the field. // It has already been encoded into the field. // // 2. acsCurrent is the color state that the current TEXT will be shown // with. It hasn't been encoded into the field, yet, and if we don't // have enough room for at least one character of TEXT, then it may // never be encoded into the field. // // 3. acsFinal is the required color state at the end. This is usually // the normal state or in the case of NOBLEED, it's a specific (and // somewhate arbitrary) foreground/background combination. // void ANSI_String_Copy ( struct ANSI_Out_Context *pacOut, struct ANSI_In_Context *pacIn, size_t maxVisualWidth0 ) { // Check whether we have previous struck the session limits (given // by ANSI_String_Out_Init() for field size or visual width. // if (pacOut->m_bDone) { return; } // What is the working limit for visual width. // size_t vw = 0; size_t vwMax = pacOut->m_vwMax; if (maxVisualWidth0 < vwMax) { vwMax = maxVisualWidth0; } // What is the working limit for field size. // size_t nMax = pacOut->m_nMax; char *pField = pacOut->m_p; while (pacIn->m_n) { size_t nTokenLength0; size_t nTokenLength1; int iType = ANSI_lex(pacIn->m_n, pacIn->m_p, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { // We have a TEXT+[ANSI] phrase. The text length is given // by nTokenLength0, and the ANSI characters that follow // (if present) are of length nTokenLength1. // // Process TEXT part first. // // TODO: If there is a maximum size for the transitions, // and we have gobs of space, don't bother calculating // sizes so carefully. It might be faster // nFieldEffective is used to allocate and plan space for // the rest of the physical field (given by the current // nField length). // size_t nFieldAvailable = nMax - 1; // Leave room for '\0'. size_t nFieldNeeded = 0; size_t nTransitionFinal = 0; if (pacOut->m_iEndGoal <= ANSI_ENDGOAL_NOBLEED) { // If we lay down -any- of the TEXT part, we need to make // sure we always leave enough room to get back to the // required final ANSI color state. // if (memcmp( &(pacIn->m_acs), &acsRestingStates[pacOut->m_iEndGoal], sizeof(ANSI_ColorState)) != 0) { // The color state of the TEXT isn't the final state, // so how much room will the transition back to the // final state take? // ANSI_TransitionColorBinary( &(pacIn->m_acs), &acsRestingStates[pacOut->m_iEndGoal], &nTransitionFinal, pacOut->m_iEndGoal); nFieldNeeded += nTransitionFinal; } } // If we lay down -any- of the TEXT part, it needs to be // the right color. // size_t nTransition = 0; char *pTransition = ANSI_TransitionColorBinary( &(pacOut->m_acs), &(pacIn->m_acs), &nTransition, pacOut->m_iEndGoal); nFieldNeeded += nTransition; // If we find that there is no room for any of the TEXT, // then we're done. // // TODO: The visual width test can be done further up to save time. // if ( nFieldAvailable <= nTokenLength0 + nFieldNeeded || vwMax < vw + nTokenLength0) { // We have reached the limits of the field. // if (nFieldNeeded < nFieldAvailable) { // There was enough physical room in the field, but // we would have exceeded the maximum visual width // if we used all the text. // if (nTransition) { // Encode the TEXT color. // memcpy(pField, pTransition, nTransition); pField += nTransition; } // Place just enough of the TEXT in the field. // size_t nTextToAdd = vwMax - vw; if (nFieldAvailable < nTextToAdd + nFieldNeeded) { nTextToAdd = nFieldAvailable - nFieldNeeded; } memcpy(pField, pacIn->m_p, nTextToAdd); pField += nTextToAdd; pacIn->m_p += nTextToAdd; pacIn->m_n -= nTextToAdd; vw += nTextToAdd; pacOut->m_acs = pacIn->m_acs; // Was this visual width limit related to the session or // the call? // if (vwMax != maxVisualWidth0) { pacOut->m_bDone = true; } } else { // Was size limit related to the session or the call? // pacOut->m_bDone = true; } pacOut->m_n += pField - pacOut->m_p; pacOut->m_nMax -= pField - pacOut->m_p; pacOut->m_p = pField; pacOut->m_vw += vw; return; } if (nTransition) { memcpy(pField, pTransition, nTransition); pField += nTransition; nMax -= nTransition; } memcpy(pField, pacIn->m_p, nTokenLength0); pField += nTokenLength0; nMax -= nTokenLength0; pacIn->m_p += nTokenLength0; pacIn->m_n -= nTokenLength0; vw += nTokenLength0; pacOut->m_acs = pacIn->m_acs; if (nTokenLength1) { // Process ANSI // ANSI_Parse_m(&(pacIn->m_acs), nTokenLength1, pacIn->m_p); pacIn->m_p += nTokenLength1; pacIn->m_n -= nTokenLength1; } } else { // Process ANSI // ANSI_Parse_m(&(pacIn->m_acs), nTokenLength0, pacIn->m_p); pacIn->m_n -= nTokenLength0; pacIn->m_p += nTokenLength0; } } pacOut->m_n += pField - pacOut->m_p; pacOut->m_nMax -= pField - pacOut->m_p; pacOut->m_p = pField; pacOut->m_vw += vw; } size_t ANSI_String_Finalize ( struct ANSI_Out_Context *pacOut, size_t *pnVisualWidth ) { char *pField = pacOut->m_p; if (pacOut->m_iEndGoal <= ANSI_ENDGOAL_NOBLEED) { size_t nTransition = 0; char *pTransition = ANSI_TransitionColorBinary( &(pacOut->m_acs), &acsRestingStates[pacOut->m_iEndGoal], &nTransition, pacOut->m_iEndGoal); if (nTransition) { memcpy(pField, pTransition, nTransition); pField += nTransition; } } *pField = '\0'; pacOut->m_n += pField - pacOut->m_p; pacOut->m_p = pField; *pnVisualWidth = pacOut->m_vw; return pacOut->m_n; } // Take an ANSI string and fit as much of the information as possible // into a field of size nField. Truncate text. Also make sure that no color // leaks out of the field. // size_t ANSI_TruncateToField ( const char *szString, size_t nField, char *pField0, size_t maxVisualWidth, size_t *pnVisualWidth, int iEndGoal ) { if (0 == nField) { return 0; } if (!szString) { pField0[0] = '\0'; return 0; } struct ANSI_In_Context aic; struct ANSI_Out_Context aoc; ANSI_String_In_Init(&aic, szString, iEndGoal); ANSI_String_Out_Init(&aoc, pField0, nField, maxVisualWidth, iEndGoal); ANSI_String_Copy(&aoc, &aic, maxVisualWidth); return ANSI_String_Finalize(&aoc, pnVisualWidth); } char *ANSI_TruncateAndPad_sbuf(const char *pString, size_t nMaxVisualWidth, char fill) { char *pStringModified = alloc_sbuf("ANSI_TruncateAndPad_sbuf"); size_t nAvailable = SBUF_SIZE - nMaxVisualWidth; size_t nVisualWidth; size_t nLen = ANSI_TruncateToField(pString, nAvailable, pStringModified, nMaxVisualWidth, &nVisualWidth, ANSI_ENDGOAL_NORMAL); for (size_t i = nMaxVisualWidth - nVisualWidth; i > 0; i--) { pStringModified[nLen] = fill; nLen++; } pStringModified[nLen] = '\0'; return pStringModified; } char *normal_to_white(const char *szString) { static char Buffer[LBUF_SIZE]; size_t nVisualWidth; ANSI_TruncateToField( szString, sizeof(Buffer), Buffer, sizeof(Buffer), &nVisualWidth, ANSI_ENDGOAL_NOBLEED ); return Buffer; } void utf8_safe_chr(const UTF8 *src, UTF8 *buff, UTF8 **bufc) { size_t nLen; size_t nLeft; if ( NULL == src || UTF8_CONTINUE <= (nLen = utf8_FirstByte[*src]) || (nLeft = LBUF_SIZE - (*bufc - buff) - 1) < nLen) { return; } memcpy(*bufc, src, nLen); *bufc += nLen; } typedef struct { const char *pAnsi; size_t nAnsi; } MUX_COLOR_SET; #define COLOR_LAST_CODE 21 const MUX_COLOR_SET aColors[COLOR_LAST_CODE+1] = { { "", 0 }, // COLOR_NOTCOLOR { ANSI_NORMAL, sizeof(ANSI_NORMAL)-1 }, // COLOR_INDEX_RESET { ANSI_HILITE, sizeof(ANSI_HILITE)-1 }, // COLOR_INDEX_ATTR, COLOR_INDEX_INTENSE { ANSI_UNDER, sizeof(ANSI_UNDER)-1 }, // COLOR_INDEX_UNDERLINE { ANSI_BLINK, sizeof(ANSI_BLINK)-1 }, // COLOR_INDEX_BLINK { ANSI_INVERSE, sizeof(ANSI_INVERSE)-1 }, // COLOR_INDEX_INVERSE { ANSI_BLACK, sizeof(ANSI_BLACK)-1 }, // COLOR_INDEX_FG { ANSI_RED, sizeof(ANSI_RED)-1 }, { ANSI_GREEN, sizeof(ANSI_GREEN)-1 }, { ANSI_YELLOW, sizeof(ANSI_YELLOW)-1 }, { ANSI_BLUE, sizeof(ANSI_BLUE)-1 }, { ANSI_MAGENTA, sizeof(ANSI_MAGENTA)-1 }, { ANSI_CYAN, sizeof(ANSI_CYAN)-1 }, { ANSI_WHITE, sizeof(ANSI_WHITE)-1 }, // COLOR_INDEX_FG_WHITE { ANSI_BBLACK, sizeof(ANSI_BBLACK)-1 }, // COLOR_INDEX_BG { ANSI_BRED, sizeof(ANSI_BRED)-1 }, { ANSI_BGREEN, sizeof(ANSI_BGREEN)-1 }, { ANSI_BYELLOW, sizeof(ANSI_BYELLOW)-1 }, { ANSI_BBLUE, sizeof(ANSI_BBLUE)-1 }, { ANSI_BMAGENTA, sizeof(ANSI_BMAGENTA)-1 }, { ANSI_BCYAN, sizeof(ANSI_BCYAN)-1 }, { ANSI_BWHITE, sizeof(ANSI_BWHITE)-1 } // COLOR_LAST_CODE }; UTF8 *convert_color(const UTF8 *pString) { static UTF8 aBuffer[2*LBUF_SIZE]; UTF8 *pBuffer = aBuffer; while ('\0' != *pString) { unsigned int iCode = mux_color(pString); if (COLOR_NOTCOLOR == iCode) { utf8_safe_chr(pString, aBuffer, &pBuffer); } else { memcpy(pBuffer, aColors[iCode].pAnsi, aColors[iCode].nAnsi); pBuffer += aColors[iCode].nAnsi; } pString = utf8_NextCodePoint(pString); } *pBuffer = '\0'; return aBuffer; } /*! \brief Convert UTF8 to latin1 with '?' for all unsupported characters. * * \param pString UTF8 string. * \return Equivalent string in latin1 codeset. */ char *ConvertToLatin(const UTF8 *pString) { static char buffer[LBUF_SIZE]; char *q = buffer; while ('\0' != *pString) { const UTF8 *p = pString; int iState = TR_LATIN1_START_STATE; do { unsigned char ch = *p++; iState = tr_latin1_stt[iState][tr_latin1_itt[(unsigned char)ch]]; } while (iState < TR_LATIN1_ACCEPTING_STATES_START); *q++ = (char)(iState - TR_LATIN1_ACCEPTING_STATES_START); pString = utf8_NextCodePoint(pString); } *q = '\0'; return buffer; } typedef struct { int len; const char *p; } LITERAL_STRING_STRUCT; #define NUM_MU_SUBS 14 static LITERAL_STRING_STRUCT MU_Substitutes[NUM_MU_SUBS] = { { 1, " " }, // 0 { 1, " " }, // 1 { 2, "%t" }, // 2 { 2, "%r" }, // 3 { 0, NULL }, // 4 { 2, "%b" }, // 5 { 2, "%%" }, // 6 { 2, "%(" }, // 7 { 2, "%)" }, // 8 { 2, "%[" }, // 9 { 2, "%]" }, // 10 { 2, "%{" }, // 11 { 2, "%}" }, // 12 { 2, "\\\\" } // 13 }; const unsigned char MU_EscapeConvert[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 4, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 1, 0, 0, 0, 0, 6, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,13,10, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,11, 0,12, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; const unsigned char MU_EscapeNoConvert[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 4, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; // Convert raw character sequences into MUX substitutions (type = 1) // or strips them (type = 0). // char *translate_string(const char *szString, bool bConvert) { static char szTranslatedString[LBUF_SIZE]; char *pTranslatedString = szTranslatedString; const char *pString = szString; if (!szString) { *pTranslatedString = '\0'; return szTranslatedString; } size_t nString = strlen(szString); ANSI_ColorState acsCurrent; ANSI_ColorState acsPrevious; acsCurrent = acsRestingStates[ANSI_ENDGOAL_NOBLEED]; acsPrevious = acsCurrent; const unsigned char *MU_EscapeChar = (bConvert)? MU_EscapeConvert : MU_EscapeNoConvert; while (nString) { size_t nTokenLength0; size_t nTokenLength1; int iType = ANSI_lex(nString, pString, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { // Process TEXT // int nTransition = 0; if (bConvert) { char *pTransition = ANSI_TransitionColorEscape(&acsPrevious, &acsCurrent, &nTransition); safe_str(pTransition, szTranslatedString, &pTranslatedString); } nString -= nTokenLength0; while (nTokenLength0--) { unsigned char ch = *pString++; unsigned char code = MU_EscapeChar[ch]; if ( 0 < code && code < NUM_MU_SUBS) { // The following can look one ahead off the end of the // current token (and even at the '\0' at the end of the // string, but this is acceptable. An extra look will // always see either ESC from the next ANSI sequence, // or the '\0' on the end of the string. No harm done. // if (ch == ' ' && pString[0] == ' ') { code = 5; } safe_copy_buf(MU_Substitutes[code].p, MU_Substitutes[code].len, szTranslatedString, &pTranslatedString); } else { safe_chr(ch, szTranslatedString, &pTranslatedString); } } acsPrevious = acsCurrent; if (nTokenLength1) { // Process ANSI // ANSI_Parse_m(&acsCurrent, nTokenLength1, pString); pString += nTokenLength1; nString -= nTokenLength1; } } else { // Process ANSI // ANSI_Parse_m(&acsCurrent, nTokenLength0, pString); nString -= nTokenLength0; pString += nTokenLength0; } } *pTranslatedString = '\0'; return szTranslatedString; } /* --------------------------------------------------------------------------- * munge_space: Compress multiple spaces to one space, also remove leading and * trailing spaces. */ char *munge_space(const char *string) { char *buffer = alloc_lbuf("munge_space"); const char *p = string; char *q = buffer; if (p) { // Remove initial spaces. // while (mux_isspace(*p)) p++; while (*p) { while (*p && !mux_isspace(*p)) *q++ = *p++; while (mux_isspace(*p)) { p++; } if (*p) *q++ = ' '; } } // Remove terminal spaces and terminate string. // *q = '\0'; return buffer; } /* --------------------------------------------------------------------------- * trim_spaces: Remove leading and trailing spaces. */ char *trim_spaces(const char *string) { char *buffer = alloc_lbuf("trim_spaces"); const char *p = string; char *q = buffer; if (p) { // Remove initial spaces. // while (mux_isspace(*p)) { p++; } while (*p) { // Copy non-space characters. // while (*p && !mux_isspace(*p)) { *q++ = *p++; } // Compress spaces. // while (mux_isspace(*p)) { p++; } // Leave one space. // if (*p) { *q++ = ' '; } } } // Terminate string. // *q = '\0'; return buffer; } /* * --------------------------------------------------------------------------- * * grabto: Return portion of a string up to the indicated character. Also * * returns a modified pointer to the string ready for another call. */ char *grabto(char **str, char targ) { char *savec, *cp; if (!str || !*str || !**str) return NULL; savec = cp = *str; while (*cp && *cp != targ) cp++; if (*cp) *cp++ = '\0'; *str = cp; return savec; } int string_compare(const char *s1, const char *s2) { if ( mudstate.bStandAlone || mudconf.space_compress) { while (mux_isspace(*s1)) { s1++; } while (mux_isspace(*s2)) { s2++; } while ( *s1 && *s2 && ( (mux_tolower(*s1) == mux_tolower(*s2)) || (mux_isspace(*s1) && mux_isspace(*s2)))) { if (mux_isspace(*s1) && mux_isspace(*s2)) { // skip all other spaces. // do { s1++; } while (mux_isspace(*s1)); do { s2++; } while (mux_isspace(*s2)); } else { s1++; s2++; } } if ( *s1 && *s2) { return 1; } if (mux_isspace(*s1)) { while (mux_isspace(*s1)) { s1++; } return *s1; } if (mux_isspace(*s2)) { while (mux_isspace(*s2)) { s2++; } return *s2; } if ( *s1 || *s2) { return 1; } return 0; } else { return mux_stricmp(s1, s2); } } int string_prefix(const char *string, const char *prefix) { int count = 0; while (*string && *prefix && (mux_tolower(*string) == mux_tolower(*prefix))) { string++, prefix++, count++; } if (*prefix == '\0') { // Matched all of prefix. // return count; } else { return 0; } } /* * accepts only nonempty matches starting at the beginning of a word */ const char *string_match(const char *src, const char *sub) { if ((*sub != '\0') && (src)) { while (*src) { if (string_prefix(src, sub)) { return src; } // else scan to beginning of next word // while (mux_isalnum(*src)) { src++; } while (*src && !mux_isalnum(*src)) { src++; } } } return 0; } /* * --------------------------------------------------------------------------- * * replace_string: Returns an lbuf containing string STRING with all occurances * * of OLD replaced by NEW. OLD and NEW may be different lengths. * * (mitch 1 feb 91) */ char *replace_string(const char *old, const char *new0, const char *s) { if (!s) { return NULL; } size_t olen = strlen(old); char *result = alloc_lbuf("replace_string"); char *r = result; while (*s) { // Find next occurrence of the first character of OLD string. // const char *p = strchr(s, old[0]); if ( olen && p) { // Copy up to the next occurrence of the first char of OLD. // size_t n = p - s; if (n) { safe_copy_buf(s, n, result, &r); s += n; } // If we are really at an complete OLD, append NEW to the result // and bump the input string past the occurrence of OLD. // Otherwise, copy the character and try matching again. // if (!strncmp(old, s, olen)) { safe_str(new0, result, &r); s += olen; } else { safe_chr(*s, result, &r); s++; } } else { // Finish copying source string. No matches. No further // work to perform. // safe_str(s, result, &r); break; } } *r = '\0'; return result; } // --------------------------------------------------------------------------- // replace_tokens: Performs ## and #@ substitution. // char *replace_tokens ( const char *s, const char *pBound, const char *pListPlace, const char *pSwitch ) { if (!s) { return NULL; } char *result = alloc_lbuf("replace_tokens"); char *r = result; while (*s) { // Find next '#'. // const char *p = strchr(s, '#'); if (p) { // Copy up to the next occurrence of the first character. // size_t n = p - s; if (n) { safe_copy_buf(s, n, result, &r); s += n; } if ( s[1] == '#' && pBound) { // BOUND_VAR // safe_str(pBound, result, &r); s += 2; } else if ( s[1] == '@' && pListPlace) { // LISTPLACE_VAR // safe_str(pListPlace, result, &r); s += 2; } else if ( s[1] == '$' && pSwitch) { // SWITCH_VAR // safe_str(pSwitch, result, &r); s += 2; } else { safe_chr(*s, result, &r); s++; } } else { // Finish copying source string. No matches. No further // work to perform. // safe_str(s, result, &r); break; } } *r = '\0'; return result; } #if 0 // Returns the number of identical characters in the two strings. // int prefix_match(const char *s1, const char *s2) { int count = 0; while (*s1 && *s2 && (mux_tolower(*s1) == mux_tolower(*s2))) { s1++, s2++, count++; } // If the whole string matched, count the null. (Yes really.) // if (!*s1 && !*s2) { count++; } return count; } #endif // 0 bool minmatch(const char *str, const char *target, int min) { while (*str && *target && (mux_tolower(*str) == mux_tolower(*target))) { str++; target++; min--; } if (*str) { return false; } if (!*target) { return true; } return (min <= 0); } // -------------------------------------------------------------------------- // StringCloneLen: allocate memory and copy string // char *StringCloneLen(const char *str, size_t nStr) { char *buff = (char *)MEMALLOC(nStr+1); if (buff) { memcpy(buff, str, nStr); buff[nStr] = '\0'; } else { ISOUTOFMEMORY(buff); } return buff; } // -------------------------------------------------------------------------- // StringClone: allocate memory and copy string // char *StringClone(const char *str) { return StringCloneLen(str, strlen(str)); } #if 0 // -------------------------------------------------------------------------- // BufferCloneLen: allocate memory and copy buffer // char *BufferCloneLen(const char *pBuffer, unsigned int nBuffer) { char *buff = (char *)MEMALLOC(nBuffer); ISOUTOFMEMORY(buff); memcpy(buff, pBuffer, nBuffer); return buff; } #endif // 0 /* --------------------------------------------------------------------------- * safe_copy_str, safe_copy_chr - Copy buffers, watching for overflows. */ void safe_copy_str(const char *src, char *buff, char **bufp, int nSizeOfBuffer) { if (src == NULL) return; char *tp = *bufp; char *maxtp = buff + nSizeOfBuffer; while (tp < maxtp && *src) { *tp++ = *src++; } *bufp = tp; } void safe_copy_str_lbuf(const char *src, char *buff, char **bufp) { if (src == NULL) { return; } char *tp = *bufp; char *maxtp = buff + LBUF_SIZE - 1; while (tp < maxtp && *src) { *tp++ = *src++; } *bufp = tp; } size_t safe_copy_buf(const char *src, size_t nLen, char *buff, char **bufc) { size_t left = LBUF_SIZE - (*bufc - buff) - 1; if (left < nLen) { nLen = left; } memcpy(*bufc, src, nLen); *bufc += nLen; return nLen; } size_t safe_fill(char *buff, char **bufc, char chFill, size_t nSpaces) { // Check for buffer limits. // size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; if (nSpaces > nBufferAvailable) { nSpaces = nBufferAvailable; } // Fill with spaces. // memset(*bufc, chFill, nSpaces); *bufc += nSpaces; return nSpaces; } // mux_strncpy: Copies up to specified number of chars from source. // Note: unlike strncpy(), this null-terminates after copying. // void mux_strncpy(char *dest, const char *src, size_t nSizeOfBuffer) { if (src == NULL) return; char *tp = dest; char *maxtp = dest + nSizeOfBuffer; while (tp < maxtp && *src) { *tp++ = *src++; } *tp = '\0'; } bool matches_exit_from_list(char *str, const char *pattern) { char *s; while (*pattern) { for (s = str; // check out this one ( *s && (mux_tolower(*s) == mux_tolower(*pattern)) && *pattern && (*pattern != EXIT_DELIMITER)); s++, pattern++) ; // Did we match it all? // if (*s == '\0') { // Make sure nothing afterwards // while (mux_isspace(*pattern)) { pattern++; } // Did we get it? // if ( !*pattern || (*pattern == EXIT_DELIMITER)) { return true; } } // We didn't get it, find next string to test // while ( *pattern && *pattern++ != EXIT_DELIMITER) { ; // Nothing. } while (mux_isspace(*pattern)) { pattern++; } } return false; } const char Digits100[201] = "001020304050607080900111213141516171819102122232425262728292\ 031323334353637383930414243444546474849405152535455565758595\ 061626364656667686960717273747576777879708182838485868788898\ 09192939495969798999"; size_t mux_ltoa(long val, char *buf) { char *p = buf; if (val < 0) { *p++ = '-'; val = -val; } unsigned long uval = (unsigned long)val; char *q = p; const char *z; while (uval > 99) { z = Digits100 + ((uval % 100) << 1); uval /= 100; *p++ = *z; *p++ = *(z+1); } z = Digits100 + (uval << 1); *p++ = *z; if (uval > 9) { *p++ = *(z+1); } size_t nLength = p - buf; *p-- = '\0'; // The digits are in reverse order with a possible leading '-' // if the value was negative. q points to the first digit, // and p points to the last digit. // while (q < p) { // Swap characters are *p and *q // char temp = *p; *p = *q; *q = temp; // Move p and first digit towards the middle. // --p; ++q; // Stop when we reach or pass the middle. // } return nLength; } char *mux_ltoa_t(long val) { static char buff[12]; mux_ltoa(val, buff); return buff; } void safe_ltoa(long val, char *buff, char **bufc) { static char temp[12]; size_t n = mux_ltoa(val, temp); safe_copy_buf(temp, n, buff, bufc); } size_t mux_i64toa(INT64 val, char *buf) { char *p = buf; if (val < 0) { *p++ = '-'; val = -val; } UINT64 uval = (UINT64)val; char *q = p; const char *z; while (uval > 99) { z = Digits100 + ((uval % 100) << 1); uval /= 100; *p++ = *z; *p++ = *(z+1); } z = Digits100 + (uval << 1); *p++ = *z; if (uval > 9) { *p++ = *(z+1); } size_t nLength = p - buf; *p-- = '\0'; // The digits are in reverse order with a possible leading '-' // if the value was negative. q points to the first digit, // and p points to the last digit. // while (q < p) { // Swap characters are *p and *q // char temp = *p; *p = *q; *q = temp; // Move p and first digit towards the middle. // --p; ++q; // Stop when we reach or pass the middle. // } return nLength; } char *mux_i64toa_t(INT64 val) { static char buff[22]; mux_i64toa(val, buff); return buff; } void safe_i64toa(INT64 val, char *buff, char **bufc) { static char temp[22]; size_t n = mux_i64toa(val, temp); safe_copy_buf(temp, n, buff, bufc); } const char TableATOI[16][10] = { { 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, 65, 66, 67, 68, 69}, { 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}, { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89}, { 90, 91, 92, 93, 94, 95, 96, 97, 98, 99} }; long mux_atol(const char *pString) { long sum = 0; int LeadingCharacter = 0; // Convert ASCII digits // unsigned int c1; unsigned int c0 = pString[0]; if (!mux_isdigit(c0)) { while (mux_isspace(pString[0])) { pString++; } LeadingCharacter = pString[0]; if ( LeadingCharacter == '-' || LeadingCharacter == '+') { pString++; } c0 = pString[0]; if (!mux_isdigit(c0)) { return 0; } } do { c1 = pString[1]; if (mux_isdigit(c1)) { sum = 100 * sum + TableATOI[c0-'0'][c1-'0']; pString += 2; } else { sum = 10 * sum + (c0-'0'); break; } } while (mux_isdigit(c0 = pString[0])); // Interpret sign // if (LeadingCharacter == '-') { sum = -sum; } return sum; } INT64 mux_atoi64(const char *pString) { INT64 sum = 0; int LeadingCharacter = 0; // Convert ASCII digits // unsigned int c1; unsigned int c0 = pString[0]; if (!mux_isdigit(c0)) { while (mux_isspace(pString[0])) { pString++; } LeadingCharacter = pString[0]; if ( LeadingCharacter == '-' || LeadingCharacter == '+') { pString++; } c0 = pString[0]; if (!mux_isdigit(c0)) { return 0; } } do { c1 = pString[1]; if (mux_isdigit(c1)) { sum = 100 * sum + TableATOI[c0-'0'][c1-'0']; pString += 2; } else { sum = 10 * sum + (c0-'0'); break; } } while (mux_isdigit(c0 = pString[0])); // Interpret sign // if (LeadingCharacter == '-') { sum = -sum; } return sum; } // Floating-point strings match one of the following patterns: // // [+-]?[0-9]?(.[0-9]+)([eE][+-]?[0-9]{1,3})? // [+-]?[0-9]+(.[0-9]?)([eE][+-]?[0-9]{1,3})? // +Inf // -Inf // Ind // NaN // bool ParseFloat(PARSE_FLOAT_RESULT *pfr, const char *str, bool bStrict) { memset(pfr, 0, sizeof(PARSE_FLOAT_RESULT)); // Parse Input // unsigned char ch; pfr->pMeat = str; if ( !mux_isdigit(*str) && *str != '.') { while (mux_isspace(*str)) { str++; } pfr->pMeat = str; if (*str == '-') { pfr->iLeadingSign = '-'; str++; } else if (*str == '+') { pfr->iLeadingSign = '+'; str++; } if ( !mux_isdigit(*str) && *str != '.') { // Look for three magic strings. // ch = mux_toupper(str[0]); if (ch == 'I') { // Could be 'Inf' or 'Ind' // ch = mux_toupper(str[1]); if (ch == 'N') { ch = mux_toupper(str[2]); if (ch == 'F') { // Inf // if (pfr->iLeadingSign == '-') { pfr->iString = IEEE_MAKE_NINF; } else { pfr->iString = IEEE_MAKE_PINF; } str += 3; goto LastSpaces; } else if (ch == 'D') { // Ind // pfr->iString = IEEE_MAKE_IND; str += 3; goto LastSpaces; } } } else if (ch == 'N') { // Could be 'Nan' // ch = mux_toupper(str[1]); if (ch == 'A') { ch = mux_toupper(str[2]); if (ch == 'N') { // Nan // pfr->iString = IEEE_MAKE_NAN; str += 3; goto LastSpaces; } } } return false; } } // At this point, we have processed the leading sign, handled all // the magic strings, skipped the leading spaces, and best of all // we either have a digit or a decimal point. // pfr->pDigitsA = str; while (mux_isdigit(*str)) { pfr->nDigitsA++; str++; } if (*str == '.') { str++; } pfr->pDigitsB = str; while (mux_isdigit(*str)) { pfr->nDigitsB++; str++; } if ( pfr->nDigitsA == 0 && pfr->nDigitsB == 0) { return false; } ch = mux_toupper(*str); if (ch == 'E') { // There is an exponent portion. // str++; if (*str == '-') { pfr->iExponentSign = '-'; str++; } else if (*str == '+') { pfr->iExponentSign = '+'; str++; } pfr->pDigitsC = str; while (mux_isdigit(*str)) { pfr->nDigitsC++; str++; } if ( pfr->nDigitsC < 1 || 4 < pfr->nDigitsC) { return false; } } LastSpaces: pfr->nMeat = str - pfr->pMeat; // Trailing spaces. // while (mux_isspace(*str)) { str++; } if (bStrict) { return (!*str); } else { return true; } } #define ATOF_LIMIT 100 static const double powerstab[10] = { 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0 }; double mux_atof(char *szString, bool bStrict) { PARSE_FLOAT_RESULT pfr; if (!ParseFloat(&pfr, szString, bStrict)) { return 0.0; } if (pfr.iString) { // Return the double value which corresponds to the // string when HAVE_IEEE_FORMAT. // #ifdef HAVE_IEEE_FP_FORMAT return MakeSpecialFloat(pfr.iString); #else // HAVE_IEEE_FP_FORMAT return 0.0; #endif // HAVE_IEEE_FP_FORMAT } // See if we can shortcut the decoding process. // double ret; if ( pfr.nDigitsA <= 9 && pfr.nDigitsC == 0) { if (pfr.nDigitsB <= 9) { if (pfr.nDigitsB == 0) { // This 'floating-point' number is just an integer. // ret = (double)mux_atol(pfr.pDigitsA); } else { // This 'floating-point' number is fixed-point. // double rA = (double)mux_atol(pfr.pDigitsA); double rB = (double)mux_atol(pfr.pDigitsB); double rScale = powerstab[pfr.nDigitsB]; ret = rA + rB/rScale; // As it is, ret is within a single bit of what a // a call to atof would return. However, we can // achieve that last lowest bit of precision by // computing a residual. // double residual = (ret - rA)*rScale; ret += (rB - residual)/rScale; } if (pfr.iLeadingSign == '-') { ret = -ret; } return ret; } } const char *p = pfr.pMeat; size_t n = pfr.nMeat; // We need to protect certain libraries from going nuts from being // force fed lots of ASCII. // char *pTmp = NULL; if (n > ATOF_LIMIT) { pTmp = alloc_lbuf("mux_atof"); memcpy(pTmp, p, ATOF_LIMIT); pTmp[ATOF_LIMIT] = '\0'; p = pTmp; } ret = mux_strtod(p, NULL); if (pTmp) { free_lbuf(pTmp); } return ret; } char *mux_ftoa(double r, bool bRounded, int frac) { static char buffer[100]; char *q = buffer; char *rve = NULL; int iDecimalPoint = 0; int bNegative = 0; int mode = 0; int nRequestMaximum = 50; const int nRequestMinimum = -20; int nRequest = nRequestMaximum; // If float_precision is enabled, let it override nRequestMaximum. // if (0 <= mudconf.float_precision) { mode = 3; if (mudconf.float_precision < nRequestMaximum) { nRequestMaximum = mudconf.float_precision; nRequest = mudconf.float_precision; } } if (bRounded) { mode = 3; nRequest = frac; if (nRequestMaximum < nRequest) { nRequest = nRequestMaximum; } else if (nRequest < nRequestMinimum) { nRequest = nRequestMinimum; } } char *p = mux_dtoa(r, mode, nRequest, &iDecimalPoint, &bNegative, &rve); size_t nSize = rve - p; if (nSize > 50) { nSize = 50; } if (bNegative) { *q++ = '-'; } if (iDecimalPoint == 9999) { // Inf or NaN // memcpy(q, p, nSize); q += nSize; } else if (nSize <= 0) { // Zero // if (bNegative) { // If we laid down a minus sign, we should remove it. // q--; } *q++ = '0'; if ( bRounded && 0 < nRequest) { *q++ = '.'; memset(q, '0', nRequest); q += nRequest; } } else if ( iDecimalPoint <= -6 || 18 <= iDecimalPoint) { *q++ = *p++; if (1 < nSize) { *q++ = '.'; memcpy(q, p, nSize-1); q += nSize-1; } *q++ = 'E'; q += mux_ltoa(iDecimalPoint-1, q); } else if (iDecimalPoint <= 0) { // iDecimalPoint = -5 to 0 // *q++ = '0'; *q++ = '.'; memset(q, '0', -iDecimalPoint); q += -iDecimalPoint; memcpy(q, p, nSize); q += nSize; if (bRounded) { size_t nPad = nRequest - (nSize - iDecimalPoint); if (0 < nPad) { memset(q, '0', nPad); q += nPad; } } } else { // iDecimalPoint = 1 to 17 // if (nSize <= static_cast(iDecimalPoint)) { memcpy(q, p, nSize); q += nSize; memset(q, '0', iDecimalPoint - nSize); q += iDecimalPoint - nSize; if ( bRounded && 0 < nRequest) { *q++ = '.'; memset(q, '0', nRequest); q += nRequest; } } else { memcpy(q, p, iDecimalPoint); q += iDecimalPoint; p += iDecimalPoint; *q++ = '.'; memcpy(q, p, nSize - iDecimalPoint); q += nSize - iDecimalPoint; if (bRounded) { size_t nPad = nRequest - (nSize - iDecimalPoint); if (0 < nPad) { memset(q, '0', nPad); q += nPad; } } } } *q = '\0'; return buffer; } bool is_integer(char *str, int *pDigits) { int nDigits = 0; if (pDigits) { *pDigits = 0; } // Leading spaces. // while (mux_isspace(*str)) { str++; } // Leading minus or plus // if (*str == '-' || *str == '+') { str++; // Just a sign by itself isn't an integer. // if (!*str) { return false; } } // Need at least 1 integer // if (!mux_isdigit(*str)) { return false; } // The number (int) // do { str++; nDigits++; } while (mux_isdigit(*str)); if (pDigits) { *pDigits = nDigits; } // Trailing Spaces. // while (mux_isspace(*str)) { str++; } return (!*str); } bool is_rational(char *str) { // Leading spaces. // while (mux_isspace(*str)) { str++; } // Leading minus or plus sign. // if (*str == '-' || *str == '+') { str++; // But not if just a sign. // if (!*str) { return false; } } // Need at least one digit. // bool got_one = false; if (mux_isdigit(*str)) { got_one = true; } // The number (int) // while (mux_isdigit(*str)) { str++; } // Decimal point. // if (*str == '.') { str++; } // Need at least one digit // if (mux_isdigit(*str)) { got_one = true; } if (!got_one) { return false; } // The number (fract) // while (mux_isdigit(*str)) { str++; } // Trailing spaces. // while (mux_isspace(*str)) { str++; } // There must be nothing else after the trailing spaces. // return (!*str); } bool is_real(char *str) { PARSE_FLOAT_RESULT pfr; return ParseFloat(&pfr, str); } // mux_strtok_src, mux_strtok_ctl, mux_strtok_parse. // // These three functions work together to replace the functionality of the // strtok() C runtime library function. Call mux_strtok_src() first with // the string to parse, then mux_strtok_ctl() with the control // characters, and finally mux_strtok_parse() to parse out the tokens. // // You may call mux_strtok_ctl() to change the set of control characters // between mux_strtok_parse() calls, however keep in mind that the parsing // may not occur how you intend it to as mux_strtok_parse() does not // consume -all- of the controlling delimiters that separate two tokens. // It consumes only the first one. // void mux_strtok_src(MUX_STRTOK_STATE *tts, char *arg_pString) { if (!tts || !arg_pString) return; // Remember the string to parse. // tts->pString = arg_pString; } void mux_strtok_ctl(MUX_STRTOK_STATE *tts, const char *pControl) { if (!tts || !pControl) return; // No character is a control character. // memset(tts->aControl, 0, sizeof(tts->aControl)); // The NULL character is always a control character. // tts->aControl[0] = 1; // Record the user-specified control characters. // while (*pControl) { tts->aControl[(unsigned char)*pControl] = 1; pControl++; } } char *mux_strtok_parseLEN(MUX_STRTOK_STATE *tts, size_t *pnLen) { *pnLen = 0; if (!tts) { return NULL; } char *p = tts->pString; if (!p) { return NULL; } // Skip over leading control characters except for the NUL character. // while (tts->aControl[(unsigned char)*p] && *p) { p++; } char *pReturn = p; // Skip over non-control characters. // while (tts->aControl[(unsigned char)*p] == 0) { p++; } // What is the length of this token? // *pnLen = p - pReturn; // Terminate the token with a NUL. // if (p[0]) { // We found a non-NUL delimiter, so the next call will begin parsing // on the character after this one. // tts->pString = p+1; } else { // We hit the end of the string, so the end of the string is where // the next call will begin. // tts->pString = p; } // Did we find a token? // if (*pnLen > 0) { return pReturn; } else { return NULL; } } char *mux_strtok_parse(MUX_STRTOK_STATE *tts) { size_t nLen; char *p = mux_strtok_parseLEN(tts, &nLen); if (p) { p[nLen] = '\0'; } return p; } // This function will filter out any characters in the the set from // the string. // char *RemoveSetOfCharacters(char *pString, const char *pSetToRemove) { static char Buffer[LBUF_SIZE]; char *pBuffer = Buffer; size_t nLen; size_t nLeft = sizeof(Buffer) - 1; char *p; MUX_STRTOK_STATE tts; mux_strtok_src(&tts, pString); mux_strtok_ctl(&tts, pSetToRemove); for ( p = mux_strtok_parseLEN(&tts, &nLen); p && nLeft; p = mux_strtok_parseLEN(&tts, &nLen)) { if (nLeft < nLen) { nLen = nLeft; } memcpy(pBuffer, p, nLen); pBuffer += nLen; nLeft -= nLen; } *pBuffer = '\0'; return Buffer; } void ItemToList_Init(ITL *p, char *arg_buff, char **arg_bufc, char arg_chPrefix, char arg_chSep) { p->bFirst = true; p->chPrefix = arg_chPrefix; p->chSep = arg_chSep; p->buff = arg_buff; p->bufc = arg_bufc; p->nBufferAvailable = LBUF_SIZE - (*arg_bufc - arg_buff) - 1; } bool ItemToList_AddInteger(ITL *pContext, int i) { char smbuf[SBUF_SIZE]; char *p = smbuf; if ( !pContext->bFirst && pContext->chSep) { *p++ = pContext->chSep; } if (pContext->chPrefix) { *p++ = pContext->chPrefix; } p += mux_ltoa(i, p); size_t nLen = p - smbuf; if (nLen > pContext->nBufferAvailable) { // Out of room. // return false; } if (pContext->bFirst) { pContext->bFirst = false; } memcpy(*(pContext->bufc), smbuf, nLen); *(pContext->bufc) += nLen; pContext->nBufferAvailable -= nLen; return true; } bool ItemToList_AddInteger64(ITL *pContext, INT64 i64) { char smbuf[SBUF_SIZE]; char *p = smbuf; if ( !pContext->bFirst && pContext->chSep) { *p++ = pContext->chSep; } if (pContext->chPrefix) { *p++ = pContext->chPrefix; } p += mux_i64toa(i64, p); size_t nLen = p - smbuf; if (nLen > pContext->nBufferAvailable) { // Out of room. // return false; } if (pContext->bFirst) { pContext->bFirst = false; } memcpy(*(pContext->bufc), smbuf, nLen); *(pContext->bufc) += nLen; pContext->nBufferAvailable -= nLen; return true; } bool ItemToList_AddStringLEN(ITL *pContext, size_t nStr, const char *pStr) { size_t nLen = nStr; if ( !pContext->bFirst && pContext->chSep) { nLen++; } if (pContext->chPrefix) { nLen++; } if (nLen > pContext->nBufferAvailable) { // Out of room. // return false; } char *p = *(pContext->bufc); if (pContext->bFirst) { pContext->bFirst = false; } else if (pContext->chSep) { *p++ = pContext->chSep; } if (pContext->chPrefix) { *p++ = pContext->chPrefix; } memcpy(p, pStr, nStr); *(pContext->bufc) += nLen; pContext->nBufferAvailable -= nLen; return true; } bool ItemToList_AddString(ITL *pContext, const char *pStr) { size_t nStr = strlen(pStr); return ItemToList_AddStringLEN(pContext, nStr, pStr); } void ItemToList_Final(ITL *pContext) { **(pContext->bufc) = '\0'; } // mux_stricmp - Compare two strings ignoring case. // int mux_stricmp(const char *a, const char *b) { while ( *a && *b && mux_tolower(*a) == mux_tolower(*b)) { a++; b++; } int c1 = mux_tolower(*a); int c2 = mux_tolower(*b); if (c1 < c2) { return -1; } else if (c1 > c2) { return 1; } else { return 0; } } // mux_memicmp - Compare two buffers ignoring case. // int mux_memicmp(const void *p1_arg, const void *p2_arg, size_t n) { unsigned char *p1 = (unsigned char *)p1_arg; unsigned char *p2 = (unsigned char *)p2_arg; while ( n && mux_tolower(*p1) == mux_tolower(*p2)) { n--; p1++; p2++; } if (n) { int c1 = mux_tolower(*p1); int c2 = mux_tolower(*p2); if (c1 < c2) { return -1; } else if (c1 > c2) { return 1; } } return 0; } // mux_strlwr - Convert string to all lower case. // void mux_strlwr(char *a) { while (*a) { *a = mux_tolower(*a); a++; } } // mux_strupr - Convert string to all upper case. // void mux_strupr(char *a) { while (*a) { *a = mux_toupper(*a); a++; } } // mux_vsnprintf - Is an sprintf-like function that will not overflow // a buffer of specific size. The size is give by count, and count // should be chosen to include the '\0' termination. // // Returns: A number from 0 to count-1 that is the string length of // the returned (possibly truncated) buffer. // size_t DCL_CDECL mux_vsnprintf(char *buff, size_t count, const char *fmt, va_list va) { // From the manuals: // // vsnprintf returns the number of characters written, not // including the terminating '\0' character. // // It returns a -1 if an output error occurs. // // It can return a number larger than the size of the buffer // on some systems to indicate how much space it -would- have taken // if not limited by the request. // // On Win32, it can fill the buffer completely without a // null-termination and return -1. // To favor the Unix case, if there is an output error, but // vsnprint doesn't touch the buffer, we avoid undefined trash by // null-terminating the buffer to zero-length before the call. // Not sure that this happens, but it's a cheap precaution. // buff[0] = '\0'; // If Unix version does start touching the buffer, null-terminates, // and returns -1, we are still safe. However, if Unix version // touches the buffer writes garbage, and then returns -1, we may // pass garbage, but this possibility seems very unlikely. // size_t len; #if defined(WIN32) #if !defined(__INTEL_COMPILER) && (_MSC_VER >= 1400) int cc = vsnprintf_s(buff, count, _TRUNCATE, fmt, va); #else // _MSC_VER int cc = _vsnprintf(buff, count, fmt, va); #endif // _MSC_VER #else // WIN32 #ifdef NEED_VSPRINTF_DCL extern char *vsprintf(char *, char *, va_list); #endif // NEED_VSPRINTF_DCL int cc = vsnprintf(buff, count, fmt, va); #endif // WIN32 if (0 <= cc && static_cast(cc) <= count-1) { len = cc; } else { if (buff[0] == '\0') { // vsnprintf did not touch the buffer. // len = 0; } else { len = count-1; } } buff[len] = '\0'; return len; } void DCL_CDECL mux_sprintf(char *buff, size_t count, const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void)mux_vsnprintf(buff, count, fmt, ap); va_end(ap); } // This function acts like fgets except that any data on the end of the // line past the buffer size is truncated instead of being returned on // the next call. // size_t GetLineTrunc(char *Buffer, size_t nBuffer, FILE *fp) { size_t lenBuffer = 0; if (fgets(Buffer, static_cast(nBuffer), fp)) { lenBuffer = strlen(Buffer); } if (lenBuffer <= 0) { memcpy(Buffer, "\n", 2); return 1; } if (Buffer[lenBuffer-1] != '\n') { // The line was too long for the buffer. Continue reading until the // end of the line. // char TruncBuffer[SBUF_SIZE]; size_t lenTruncBuffer; do { if (!fgets(TruncBuffer, sizeof(TruncBuffer), fp)) { break; } lenTruncBuffer = strlen(TruncBuffer); } while (TruncBuffer[lenTruncBuffer-1] != '\n'); } return lenBuffer; } // Method: Boyer-Moore-Horspool // // This method is a simplification of the Boyer-Moore String Searching // Algorithm, but a useful one. It does not require as much temporary // storage, and the setup costs are not as high as the full Boyer-Moore. // // If we were searching megabytes of data instead of 8KB at most, then // the full Boyer-Moore would make more sense. // #define BMH_LARGE 32767 void BMH_Prepare(BMH_State *bmhs, size_t nPat, const char *pPat) { if (nPat <= 0) { return; } size_t k; for (k = 0; k < 256; k++) { bmhs->m_d[k] = nPat; } char chLastPat = pPat[nPat-1]; bmhs->m_skip2 = nPat; for (k = 0; k < nPat - 1; k++) { bmhs->m_d[(unsigned char)pPat[k]] = nPat - k - 1; if (pPat[k] == chLastPat) { bmhs->m_skip2 = nPat - k - 1; } } bmhs->m_d[(unsigned char)chLastPat] = BMH_LARGE; } bool BMH_Execute(BMH_State *bmhs, size_t *pnMatched, size_t nPat, const char *pPat, size_t nSrc, const char *pSrc) { if (nPat <= 0) { return false; } for (size_t i = nPat-1; i < nSrc; i += bmhs->m_skip2) { while ((i += bmhs->m_d[(unsigned char)(pSrc[i])]) < nSrc) { ; // Nothing. } if (i < BMH_LARGE) { break; } i -= BMH_LARGE; int j = static_cast(nPat - 1); const char *s = pSrc + (i - j); while (--j >= 0 && s[j] == pPat[j]) { ; // Nothing. } if (j < 0) { *pnMatched = s-pSrc; return true; } } return false; } bool BMH_StringSearch(size_t *pnMatched, size_t nPat, const char *pPat, size_t nSrc, const char *pSrc) { BMH_State bmhs; BMH_Prepare(&bmhs, nPat, pPat); return BMH_Execute(&bmhs, pnMatched, nPat, pPat, nSrc, pSrc); } void BMH_PrepareI(BMH_State *bmhs, size_t nPat, const char *pPat) { if (nPat <= 0) { return; } size_t k; for (k = 0; k < 256; k++) { bmhs->m_d[k] = nPat; } char chLastPat = pPat[nPat-1]; bmhs->m_skip2 = nPat; for (k = 0; k < nPat - 1; k++) { bmhs->m_d[mux_toupper(pPat[k])] = nPat - k - 1; bmhs->m_d[mux_tolower(pPat[k])] = nPat - k - 1; if (mux_toupper(pPat[k]) == mux_toupper(chLastPat)) { bmhs->m_skip2 = nPat - k - 1; } } bmhs->m_d[mux_toupper(chLastPat)] = BMH_LARGE; bmhs->m_d[mux_tolower(chLastPat)] = BMH_LARGE; } bool BMH_ExecuteI(BMH_State *bmhs, size_t *pnMatched, size_t nPat, const char *pPat, size_t nSrc, const char *pSrc) { if (nPat <= 0) { return false; } for (size_t i = nPat-1; i < nSrc; i += bmhs->m_skip2) { while ((i += bmhs->m_d[(unsigned char)(pSrc[i])]) < nSrc) { ; // Nothing. } if (i < BMH_LARGE) { break; } i -= BMH_LARGE; int j = static_cast(nPat - 1); const char *s = pSrc + (i - j); while ( --j >= 0 && mux_toupper(s[j]) == mux_toupper(pPat[j])) { ; // Nothing. } if (j < 0) { *pnMatched = s-pSrc; return true; } } return false; } bool BMH_StringSearchI(size_t *pnMatched, size_t nPat, const char *pPat, size_t nSrc, const char *pSrc) { BMH_State bmhs; BMH_PrepareI(&bmhs, nPat, pPat); return BMH_ExecuteI(&bmhs, pnMatched, nPat, pPat, nSrc, pSrc); } // --------------------------------------------------------------------------- // cf_art_except: // // Add an article rule to the ruleset. // CF_HAND(cf_art_rule) { UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); char* pCurrent = str; while (mux_isspace(*pCurrent)) { pCurrent++; } char* pArticle = pCurrent; while ( !mux_isspace(*pCurrent) && *pCurrent != '\0') { pCurrent++; } if (*pCurrent == '\0') { cf_log_syntax(player, cmd, "No article or regexp specified."); return -1; } bool bUseAn = false; bool bOkay = false; if (pCurrent - pArticle <= 2) { if (mux_tolower(pArticle[0]) == 'a') { if (mux_tolower(pArticle[1]) == 'n') { bUseAn = true; bOkay = true; } if (mux_isspace(pArticle[1])) { bOkay = true; } } } if (!bOkay) { *pCurrent = '\0'; cf_log_syntax(player, cmd, "Invalid article '%s'.", pArticle); return -1; } while (mux_isspace(*pCurrent)) { pCurrent++; } if (*pCurrent == '\0') { cf_log_syntax(player, cmd, "No regexp specified."); return -1; } const char *errptr; int erroffset; pcre* reNewRegexp = pcre_compile(pCurrent, 0, &errptr, &erroffset, NULL); if (!reNewRegexp) { cf_log_syntax(player, cmd, "Error processing regexp '%s':.", pCurrent, errptr); return -1; } pcre_extra *study = pcre_study(reNewRegexp, 0, &errptr); ArtRuleset** arRules = (ArtRuleset **) vp; ArtRuleset* arNewRule = NULL; try { arNewRule = new ArtRuleset; } catch (...) { ; // Nothing. } if (NULL != arNewRule) { // Push new rule at head of list. // arNewRule->m_pNextRule = *arRules; arNewRule->m_bUseAn = bUseAn; arNewRule->m_pRegexp = reNewRegexp; arNewRule->m_pRegexpStudy = study; *arRules = arNewRule; } else { MEMFREE(reNewRegexp); if (study) { MEMFREE(study); } cf_log_syntax(player, cmd, "Out of memory."); return -1; } return 0; } #if defined(FIRANMUX) char *linewrap_general(char *strret, int field, const char *left, const char *right) { int tabsets[] = { 1, 9, 17, 25, 33, 41, 49, 57, 65, 73, 81 }; int leftmargin = 1; int rightmargin = 1+field; int position = 1; int index1 = 0; int spacesleft; bool space_eaten = true; bool line_indented = false; bool skip_out = false; char *str = alloc_lbuf("linewrap_desc"); char *ostr = str; const char *original = strret; for (;;) { if (!original[index1]) { break; } if (position == rightmargin) { line_indented = false; space_eaten = false; position = leftmargin; safe_str(right, str, &ostr); safe_str("\r\n", str, &ostr); continue; } if (position == leftmargin) { if (!line_indented) { safe_str(left, str, &ostr); line_indented = true; } if (!space_eaten) { if (' ' == original[index1]) { index1++; space_eaten = true; continue; } } } spacesleft = rightmargin - position; int index3 = index1; while (original[index3]) { if (ESC_CHAR == original[index3]) { while ( original[index3] && original[index3++] != 'm') { ; // Nothing. } continue; } if (mux_isspace(original[index3])) { break; } spacesleft--; index3++; } if ((index3 - index1) > field) { skip_out = true; } if (mux_isspace(original[index1])) { skip_out = false; } if (!skip_out) { if (spacesleft < 0) { int loop; for (loop = rightmargin - position; loop; loop--) { safe_chr(' ', str, &ostr); } position = rightmargin; continue; } } switch (original[index1]) { case ESC_CHAR: do { safe_chr(original[index1], str, &ostr); } while ( original[index1++] != 'm' && original[index1]); break; case '\r': { int loop; for (loop = rightmargin-position; loop; loop--) { safe_chr(' ', str, &ostr); } } position = rightmargin; index1 = index1 + 2; break; case '\t': { int index3 = 0; int difference = 0; index1++; for (;;) { if (position < tabsets[index3]) { break; } index3++; } difference = (rightmargin < tabsets[index3]) ? rightmargin - position : tabsets[index3] - position; position = (rightmargin < tabsets[index3]) ? rightmargin : tabsets[index3]; for (; difference; difference--) { safe_chr(' ', str, &ostr); } if (position == rightmargin) { continue; } break; } default: safe_chr(original[index1], str, &ostr); index1++; position++; break; } } int loop; for (loop = rightmargin - position; loop; loop--) { safe_chr(' ', str, &ostr); } safe_str(right, str, &ostr); *ostr = '\0'; char *bp = strret; safe_str(str, strret, &bp); *bp = '\0'; free_lbuf(str); return strret; } char *linewrap_desc(char *str) { return linewrap_general(str, 70, " ", ""); } #endif // FIRANMUX /*! \brief Constructs mux_string object. * * This constructor puts the mux_string object into an initial, reasonable, * and empty state. * * \return None. */ mux_string::mux_string(void) { m_n = 0; } /*! \brief Import ANSI string. * * Parses the given ANSI string into a form which can be more-easily * navigated. * * \param n Length of string, str. * \param str ANSI-color encoded string to import. * \return None. */ void mux_string::import(size_t n, const char *str) { m_n = 0; while (n) { ANSI_ColorState acs = acsRestingStates[ANSI_ENDGOAL_NORMAL]; size_t nToken0; size_t nToken1; int iType = ANSI_lex(n, str, &nToken0, &nToken1); if (iType == TOKEN_TEXT_ANSI) { // Process TEXT // size_t nTextToLoad = nToken0; if (sizeof(m_ach) - m_n - 1 < nTextToLoad) { nTextToLoad = sizeof(m_ach) - 1; } // Copy text and replicate corresponding color state. // memcpy(m_ach, str, nTextToLoad); for (size_t i = 0; i < nTextToLoad; i++) { m_acs[m_n+i] = acs; } m_n += nTextToLoad; str += nToken0; n -= nToken0; nToken0 = nToken1; } if (nToken0) { // Process ANSI // ANSI_Parse_m(&acs, nToken0, str); str += nToken0; n -= nToken0; } } m_ach[m_n] = '\0'; } /*! \brief Generates ANSI string from internal form. * * \param buff Pointer to beginning of lbuf. * \param bufc Pointer to current position. * \return None. */ void mux_string::copy(char *buff, char **bufc) { } mux2.6/src/ansi.h0000600000175000017500000000247611025753746013712 0ustar sdennissdennis// ansi.h // // $Id: ansi.h 8 2006-09-05 01:55:58Z brazilofmux $ */ // // ANSI control codes for various neat-o terminal effects // // Some older versions of Ultrix don't appear to be able to handle these // escape sequences. If lowercase 'a's are being stripped from @doings, // and/or the output of the ANSI flag is screwed up, you have the Ultrix // problem. // #ifndef _ANSI_H #define _ANSI_H #define BEEP_CHAR '\07' #define ESC_CHAR '\033' #define ANSI_ATTR_CMD 'm' #define ANSI_NORMAL "\033[0m" #define ANSI_HILITE "\033[1m" #define ANSI_UNDER "\033[4m" #define ANSI_BLINK "\033[5m" #define ANSI_INVERSE "\033[7m" // Foreground colors. // #define ANSI_FOREGROUND "\033[3" #define ANSI_BLACK "\033[30m" #define ANSI_RED "\033[31m" #define ANSI_GREEN "\033[32m" #define ANSI_YELLOW "\033[33m" #define ANSI_BLUE "\033[34m" #define ANSI_MAGENTA "\033[35m" #define ANSI_CYAN "\033[36m" #define ANSI_WHITE "\033[37m" // Background colors. // #define ANSI_BACKGROUND "\033[4" #define ANSI_BBLACK "\033[40m" #define ANSI_BRED "\033[41m" #define ANSI_BGREEN "\033[42m" #define ANSI_BYELLOW "\033[43m" #define ANSI_BBLUE "\033[44m" #define ANSI_BMAGENTA "\033[45m" #define ANSI_BCYAN "\033[46m" #define ANSI_BWHITE "\033[47m" #endif // !_ANSI_H mux2.6/src/help.cpp0000600000175000017500000003005311025753746014233 0ustar sdennissdennis// help.cpp -- Commands for giving help. // // $Id: help.cpp 492 2006-11-30 17:12:25Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include #include "help.h" #include "command.h" // Pointers to this struct is what gets stored in the help_htab's. // struct help_entry { size_t pos; // Position, copied from help_indx char original; // 1 for the longest name for a topic. 0 for // abbreviations. char *key; // The key this is stored under. }; void helpindex_clean(int iHelpfile) { CHashTable *htab = mudstate.aHelpDesc[iHelpfile].ht; if (htab == NULL) { return; } struct help_entry *htab_entry; for (htab_entry = (struct help_entry *)hash_firstentry(htab); htab_entry; htab_entry = (struct help_entry *)hash_nextentry(htab)) { MEMFREE(htab_entry->key); htab_entry->key = NULL; delete htab_entry; htab_entry = NULL; } delete mudstate.aHelpDesc[iHelpfile].ht; mudstate.aHelpDesc[iHelpfile].ht = NULL; } static bool bHaveTopic; static size_t pos; static int lineno; static int ntopics; static FILE *rfp; #define LINE_SIZE 4096 static char Line[LINE_SIZE + 1]; static size_t nLine; static void HelpIndex_Start(FILE *fp) { pos = 0L; lineno = 0; ntopics = 0; rfp = fp; bHaveTopic = false; nLine = 0; } static bool HelpIndex_Read(help_indx *pEntry) { for (;;) { while (nLine == 0) { if (fgets(Line, LINE_SIZE, rfp) == NULL) { if (bHaveTopic) { pEntry->len = (int)(pos - pEntry->pos); bHaveTopic = false; return true; } return false; } ++lineno; nLine = strlen(Line); if ( nLine > 0 && Line[nLine - 1] != '\n') { Log.tinyprintf("HelpIndex_Read, line %d: line too long\n", lineno); } } if (Line[0] == '&') { if (bHaveTopic) { pEntry->len = (int)(pos - pEntry->pos); bHaveTopic = false; return true; } ++ntopics; char *topic = Line + 1; while ( *topic == ' ' || *topic == '\t' || *topic == '\r') { topic++; } memset(pEntry->topic, 0, sizeof(pEntry->topic)); char *s = topic; size_t i = 0; while ( *s != '\n' && *s != '\r' && *s != '\0' && i < TOPIC_NAME_LEN) { if ( *s != ' ' || ( 0 < i && pEntry->topic[i-1] != ' ')) { pEntry->topic[i++] = *s; } s++; } pEntry->topic[i] = '\0'; pEntry->pos = pos + nLine; bHaveTopic = true; } pos += nLine; nLine = 0; } } static void HelpIndex_End(void) { pos = 0L; lineno = 0; ntopics = 0; rfp = NULL; } static int helpindex_read(int iHelpfile) { helpindex_clean(iHelpfile); mudstate.aHelpDesc[iHelpfile].ht = new CHashTable; CHashTable *htab = mudstate.aHelpDesc[iHelpfile].ht; char szTextFilename[SBUF_SIZE+8]; mux_sprintf(szTextFilename, sizeof(szTextFilename), "%s.txt", mudstate.aHelpDesc[iHelpfile].pBaseFilename); help_indx entry; FILE *fp; if (!mux_fopen(&fp, szTextFilename, "rb")) { STARTLOG(LOG_PROBLEMS, "HLP", "RINDX"); char *p = alloc_lbuf("helpindex_read.LOG"); mux_sprintf(p, LBUF_SIZE, "Can't open %s for reading.", szTextFilename); log_text(p); free_lbuf(p); ENDLOG; return -1; } DebugTotalFiles++; int count = 0; HelpIndex_Start(fp); while (HelpIndex_Read(&entry)) { // Convert the entry to all lowercase letters and add all leftmost // substrings. // // Topic names which appear earlier in the help file have priority // over topics names which appear later in the help file. That is, // we do not associate prefixes with this topic if they have already // been used on a previous topic. // mux_strlwr(entry.topic); bool bOriginal = true; // First is the longest. size_t nTopic = strlen(entry.topic); for (nTopic = strlen(entry.topic); nTopic > 0; nTopic--) { if (mux_isspace(entry.topic[nTopic-1])) { continue; } struct help_entry *htab_entry = NULL; try { htab_entry = new struct help_entry; } catch (...) { ; // Nothing. } if (NULL != htab_entry) { htab_entry->pos = entry.pos; htab_entry->original = bOriginal; bOriginal = false; htab_entry->key = StringCloneLen(entry.topic, nTopic); if (!hashfindLEN(entry.topic, nTopic, htab)) { hashaddLEN(entry.topic, nTopic, htab_entry, htab); count++; } else { MEMFREE(htab_entry->key); htab_entry->key = NULL; delete htab_entry; htab_entry = NULL; } } } } HelpIndex_End(); if (fclose(fp) == 0) { DebugTotalFiles--; } hashreset(htab); return count; } void helpindex_load(dbref player) { for (int i = 0; i < mudstate.nHelpDesc; i++) { helpindex_read(i); } if ( player != NOTHING && !Quiet(player)) { notify(player, "Cache for help indexes refreshed."); } } void helpindex_init(void) { helpindex_load(NOTHING); } static const char *MakeCanonicalTopicName(char *topic_arg) { const char *topic; if (topic_arg[0] == '\0') { topic = "help"; } else { mux_strlwr(topic_arg); topic = topic_arg; } return topic; } static void ReportMatchedTopics(dbref executor, const char *topic, CHashTable *htab) { bool matched = false; char *topic_list = NULL; char *buffp = NULL; struct help_entry *htab_entry; for (htab_entry = (struct help_entry *)hash_firstentry(htab); htab_entry != NULL; htab_entry = (struct help_entry *)hash_nextentry(htab)) { mudstate.wild_invk_ctr = 0; if ( htab_entry->original && quick_wild(topic, htab_entry->key)) { if (!matched) { matched = true; topic_list = alloc_lbuf("help_write"); buffp = topic_list; } safe_str(htab_entry->key, topic_list, &buffp); safe_chr(' ', topic_list, &buffp); safe_chr(' ', topic_list, &buffp); } } if (!matched) { notify(executor, tprintf("No entry for '%s'.", topic)); } else { notify(executor, tprintf("Here are the entries which match '%s':", topic)); *buffp = '\0'; notify(executor, topic_list); free_lbuf(topic_list); } } static bool ReportTopic(dbref executor, struct help_entry *htab_entry, int iHelpfile, char *result) { char szTextFilename[SBUF_SIZE+8]; mux_sprintf(szTextFilename, sizeof(szTextFilename), "%s.txt", mudstate.aHelpDesc[iHelpfile].pBaseFilename); size_t offset = htab_entry->pos; FILE *fp; if (!mux_fopen(&fp, szTextFilename, "rb")) { STARTLOG(LOG_PROBLEMS, "HLP", "OPEN"); char *line = alloc_lbuf("ReportTopic.open"); mux_sprintf(line, LBUF_SIZE, "Can't open %s for reading.", szTextFilename); log_text(line); free_lbuf(line); ENDLOG; return false; } DebugTotalFiles++; if (fseek(fp, static_cast(offset), 0) < 0L) { STARTLOG(LOG_PROBLEMS, "HLP", "SEEK"); char *line = alloc_lbuf("ReportTopic.seek"); mux_sprintf(line, LBUF_SIZE, "Seek error in file %s.", szTextFilename); log_text(line); free_lbuf(line); ENDLOG; if (fclose(fp) == 0) { DebugTotalFiles--; } return false; } char *line = alloc_lbuf("ReportTopic"); char *bp = result; for (;;) { if ( fgets(line, LBUF_SIZE - 2, fp) == NULL || line[0] == '&' || line[0] == '\0') { break; } // Transform LF into CRLF to be telnet-friendly. // size_t len = strlen(line); if ( 0 < len && '\n' == line[len-1] && ( 1 == len || '\r' != line[len-2])) { line[len-1] = '\r'; line[len ] = '\n'; line[len+1] = '\0'; } bool bEval = mudstate.aHelpDesc[iHelpfile].bEval; if (bEval) { char *str = line; mux_exec(result, &bp, executor, executor, executor, EV_NO_COMPRESS | EV_FIGNORE | EV_EVAL, &str, NULL, 0); } else { safe_str(line, result, &bp); } } // Zap trailing CRLF if present. // if ( result < bp - 1 && '\r' == bp[-2] && '\n' == bp[-1]) { bp -= 2; } *bp = '\0'; if (fclose(fp) == 0) { DebugTotalFiles--; } free_lbuf(line); return true; } static void help_write(dbref executor, char *topic_arg, int iHelpfile) { const char *topic = MakeCanonicalTopicName(topic_arg); CHashTable *htab = mudstate.aHelpDesc[iHelpfile].ht; struct help_entry *htab_entry = (struct help_entry *)hashfindLEN(topic, strlen(topic), htab); if (htab_entry) { char *result = alloc_lbuf("help_write"); if (ReportTopic(executor, htab_entry, iHelpfile, result)) { notify(executor, result); } else { notify(executor, "Sorry, that function is temporarily unavailable."); } free_lbuf(result); } else { ReportMatchedTopics(executor, topic, htab); return; } } static bool ValidateHelpFileIndex(int iHelpfile) { if ( iHelpfile < 0 || mudstate.mHelpDesc <= iHelpfile) { char *buf = alloc_mbuf("do_help.LOG"); STARTLOG(LOG_BUGS, "BUG", "HELP"); mux_sprintf(buf, MBUF_SIZE, "Unknown help file number: %d", iHelpfile); log_text(buf); ENDLOG; free_mbuf(buf); return false; } return true; } /* * --------------------------------------------------------------------------- * * do_help: display information from new-format news and help files */ void do_help(dbref executor, dbref caller, dbref enactor, int eval, int key, char *message) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); int iHelpfile = key; if (!ValidateHelpFileIndex(iHelpfile)) { notify(executor, "No such indexed file found."); return; } help_write(executor, message, iHelpfile); } void help_helper(dbref executor, int iHelpfile, char *topic_arg, char *buff, char **bufc) { if (!ValidateHelpFileIndex(iHelpfile)) { return; } const char *topic = MakeCanonicalTopicName(topic_arg); CHashTable *htab = mudstate.aHelpDesc[iHelpfile].ht; struct help_entry *htab_entry = (struct help_entry *)hashfindLEN(topic, strlen(topic), htab); if (htab_entry) { char *result = alloc_lbuf("help_helper"); if (ReportTopic(executor, htab_entry, iHelpfile, result)) { safe_str(result, buff, bufc); } else { safe_str("#-1 ERROR", buff, bufc); } free_lbuf(result); } else { safe_str("#-1 TOPIC DOES NOT EXIST", buff, bufc); } } mux2.6/src/unparse.cpp0000600000175000017500000001523611025753746014766 0ustar sdennissdennis// unparse.cpp // // $Id: unparse.cpp 8 2006-09-05 01:55:58Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" // Boolexp decompile formats // #define F_EXAMINE 1 // Normal #define F_QUIET 2 // Binary for db dumps #define F_DECOMPILE 3 // @decompile output #define F_FUNCTION 4 // [lock()] output /* * Take a dbref (loc) and generate a string. -1, -3, or (#loc) Note, this * will give players object numbers of stuff they don't control, but it's * only internal currently, so it's not a problem. */ static char *unparse_object_quiet(dbref player, dbref loc) { UNUSED_PARAMETER(player); static char buf[SBUF_SIZE]; switch (loc) { case NOTHING: return (char *)"-1"; case HOME: return (char *)"-3"; default: mux_sprintf(buf, SBUF_SIZE, "(#%d)", loc); return buf; } } static char boolexp_buf[LBUF_SIZE]; static char *buftop; static void unparse_boolexp1(dbref player, BOOLEXP *b, char outer_type, int format) { if ((b == TRUE_BOOLEXP)) { if (format == F_EXAMINE) { safe_str("*UNLOCKED*", boolexp_buf, &buftop); } return; } switch (b->type) { case BOOLEXP_AND: if (outer_type == BOOLEXP_NOT) { safe_chr('(', boolexp_buf, &buftop); } unparse_boolexp1(player, b->sub1, b->type, format); safe_chr(AND_TOKEN, boolexp_buf, &buftop); unparse_boolexp1(player, b->sub2, b->type, format); if (outer_type == BOOLEXP_NOT) { safe_chr(')', boolexp_buf, &buftop); } break; case BOOLEXP_OR: if (outer_type == BOOLEXP_NOT || outer_type == BOOLEXP_AND) { safe_chr('(', boolexp_buf, &buftop); } unparse_boolexp1(player, b->sub1, b->type, format); safe_chr(OR_TOKEN, boolexp_buf, &buftop); unparse_boolexp1(player, b->sub2, b->type, format); if (outer_type == BOOLEXP_NOT || outer_type == BOOLEXP_AND) { safe_chr(')', boolexp_buf, &buftop); } break; case BOOLEXP_NOT: safe_chr('!', boolexp_buf, &buftop); unparse_boolexp1(player, b->sub1, b->type, format); break; case BOOLEXP_INDIR: safe_chr(INDIR_TOKEN, boolexp_buf, &buftop); unparse_boolexp1(player, b->sub1, b->type, format); break; case BOOLEXP_IS: safe_chr(IS_TOKEN, boolexp_buf, &buftop); unparse_boolexp1(player, b->sub1, b->type, format); break; case BOOLEXP_CARRY: safe_chr(CARRY_TOKEN, boolexp_buf, &buftop); unparse_boolexp1(player, b->sub1, b->type, format); break; case BOOLEXP_OWNER: safe_chr(OWNER_TOKEN, boolexp_buf, &buftop); unparse_boolexp1(player, b->sub1, b->type, format); break; case BOOLEXP_CONST: if (mudstate.bStandAlone) { safe_str(unparse_object_quiet(player, b->thing), boolexp_buf, &buftop); } else { switch (format) { case F_QUIET: // Quiet output - for dumps and internal use. Always #Num. // safe_str(unparse_object_quiet(player, b->thing), boolexp_buf, &buftop); break; case F_EXAMINE: // Examine output - informative. Name(#Num) or Name. // char *buff; buff = unparse_object(player, b->thing, false); safe_str(buff, boolexp_buf, &buftop); free_lbuf(buff); break; case F_DECOMPILE: // Decompile output - should be usable on other MUXes. Name if // player, Name if thing, else #Num. // switch (Typeof(b->thing)) { case TYPE_PLAYER: safe_chr('*', boolexp_buf, &buftop); case TYPE_THING: safe_str(Name(b->thing), boolexp_buf, &buftop); break; default: safe_tprintf_str(boolexp_buf, &buftop, "#%d", b->thing); break; } break; case F_FUNCTION: // Function output - must be usable by @lock cmd. Name if player, // else #Num. // switch (Typeof(b->thing)) { case TYPE_PLAYER: safe_chr('*', boolexp_buf, &buftop); safe_str(Name(b->thing), boolexp_buf, &buftop); break; default: safe_tprintf_str(boolexp_buf, &buftop, "#%d", b->thing); break; } } } break; case BOOLEXP_ATR: case BOOLEXP_EVAL: ATTR *ap; ap = atr_num(b->thing); if (ap && ap->number) { // Use the attribute name if the attribute exists. // safe_str(ap->name, boolexp_buf, &buftop); } else { // Otherwise use the attribute number. // // Only god or the db loader can create a new boolexp // with an invalid attribute, but anyone may keep a lock // whose attribute has subsequently disappeared. // safe_ltoa(b->thing, boolexp_buf, &buftop); } if (b->type == BOOLEXP_EVAL) { safe_chr('/', boolexp_buf, &buftop); } else { safe_chr(':', boolexp_buf, &buftop); } safe_str((char *)b->sub1, boolexp_buf, &buftop); break; default: // Bad type. // Log.WriteString("ABORT! unparse.cpp, fell off the end of switch in unparse_boolexp1()" ENDLINE); Log.Flush(); abort(); break; } } char *unparse_boolexp_quiet(dbref player, BOOLEXP *b) { buftop = boolexp_buf; unparse_boolexp1(player, b, BOOLEXP_CONST, F_QUIET); *buftop = '\0'; return boolexp_buf; } char *unparse_boolexp(dbref player, BOOLEXP *b) { buftop = boolexp_buf; unparse_boolexp1(player, b, BOOLEXP_CONST, F_EXAMINE); *buftop = '\0'; return boolexp_buf; } char *unparse_boolexp_decompile(dbref player, BOOLEXP *b) { buftop = boolexp_buf; unparse_boolexp1(player, b, BOOLEXP_CONST, F_DECOMPILE); *buftop = '\0'; return boolexp_buf; } char *unparse_boolexp_function(dbref player, BOOLEXP *b) { buftop = boolexp_buf; unparse_boolexp1(player, b, BOOLEXP_CONST, F_FUNCTION); *buftop = '\0'; return boolexp_buf; } mux2.6/src/levels.h0000700000175000017500000000153511025753746014246 0ustar sdennissdennis/* levels.h - Reality levels */ #include "copyright.h" #ifndef __LEVELS_H #define __LEVELS_H #include "htab.h" #include "db.h" #define IsReal(R, T) ((R) == (T) || (RxLevel(R) & TxLevel(T))) RLEVEL RxLevel(dbref); RLEVEL TxLevel(dbref); void notify_except_rlevel(dbref, dbref, dbref, const char *, int); void notify_except2_rlevel(dbref, dbref, dbref, dbref,const char *); void notify_except2_rlevel2(dbref, dbref, dbref, dbref,const char *); char * rxlevel_description(dbref, dbref); char * txlevel_description(dbref, dbref); void decompile_rlevels(dbref, dbref, char *); RLEVEL find_rlevel(char *); void did_it_rlevel ( dbref player, dbref thing, int what, const char *def, int owhat, const char *odef, int awhat, int ctrl_flags, char *args[], int nargs ); #endif // __LEVELS_H mux2.6/src/file_c.cpp0000600000175000017500000001506711025753746014534 0ustar sdennissdennis// file_c.cpp -- File cache management. // // $Id: file_c.cpp 229 2006-10-04 06:42:24Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "command.h" #include "file_c.h" typedef struct filecache_block_hdr FBLKHDR; typedef struct filecache_block FBLOCK; struct filecache_block { struct filecache_block_hdr { struct filecache_block *nxt; unsigned int nchars; } hdr; char data[MBUF_SIZE - sizeof(struct filecache_block_hdr)]; }; struct filecache_hdr { char **ppFilename; FBLOCK *fileblock; const char *desc; }; typedef struct filecache_hdr FCACHE; #define FBLOCK_SIZE (MBUF_SIZE - sizeof(FBLKHDR)) static FCACHE fcache[] = { { &mudconf.conn_file, NULL, "Conn" }, { &mudconf.site_file, NULL, "Conn/Badsite" }, { &mudconf.down_file, NULL, "Conn/Down" }, { &mudconf.full_file, NULL, "Conn/Full" }, { &mudconf.guest_file, NULL, "Conn/Guest" }, { &mudconf.creg_file, NULL, "Conn/Reg" }, { &mudconf.crea_file, NULL, "Crea/Newuser" }, { &mudconf.regf_file, NULL, "Crea/RegFaill" }, { &mudconf.motd_file, NULL, "Motd" }, { &mudconf.wizmotd_file, NULL, "Wizmotd" }, { &mudconf.quit_file, NULL, "Quit" }, { NULL, NULL, NULL } }; static NAMETAB list_files[] = { {"badsite_connect", 1, CA_WIZARD, FC_CONN_SITE}, {"connect", 2, CA_WIZARD, FC_CONN}, {"create_register", 2, CA_WIZARD, FC_CREA_REG}, {"down", 1, CA_WIZARD, FC_CONN_DOWN}, {"full", 1, CA_WIZARD, FC_CONN_FULL}, {"guest_motd", 1, CA_WIZARD, FC_CONN_GUEST}, {"motd", 1, CA_WIZARD, FC_MOTD}, {"newuser", 1, CA_WIZARD, FC_CREA_NEW}, {"quit", 1, CA_WIZARD, FC_QUIT}, {"register_connect", 1, CA_WIZARD, FC_CONN_REG}, {"wizard_motd", 1, CA_WIZARD, FC_WIZMOTD}, { NULL, 0, 0, 0} }; void do_list_file(dbref executor, dbref caller, dbref enactor, int eval, int extra, char *arg) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(extra); int flagvalue; if (!search_nametab(executor, list_files, arg, &flagvalue)) { display_nametab(executor, list_files, "Unknown file. Use one of:", true); return; } fcache_send(executor, flagvalue); } static FBLOCK *fcache_fill(FBLOCK *fp, char ch) { if (fp->hdr.nchars >= sizeof(fp->data)) { // We filled the current buffer. Go get a new one. // FBLOCK *tfp = fp; fp = (FBLOCK *) alloc_mbuf("fcache_fill"); fp->hdr.nxt = NULL; fp->hdr.nchars = 0; tfp->hdr.nxt = fp; } fp->data[fp->hdr.nchars++] = ch; return fp; } static int fcache_read(FBLOCK **cp, char *filename) { // Free a prior buffer chain. // FBLOCK *fp = *cp; while (fp != NULL) { FBLOCK *tfp = fp->hdr.nxt; free_mbuf(fp); fp = tfp; } *cp = NULL; // Read the text file into a new chain. // int fd; char *buff; if (!mux_open(&fd, filename, O_RDONLY|O_BINARY)) { // Failure: log the event // STARTLOG(LOG_PROBLEMS, "FIL", "OPEN"); buff = alloc_mbuf("fcache_read.LOG"); mux_sprintf(buff, MBUF_SIZE, "Couldn't open file '%s'.", filename); log_text(buff); free_mbuf(buff); ENDLOG return -1; } DebugTotalFiles++; buff = alloc_lbuf("fcache_read.temp"); // Set up the initial cache buffer to make things easier. // fp = (FBLOCK *) alloc_mbuf("fcache_read.first"); fp->hdr.nxt = NULL; fp->hdr.nchars = 0; *cp = fp; int tchars = 0; // Process the file, one lbuf at a time. // int nmax = mux_read(fd, buff, LBUF_SIZE); while (nmax > 0) { for (int n = 0; n < nmax; n++) { switch (buff[n]) { case '\n': fp = fcache_fill(fp, '\r'); fp = fcache_fill(fp, '\n'); tchars += 2; case '\0': case '\r': break; default: fp = fcache_fill(fp, buff[n]); tchars++; } } nmax = mux_read(fd, buff, LBUF_SIZE); } free_lbuf(buff); if (mux_close(fd) == 0) { DebugTotalFiles--; } // If we didn't read anything in, toss the initial buffer. // if (fp->hdr.nchars == 0) { *cp = NULL; free_mbuf(fp); } return tchars; } void fcache_rawdump(SOCKET fd, int num) { if ((num < 0) || (num > FC_LAST)) { return; } FBLOCK *fp = fcache[num].fileblock; int cnt, remaining; char *start; while (fp != NULL) { start = fp->data; remaining = fp->hdr.nchars; while (remaining > 0) { cnt = SOCKET_WRITE(fd, start, remaining, 0); if (cnt < 0) { return; } remaining -= cnt; start += cnt; } fp = fp->hdr.nxt; } return; } void fcache_dump(DESC *d, int num) { if ((num < 0) || (num > FC_LAST)) { return; } FBLOCK *fp = fcache[num].fileblock; while (fp != NULL) { queue_write_LEN(d, fp->data, fp->hdr.nchars); fp = fp->hdr.nxt; } } void fcache_send(dbref player, int num) { DESC *d; DESC_ITER_PLAYER(player, d) { fcache_dump(d, num); } } void fcache_load(dbref player) { FCACHE *fp; char *buff, *bufc, *sbuf; buff = bufc = alloc_lbuf("fcache_load.lbuf"); sbuf = alloc_sbuf("fcache_load.sbuf"); for (fp = fcache; fp->ppFilename; fp++) { int i = fcache_read(&fp->fileblock, *fp->ppFilename); if ( player != NOTHING && !Quiet(player)) { mux_ltoa(i, sbuf); if (fp == fcache) { safe_str("File sizes: ", buff, &bufc); } else { safe_str(" ", buff, &bufc); } safe_str(fp->desc, buff, &bufc); safe_str("...", buff, &bufc); safe_str(sbuf, buff, &bufc); } } *bufc = '\0'; if ( player != NOTHING && !Quiet(player)) { notify(player, buff); } free_lbuf(buff); free_sbuf(sbuf); } void fcache_init(void) { FCACHE *fp = fcache; for (fp = fcache; fp->ppFilename; fp++) { fp->fileblock = NULL; } fcache_load(NOTHING); } mux2.6/src/htab.h0000600000175000017500000000506111025753746013667 0ustar sdennissdennis// htab.h - Structures and declarations needed for table hashing. // // $Id: htab.h 2734 2007-10-28 23:02:55Z brazilofmux $ // #include "copyright.h" #ifndef __HTAB_H #define __HTAB_H #include "db.h" #include "svdhash.h" typedef struct name_table NAMETAB; struct name_table { const char *name; int minlen; int perm; int flag; }; /* BQUE - Command queue */ typedef struct bque BQUE; struct bque { CLinearTimeAbsolute waittime; // time to run command dbref executor; // executor who will do command dbref caller; // caller. dbref enactor; // enactor causing command (for %N) int eval; dbref sem; // blocking semaphore int attr; // blocking attribute int nargs; // How many args I have char *text; // buffer for comm, env, and scr text char *comm; // command char *env[NUM_ENV_VARS]; // environment vars reg_ref *scr[MAX_GLOBAL_REGS]; // temp vars bool IsTimed; // Is there a waittime time on this entry? }; class CBitField { unsigned int nBitsPer; unsigned int nShift; unsigned int nMask; unsigned int nMaximum; size_t nInts; UINT32 *pInts; UINT32 *pMasks; public: CBitField(unsigned int max = 0); void Resize(unsigned int max); ~CBitField(void); void ClearAll(void); void Set(unsigned int i); void Clear(unsigned int i); bool IsSet(unsigned int i); }; void hashreset(CHashTable *); void *hashfindLEN(const void *pKey, size_t nKey, CHashTable *htab); bool hashaddLEN(const void *pKey, size_t nKey, void *pData, CHashTable *htab); void hashdeleteLEN(const void *Str, size_t nStr, CHashTable *htab); void hashflush(CHashTable *); bool hashreplLEN(const void *Str, size_t nStr, void *hashdata, CHashTable *htab); void hashreplall(const void *, void *, CHashTable *); void *hash_nextentry(CHashTable *htab); void *hash_firstentry(CHashTable *htab); void *hash_firstkey(CHashTable *htab, int *, char **); void *hash_nextkey(CHashTable *htab, int *, char **); extern NAMETAB powers_nametab[]; extern bool search_nametab(dbref, NAMETAB *, char *, int *); extern NAMETAB *find_nametab_ent(dbref, NAMETAB *, char *); extern void display_nametab(dbref, NAMETAB *, const char *, bool); extern void interp_nametab(dbref, NAMETAB *, int, const char *, const char *, const char *); extern void listset_nametab(dbref, NAMETAB *, int, char *, bool); #endif // !__HTAB_H mux2.6/src/look.cpp0000600000175000017500000022166211025753746014257 0ustar sdennissdennis// look.cpp -- Commands which look at things. // // $Id: look.cpp 2734 2007-10-28 23:02:55Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "ansi.h" #include "attrs.h" #include "command.h" #include "interface.h" #include "powers.h" #ifdef REALITY_LVLS #include "levels.h" #endif // REALITY_LVLS #if defined(WOD_REALMS) || defined(REALITY_LVLS) #define NORMAL_REALM 0 #define UMBRA_REALM 1 #define SHROUD_REALM 2 #define MATRIX_REALM 3 #define FAE_REALM 4 #define CHIMERA_REALM 5 #define BLIND_REALM 6 #define STAFF_REALM 7 #define NUMBER_OF_REALMS 8 static int RealmActions[NUMBER_OF_REALMS] = { REALM_DO_NORMALLY_SEEN, REALM_DO_SHOW_UMBRADESC, REALM_DO_SHOW_WRAITHDESC, REALM_DO_SHOW_MATRIXDESC, REALM_DO_SHOW_FAEDESC, REALM_DO_SHOW_FAEDESC, REALM_DO_HIDDEN_FROM_YOU, REALM_DO_NORMALLY_SEEN }; // Umbra and Matrix are realms unto themselves, so if you aren't in the same // realm as what you're looking at, you can't see it. // // Normal things can't see shroud things, but shroud things can see normal things. // // Only Fae and Chimera can see Chimera. // #define MAP_SEEN 0 // Show this to that. #define MAP_HIDE 1 // Always hide this from that. #define MAP_NO_ADESC 2 // Don't trigger DESC actions on that. #define MAP_MEDIUM 4 // Hide this from that unless that is a medium and this is moving or talking. static int RealmHiddenMap[NUMBER_OF_REALMS][NUMBER_OF_REALMS] = { /* NORMAL LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_MEDIUM, MAP_HIDE, MAP_SEEN, MAP_HIDE, MAP_NO_ADESC, MAP_SEEN}, /* UMBRA LOOKER */ { MAP_HIDE, MAP_SEEN, MAP_MEDIUM, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_SEEN}, /* SHROUD LOOKER */ { MAP_NO_ADESC, MAP_HIDE, MAP_SEEN, MAP_HIDE, MAP_NO_ADESC, MAP_HIDE, MAP_NO_ADESC, MAP_SEEN}, /* MATRIX LOOKER */ { MAP_HIDE, MAP_HIDE, MAP_MEDIUM, MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_SEEN}, /* FAE LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_MEDIUM, MAP_HIDE, MAP_SEEN, MAP_SEEN, MAP_NO_ADESC, MAP_SEEN}, /* CHIMERA LOOKER */ { MAP_NO_ADESC, MAP_HIDE, MAP_MEDIUM, MAP_HIDE, MAP_SEEN, MAP_SEEN, MAP_NO_ADESC, MAP_SEEN}, /* BLIND LOOKER */ { MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_SEEN}, /* STAFF LOOKER */ { MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN} }; static int RealmExitsMap[NUMBER_OF_REALMS][NUMBER_OF_REALMS] = { /* NORMAL LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE}, /* UMBRA LOOKER */ { MAP_SEEN, MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE}, /* SHROUD LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE}, /* MATRIX LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE}, /* FAE LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_SEEN, MAP_SEEN, MAP_HIDE, MAP_HIDE}, /* CHIMERA LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_SEEN, MAP_SEEN, MAP_HIDE, MAP_HIDE}, /* BLIND LOOKER */ { MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE}, /* STAFF LOOKER */ { MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN} }; static int WhichRealm(dbref what, bool bPeering) { int realm = NORMAL_REALM; if (isMatrix(what)) realm = MATRIX_REALM; else if (isUmbra(what)) realm = UMBRA_REALM; else if (isShroud(what)) realm = SHROUD_REALM; else if (isChimera(what)) realm = CHIMERA_REALM; else if (isFae(what)) realm = FAE_REALM; if (bPeering) { char *buff; dbref owner; int flags; int iPeeringRealm = get_atr("PEERING_REALM"); if (0 < iPeeringRealm) { buff = atr_get(what, iPeeringRealm, &owner, &flags); if (*buff) { if (mux_stricmp(buff, "FAE") == 0) realm = FAE_REALM; else if (mux_stricmp(buff, "CHIMERA") == 0) realm = CHIMERA_REALM; else if (mux_stricmp(buff, "SHROUD") == 0) realm = SHROUD_REALM; else if (mux_stricmp(buff, "UMBRA") == 0) realm = UMBRA_REALM; else if (mux_stricmp(buff, "MATRIX") == 0) realm = MATRIX_REALM; else if (mux_stricmp(buff, "NORMAL") == 0) realm = NORMAL_REALM; else if (mux_stricmp(buff, "BLIND") == 0) realm = BLIND_REALM; else if (mux_stricmp(buff, "STAFF") == 0) realm = STAFF_REALM; } free_lbuf(buff); } } return realm; } static int HandleObfuscation(dbref looker, dbref lookee, int threshhold) { int iReturn = REALM_DO_NORMALLY_SEEN; if (isObfuscate(lookee)) { char *buff; int iObfuscateLevel = 0; dbref owner; int flags; buff = atr_get(lookee, get_atr("OBF_LEVEL"), &owner, &flags); if (*buff) { iObfuscateLevel = mux_atol(buff); } free_lbuf(buff); // For OBF_LEVELS of 0, 1, and 2, we show the regular description. // 3 and above start showing a different OBFDESC. // if (3 <= iObfuscateLevel) { iReturn = REALM_DO_SHOW_OBFDESC; } if (threshhold < iObfuscateLevel) { int iHeightenSensesLevel = 0; if (isHeightenedSenses(looker)) { buff = atr_get(looker, get_atr("HSS_LEVEL"), &owner, &flags); if (*buff) { iHeightenSensesLevel = mux_atol(buff); } free_lbuf(buff); } if (iHeightenSensesLevel < iObfuscateLevel) { iReturn = REALM_DO_HIDDEN_FROM_YOU; } else if (iObfuscateLevel == iHeightenSensesLevel) { if (RandomINT32(0,1)) { iReturn = REALM_DO_HIDDEN_FROM_YOU; } } } } return iReturn; } int DoThingToThingVisibility(dbref looker, dbref lookee, int action_state) { // If the looker is a room, then there is some contents/recursion stuff // that happens in the rest of the game code. We'll be called later for // each item in the room, things that are nearby the room, etc. // if (isRoom(looker)) { return REALM_DO_NORMALLY_SEEN; } if (Staff(looker)) { if (Connected(looker)) { // Staff players can see everything // return REALM_DO_NORMALLY_SEEN; } if (isThing(looker)) { // Wizard things in the master room can see everything. // if (Location(looker) == mudconf.master_room) { return REALM_DO_NORMALLY_SEEN; } } } int realmLooker = WhichRealm(looker, isPeering(looker)); int realmLookee = WhichRealm(lookee, false); // You can always see yourself. // if (looker == lookee) { return RealmActions[realmLooker]; } bool bDisableADESC = false; if (isRoom(lookee) || isExit(lookee)) { // All realms see normal rooms and exits, however, if a realm // specific description exists, they use that one. If a room or exit // is flagged with a specific realm, then -only- players and things of // that realm can see it. // // Fae and Chimera are treated as the same realm for this purpose. // if (RealmExitsMap[realmLooker][realmLookee] == MAP_HIDE) { return REALM_DO_HIDDEN_FROM_YOU; } } else { if (Staff(lookee)) { // Staff players are seen in every realm. // if (Connected(lookee)) { return REALM_DO_NORMALLY_SEEN; } if (isThing(lookee)) { // Everyone can use wizard things in the master room. // // Wizard things that aren't in the master room follow the same // realm-rules as everything else. // if (Location(lookee) == mudconf.master_room) { return REALM_DO_NORMALLY_SEEN; } } } int iMap = RealmHiddenMap[realmLooker][realmLookee]; if (iMap & MAP_HIDE) { return REALM_DO_HIDDEN_FROM_YOU; } if (iMap & MAP_MEDIUM) { if (isMedium(looker)) { if (action_state == ACTION_IS_STATIONARY) { // Even Mediums can't hear it if the Wraith is just standing still. // return REALM_DO_HIDDEN_FROM_YOU; } } else { return REALM_DO_HIDDEN_FROM_YOU; } } if (iMap & MAP_NO_ADESC) { bDisableADESC = true; } } // Do default see rules. // int iReturn = RealmActions[realmLooker]; if (iReturn == REALM_DO_HIDDEN_FROM_YOU) { return iReturn; } // Do Obfuscate/Heighten Senses rules. // int threshhold = 0; switch (action_state) { case ACTION_IS_STATIONARY: threshhold = 0; break; case ACTION_IS_MOVING: threshhold = 1; break; case ACTION_IS_TALKING: if (bDisableADESC) { iReturn |= REALM_DISABLE_ADESC; } return iReturn; } int iObfReturn = HandleObfuscation(looker, lookee, threshhold); switch (iObfReturn) { case REALM_DO_SHOW_OBFDESC: case REALM_DO_HIDDEN_FROM_YOU: iReturn = iObfReturn; break; } // Decide whether to disable ADESC or not. If we can look at them, // and ADESC isn't -already- disabled via SHROUD looking at NORMAL (see above). // then, ADESC may be disabled here if the looker is Obfuscated to the lookee. // if (iReturn != REALM_DO_HIDDEN_FROM_YOU && !bDisableADESC) { if (REALM_DO_HIDDEN_FROM_YOU == HandleObfuscation(lookee, looker, 0)) { bDisableADESC = true; } } if (bDisableADESC) { iReturn |= REALM_DISABLE_ADESC; } return iReturn; } static void LetDescriptionsDefault(dbref thing, int *piDESC, int *piADESC, int RealmDirective) { int iDesc = 0; dbref owner; int flags; *piDESC = A_DESC; *piADESC = A_ADESC; if (RealmDirective & REALM_DISABLE_ADESC) { *piADESC = 0; } switch (RealmDirective & REALM_DO_MASK) { case REALM_DO_SHOW_OBFDESC: iDesc = get_atr("OBFDESC"); break; case REALM_DO_SHOW_WRAITHDESC: iDesc = get_atr("WRAITHDESC"); *piADESC = 0; break; case REALM_DO_SHOW_UMBRADESC: iDesc = get_atr("UMBRADESC"); break; case REALM_DO_SHOW_MATRIXDESC: iDesc = get_atr("MATRIXDESC"); break; case REALM_DO_SHOW_FAEDESC: iDesc = get_atr("FAEDESC"); break; } if (iDesc > 0) { char *buff = atr_pget(thing, iDesc, &owner, &flags); if (buff) { if (*buff) { *piDESC = iDesc; } free_lbuf(buff); } } } #endif static void look_exits(dbref player, dbref loc, const char *exit_name) { // Make sure location has exits. // if ( !Good_obj(loc) || !Has_exits(loc)) { return; } dbref thing, parent; char *buff, *e, *buff1, *e1; const char *s; // make sure there is at least one visible exit. // bool bFoundAnyDisplayable = false; bool bFoundAny = false; int key = 0; int lev; #ifdef REALITY_LVLS if (Dark(loc) || !IsReal(player, loc)) #else if (Dark(loc)) #endif // REALITY_LVLS { key |= VE_BASE_DARK; } ITER_PARENTS(loc, parent, lev) { key &= ~VE_LOC_DARK; if (Dark(parent)) { key |= VE_LOC_DARK; } DOLIST(thing, Exits(parent)) { bFoundAny = true; if (exit_displayable(thing, player, key)) { bFoundAnyDisplayable = true; break; } } if (bFoundAnyDisplayable) { break; } } if (!bFoundAny) { return; } // Retrieve the ExitFormat attribute from the location, evaluate and display // the results in lieu of the traditional exits list if it exists. // dbref aowner; int aflags; char *ExitFormatBuffer = atr_pget(loc, A_EXITFORMAT, &aowner, &aflags); char *ExitFormat = ExitFormatBuffer; bool bDisplayExits = bFoundAnyDisplayable; if (*ExitFormat) { char *VisibleObjectList = alloc_lbuf("look_exits.VOL"); char *tPtr = VisibleObjectList; ITL pContext; ItemToList_Init(&pContext, VisibleObjectList, &tPtr, '#'); ITER_PARENTS(loc, parent, lev) { key &= ~VE_LOC_DARK; if (Dark(parent)) { key |= VE_LOC_DARK; } bool bShortCircuit = false; DOLIST(thing, Exits(parent)) { if ( exit_displayable(thing, player, key) && !ItemToList_AddInteger(&pContext, thing)) { bShortCircuit = true; break; } } if (bShortCircuit) break; } ItemToList_Final(&pContext); char *FormatOutput = alloc_lbuf("look_exits.FO"); tPtr = FormatOutput; reg_ref **preserve = NULL; preserve = PushRegisters(MAX_GLOBAL_REGS); save_and_clear_global_regs(preserve); mux_exec(FormatOutput, &tPtr, loc, player, player, AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP), &ExitFormat, &VisibleObjectList, 1); *tPtr = '\0'; restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); notify(player, FormatOutput); free_lbuf(FormatOutput); free_lbuf(VisibleObjectList); bDisplayExits = 0; } free_lbuf(ExitFormatBuffer); if (!bDisplayExits) { return; } // Display the list of exit names // notify(player, exit_name); e = buff = alloc_lbuf("look_exits"); e1 = buff1 = alloc_lbuf("look_exits2"); ITER_PARENTS(loc, parent, lev) { key &= ~VE_LOC_DARK; if (Dark(parent)) { key |= VE_LOC_DARK; } if (Transparent(loc)) { DOLIST(thing, Exits(parent)) { if (exit_displayable(thing, player, key)) { mux_strncpy(buff, Moniker(thing), LBUF_SIZE-1); for (e = buff; *e && *e != ';'; e++) { ; // Nothing. } *e = '\0'; notify(player, tprintf("%s leads to %s.", buff, Moniker(Location(thing)))); } } } else { DOLIST(thing, Exits(parent)) { if (exit_displayable(thing, player, key)) { e1 = buff1; // Put the exit name in buff1. // // chop off first exit alias to display // if (buff != e) { safe_str(" ", buff, &e); } for (s = Moniker(thing); *s && (*s != ';'); s++) { safe_chr(*s, buff1, &e1); } *e1 = 0; /* Copy the exit name into 'buff' */ if (Html(player)) { /* XXX The exit name needs to be HTML escaped. */ safe_str(" ", buff, &e); html_escape(buff1, buff, &e); safe_str(" ", buff, &e); } else { /* Append this exit to the list */ safe_str(buff1, buff, &e); } } } } } if (!Transparent(loc)) { if (Html(player)) { safe_str("\r\n", buff, &e); *e = 0; notify_html(player, buff); } else { *e = 0; notify(player, buff); } } free_lbuf(buff); free_lbuf(buff1); } #define CONTENTS_LOCAL 0 #define CONTENTS_NESTED 1 #define CONTENTS_REMOTE 2 static void look_contents(dbref player, dbref loc, const char *contents_name, int style) { dbref thing; char *buff; char *html_buff, *html_cp; char remote_num[32]; // Check to see if he can see the location. // #ifdef REALITY_LVLS bool can_see_loc = ( !Dark(loc) && IsReal(player, loc) #else bool can_see_loc = ( !Dark(loc) #endif // REALITY_LVLS || (mudconf.see_own_dark && Examinable(player, loc))); dbref aowner; int aflags; char *ContentsFormatBuffer = atr_pget(loc, A_CONFORMAT, &aowner, &aflags); char *ContentsFormat = ContentsFormatBuffer; bool bDisplayContents = true; if (*ContentsFormat) { char *VisibleObjectList = alloc_lbuf("look_contents.VOL"); char *tPtr = VisibleObjectList; ITL pContext; ItemToList_Init(&pContext, VisibleObjectList, &tPtr, '#'); DOLIST(thing, Contents(loc)) { #if defined(WOD_REALMS) || defined(REALITY_LVLS) if ( can_see(player, thing, can_see_loc) && (REALM_DO_HIDDEN_FROM_YOU != DoThingToThingVisibility(player, thing, ACTION_IS_STATIONARY)) ) #else if (can_see(player, thing, can_see_loc)) #endif { if (!ItemToList_AddInteger(&pContext, thing)) { break; } } } ItemToList_Final(&pContext); char *ContentsNameScratch = alloc_lbuf("look_contents.CNS"); tPtr = ContentsNameScratch; safe_str(contents_name, ContentsNameScratch, &tPtr); *tPtr = '\0'; char *FormatOutput = alloc_lbuf("look_contents.FO"); tPtr = FormatOutput; char* ParameterList[] = { VisibleObjectList, ContentsNameScratch }; reg_ref **preserve = NULL; preserve = PushRegisters(MAX_GLOBAL_REGS); save_and_clear_global_regs(preserve); mux_exec(FormatOutput, &tPtr, loc, player, player, AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP), &ContentsFormat, ParameterList, 2); *tPtr = '\0'; restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); notify(player, FormatOutput); free_lbuf(FormatOutput); free_lbuf(ContentsNameScratch); free_lbuf(VisibleObjectList); bDisplayContents = false; } free_lbuf(ContentsFormatBuffer); if (!bDisplayContents) { return; } html_buff = html_cp = alloc_lbuf("look_contents"); // Check to see if there is anything there. // DOLIST(thing, Contents(loc)) { #if defined(WOD_REALMS) || defined(REALITY_LVLS) if ( can_see(player, thing, can_see_loc) && (REALM_DO_HIDDEN_FROM_YOU != DoThingToThingVisibility(player, thing, ACTION_IS_STATIONARY))) #else if (can_see(player, thing, can_see_loc)) #endif { // Something exists! Show him everything. // notify(player, contents_name); DOLIST(thing, Contents(loc)) { #if defined(WOD_REALMS) || defined(REALITY_LVLS) if ( can_see(player, thing, can_see_loc) && (REALM_DO_HIDDEN_FROM_YOU != DoThingToThingVisibility(player, thing, ACTION_IS_STATIONARY))) #else if (can_see(player, thing, can_see_loc)) #endif { buff = unparse_object(player, thing, true, true); html_cp = html_buff; if (Html(player)) { safe_str("", html_buff, &html_cp); html_escape(buff, html_buff, &html_cp); safe_str("\r\n", html_buff, &html_cp); *html_cp = 0; notify_html(player, html_buff); } else { notify(player, buff); } free_lbuf(buff); } } break; // we're done. } } free_lbuf(html_buff); } typedef struct { int mask; char letter; const char *name; } ATTR_DECODE_ENTRY, *PATTR_DECODE_ENTRY; static ATTR_DECODE_ENTRY attr_decode_table[NUM_ATTRIBUTE_CODES+1] = { { AF_LOCK, '+', "LOCK" }, { AF_NOPROG, '$', "NO_COMMAND" }, { AF_CASE, 'C', "CASE" }, { AF_HTML, 'H', "HTML" }, { AF_PRIVATE, 'I', "NO_INHERIT" }, { AF_NONAME, 'N', "NO_NAME" }, { AF_NOPARSE, 'P', "NO_PARSE" }, { AF_REGEXP, 'R', "REGEXP" }, { AF_TRACE, 'T', "TRACE" }, { AF_VISUAL, 'V', "VISUAL" }, { AF_MDARK, 'M', "DARK" }, { AF_WIZARD, 'W', "WIZARD" }, { 0, 0, NULL } }; size_t decode_attr_flags(int aflags, char buff[NUM_ATTRIBUTE_CODES+1]) { size_t n = 0; PATTR_DECODE_ENTRY pEntry; for (pEntry = attr_decode_table; pEntry->mask && n < NUM_ATTRIBUTE_CODES; pEntry++) { if (aflags & pEntry->mask) { buff[n++] = pEntry->letter; } } buff[n] = '\0'; return n; } void decode_attr_flag_names(int aflags, char *buf, char **bufc) { PATTR_DECODE_ENTRY pEntry; bool bFirst = true; for (pEntry = attr_decode_table; pEntry->mask; pEntry++) { if (aflags & pEntry->mask) { if (!bFirst) { safe_chr(' ', buf, bufc); } bFirst = false; safe_str(pEntry->name, buf, bufc); } } } static void view_atr ( dbref player, dbref thing, ATTR *ap, char *text, dbref aowner, int aflags, bool skip_tag ) { char *buf; if (ap->flags & AF_IS_LOCK) { BOOLEXP *pBoolExp = parse_boolexp(player, text, true); text = unparse_boolexp(player, pBoolExp); free_boolexp(pBoolExp); } // If we don't control the object or own the attribute, hide the // attr owner and flag info. // if ( !Controls(player, thing) && Owner(player) != aowner) { if ( skip_tag && ap->number == A_DESC) { buf = text; } else { buf = tprintf("%s%s:%s %s", ANSI_HILITE, ap->name, ANSI_NORMAL, text); } notify(player, buf); return; } // Generate flags. // char xbuf[11]; decode_attr_flags(aflags, xbuf); if ( aowner != Owner(thing) && aowner != NOTHING) { buf = tprintf("%s%s [#%d%s]:%s %s", ANSI_HILITE, ap->name, aowner, xbuf, ANSI_NORMAL, text); } else if (*xbuf) { buf = tprintf("%s%s [%s]:%s %s", ANSI_HILITE, ap->name, xbuf, ANSI_NORMAL, text); } else if ( !skip_tag || ap->number != A_DESC) { buf = tprintf("%s%s:%s %s", ANSI_HILITE, ap->name, ANSI_NORMAL, text); } else { buf = text; } notify(player, buf); } static void look_atrs1 ( dbref player, dbref thing, dbref othing, bool check_exclude, bool hash_insert ) { bool bFoundCommands = false; bool bFoundListens = false; char *as; for (int ca = atr_head(thing, &as); ca; ca = atr_next(&as)) { if ( ca == A_DESC || ca == A_LOCK) { continue; } ATTR *pattr = atr_num(ca); if (!pattr) { continue; } ATTR cattr; memcpy(&cattr, pattr, sizeof(ATTR)); // Should we exclude this attr? // if ( check_exclude && ( (pattr->flags & AF_PRIVATE) || hashfindLEN(&ca, sizeof(ca), &mudstate.parent_htab))) { continue; } int aflags; dbref aowner; char *buf = atr_get(thing, ca, &aowner, &aflags); if (!(aflags & AF_NOPROG)) { if ( AMATCH_CMD == buf[0] || AMATCH_LISTEN == buf[0]) { char *s = strchr(buf+1, ':'); if (s) { if (AMATCH_CMD == buf[0]) { bFoundCommands = true; } else { bFoundListens = true; } } } } if (bCanReadAttr(player, othing, &cattr, false)) { if (!(check_exclude && (aflags & AF_PRIVATE))) { if (hash_insert) { hashaddLEN(&ca, sizeof(ca), pattr, &mudstate.parent_htab); } view_atr(player, thing, &cattr, buf, aowner, aflags, false); } } free_lbuf(buf); } if (bFoundCommands) { mudstate.bfNoCommands.Clear(thing); mudstate.bfCommands.Set(thing); } else { mudstate.bfCommands.Clear(thing); mudstate.bfNoCommands.Set(thing); } if (bFoundListens) { mudstate.bfNoListens.Clear(thing); mudstate.bfListens.Set(thing); } else { mudstate.bfListens.Clear(thing); mudstate.bfNoListens.Set(thing); } } static void look_atrs(dbref player, dbref thing, bool check_parents) { dbref parent; int lev; bool check_exclude, hash_insert; if (!check_parents) { look_atrs1(player, thing, thing, false, false); } else { hash_insert = true; check_exclude = false; hashflush(&mudstate.parent_htab); ITER_PARENTS(thing, parent, lev) { if (!Good_obj(Parent(parent))) { hash_insert = false; } look_atrs1(player, parent, thing, check_exclude, hash_insert); check_exclude = true; } } } static bool show_a_desc(dbref player, dbref loc) { int iDescDefault = A_DESC; int iADescDefault = A_ADESC; #if defined(WOD_REALMS) || defined(REALITY_LVLS) int iRealmDirective = DoThingToThingVisibility(player, loc, ACTION_IS_STATIONARY); if (REALM_DO_HIDDEN_FROM_YOU == iRealmDirective) { return true; } LetDescriptionsDefault(loc, &iDescDefault, &iADescDefault, iRealmDirective); #endif bool ret = false; dbref aowner1; int aflags1; bool indent = (isRoom(loc) && mudconf.indent_desc && atr_get_raw(loc, A_DESC)); char *DescFormatBuffer = atr_pget(loc, A_DESCFORMAT, &aowner1, &aflags1); char *DescFormat = DescFormatBuffer; if (*DescFormat) { reg_ref **preserve = NULL; preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); char *FormatOutput = alloc_lbuf("look_description.FO"); char *tPtr = FormatOutput; ATTR *cattr = atr_num(iDescDefault); dbref aowner2; int aflags2; char *tbuf1 = atr_pget(loc, iDescDefault, &aowner2, &aflags2); char *str = tbuf1; char *temp = alloc_lbuf("look_description.ET"); char *bp = temp; mux_exec(temp, &bp, loc, player, player, AttrTrace(aflags2, EV_FCHECK|EV_EVAL|EV_TOP), &str, NULL, 0); *bp = '\0'; char *attrname = alloc_lbuf("look_description.AN"); char *cp = attrname; safe_str(cattr->name, attrname, &cp); *cp = '\0'; char* ParameterList[] = { temp, attrname }; mux_exec(FormatOutput, &tPtr, loc, player, player, AttrTrace(aflags1, EV_FCHECK|EV_EVAL|EV_TOP), &DescFormat, ParameterList, 2); *tPtr = '\0'; notify(player, FormatOutput); #ifdef REALITY_LVLS did_it_rlevel(player, loc, 0, NULL, A_ODESC, NULL, iADescDefault, 0, NULL, 0); #else did_it(player, loc, 0, NULL, A_ODESC, NULL, iADescDefault, 0, NULL, 0); #endif // REALITY_LVLS free_lbuf(tbuf1); free_lbuf(attrname); free_lbuf(FormatOutput); free_lbuf(temp); restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); ret = true; } else { char *got; if (Html(player)) { got = atr_pget(loc, A_HTDESC, &aowner1, &aflags1); if (*got) { #ifdef REALITY_LVLS did_it_rlevel(player, loc, A_HTDESC, NULL, A_ODESC, NULL, A_ADESC, 0, NULL, 0); #else did_it(player, loc, A_HTDESC, NULL, A_ODESC, NULL, A_ADESC, 0, NULL, 0); #endif // REALITY_LVLS ret = true; } else { free_lbuf(got); got = atr_pget(loc, iDescDefault, &aowner1, &aflags1); if (*got) { if (indent) { raw_notify_newline(player); } #ifdef REALITY_LVLS did_it_rlevel(player, loc, iDescDefault, NULL, A_ODESC, NULL, iADescDefault, 0, NULL, 0); #else did_it(player, loc, iDescDefault, NULL, A_ODESC, NULL, iADescDefault, 0, NULL, 0); #endif // REALITY_LVLS if (indent) { raw_notify_newline(player); } ret = true; } } } else if (*(got = atr_pget(loc, iDescDefault, &aowner1, &aflags1))) { if (indent) { raw_notify_newline(player); } #ifdef REALITY_LVLS did_it_rlevel(player, loc, iDescDefault, NULL, A_ODESC, NULL, iADescDefault, 0, NULL, 0); #else did_it(player, loc, iDescDefault, NULL, A_ODESC, NULL, iADescDefault, 0, NULL, 0); #endif // REALITY_LVLS if (indent) { raw_notify_newline(player); } ret = true; } free_lbuf(got); } free_lbuf(DescFormatBuffer); return ret; } static void look_simple(dbref player, dbref thing, bool obey_terse) { // Only makes sense for things that can hear. // if (!Hearer(player)) { return; } #if defined(WOD_REALMS) || defined(REALITY_LVLS) int iRealmDirective = DoThingToThingVisibility(player, thing, ACTION_IS_STATIONARY); if (REALM_DO_HIDDEN_FROM_YOU == iRealmDirective) { notify(player, NOMATCH_MESSAGE); return; } #endif // Get the name and db-number if we can examine it. // int can_see_thing = Examinable(player, thing); if (can_see_thing) { char *buff = unparse_object(player, thing, true, true); notify(player, buff); free_lbuf(buff); } int iDescDefault = A_DESC; int iADescDefault = A_ADESC; #if defined(WOD_REALMS) || defined(REALITY_LVLS) LetDescriptionsDefault(thing, &iDescDefault, &iADescDefault, iRealmDirective); #endif int pattr = (obey_terse && Terse(player)) ? 0 : iDescDefault; if (!show_a_desc(player, thing)) { notify(player, "You see nothing special."); #ifdef REALITY_LVLS did_it_rlevel(player, thing, 0, NULL, A_ODESC, NULL, iADescDefault, 0, NULL, 0); #else did_it(player, thing, pattr, NULL, A_ODESC, NULL, iADescDefault, 0, NULL, 0); #endif // REALITY_LVLS } if ( !mudconf.quiet_look && ( !Terse(player) || mudconf.terse_look)) { look_atrs(player, thing, false); } } static void show_desc(dbref player, dbref loc, int key) { char *got; dbref aowner; int aflags; if ( (key & LK_OBEYTERSE) && Terse(player)) { #ifdef REALITY_LVLS did_it_rlevel(player, loc, 0, NULL, A_ODESC, NULL, A_ADESC, 0, NULL, 0); #else did_it(player, loc, 0, NULL, A_ODESC, NULL, A_ADESC, 0, NULL, 0); #endif // REALITY_LVLS } else if ( !isRoom(loc) && (key & LK_IDESC)) { if (*(got = atr_pget(loc, A_IDESC, &aowner, &aflags))) { #ifdef REALITY_LVLS did_it_rlevel(player, loc, A_IDESC, NULL, A_ODESC, NULL, A_ADESC, 0, NULL, 0); #else did_it(player, loc, A_IDESC, NULL, A_ODESC, NULL, A_ADESC, 0, NULL, 0); #endif // REALITY_LVLS } else { show_a_desc(player, loc); } free_lbuf(got); } else { show_a_desc(player, loc); } } void look_in(dbref player, dbref loc, int key) { // Only makes sense for things that can hear. // if (!Hearer(player)) { return; } // If he needs the VMRL URL, send it: // if (key & LK_SHOWVRML) { show_vrml_url(player, loc); } // Use @nameformat (by Marlek) if it's present, otherwise, use the // name and if the player can link to it, it's dbref as well. // dbref aowner; int aflags; char *NameFormatBuffer = atr_pget(loc, A_NAMEFORMAT, &aowner, &aflags); char *NameFormat = NameFormatBuffer; if (*NameFormat) { char *FormatOutput = alloc_lbuf("look_name.FO"); char *tPtr = FormatOutput; reg_ref **preserve = NULL; preserve = PushRegisters(MAX_GLOBAL_REGS); save_and_clear_global_regs(preserve); mux_exec(FormatOutput, &tPtr, loc, player, player, AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP), &NameFormat, 0, 0); *tPtr = '\0'; restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); notify(player, FormatOutput); free_lbuf(FormatOutput); } else { // Okay, no @NameFormat. Show the normal name. // char *buff = unparse_object(player, loc, true, true); if (Html(player)) { notify_html(player, "

"); notify(player, buff); notify_html(player, "

"); } else { notify(player, buff); } free_lbuf(buff); } free_lbuf(NameFormatBuffer); if (!Good_obj(loc)) { // If we went to NOTHING et al, then skip the rest. // return; } // Tell him the description. // int showkey = 0; if (loc == Location(player)) { showkey |= LK_IDESC; } if (key & LK_OBEYTERSE) { showkey |= LK_OBEYTERSE; } show_desc(player, loc, showkey); bool is_terse = (key & LK_OBEYTERSE) ? Terse(player) : false; // Tell him the appropriate messages if he has the key. // if (isRoom(loc)) { int pattr, oattr, aattr; if (could_doit(player, loc, A_LOCK)) { pattr = A_SUCC; oattr = A_OSUCC; aattr = A_ASUCC; } else { pattr = A_FAIL; oattr = A_OFAIL; aattr = A_AFAIL; } if (is_terse) { pattr = 0; } did_it(player, loc, pattr, NULL, oattr, NULL, aattr, 0, NULL, 0); } // Tell him the attributes, contents and exits. // if ( (key & LK_SHOWATTR) && !mudconf.quiet_look && !is_terse) { look_atrs(player, loc, false); } if ( !is_terse || mudconf.terse_contents) { look_contents(player, loc, "Contents:", CONTENTS_LOCAL); } if ( (key & LK_SHOWEXIT) && ( !is_terse || mudconf.terse_exits)) { look_exits(player, loc, "Obvious exits:"); } } static void look_here ( dbref executor, dbref thing, int key, int look_key ) { if (Good_obj(thing)) { if (key & LOOK_OUTSIDE) { if ( isRoom(thing) || Opaque(thing)) { notify_quiet(executor, "You can't look outside."); return; } thing = Location(thing); } look_in(executor, thing, look_key); } } void do_look(dbref executor, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); int look_key = LK_SHOWATTR | LK_SHOWEXIT; if (!mudconf.terse_look) { look_key |= LK_OBEYTERSE; } dbref loc = Location(executor); dbref thing; if ( NULL == name || '\0' == name[0]) { look_here(executor, loc, key, look_key); return; } // Look for the target locally. // thing = (key & LOOK_OUTSIDE) ? loc : executor; init_match(thing, name, NOTYPE); match_exit_with_parents(); match_neighbor(); match_possession(); if (Long_Fingers(executor)) { match_absolute(); match_player(); } match_here(); match_me(); match_master_exit(); thing = match_result(); // Not found locally, check possessive. // if (!Good_obj(thing)) { thing = match_status(executor, match_possessed(executor, ((key & LOOK_OUTSIDE) ? loc : executor), name, thing, false)); } // If the matching picked our current location, that's handled // differently. // if (thing == loc) { look_here(executor, loc, key, look_key); return; } // If we found something, go handle it. // if (Good_obj(thing)) { #ifdef REALITY_LVLS if (!IsReal(executor, thing)) return; #endif // REALITY_LVLS switch (Typeof(thing)) { case TYPE_ROOM: look_in(executor, thing, look_key); break; case TYPE_THING: case TYPE_PLAYER: look_simple(executor, thing, !mudconf.terse_look); if ( !Opaque(thing) && ( mudconf.terse_contents || !Terse(executor))) { look_contents(executor, thing, "Carrying:", CONTENTS_NESTED); } break; case TYPE_EXIT: look_simple(executor, thing, !mudconf.terse_look); if ( Transparent(thing) && Location(thing) != NOTHING) { look_key &= ~LK_SHOWATTR; look_in(executor, Location(thing), look_key); } break; default: look_simple(executor, thing, !mudconf.terse_look); break; } } } static void debug_examine(dbref player, dbref thing) { dbref aowner; char *buf; int aflags, ca; BOOLEXP *pBoolExp; ATTR *pattr; char *as, *cp; notify(player, tprintf("Number = %d", thing)); if (!Good_obj(thing)) { return; } notify(player, tprintf("Name = %s", Name(thing))); notify(player, tprintf("Location= %d", Location(thing))); notify(player, tprintf("Contents= %d", Contents(thing))); notify(player, tprintf("Exits = %d", Exits(thing))); notify(player, tprintf("Link = %d", Link(thing))); notify(player, tprintf("Next = %d", Next(thing))); notify(player, tprintf("Owner = %d", Owner(thing))); notify(player, tprintf("Pennies = %d", Pennies(thing))); notify(player, tprintf("Zone = %d", Zone(thing))); buf = flag_description(player, thing); notify(player, tprintf("Flags = %s", buf)); free_mbuf(buf); buf = powers_list(player, thing); notify(player, tprintf("Powers = %s", buf)); free_lbuf(buf); #ifdef REALITY_LVLS buf = rxlevel_description(player, thing); notify(player, tprintf("RxLevel = %s", buf)); free_lbuf(buf); buf = txlevel_description(player, thing); notify(player, tprintf("TxLevel = %s", buf)); free_lbuf(buf); #endif // REALITY_LVLS buf = atr_get(thing, A_LOCK, &aowner, &aflags); pBoolExp = parse_boolexp(player, buf, true); free_lbuf(buf); notify(player, tprintf("Lock = %s", unparse_boolexp(player, pBoolExp))); free_boolexp(pBoolExp); buf = alloc_lbuf("debug_dexamine"); cp = buf; safe_str("Attr list: ", buf, &cp); for (ca = atr_head(thing, &as); ca; ca = atr_next(&as)) { pattr = atr_num(ca); if (!pattr) { continue; } atr_get_info(thing, ca, &aowner, &aflags); if (bCanReadAttr(player, thing, pattr, false)) { if (pattr) { // Valid attr. // safe_str(pattr->name, buf, &cp); safe_chr(' ', buf, &cp); } else { safe_str(tprintf("%d ", ca), buf, &cp); } } } *cp = '\0'; notify(player, buf); free_lbuf(buf); for (ca = atr_head(thing, &as); ca; ca = atr_next(&as)) { pattr = atr_num(ca); if (!pattr) { continue; } buf = atr_get(thing, ca, &aowner, &aflags); if (bCanReadAttr(player, thing, pattr, false)) { view_atr(player, thing, pattr, buf, aowner, aflags, 0); } free_lbuf(buf); } } static void exam_wildattrs ( dbref player, dbref thing, bool do_parent ) { int atr; bool got_any = false; for (atr = olist_first(); atr != NOTHING; atr = olist_next()) { ATTR *ap = atr_num(atr); if (!ap) { continue; } int aflags; dbref aowner; char *buf; if ( do_parent && !(ap->flags & AF_PRIVATE)) { buf = atr_pget(thing, atr, &aowner, &aflags); } else { buf = atr_get(thing, atr, &aowner, &aflags); } // Decide if the player should see the attr: If obj is // Examinable and has rights to see, yes. If a player and has // rights to see, yes... except if faraway, attr=DESC, and // remote DESC-reading is not turned on. If I own the attrib // and have rights to see, yes... except if faraway, attr=DESC, // and remote DESC-reading is not turned on. // if ( Examinable(player, thing) && bCanReadAttr(player, thing, ap, do_parent)) { got_any = true; view_atr(player, thing, ap, buf, aowner, aflags, 0); } else if (bCanReadAttr(player, thing, ap, isPlayer(thing) ? do_parent : false)) { got_any = true; if (aowner == Owner(player)) { view_atr(player, thing, ap, buf, aowner, aflags, 0); } else if ( atr == A_DESC && ( mudconf.read_rem_desc || nearby(player, thing))) { show_desc(player, thing, 0); } else if (atr != A_DESC) { view_atr(player, thing, ap, buf, aowner, aflags, 0); } else { notify(player, ""); } } free_lbuf(buf); } if (!got_any) { notify_quiet(player, "No matching attributes found."); } } void do_examine(dbref executor, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); // This command is pointless if the player can't hear. // if (!Hearer(executor)) { return; } dbref content, exit, aowner, loc; char savec; char *temp, *buf, *buf2; BOOLEXP *pBoolExp; int aflags; bool control; bool do_parent = ((key & EXAM_PARENT) ? true : false); dbref thing = NOTHING; if ( !name || !*name) { thing = Location(executor); if (thing == NOTHING) { return; } } else { // Check for obj/attr first. // olist_push(); if (parse_attrib_wild(executor, name, &thing, do_parent, true, false)) { exam_wildattrs(executor, thing, do_parent); olist_pop(); return; } olist_pop(); // Look it up. // init_match(executor, name, NOTYPE); match_everything(MAT_EXIT_PARENTS); thing = noisy_match_result(); if (!Good_obj(thing)) { return; } } #if defined(WOD_REALMS) || defined(REALITY_LVLS) if (REALM_DO_HIDDEN_FROM_YOU == DoThingToThingVisibility(executor, thing, ACTION_IS_STATIONARY)) { notify(executor, NOMATCH_MESSAGE); return; } #endif // Check for the /debug switch. // if (key & EXAM_DEBUG) { if (!Examinable(executor, thing)) { notify_quiet(executor, NOPERM_MESSAGE); } else { debug_examine(executor, thing); } return; } control = ( Examinable(executor, thing) || Link_exit(executor, thing)); if (control) { buf2 = unparse_object(executor, thing, false, true); notify(executor, buf2); free_lbuf(buf2); if (mudconf.ex_flags) { buf2 = flag_description(executor, thing); notify(executor, buf2); free_mbuf(buf2); } } else { if ( key == EXAM_DEFAULT && !mudconf.exam_public) { if (mudconf.read_rem_name) { buf2 = alloc_lbuf("do_examine.pub_name"); mux_strncpy(buf2, Moniker(thing), LBUF_SIZE-1); notify(executor, tprintf("%s is owned by %s", buf2, Moniker(Owner(thing)))); free_lbuf(buf2); } else { notify(executor, tprintf("Owned by %s", Moniker(Owner(thing)))); } return; } } temp = alloc_lbuf("do_examine.info"); if ( control || mudconf.read_rem_desc || nearby(executor, thing)) { temp = atr_get_str(temp, thing, A_DESC, &aowner, &aflags); if (*temp) { if ( Examinable(executor, thing) || (aowner == Owner(executor))) { view_atr(executor, thing, atr_num(A_DESC), temp, aowner, aflags, true); } else { show_desc(executor, thing, 0); } } } else { notify(executor, ""); } if (control) { // Print owner, key, and value. // savec = mudconf.many_coins[0]; mudconf.many_coins[0] = mux_toupper(mudconf.many_coins[0]); buf2 = atr_get(thing, A_LOCK, &aowner, &aflags); pBoolExp = parse_boolexp(executor, buf2, true); buf = unparse_boolexp(executor, pBoolExp); free_boolexp(pBoolExp); mux_strncpy(buf2, Moniker(Owner(thing)), LBUF_SIZE-1); notify(executor, tprintf("Owner: %s Key: %s %s: %d", buf2, buf, mudconf.many_coins, Pennies(thing))); free_lbuf(buf2); mudconf.many_coins[0] = savec; // Print the zone // if (mudconf.have_zones) { buf2 = unparse_object(executor, Zone(thing), false, true); notify(executor, tprintf("Zone: %s", buf2)); free_lbuf(buf2); } // Print parent // loc = Parent(thing); if (loc != NOTHING) { buf2 = unparse_object(executor, loc, false, true); notify(executor, tprintf("Parent: %s", buf2)); free_lbuf(buf2); } buf2 = powers_list(executor, thing); notify(executor, tprintf("Powers: %s", buf2)); free_lbuf(buf2); #ifdef REALITY_LVLS // Show Rx and Tx levels. // buf2 = rxlevel_description(executor, thing); notify(executor, tprintf("RxLevel: %s", buf2)); free_mbuf(buf2); buf2 = txlevel_description(executor, thing); notify(executor, tprintf("TxLevel: %s", buf2)); free_mbuf(buf2); #endif // REALITY_LVLS } if (!(key & EXAM_BRIEF)) { look_atrs(executor, thing, do_parent); } // Show him interesting stuff // if (control) { // Contents // if (Contents(thing) != NOTHING) { notify(executor, "Contents:"); DOLIST(content, Contents(thing)) { buf2 = unparse_object(executor, content, false, true); notify(executor, buf2); free_lbuf(buf2); } } // Show stuff that depends on the object type. // switch (Typeof(thing)) { case TYPE_ROOM: // Tell him about exits // if (Exits(thing) != NOTHING) { notify(executor, "Exits:"); DOLIST(exit, Exits(thing)) { buf2 = unparse_object(executor, exit, false, true); notify(executor, buf2); free_lbuf(buf2); } } else { notify(executor, "No exits."); } // print dropto if present // if (Dropto(thing) != NOTHING) { buf2 = unparse_object(executor, Dropto(thing), false, true); notify(executor, tprintf("Dropped objects go to: %s", buf2)); free_lbuf(buf2); } break; case TYPE_THING: case TYPE_PLAYER: // Tell him about exits // if (Exits(thing) != NOTHING) { notify(executor, "Exits:"); DOLIST(exit, Exits(thing)) { buf2 = unparse_object(executor, exit, false, true); notify(executor, buf2); free_lbuf(buf2); } } else { notify(executor, "No exits."); } // Print home // loc = Home(thing); buf2 = unparse_object(executor, loc, false, true); notify(executor, tprintf("Home: %s", buf2)); free_lbuf(buf2); // print location if player can link to it // loc = Location(thing); if ( Location(thing) != NOTHING && ( Examinable(executor, loc) || Examinable(executor, thing) || Linkable(executor, loc))) { buf2 = unparse_object(executor, loc, false, true); notify(executor, tprintf("Location: %s", buf2)); free_lbuf(buf2); } break; case TYPE_EXIT: buf2 = unparse_object(executor, Exits(thing), false, true); notify(executor, tprintf("Source: %s", buf2)); free_lbuf(buf2); // print destination. // switch (Location(thing)) { case NOTHING: // Special case. unparse_object() normally returns -1 as '*NOTHING*'. // notify(executor, "Destination: *UNLINKED*"); break; default: buf2 = unparse_object(executor, Location(thing), false, true); notify(executor, tprintf("Destination: %s", buf2)); free_lbuf(buf2); break; } break; default: break; } } else if ( !Opaque(thing) && nearby(executor, thing)) { if (Has_contents(thing)) { look_contents(executor, thing, "Contents:", CONTENTS_REMOTE); } if (!isExit(thing)) { look_exits(executor, thing, "Obvious exits:"); } } free_lbuf(temp); if (!control) { if (mudconf.read_rem_name) { buf2 = alloc_lbuf("do_examine.pub_name"); mux_strncpy(buf2, Moniker(thing), LBUF_SIZE-1); notify(executor, tprintf("%s is owned by %s", buf2, Moniker(Owner(thing)))); free_lbuf(buf2); } else { notify(executor, tprintf("Owned by %s", Moniker(Owner(thing)))); } } } void do_score(dbref executor, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); int nPennies = Pennies(executor); notify(executor, tprintf("You have %d %s.", nPennies, (1 == nPennies) ? mudconf.one_coin : mudconf.many_coins)); } void do_inventory(dbref executor, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); dbref thing; char *buff, *e; const char *s; thing = Contents(executor); if (thing == NOTHING) { notify(executor, "You aren't carrying anything."); } else { notify(executor, "You are carrying:"); DOLIST(thing, thing) { buff = unparse_object(executor, thing, true, true); notify(executor, buff); free_lbuf(buff); } } thing = Exits(executor); if (thing != NOTHING) { notify(executor, "Exits:"); e = buff = alloc_lbuf("look_exits"); DOLIST(thing, thing) { // Chop off first exit alias to display. // for (s = Moniker(thing); *s && (*s != ';'); s++) { safe_chr(*s, buff, &e); } safe_str(" ", buff, &e); } *e = 0; notify(executor, buff); free_lbuf(buff); } do_score(executor, caller, executor, 0); } void do_entrances(dbref executor, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); dbref thing, i, j; char *exit, *message; int control_thing, count, low_bound, high_bound; FWDLIST *fp; parse_range(&name, &low_bound, &high_bound); if ( !name || !*name) { if (Has_location(executor)) { thing = Location(executor); } else { thing = executor; } if (!Good_obj(thing)) { return; } } else { init_match(executor, name, NOTYPE); match_everything(MAT_EXIT_PARENTS); thing = noisy_match_result(); if (!Good_obj(thing)) { return; } } if (!payfor(executor, mudconf.searchcost)) { notify(executor, tprintf("You don't have enough %s.", mudconf.many_coins)); return; } message = alloc_lbuf("do_entrances"); control_thing = Examinable(executor, thing); count = 0; for (i = low_bound; i <= high_bound; i++) { if (control_thing || Examinable(executor, i)) { switch (Typeof(i)) { case TYPE_EXIT: if (Location(i) == thing) { exit = unparse_object(executor, Exits(i), false, true); notify(executor, tprintf("%s (%s)", exit, Moniker(i))); free_lbuf(exit); count++; } break; case TYPE_ROOM: if (Dropto(i) == thing) { exit = unparse_object(executor, i, false, true); notify(executor, tprintf("%s [dropto]", exit)); free_lbuf(exit); count++; } break; case TYPE_THING: case TYPE_PLAYER: if (Home(i) == thing) { exit = unparse_object(executor, i, false, true); notify(executor, tprintf("%s [home]", exit)); free_lbuf(exit); count++; } break; } // Check for parents. // if (Parent(i) == thing) { exit = unparse_object(executor, i, false, true); notify(executor, tprintf("%s [parent]", exit)); free_lbuf(exit); count++; } // Check for forwarding. // if (H_Fwdlist(i)) { fp = fwdlist_get(i); if (!fp) { continue; } for (j = 0; j < fp->count; j++) { if (fp->data[j] != thing) { continue; } exit = unparse_object(executor, i, false, true); notify(executor, tprintf("%s [forward]", exit)); free_lbuf(exit); count++; } } } } free_lbuf(message); notify(executor, tprintf("%d entrance%s found.", count, (count == 1) ? "" : "s")); } // Check the current location for bugs. // static void sweep_check(dbref player, dbref what, int key, bool is_loc) { if ( Can_Hide(what) && Hidden(what) && !See_Hidden(player)) { return; } bool canhear = false; bool cancom = false; bool isplayer = false; bool ispuppet = false; bool isconnected = false; bool is_parent = false; if (key & SWEEP_LISTEN) { if ( ( ( isExit(what) || is_loc) && Audible(what)) || H_Listen(what) || mudstate.bfListens.IsSet(what)) { canhear = true; } else if ( !mudstate.bfNoListens.IsSet(what) && Monitor(what)) { bool bFoundCommands = false; char *as; char *buff = alloc_lbuf("sweep_check.Hearer"); for (int atr = atr_head(what, &as); atr; atr = atr_next(&as)) { ATTR *ap = atr_num(atr); if ( !ap || (ap->flags & AF_NOPROG)) { continue; } int aflags; dbref aowner; atr_get_str(buff, what, atr, &aowner, &aflags); if (aflags & AF_NOPROG) { continue; } char *s = NULL; if ( AMATCH_CMD == buff[0] || AMATCH_LISTEN == buff[0]) { s = strchr(buff+1, ':'); if (s) { if (AMATCH_CMD == buff[0]) { bFoundCommands = true; } else { canhear = true; break; } } } } free_lbuf(buff); if (canhear) { mudstate.bfListens.Set(what); } else { mudstate.bfNoListens.Set(what); } if (bFoundCommands) { mudstate.bfNoCommands.Clear(what); mudstate.bfCommands.Set(what); } else { mudstate.bfCommands.Clear(what); mudstate.bfNoCommands.Set(what); } } } if ( (key & SWEEP_COMMANDS) && !isExit(what)) { // Look for commands on the object and parents too. // dbref parent; int lev; ITER_PARENTS(what, parent, lev) { if (Commer(parent)) { cancom = true; if (lev) { is_parent = true; break; } } } } if (key & SWEEP_CONNECT) { if ( Connected(what) || ( Puppet(what) && Connected(Owner(what))) || ( mudconf.player_listen && isPlayer(what) && canhear && Connected(Owner(what)))) { isconnected = true; } } if ( (key & SWEEP_PLAYER) || isconnected) { if (isPlayer(what)) { isplayer = true; } if (Puppet(what)) { ispuppet = true; } } if ( canhear || cancom || isplayer || ispuppet || isconnected) { char *buf = alloc_lbuf("sweep_check.types"); char *bp = buf; if (cancom) { safe_str("commands ", buf, &bp); } if (canhear) { safe_str("messages ", buf, &bp); } if (isplayer) { safe_str("player ", buf, &bp); } if (ispuppet) { safe_str("puppet(", buf, &bp); safe_str(Moniker(Owner(what)), buf, &bp); safe_str(") ", buf, &bp); } if (isconnected) { safe_str("connected ", buf, &bp); } if (is_parent) { safe_str("parent ", buf, &bp); } bp[-1] = '\0'; if (!isExit(what)) { notify(player, tprintf(" %s is listening. [%s]", Moniker(what), buf)); } else { char *buf2 = alloc_lbuf("sweep_check.name"); mux_strncpy(buf2, Moniker(what), LBUF_SIZE-1); for (bp = buf2; *bp && (*bp != ';'); bp++) { ; // Nothing. } *bp = '\0'; notify(player, tprintf(" %s is listening. [%s]", buf2, buf)); free_lbuf(buf2); } free_lbuf(buf); } } void do_sweep(dbref executor, dbref caller, dbref enactor, int eval, int key, char *where) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); dbref here, sweeploc; int where_key, what_key; where_key = key & (SWEEP_ME | SWEEP_HERE | SWEEP_EXITS); what_key = key & (SWEEP_COMMANDS | SWEEP_LISTEN | SWEEP_PLAYER | SWEEP_CONNECT); if (where && *where) { sweeploc = match_controlled(executor, where); if (!Good_obj(sweeploc)) { return; } } else { sweeploc = executor; } if (!where_key) { where_key = -1; } if (!what_key) { what_key = -1; } else if (what_key == SWEEP_VERBOSE) { what_key = SWEEP_VERBOSE | SWEEP_COMMANDS; } // Check my location. If I have none or it is dark, check just me. // if (where_key & SWEEP_HERE) { notify(executor, "Sweeping location..."); if (Has_location(sweeploc)) { here = Location(sweeploc); if ( here == NOTHING || ( Dark(here) && !mudconf.sweep_dark && !Examinable(executor, here))) { notify_quiet(executor, "Sorry, it is dark here and you can't search for bugs"); sweep_check(executor, sweeploc, what_key, false); } else { sweep_check(executor, here, what_key, true); for (here = Contents(here); here != NOTHING; here = Next(here)) { sweep_check(executor, here, what_key, false); } } } else { sweep_check(executor, sweeploc, what_key, false); } } // Check exits in my location // if ( (where_key & SWEEP_EXITS) && Has_location(sweeploc)) { notify(executor, "Sweeping exits..."); for (here = Exits(Location(sweeploc)); here != NOTHING; here = Next(here)) { sweep_check(executor, here, what_key, false); } } // Check my inventory // if ( (where_key & SWEEP_ME) && Has_contents(sweeploc)) { notify(executor, "Sweeping inventory..."); for (here = Contents(sweeploc); here != NOTHING; here = Next(here)) { sweep_check(executor, here, what_key, false); } } // Check carried exits // if ( (where_key & SWEEP_EXITS) && Has_exits(sweeploc)) { notify(executor, "Sweeping carried exits..."); for (here = Exits(sweeploc); here != NOTHING; here = Next(here)) { sweep_check(executor, here, what_key, false); } } notify(executor, "Sweep complete."); } /* Output the sequence of commands needed to duplicate the specified * object. If you're moving things to another system, your mileage * will almost certainly vary. (i.e. different flags, etc.) */ void do_decomp ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *qual ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); BOOLEXP *pBoolExp; char *got, *thingname, *as, *ltext, *buff; dbref aowner, thing; int val, aflags, ca; ATTR *pattr; NAMETAB *np; bool wild_decomp; // Check for obj/attr first. // olist_push(); if (parse_attrib_wild(executor, name, &thing, false, true, false)) { wild_decomp = true; } else { wild_decomp = false; init_match(executor, name, TYPE_THING); match_everything(MAT_EXIT_PARENTS); thing = noisy_match_result(); } // get result // if (thing == NOTHING) { olist_pop(); return; } if (!Examinable(executor, thing)) { notify_quiet(executor, "You can only decompile things you can examine."); olist_pop(); return; } thingname = atr_get(thing, A_LOCK, &aowner, &aflags); pBoolExp = parse_boolexp(executor, thingname, true); // Determine the name of the thing to use in reporting and then // report the command to make the thing. // if (qual && *qual) { mux_strncpy(thingname, qual, LBUF_SIZE-1); } else { if (key == DECOMP_DBREF) { mux_strncpy(thingname, tprintf("#%d",thing), LBUF_SIZE-1); } else { switch (Typeof(thing)) { case TYPE_THING: mux_strncpy(thingname, Moniker(thing), LBUF_SIZE-1); val = OBJECT_DEPOSIT(Pennies(thing)); notify(executor, tprintf("@create %s=%d", translate_string(thingname, true), val)); break; case TYPE_ROOM: mux_strncpy(thingname, "here", LBUF_SIZE-1); notify(executor, tprintf("@dig/teleport %s", translate_string(Moniker(thing), true))); break; case TYPE_EXIT: mux_strncpy(thingname, Moniker(thing), LBUF_SIZE-1); notify(executor, tprintf("@open %s", translate_string(thingname, true))); for (got = thingname; *got; got++) { if (*got == EXIT_DELIMITER) { *got = '\0'; break; } } break; case TYPE_PLAYER: if (executor == thing) { mux_strncpy(thingname, "me", LBUF_SIZE-1); } else { mux_strncpy(thingname, Name(thing), LBUF_SIZE-1); } break; } } } // Strip out ANSI in one place rather than have it done in // several places. // size_t len; char *p = strip_ansi(thingname, &len); memcpy(thingname, p, len+1); // Report the lock (if any). // if ( !wild_decomp && pBoolExp != TRUE_BOOLEXP) { notify(executor, tprintf("@lock %s=%s", thingname, unparse_boolexp_decompile(executor, pBoolExp))); } free_boolexp(pBoolExp); // Report attributes. // buff = alloc_mbuf("do_decomp.attr_name"); for (ca = (wild_decomp ? olist_first() : atr_head(thing, &as)); (wild_decomp) ? (ca != NOTHING) : (ca != 0); ca = (wild_decomp ? olist_next() : atr_next(&as))) { if ( ca == A_NAME || ca == A_LOCK) { continue; } pattr = atr_num(ca); if (!pattr) { continue; } if ( (pattr->flags & AF_NOCMD) && !(pattr->flags & AF_IS_LOCK)) { continue; } got = atr_get(thing, ca, &aowner, &aflags); if (bCanReadAttr(executor, thing, pattr, false)) { if (pattr->flags & AF_IS_LOCK) { pBoolExp = parse_boolexp(executor, got, true); ltext = unparse_boolexp_decompile(executor, pBoolExp); free_boolexp(pBoolExp); notify(executor, tprintf("@lock/%s %s=%s", pattr->name, thingname, ltext)); } else { mux_strncpy(buff, pattr->name, MBUF_SIZE-1); notify(executor, tprintf("%c%s %s=%s", ((ca < A_USER_START) ? '@' : '&'), buff, thingname, got)); for (np = indiv_attraccess_nametab; np->name; np++) { if ( (aflags & np->flag) && check_access(executor, np->perm) && (!(np->perm & CA_NO_DECOMP))) { notify(executor, tprintf("@set %s/%s = %s", thingname, buff, np->name)); } } if (aflags & AF_LOCK) { notify(executor, tprintf("@lock %s/%s", thingname, buff)); } } } free_lbuf(got); } free_mbuf(buff); if (!wild_decomp) { decompile_flags(executor, thing, thingname); decompile_powers(executor, thing, thingname); #ifdef REALITY_LVLS decompile_rlevels(executor, thing, thingname); #endif // REALITY_LVLS } // If the object has a parent, report it. // if ( !wild_decomp && (Parent(thing) != NOTHING)) { notify(executor, tprintf("@parent %s=#%d", thingname, Parent(thing))); } // If the object has a zone, report it. // int zone; if ( !wild_decomp && Good_obj(zone = Zone(thing))) { notify(executor, tprintf("@chzone %s=#%d", thingname, zone)); } free_lbuf(thingname); olist_pop(); } // show_vrml_url // void show_vrml_url(dbref thing, dbref loc) { char *vrml_url; dbref aowner; int aflags; // If they don't care about HTML, just return. // if (!Html(thing)) { return; } vrml_url = atr_pget(loc, A_VRML_URL, &aowner, &aflags); if (*vrml_url) { char *vrml_message, *vrml_cp; vrml_message = vrml_cp = alloc_lbuf("show_vrml_url"); safe_str("", vrml_message, &vrml_cp); *vrml_cp = 0; notify_html(thing, vrml_message); free_lbuf(vrml_message); } else { notify_html(thing, ""); } free_lbuf(vrml_url); } mux2.6/src/local.cpp0000600000175000017500000001375511025753746014407 0ustar sdennissdennis/* local.cpp * * Inspired by Penn's local extensions; implemented for TinyMUX by * M. Hassman (June 2005) */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "functions.h" #include "command.h" // ---------------------------------------------------------------------------- // local_funlist: List of existing functions in alphabetical order. // // Name Handler # of args min # max # flags permissions // to parse of args of args // static FUN local_funlist[] = { {NULL, NULL, MAX_ARG, 0, 0, 0, 0} }; // --------------------------------------------------------------------------- // Local command tables: Definitions for local hardcode commands. // // Name Switches Permissions Key Calling Seq hook mask Handler // static CMDENT_NO_ARG local_command_table_no_arg[] = { {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_ONE_ARG local_command_table_one_arg[] = { {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_ONE_ARG_CMDARG local_command_table_one_arg_cmdarg[] = { {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG local_command_table_two_arg[] = { {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG_CMDARG local_command_table_two_arg_cmdarg[] = { {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG_ARGV local_command_table_two_arg_argv[] = { {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG_ARGV_CMDARG local_command_table_two_argv_cmdarg[] = { {NULL, NULL, 0, 0, 0, 0, NULL} }; // Called after all normal MUX initialization is complete // void local_startup(void) { // Add additional hardcode functions to the above table. // functions_add(local_funlist); // Add additional CMDENT_NO_ARG commands to the above table. // commands_no_arg_add(local_command_table_no_arg); commands_one_arg_add(local_command_table_one_arg); commands_one_arg_cmdarg_add(local_command_table_one_arg_cmdarg); commands_two_arg_add(local_command_table_two_arg); commands_two_arg_cmdarg_add(local_command_table_two_arg_cmdarg); commands_two_arg_argv_add(local_command_table_two_arg_argv); commands_two_arg_argv_cmdarg_add(local_command_table_two_argv_cmdarg); } // This is called prior to the game syncronizing its own state to its own // database. If you depend on the the core database to store your data, you // need to checkpoint your changes here. The write-protection // mechanism in MUX is not turned on at this point. You are guaranteed // to not be a fork()-ed dumping process. // void local_presync_database(void) { } // Like the above routine except that it called from the SIGSEGV handler. // At this point, your choices are limited. You can attempt to use the core // database. The core won't stop you, but it is risky. // void local_presync_database_sigsegv(void) { } // This is called prior to the game database writing out it's own database. // This is typically only called from the fork()-ed process so write- // protection is in force and you will be unable to modify the game's // database for you own needs. You can however, use this point to maintain // your own dump file. // // The caveat is that it is possible the game will crash while you are doing // this, or it is already in the process of crashing. You may be called // reentrantly. Therefore, it is recommended that you follow the pattern in // dump_database_internal() and write your database to a temporary file, and // then if completed successfully, move your temporary over the top of your // old database. // // The argument dump_type is one of the 5 DUMP_I_x defines declared in // externs.h // void local_dump_database(int dump_type) { UNUSED_PARAMETER(dump_type); } // The function is called when the dumping process has completed. Typically, // this will be called from within a signal handler. Your ability to do // anything interesting from within a signal handler is severly limited. // This is also called at the end of the dumping process if either no dumping // child was created or if the child finished quickly. In fact, this // may be called twice at the end of the same dump. // void local_dump_complete_signal(void) { } // Called when the game is shutting down, after the game database has // been saved but prior to the logfiles being closed. // void local_shutdown(void) { } // Called after the database consistency check is completed. Add // checks for local data consistency here. // void local_dbck(void) { } // Called when a player connects or creates at the connection screen. // isnew of 1 indicates it was a creation, 0 is for a connection. // num indicates the number of current connections for player. // void local_connect(dbref player, int isnew, int num) { UNUSED_PARAMETER(player); UNUSED_PARAMETER(isnew); UNUSED_PARAMETER(num); } // Called when player disconnects from the game. The parameter 'num' is // the number of connections the player had upon being disconnected. // Any value greater than 1 indicates multiple connections. // void local_disconnect(dbref player, int num) { UNUSED_PARAMETER(player); UNUSED_PARAMETER(num); } // Called after any object type is created. // void local_data_create(dbref object) { UNUSED_PARAMETER(object); } // Called when an object is cloned. clone is the new object created // from source. // void local_data_clone(dbref clone, dbref source) { UNUSED_PARAMETER(clone); UNUSED_PARAMETER(source); } // Called when the object is truly destroyed, not just set GOING // void local_data_free(dbref object) { UNUSED_PARAMETER(object); } static const char *LocalDumpInfoTable[] = { NULL }; const char **local_get_info_table(void) { return LocalDumpInfoTable; } mux2.6/src/levels.cpp0000700000175000017500000004416311025753746014605 0ustar sdennissdennis#ifdef REALITY_LVLS /* * levels.cpp - Reality levels stuff */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "db.h" #include "attrs.h" #include "mudconf.h" #include "command.h" #include "powers.h" #include "alloc.h" #include "match.h" #include "levels.h" #include "stringutil.h" extern void cf_log_notfound(dbref, char *, const char *, char *); RLEVEL RxLevel(dbref thing) { const char *buff = atr_get_raw(thing, A_RLEVEL); if ( NULL == buff || strlen(buff) != 17) { switch(Typeof(thing)) { case TYPE_ROOM: return(mudconf.def_room_rx); case TYPE_PLAYER: return(mudconf.def_player_rx); case TYPE_EXIT: return(mudconf.def_exit_rx); default: return(mudconf.def_thing_rx); } } int i; RLEVEL rx = 0; for (i = 0; mux_isxdigit(buff[i]); i++) { rx = 16 * rx + mux_hex2dec(buff[i]); } return rx; } RLEVEL TxLevel(dbref thing) { const char *buff = atr_get_raw(thing, A_RLEVEL); if ( NULL == buff || strlen(buff) != 17) { switch(Typeof(thing)) { case TYPE_ROOM: return(mudconf.def_room_tx); case TYPE_PLAYER: return(mudconf.def_player_tx); case TYPE_EXIT: return(mudconf.def_exit_tx); default: return(mudconf.def_thing_tx); } } // Skip the first field. // int i; for (i = 0; buff[i] && !mux_isspace(buff[i]); i++) { ; // Nothing. } RLEVEL tx = 0; if (buff[i]) { // Skip space found above. // i++; // Decode second field. // for ( ; mux_isxdigit(buff[i]); i++) { tx = 16 * tx + mux_hex2dec(buff[i]); } } return tx; } void notify_except_rlevel ( dbref loc, dbref player, dbref exception, const char *msg, int xflags ) { if ( loc != exception && IsReal(loc, player)) { notify_check(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A| xflags)); } dbref first; DOLIST(first, Contents(loc)) { if ( first != exception && IsReal(first, player)) { notify_check(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE | xflags)); } } } void notify_except2_rlevel ( dbref loc, dbref player, dbref exc1, dbref exc2, const char *msg ) { if ( loc != exc1 && loc != exc2 && IsReal(loc, player)) { notify_check(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A)); } dbref first; DOLIST(first, Contents(loc)) { if ( first != exc1 && first != exc2 && IsReal(first, player)) { notify_check(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE)); } } } void notify_except2_rlevel2 ( dbref loc, dbref player, dbref exc1, dbref exc2, const char *msg ) { if ( loc != exc1 && loc != exc2 && IsReal(loc, player)) { notify_check(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A)); } dbref first; DOLIST(first, Contents(loc)) { if ( first != exc1 && first != exc2 && IsReal(first, player) && IsReal(first, exc2)) { notify_check(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE)); } } } /* * --------------------------------------------------------------------------- * * rxlevel_description: Return an mbuf containing the RxLevels of the thing. */ char *rxlevel_description(dbref player, dbref target) { // Allocate the return buffer. // int otype = Typeof(target); char *buff = alloc_mbuf("rxlevel_description"); char *bp = buff; int i; RLEVEL rl = RxLevel(target); for (i = 0; i < mudconf.no_levels; ++i) { if ( (rl & mudconf.reality_level[i].value) == mudconf.reality_level[i].value) { safe_mb_chr(' ', buff, &bp); safe_mb_str(mudconf.reality_level[i].name, buff, &bp); } } // Terminate the string, and return the buffer to the caller. // *bp = '\0'; return buff; } /* * --------------------------------------------------------------------------- * * txlevel_description: Return an mbuf containing the TxLevels of the thing. */ char *txlevel_description(dbref player, dbref target) { // Allocate the return buffer. // int otype = Typeof(target); char *buff = alloc_mbuf("txlevel_description"); char *bp = buff; int i; RLEVEL tl = TxLevel(target); for (i = 0; i < mudconf.no_levels; ++i) { if ( (tl & mudconf.reality_level[i].value) == mudconf.reality_level[i].value) { safe_mb_chr(' ', buff, &bp); safe_mb_str(mudconf.reality_level[i].name, buff, &bp); } } // Terminate the string, and return the buffer to the caller. // *bp = '\0'; return buff; } RLEVEL find_rlevel(char *name) { for (int i = 0; i < mudconf.no_levels; i++) { if (mux_stricmp(name, mudconf.reality_level[i].name) == 0) { return mudconf.reality_level[i].value; } } return 0; } void do_rxlevel ( dbref player, dbref cause, dbref enactor, int nargs, int key, char *object, char *arg ) { if (!arg || !*arg) { notify_quiet(player, "I don't know what you want to set!"); return; } // Find thing. // dbref thing = match_controlled(player, object); if (NOTHING == thing) { return; } char lname[9]; RLEVEL ormask = 0; RLEVEL andmask = ~ormask; while (*arg) { int negate = 0; while ( *arg != '\0' && mux_isspace(*arg)) { arg++; } if (*arg == '!') { negate = 1; ++arg; } int i; for (i = 0; *arg && !mux_isspace(*arg); arg++) { if (i < 8) { lname[i++] = *arg; } } lname[i] = '\0'; if (!lname[0]) { if (negate) { notify(player, "You must specify a reality level to clear."); } else { notify(player, "You must specify a reality level to set."); } return; } RLEVEL result = find_rlevel(lname); if (!result) { notify(player, "No such reality level."); continue; } if (negate) { andmask &= ~result; notify(player, "Cleared."); } else { ormask |= result; notify(player, "Set."); } } // Set the Rx Level. // char *buff = alloc_lbuf("do_rxlevel"); mux_sprintf(buff, LBUF_SIZE, "%08X %08X", RxLevel(thing) & andmask | ormask, TxLevel(thing)); atr_add_raw(thing, A_RLEVEL, buff); free_lbuf(buff); } void do_txlevel ( dbref player, dbref cause, dbref enactor, int nargs, int key, char *object, char *arg ) { if (!arg || !*arg) { notify_quiet(player, "I don't know what you want to set!"); return; } // Find thing. // dbref thing = match_controlled(player, object); if (NOTHING == thing) { return; } char lname[9]; RLEVEL ormask = 0; RLEVEL andmask = ~ormask; while (*arg) { int negate = 0; while ( *arg && mux_isspace(*arg)) { arg++; } if (*arg == '!') { negate = 1; ++arg; } int i; for (i = 0; *arg && !mux_isspace(*arg); arg++) { if (i < 8) { lname[i++] = *arg; } } lname[i] = '\0'; if (!lname[0]) { if (negate) { notify(player, "You must specify a reality level to clear."); } else { notify(player, "You must specify a reality level to set."); } return; } RLEVEL result = find_rlevel(lname); if (!result) { notify(player, "No such reality level."); continue; } if (negate) { andmask &= ~result; notify(player, "Cleared."); } else { ormask |= result; notify(player, "Set."); } } // Set the Tx Level. // char *buff = alloc_lbuf("do_rxlevel"); mux_sprintf(buff, LBUF_SIZE, "%08X %08X", RxLevel(thing), TxLevel(thing) & andmask | ormask); atr_add_raw(thing, A_RLEVEL, buff); free_lbuf(buff); } /* * --------------------------------------------------------------------------- * * decompile_rlevels: Produce commands to set reality levels on target. */ void decompile_rlevels(dbref player, dbref thing, char *thingname) { char *buf = rxlevel_description(player, thing); notify(player, tprintf("@rxlevel %s=%s", strip_ansi(thingname), buf)); free_mbuf(buf); buf = txlevel_description(player, thing); notify(player, tprintf("@txlevel %s=%s", strip_ansi(thingname), buf)); free_mbuf(buf); } int *desclist_match(dbref player, dbref thing) { static int descbuffer[33]; descbuffer[0] = 1; RLEVEL match = RxLevel(player) & TxLevel(thing); for (int i = 0; i < mudconf.no_levels; i++) { if ( (match & mudconf.reality_level[i].value) == mudconf.reality_level[i].value) { ATTR *at = atr_str(mudconf.reality_level[i].attr); if (at) { int j; for (j = 1; j < descbuffer[0]; j++) { if (at->number == descbuffer[j]) { break; } } if (j == descbuffer[0]) { descbuffer[descbuffer[0]++] = at->number; } } } } return descbuffer; } /* --------------------------------------------------------------------------- * did_it_rlevel: Have player do something to/with thing, watching the * attributes. 'what' is actually ignored, the desclist match being used * instead. */ void did_it_rlevel ( dbref player, dbref thing, int what, const char *def, int owhat, const char *odef, int awhat, int ctrl_flags, char *args[], int nargs ) { char *d, *buff, *act, *charges, *bp, *str; dbref loc, aowner; int num, aflags; int i, *desclist, found_a_desc; reg_ref **preserve = NULL; bool need_pres = false; // Message to player. // if (what > 0) { // Get description list. // desclist = desclist_match(player, thing); found_a_desc = 0; for (i = 1; i < desclist[0]; i++) { // Ok, if it's A_DESC, we need to check against A_IDESC. // if ( A_IDESC == what && A_DESC == desclist[i]) { d = atr_pget(thing, A_IDESC, &aowner, &aflags); } else { d = atr_pget(thing, desclist[i], &aowner, &aflags); } if (*d) { // No need for the 'def' message. // found_a_desc = 1; if (!need_pres) { need_pres = true; preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); } buff = bp = alloc_lbuf("did_it.1"); str = d; mux_exec(buff, &bp, thing, thing, player, AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_TOP), &str, args, nargs); *bp = '\0'; if ( A_HTDESC == desclist[i] && Html(player)) { safe_str("\r\n", buff, &bp); *bp = '\0'; notify_html(player, buff); } else { notify(player, buff); } free_lbuf(buff); } free_lbuf(d); } if (!found_a_desc) { // No desc found... try the default desc (again). // A_DESC or A_HTDESC... the worst case we look for it twice. // d = atr_pget(thing, what, &aowner, &aflags); if (*d) { // No need for the 'def' message // found_a_desc = 1; if (!need_pres) { need_pres = true; preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); } buff = bp = alloc_lbuf("did_it.1"); str = d; mux_exec(buff, &bp, thing, thing, player, AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_TOP), &str, args, nargs); *bp = '\0'; if ( A_HTDESC == what && Html(player)) { safe_str("\r\n", buff, &bp); *bp = '\0'; notify_html(player, buff); } else { notify(player, buff); } free_lbuf(buff); } else if (def) { notify(player, def); } free_lbuf(d); } } else if ( what < 0 && def) { notify(player, def); } if (isPlayer(thing)) { d = atr_pget(mudconf.master_room, get_atr("ASSET_DESC"), &aowner, &aflags); if (*d) { if (!need_pres) { need_pres = true; preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); } buff = bp = alloc_lbuf("did_it.1"); str = d; mux_exec(buff, &bp, thing, thing, player, AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_TOP), &str, args, nargs); *bp = '\0'; notify(player, buff); free_lbuf(buff); } free_lbuf(d); } // Message to neighbors. // if ( 0 < owhat && Has_location(player) && Good_obj(loc = Location(player))) { d = atr_pget(thing, owhat, &aowner, &aflags); if (*d) { if (!need_pres) { need_pres = true; preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); } buff = bp = alloc_lbuf("did_it.2"); str = d; mux_exec(buff, &bp, thing, thing, player, AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_TOP), &str, args, nargs); *bp = '\0'; if (*buff) { if (aflags & AF_NONAME) { notify_except2_rlevel2(loc, player, player, thing, buff); } else { notify_except2_rlevel2(loc, player, player, thing, tprintf("%s %s", Name(player), buff)); } } free_lbuf(buff); } else if (odef) { if (ctrl_flags & VERB_NONAME) { notify_except2_rlevel2(loc, player, player, thing, odef); } else { notify_except2_rlevel2(loc, player, player, thing, tprintf("%s %s", Name(player), odef)); } } free_lbuf(d); } else if ( owhat < 0 && odef && Has_location(player) && Good_obj(loc = Location(player))) { if (ctrl_flags & VERB_NONAME) { notify_except2_rlevel2(loc, player, player, thing, odef); } else { notify_except2_rlevel2(loc, player, player, thing, tprintf("%s %s", Name(player), odef)); } } // If we preserved the state of the global registers, restore them. // if (need_pres) { restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); } // Do the action attribute. // if ( awhat > 0 && IsReal(thing, player)) { act = atr_pget(thing, awhat, &aowner, &aflags); if (*act != '\0') { charges = atr_pget(thing, A_CHARGES, &aowner, &aflags); if (*charges) { num = mux_atol(charges); if (num > 0) { buff = alloc_sbuf("did_it.charges"); mux_ltoa(num-1, buff); atr_add_raw(thing, A_CHARGES, buff); free_sbuf(buff); } else { buff = atr_pget(thing, A_RUNOUT, &aowner, &aflags); if (*buff != '\0') { free_lbuf(act); act = buff; } else { free_lbuf(act); free_lbuf(buff); free_lbuf(charges); return; } } } free_lbuf(charges); CLinearTimeAbsolute lta; wait_que(thing, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, act, nargs, args, mudstate.global_regs); } free_lbuf(act); } } #endif // REALITY_LVLS mux2.6/src/configure.in0000600000175000017500000002345611025753746015121 0ustar sdennissdennisdnl Process this file with autoconf to produce a configure script. AC_INIT(mudconf.h) AC_CONFIG_HEADER(autoconf.h) AC_MSG_CHECKING(whether to enable Reality Levels) AC_ARG_ENABLE( [realitylvls], AC_HELP_STRING([--enable-realitylvls], [enable Reality Levels (default is NO)]), [ if test "x$enableval" = "xno"; then AC_MSG_RESULT(no) else REALITY_LVLS="-DREALITY_LVLS" LIBS="-lstdc++" REALITY_SRC="levels.cpp" REALITY_OBJ="levels.o" AC_MSG_RESULT(yes) fi ], [ AC_MSG_RESULT(no) ]) AC_SUBST(REALITY_LVLS) AC_SUBST(LIBS) AC_SUBST(REALITY_SRC) AC_SUBST(REALITY_OBJ) AC_MSG_CHECKING(whether to enable WOD Realms) AC_ARG_ENABLE( [wodrealms], AC_HELP_STRING([--enable-wodrealms], [enable WOD Realms (default is NO)]), [ if test "x$enableval" = "xno"; then AC_MSG_RESULT(no) else WOD_REALMS="-DWOD_REALMS" AC_MSG_RESULT(yes) fi ], [ AC_MSG_RESULT(no) ]) AC_SUBST(WOD_REALMS) AC_MSG_CHECKING(whether to enable Memory-Based Database) AC_ARG_ENABLE( [memorybased], AC_HELP_STRING([--enable-memorybased], [enable Memory-Based Database (default is NO)]), [ if test "x$enableval" = "xno"; then AC_MSG_RESULT(no) else MEMORY_BASED="-DMEMORY_BASED" AC_MSG_RESULT(yes) fi ], [ AC_MSG_RESULT(no) ]) AC_SUBST(MEMORY_BASED) AC_MSG_CHECKING(whether to enable Firan MUX) AC_ARG_ENABLE( [firanmux], AC_HELP_STRING([--enable-firanmux], [enable Firan MUX (default is NO)]), [ if test "x$enableval" = "xno"; then AC_MSG_RESULT(no) else FIRANMUX="-DFIRANMUX" FIRANLIBS="-lmysqlclient" AC_MSG_RESULT(yes) fi ], [ AC_MSG_RESULT(no) ]) AC_SUBST(FIRANMUX) AC_SUBST(FIRANLIBS) AC_MSG_CHECKING(whether to enable Firan MUX Conversion) AC_ARG_ENABLE( [firanmuxconvert], AC_HELP_STRING([--enable-firanmuxconvert], [enable Firan MUX Conversion (default is NO)]), [ if test "x$enableval" = "xno"; then AC_MSG_RESULT(no) else FIRANMUX_CONVERT="-DFIRANMUX_CONVERT" AC_MSG_RESULT(yes) fi ], [ AC_MSG_RESULT(no) ]) AC_SUBST(FIRANMUX_CONVERT) AC_MSG_CHECKING(whether to enable deprecated features) AC_ARG_ENABLE( [deprecated], AC_HELP_STRING([--enable-deprecated], [enable deprecated features (default is NO)]), [ if test "x$enableval" = "xno"; then AC_MSG_RESULT(no) else DEPRECATED="-DDEPRECATED" AC_MSG_RESULT(yes) fi ], [ AC_MSG_RESULT(no) ]) AC_SUBST(DEPRECATED) AC_CANONICAL_HOST AC_PROG_CXX AC_PROG_CXXCPP AC_PROG_CC AC_PROG_CPP case "$host" in *irix*) LIBS="-lm" ;; esac AC_ISC_POSIX AC_AIX AC_MINIX AC_HEADER_DIRENT AC_HEADER_STDC AC_HEADER_TIME AC_CHECK_HEADERS(unistd.h memory.h string.h errno.h malloc.h sys/select.h) AC_CHECK_HEADERS(fcntl.h limits.h sys/file.h sys/ioctl.h sys/time.h sys/stat.h) AC_CHECK_HEADERS(fpu_control.h ieeefp.h fenv.h) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECKING(for sys_errlist decl) if test $ac_cv_header_errno_h = no; then AC_DEFINE(NEED_SYS_ERRLIST_DCL) else AC_EGREP_HEADER(sys_errlist,errno.h, ,AC_EGREP_HEADER(sys_errlist,stdio.h,,AC_DEFINE(NEED_SYS_ERRLIST_DCL))) fi AC_CHECK_LIB(crypt, main) AC_FUNC_STRFTIME AC_FUNC_VPRINTF AC_CHECK_FUNCS(setrlimit getrusage srandom) AC_CHECK_FUNCS(getdtablesize socket gethostbyaddr) AC_CHECK_FUNCS(gettimeofday select socket localtime_r) AC_CHECK_FUNCS(getpagesize usleep nanosleep setitimer crypt) AC_EGREP_HEADER(getpagesize,unistd.h,,AC_DEFINE(NEED_GETPAGESIZE_DCL)) if test $ac_cv_header_ieeefp_h = yes; then AC_TRY_COMPILE([ #include ],[ int main(int argc, char *argv[]) { fp_prec_t a = fpgetprec(); fpsetprec(FP_PD); return 0; } ],AC_DEFINE(IEEEFP_H_USEABLE)) fi if test $ac_cv_header_fenv_h = yes; then AC_EGREP_HEADER(fesetprec,fenv.h,AC_DEFINE(HAVE_FESETPREC)) AC_EGREP_HEADER(fegetprec,fenv.h,AC_DEFINE(HAVE_FEGETPREC)) fi AC_TYPE_OFF_T AC_TYPE_PID_T AC_TYPE_SIGNAL AC_TRY_COMPILE([#include ],[struct sigcontext scp;],AC_DEFINE(HAVE_STRUCT_SIGCONTEXT)) AC_HEADER_SYS_WAIT AC_STRUCT_TM AC_STRUCT_TIMEZONE AC_CHECKING(for extended string dcls) AC_EGREP_HEADER(rindex,string.h, ,AC_DEFINE(NEED_INDEX_DCL)) AC_CHECKING(for malloc dcl) querymalloc=no AC_EGREP_HEADER(realloc,stdlib.h,AC_DEFINE(MALLOC_IN_STDLIB_H),querymalloc=yes) if test $ac_cv_header_malloc_h = no && test $querymalloc = yes; then AC_DEFINE(NEED_MALLOC_DCL) else AC_EGREP_HEADER(realloc,malloc.h, ,AC_DEFINE(NEED_MALLOC_DCL)) fi AC_CHECKING(for vsprintf dcl) AC_EGREP_HEADER(vsprintf,stdio.h, ,AC_DEFINE(NEED_VSPRINTF_DCL)) AC_CHECKING(for sprintf dcl) AC_EGREP_HEADER(\ #include #ifndef SIGCHLD #define SIGCHLD SIGCLD #endif int rlev; RETSIGTYPE sighand(int sig, int code) { int stat; if (rlev++ > 2) exit(1); signal(SIGCHLD, sighand); wait(&stat); return; } int main(int argc, char *argv[]) { rlev = 0; signal(SIGCHLD, sighand); if (fork()) { sleep(10); } else { sleep(2); exit(1); } exit(0); } ], ,AC_DEFINE(SIGNAL_SIGCHLD_BRAINDAMAGE),AC_DEFINE(SIGNAL_SIGCHLD_BRAINDAMAGE)) AC_DECL_SYS_SIGLIST AC_MSG_CHECKING(for sys_signame decl) AC_EGREP_HEADER(sys_signame,signal.h,AC_DEFINE(HAVE_SYS_SIGNAME) AC_MSG_RESULT(yes),AC_MSG_RESULT(no)) AC_CHECKING(for IEEE floating-point format) AC_TRY_RUN([ int main(int argc, char *argv[]) { const double d_in = -1e-125; const unsigned long long i64_out = 0xA5FB13AC9AAF4C0Full; union { unsigned long long i64; double d; } u; u.d = d_in; if (u.i64 == i64_out) { return 0; } return 1; } ],AC_DEFINE(HAVE_IEEE_FP_FORMAT),AC_DEFINE(NO_IEEE_FP_FORMAT),AC_DEFINE(NO_IEEE_FP_FORMAT)) AC_CHECKING(for IEEE floating-point exception handling) AC_TRY_RUN([ #include double rZero = 0.0; int main(int argc, char *argv[]) { double d_in; const unsigned long long i64_out = 0x7FF0000000000000ull; union { unsigned long long i64; double d; } u; signal(SIGFPE, SIG_IGN); d_in = 1.0/rZero; u.d = d_in; if (u.i64 == i64_out) { return 0; } return 1; } ],AC_DEFINE(HAVE_IEEE_FP_SNAN),AC_DEFINE(NO_IEEE_FP_SNAN),AC_DEFINE(NO_IEEE_FP_SNAN)) AC_CHECKING(for how division/moduli of negative quotients are handled) AC_TRY_RUN([ int main(int argc, char *argv[]) { int top = -9; int bot = 5; int quotient = top/bot; if (quotient == -1) { return 0; } return 1; } ],AC_DEFINE(SMALLEST_INT_GTE_NEG_QUOTIENT),AC_DEFINE(LARGEST_INT_LTE_NEG_QUOTIENT),AC_DEFINE(LARGEST_INT_LTE_NEG_QUOTIENT)) AC_CHECKING(for getrusage dcl) AC_EGREP_HEADER(getrusage,sys/resource.h, ,AC_DEFINE(NEED_GETRUSAGE_DCL)) AC_CHECKING(for getrlimit dcl) AC_EGREP_HEADER(getrlimit,sys/resource.h, ,AC_DEFINE(NEED_GETRLIMIT_DCL)) AC_C_CONST AC_C_INLINE AC_C_BIGENDIAN(AC_DEFINE(WORDS_BIGENDIAN),AC_DEFINE(WORDS_LITTLEENDIAN),AC_DEFINE(WORDS_UNKNOWN)) AC_CHECK_SIZEOF(short,2) AC_CHECK_SIZEOF(unsigned short,2) AC_CHECK_SIZEOF(int,4) AC_CHECK_SIZEOF(unsigned int,4) AC_CHECK_SIZEOF(long,4) AC_CHECK_SIZEOF(unsigned long,4) AC_CHECKING(whether unaligned 'short' access is permitted) AC_TRY_RUN([ int main(int argc, char *argv[]) { char foo[sizeof(short)+1]; short *ps = (short *)(foo+1); *ps = 0; return 0; } ],AC_DEFINE(CAN_UNALIGN_SHORT)) AC_CHECKING(whether unaligned 'int' access is permitted) AC_TRY_RUN([ int main(int argc, char *argv[]) { char foo[sizeof(int)+1]; int *pi = (int *)(foo+1); *pi = 0; return 0; } ],AC_DEFINE(CAN_UNALIGN_INT)) AC_CHECKING(whether unaligned 'long' access is permitted) AC_TRY_RUN([ int main(int argc, char *argv[]) { char foo[sizeof(long)+1]; long *pl = (long *)(foo+1); *pl = 0; return 0; } ],AC_DEFINE(CAN_UNALIGN_LONG)) AC_CHECKING(whether unaligned 'long long' access is permitted) AC_TRY_RUN([ int main(int argc, char *argv[]) { char foo[sizeof(long long)+1]; long long *pll = (long long *)(foo+1); *pll = 0; return 0; } ],AC_DEFINE(CAN_UNALIGN_LONGLONG)) AC_CHECKING(for pread and pwrite) AC_TRY_RUN([ #include #include #include main() { pwrite(0, "abc", 3, 0); exit(0); }], pwrite_works=yes, pwrite_works=no,) if test $pwrite_works = yes; then AC_DEFINE(HAVE_PREAD) AC_DEFINE(HAVE_PWRITE) fi AC_TRY_COMPILE([#include #include ], [struct linger ling; ling.l_onoff = 1;], AC_DEFINE(HAVE_LINGER)) AC_CHECK_LIB(resolv, main) AC_CHECK_LIB(sun, getpwnam) AC_CHECK_LIB(seq, main) AC_CHECK_LIB(intl, main) AC_CHECK_LIB(nsl, main) if test $ac_cv_func_gethostbyaddr = no; then AC_CHECK_LIB(inet, main) fi if test $ac_cv_func_socket = no; then AC_CHECK_LIB(socket, main) fi AC_CHECK_LIB(m, main) AC_CHECKING(for /dev/urandom) if test -c /dev/urandom; then AC_DEFINE(HAVE_DEV_URANDOM) fi AC_MSG_CHECKING([for in_addr_t]) AC_TRY_COMPILE([#include #if STDC_HEADERS #include #include #endif #if HAVE_NETINET_IN_H #include #endif], [in_addr_t foo;], [AC_DEFINE([HAVE_IN_ADDR_T]) AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)]) AC_SUBST(def_force_c_compiler) AC_OUTPUT(Makefile) mux2.6/src/powers.h0000600000175000017500000001340311025753746014267 0ustar sdennissdennis// powers.h -- Object powers. // // $Id: powers.h 8 2006-09-05 01:55:58Z brazilofmux $ // #include "copyright.h" #ifndef __POWERS_H #define __POWERS_H #define POWER_EXT 0x1 /* Lives in extended powers word */ /* First word of powers */ #define POW_CHG_QUOTAS 0x00000001 /* May change and see quotas */ #define POW_CHOWN_ANY 0x00000002 /* Can @chown anything or to anyone */ #define POW_ANNOUNCE 0x00000004 /* May use @wall */ #define POW_BOOT 0x00000008 /* May use @boot */ #define POW_HALT 0x00000010 /* May @halt on other's objects */ #define POW_CONTROL_ALL 0x00000020 /* I control everything */ #define POW_WIZARD_WHO 0x00000040 /* See extra WHO information */ #define POW_EXAM_ALL 0x00000080 /* I can examine everything */ #define POW_FIND_UNFIND 0x00000100 /* Can find unfindable players */ #define POW_FREE_MONEY 0x00000200 /* I have infinite money */ #define POW_FREE_QUOTA 0x00000400 /* I have infinite quota */ #define POW_HIDE 0x00000800 /* Can set themselves DARK */ #define POW_IDLE 0x00001000 /* No idle limit */ #define POW_SEARCH 0x00002000 /* Can @search anyone */ #define POW_LONGFINGERS 0x00004000 /* Can get/whisper/etc from a distance */ #define POW_PROG 0x00008000 /* Can use the @prog command */ #define POW_SITEADMIN 0x00010000 // Can @shutdown and @restart. /* FREE: 0x00020000 - 0x00040000 */ #define POW_COMM_ALL 0x00080000 /* Channel wiz */ #define POW_SEE_QUEUE 0x00100000 /* Player can see the entire queue */ #define POW_SEE_HIDDEN 0x00200000 /* Player can see hidden players on WHO list */ #define POW_MONITOR 0x00400000 /* Player can set or clear MONITOR */ #define POW_POLL 0x00800000 /* Player can set the doing poll */ #define POW_NO_DESTROY 0x01000000 /* Cannot be destroyed */ #define POW_GUEST 0x02000000 /* Player is a guest */ #define POW_PASS_LOCKS 0x04000000 /* Player can pass any lock */ #define POW_STAT_ANY 0x08000000 /* Can @stat anyone */ #define POW_STEAL 0x10000000 /* Can give negative money */ #define POW_TEL_ANYWHR 0x20000000 /* Teleport anywhere */ #define POW_TEL_UNRST 0x40000000 /* Teleport anything */ #define POW_UNKILLABLE 0x80000000 /* Can't be killed */ /* Second word of powers */ #define POW_BUILDER 0x00000001 /* Can build */ #ifdef FIRANMUX #define POW_IMMUTABLE 0x00000002 /* Can not change */ #endif /* --------------------------------------------------------------------------- * POWERENT: Information about object powers. */ typedef struct power_entry { const char *powername; /* Name of the flag */ int powervalue; /* Which bit in the object is the flag */ int powerpower; /* Ctrl flags for this power (recursive? :-) */ int listperm; /* Who sees this flag when set */ bool (*handler)(dbref target, dbref player, POWER power, int fpowers, bool reset); /* Handler for setting/clearing this flag */ } POWERENT; typedef struct powerset { POWER word1; POWER word2; } POWERSET; extern void init_powertab(void); extern void display_powertab(dbref); extern void power_set(dbref, dbref, char *, int); extern char *powers_list(dbref executor, dbref thing); extern bool has_power(dbref, dbref, char *); extern void decompile_powers(dbref, dbref, char *); extern bool decode_power(dbref player, char *powername, POWERSET *pset); #define s_Guest(c) s_Powers((c), Powers(c) | POW_GUEST) #define Quota(c) (((Powers(c) & POW_CHG_QUOTAS) != 0) || Wizard(c)) #define Chown_Any(c) (((Powers(c) & POW_CHOWN_ANY) != 0) || Wizard(c)) #define Announce(c) (((Powers(c) & POW_ANNOUNCE) != 0) || Wizard(c)) #define Can_Boot(c) (((Powers(c) & POW_BOOT) != 0) || Wizard(c)) #define Can_Halt(c) (((Powers(c) & POW_HALT) != 0) || Wizard(c)) #define Control_All(c) (((Powers(c) & POW_CONTROL_ALL) != 0) || Wizard(c)) #define Wizard_Who(c) (((Powers(c) & POW_WIZARD_WHO) != 0) || WizRoy(c)) #define See_All(c) (((Powers(c) & POW_EXAM_ALL) != 0) || WizRoy(c)) #define Find_Unfindable(c) ((Powers(c) & POW_FIND_UNFIND) != 0) #define Free_Money(c) (((Powers(c) & POW_FREE_MONEY) != 0) || Immortal(c)) #define Free_Quota(c) (((Powers(c) & POW_FREE_QUOTA) != 0) || Wizard(c)) #define Can_Hide(c) (((Powers(c) & POW_HIDE) != 0) || Wizard(c)) #define Can_Idle(c) (((Powers(c) & POW_IDLE) != 0) || Wizard(c)) #define Search(c) (((Powers(c) & POW_SEARCH) != 0) || WizRoy(c)) #define Long_Fingers(c) (((Powers(c) & POW_LONGFINGERS) != 0) || Wizard(c)) #define Comm_All(c) (((Powers(c) & POW_COMM_ALL) != 0) || Wizard(c)) #define See_Queue(c) (((Powers(c) & POW_SEE_QUEUE) != 0) || WizRoy(c)) #define See_Hidden(c) (((Powers(c) & POW_SEE_HIDDEN) != 0) || WizRoy(c)) #define Can_Monitor(c) (((Powers(c) & POW_MONITOR) != 0) || Wizard(c)) #define Can_Poll(c) (((Powers(c) & POW_POLL) != 0) || Wizard(c)) #define No_Destroy(c) (((Powers(c) & POW_NO_DESTROY) != 0) || Wizard(c)) #define Guest(c) ((Powers(c) & POW_GUEST) != 0) #define Stat_Any(c) ((Powers(c) & POW_STAT_ANY) != 0) #define Steal(c) (((Powers(c) & POW_STEAL) != 0) || Wizard(c)) #define Tel_Anywhere(c) (((Powers(c) & POW_TEL_ANYWHR) != 0) || Tel_Anything(c)) #define Tel_Anything(c) (((Powers(c) & POW_TEL_UNRST) != 0) || WizRoy(c)) #define Unkillable(c) (((Powers(c) & POW_UNKILLABLE) != 0) || Immortal(c)) #define Prog(c) (((Powers(c) & POW_PROG) != 0) || Wizard(c)) #define Pass_Locks(c) ((Powers(c) & POW_PASS_LOCKS) != 0) #define Builder(c) (((Powers2(c) & POW_BUILDER) != 0) || WizRoy(c)) #ifdef FIRANMUX #define Immutable(c) ((Powers2(c) & POW_IMMUTABLE) != 0) #endif #define Can_SiteAdmin(c) (((Powers(c) & POW_SITEADMIN) != 0) || Wizard(c)) #endif /* POWERS_H */ mux2.6/src/flags.cpp0000600000175000017500000013063011025753746014401 0ustar sdennissdennis// flags.cpp -- Flag manipulation routines. // // $Id: flags.cpp 2734 2007-10-28 23:02:55Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "command.h" #include "powers.h" #if defined(FIRANMUX) #include "attrs.h" #endif // FIRANMUX #include "ansi.h" /* --------------------------------------------------------------------------- * fh_any: set or clear indicated bit, no security checking */ static bool fh_any(dbref target, dbref player, FLAG flag, int fflags, bool reset) { // Never let God drop his/her own wizbit. // if ( God(target) && reset && flag == WIZARD && fflags == FLAG_WORD1) { notify(player, "You cannot make God mortal."); return false; } // Otherwise we can go do it. // if (reset) { db[target].fs.word[fflags] &= ~flag; } else { db[target].fs.word[fflags] |= flag; } return true; } /* --------------------------------------------------------------------------- * fh_god: only GOD may set or clear the bit */ static bool fh_god(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (!God(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_wiz: only WIZARDS (or GOD) may set or clear the bit */ static bool fh_wiz(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (!Wizard(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_wizroy: only WIZARDS, ROYALTY, (or GOD) may set or clear the bit */ static bool fh_wizroy(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (!WizRoy(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_restrict_player (renamed from fh_fixed): Only Wizards can set * * this on players, but ordinary players can set it on other types * * of objects. */ static bool fh_restrict_player ( dbref target, dbref player, FLAG flag, int fflags, bool reset ) { if ( isPlayer(target) && !Wizard(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* --------------------------------------------------------------------------- * fh_privileged: You can set this flag on a non-player object, if you * yourself have this flag and are a player who owns themselves (i.e., * no robots). Only God can set this on a player. */ static bool fh_privileged ( dbref target, dbref player, FLAG flag, int fflags, bool reset ) { if (!God(player)) { if ( isPlayer(target) #if !defined(FIRANMUX) || !isPlayer(player) || player != Owner(player) #endif // FIRANMUX || (db[player].fs.word[fflags] & flag) == 0) { return false; } } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_inherit: only players may set or clear this bit. */ static bool fh_inherit(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (!Inherits(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_dark_bit: manipulate the dark bit. Nonwizards may not set on players. */ static bool fh_dark_bit(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if ( !reset && isPlayer(target) && !( (target == player) && Can_Hide(player)) && !Wizard(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_going_bit: manipulate the going bit. Non-gods may only clear. */ static bool fh_going_bit(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if ( Going(target) && reset && (Typeof(target) != TYPE_GARBAGE)) { notify(player, "Your object has been spared from destruction."); return (fh_any(target, player, flag, fflags, reset)); } if (!God(player)) { return false; } // Even God should not be allowed set protected dbrefs GOING. // if ( !reset && ( target == 0 || God(target) || target == mudconf.start_home || target == mudconf.start_room || target == mudconf.default_home || target == mudconf.master_room)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* * --------------------------------------------------------------------------- * * fh_hear_bit: set or clear bits that affect hearing. */ static bool fh_hear_bit(dbref target, dbref player, FLAG flag, int fflags, bool reset) { if (isPlayer(target) && (flag & MONITOR)) { if (Can_Monitor(player)) { return (fh_any(target, player, flag, fflags, reset)); } else { return false; } } bool could_hear = Hearer(target); bool result = fh_any(target, player, flag, fflags, reset); handle_ears(target, could_hear, Hearer(target)); return result; } /* --------------------------------------------------------------------------- * fh_player_bit: Can set and reset this on everything but players. */ static bool fh_player_bit ( dbref target, dbref player, FLAG flag, int fflags, bool reset ) { if (isPlayer(target)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } /* --------------------------------------------------------------------------- * fh_staff: only STAFF, WIZARDS, ROYALTY, (or GOD) may set or clear * the bit. */ static bool fh_staff ( dbref target, dbref player, FLAG flag, int fflags, bool reset ) { if (!Staff(player) && !God(player)) { return false; } return (fh_any(target, player, flag, fflags, reset)); } static FLAGBITENT fbeAbode = { ABODE, 'A', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeAnsi = { ANSI, 'X', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeAudible = { HEARTHRU, 'a', FLAG_WORD1, 0, fh_hear_bit}; static FLAGBITENT fbeAuditorium = { AUDITORIUM, 'b', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeBlind = { BLIND, 'B', FLAG_WORD2, 0, fh_wiz}; static FLAGBITENT fbeChownOk = { CHOWN_OK, 'C', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeConnected = { CONNECTED, 'c', FLAG_WORD2, CA_NO_DECOMP, fh_god}; static FLAGBITENT fbeDark = { DARK, 'D', FLAG_WORD1, 0, fh_dark_bit}; static FLAGBITENT fbeDestroyOk = { DESTROY_OK, 'd', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeEnterOk = { ENTER_OK, 'e', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeFixed = { FIXED, 'f', FLAG_WORD2, 0, fh_restrict_player}; static FLAGBITENT fbeFloating = { FLOATING, 'F', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeGagged = { GAGGED, 'j', FLAG_WORD2, 0, fh_wiz}; static FLAGBITENT fbeGoing = { GOING, 'G', FLAG_WORD1, CA_NO_DECOMP, fh_going_bit}; static FLAGBITENT fbeHalted = { HALT, 'h', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeHasDaily = { HAS_DAILY, '*', FLAG_WORD2, CA_GOD|CA_NO_DECOMP, fh_god}; static FLAGBITENT fbeHasForwardList = { HAS_FWDLIST, '&', FLAG_WORD2, CA_GOD|CA_NO_DECOMP, fh_god}; static FLAGBITENT fbeHasListen = { HAS_LISTEN, '@', FLAG_WORD2, CA_GOD|CA_NO_DECOMP, fh_god}; static FLAGBITENT fbeHasStartup = { HAS_STARTUP, '+', FLAG_WORD1, CA_GOD|CA_NO_DECOMP, fh_god}; static FLAGBITENT fbeHaven = { HAVEN, 'H', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeHead = { HEAD_FLAG, '?', FLAG_WORD2, 0, fh_wiz}; static FLAGBITENT fbeHtml = { HTML, '(', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeImmortal = { IMMORTAL, 'i', FLAG_WORD1, 0, fh_wiz}; static FLAGBITENT fbeInherit = { INHERIT, 'I', FLAG_WORD1, 0, fh_inherit}; static FLAGBITENT fbeJumpOk = { JUMP_OK, 'J', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeKeepAlive = { CKEEPALIVE, 'k', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeKey = { KEY, 'K', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeLight = { LIGHT, 'l', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeLinkOk = { LINK_OK, 'L', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeMonitor = { MONITOR, 'M', FLAG_WORD1, 0, fh_hear_bit}; static FLAGBITENT fbeMyopic = { MYOPIC, 'm', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeNoCommand = { NO_COMMAND, 'n', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeNoAccents = { NOACCENTS, '~', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeNoBleed = { NOBLEED, '-', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeNoSpoof = { NOSPOOF, 'N', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeOpaque = { TM_OPAQUE, 'O', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeOpenOk = { OPEN_OK, 'z', FLAG_WORD2, 0, fh_wiz}; static FLAGBITENT fbeParentOk = { PARENT_OK, 'Y', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbePlayerMails = { PLAYER_MAILS, ' ', FLAG_WORD2, CA_GOD|CA_NO_DECOMP, fh_god}; static FLAGBITENT fbePuppet = { PUPPET, 'p', FLAG_WORD1, 0, fh_hear_bit}; static FLAGBITENT fbeQuiet = { QUIET, 'Q', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeRobot = { ROBOT, 'r', FLAG_WORD1, 0, fh_player_bit}; static FLAGBITENT fbeRoyalty = { ROYALTY, 'Z', FLAG_WORD1, 0, fh_wiz}; static FLAGBITENT fbeSafe = { SAFE, 's', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeSlave = { SLAVE, 'x', FLAG_WORD2, CA_WIZARD, fh_wiz}; static FLAGBITENT fbeStaff = { STAFF, 'w', FLAG_WORD2, 0, fh_wiz}; static FLAGBITENT fbeSticky = { STICKY, 'S', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeSuspect = { SUSPECT, 'u', FLAG_WORD2, CA_WIZARD, fh_wiz}; static FLAGBITENT fbeTerse = { TERSE, 'q', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeTrace = { TRACE, 'T', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeTransparent = { SEETHRU, 't', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeUnfindable = { UNFINDABLE, 'U', FLAG_WORD2, 0, fh_any}; static FLAGBITENT fbeUninspected = { UNINSPECTED, 'g', FLAG_WORD2, 0, fh_wizroy}; static FLAGBITENT fbeVacation = { VACATION, '|', FLAG_WORD2, 0, fh_restrict_player}; static FLAGBITENT fbeVerbose = { VERBOSE, 'v', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeVisual = { VISUAL, 'V', FLAG_WORD1, 0, fh_any}; static FLAGBITENT fbeWizard = { WIZARD, 'W', FLAG_WORD1, 0, fh_god}; static FLAGBITENT fbeSitemon = { SITEMON, '$', FLAG_WORD3, 0, fh_wiz}; #ifdef WOD_REALMS static FLAGBITENT fbeFae = { FAE, '0', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeChimera = { CHIMERA, '1', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbePeering = { PEERING, '2', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeUmbra = { UMBRA, '3', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeShroud = { SHROUD, '4', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeMatrix = { MATRIX, '5', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeObf = { OBF, '6', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeHss = { HSS, '7', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeMedium = { MEDIUM, '8', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeDead = { DEAD, '9', FLAG_WORD3, CA_STAFF, fh_wizroy}; static FLAGBITENT fbeMarker0 = { MARK_0, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker1 = { MARK_1, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker2 = { MARK_2, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker3 = { MARK_3, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker4 = { MARK_4, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker5 = { MARK_5, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker6 = { MARK_6, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker7 = { MARK_7, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker8 = { MARK_8, ' ', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker9 = { MARK_9, ' ', FLAG_WORD3, 0, fh_god}; #else // WOD_REALMS static FLAGBITENT fbeMarker0 = { MARK_0, '0', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker1 = { MARK_1, '1', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker2 = { MARK_2, '2', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker3 = { MARK_3, '3', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker4 = { MARK_4, '4', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker5 = { MARK_5, '5', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker6 = { MARK_6, '6', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker7 = { MARK_7, '7', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker8 = { MARK_8, '8', FLAG_WORD3, 0, fh_god}; static FLAGBITENT fbeMarker9 = { MARK_9, '9', FLAG_WORD3, 0, fh_god}; #endif // WOD_REALMS #if defined(FIRANMUX) static FLAGBITENT fbeImmobile = { IMMOBILE, '#', FLAG_WORD3, 0, fh_wiz}; static FLAGBITENT fbeLineWrap = { LINEWRAP, '>', FLAG_WORD3, 0, fh_any}; static FLAGBITENT fbeQuell = { QUELL, ' ', FLAG_WORD3, 0, fh_inherit}; static FLAGBITENT fbeRestricted = { RESTRICTED, '!', FLAG_WORD3, CA_WIZARD, fh_wiz}; static FLAGBITENT fbeParent = { PARENT, '+', FLAG_WORD3, 0, fh_any}; #endif // FIRANMUX FLAGNAMEENT gen_flag_names[] = { {"ABODE", true, &fbeAbode }, {"ACCENTS", false, &fbeNoAccents }, {"ANSI", true, &fbeAnsi }, {"AUDIBLE", true, &fbeAudible }, {"AUDITORIUM", true, &fbeAuditorium }, {"BLEED", false, &fbeNoBleed }, {"BLIND", true, &fbeBlind }, {"COMMANDS", false, &fbeNoCommand }, {"CHOWN_OK", true, &fbeChownOk }, {"CONNECTED", true, &fbeConnected }, {"DARK", true, &fbeDark }, {"DESTROY_OK", true, &fbeDestroyOk }, {"ENTER_OK", true, &fbeEnterOk }, {"FIXED", true, &fbeFixed }, {"FLOATING", true, &fbeFloating }, {"GAGGED", true, &fbeGagged }, {"GOING", true, &fbeGoing }, {"HALTED", true, &fbeHalted }, {"HAS_DAILY", true, &fbeHasDaily }, {"HAS_FORWARDLIST", true, &fbeHasForwardList }, {"HAS_LISTEN", true, &fbeHasListen }, {"HAS_STARTUP", true, &fbeHasStartup }, {"HAVEN", true, &fbeHaven }, {"HEAD", true, &fbeHead }, {"HTML", true, &fbeHtml }, {"IMMORTAL", true, &fbeImmortal }, {"INHERIT", true, &fbeInherit }, {"JUMP_OK", true, &fbeJumpOk }, {"KEEPALIVE", true, &fbeKeepAlive }, {"KEY", true, &fbeKey }, {"LIGHT", true, &fbeLight }, {"LINK_OK", true, &fbeLinkOk }, {"MARKER0", true, &fbeMarker0 }, {"MARKER1", true, &fbeMarker1 }, {"MARKER2", true, &fbeMarker2 }, {"MARKER3", true, &fbeMarker3 }, {"MARKER4", true, &fbeMarker4 }, {"MARKER5", true, &fbeMarker5 }, {"MARKER6", true, &fbeMarker6 }, {"MARKER7", true, &fbeMarker7 }, {"MARKER8", true, &fbeMarker8 }, {"MARKER9", true, &fbeMarker9 }, {"MONITOR", true, &fbeMonitor }, {"MYOPIC", true, &fbeMyopic }, {"NO_COMMAND", true, &fbeNoCommand }, {"NOACCENTS", true, &fbeNoAccents }, {"NOBLEED", true, &fbeNoBleed }, {"NOSPOOF", true, &fbeNoSpoof }, {"OPAQUE", true, &fbeOpaque }, {"OPEN_OK", true, &fbeOpenOk }, {"PARENT_OK", true, &fbeParentOk }, {"PLAYER_MAILS", true, &fbePlayerMails }, {"PUPPET", true, &fbePuppet }, {"QUIET", true, &fbeQuiet }, {"ROBOT", true, &fbeRobot }, {"ROYALTY", true, &fbeRoyalty }, {"SAFE", true, &fbeSafe }, {"SITEMON", true, &fbeSitemon }, {"SLAVE", true, &fbeSlave }, {"SPOOF", false, &fbeNoSpoof }, {"STAFF", true, &fbeStaff }, {"STICKY", true, &fbeSticky }, {"SUSPECT", true, &fbeSuspect }, {"TERSE", true, &fbeTerse }, {"TRACE", true, &fbeTrace }, {"TRANSPARENT", true, &fbeTransparent }, {"UNFINDABLE", true, &fbeUnfindable }, {"UNINSPECTED", true, &fbeUninspected }, {"VACATION", true, &fbeVacation }, {"VERBOSE", true, &fbeVerbose }, {"VISUAL", true, &fbeVisual }, {"WIZARD", true, &fbeWizard }, #ifdef WOD_REALMS {"FAE", true, &fbeFae }, {"CHIMERA", true, &fbeChimera }, {"PEERING", true, &fbePeering }, {"UMBRA", true, &fbeUmbra }, {"SHROUD", true, &fbeShroud }, {"MATRIX", true, &fbeMatrix }, {"OBF", true, &fbeObf }, {"HSS", true, &fbeHss }, {"MEDIUM", true, &fbeMedium }, {"DEAD", true, &fbeDead }, #endif // WOD_REALMS #if defined(FIRANMUX) {"IMMOBILE", true, &fbeImmobile }, {"LINEWRAP", true, &fbeLineWrap }, {"QUELL", true, &fbeQuell }, {"RESTRICTED", true, &fbeRestricted }, {"PARENT", true, &fbeParent }, #endif // FIRANMUX {NULL, false, NULL} }; OBJENT object_types[8] = { {"ROOM", 'R', CA_PUBLIC, OF_CONTENTS|OF_EXITS|OF_DROPTO|OF_HOME}, {"THING", ' ', CA_PUBLIC, OF_CONTENTS|OF_LOCATION|OF_EXITS|OF_HOME|OF_SIBLINGS}, {"EXIT", 'E', CA_PUBLIC, OF_SIBLINGS}, {"PLAYER", 'P', CA_PUBLIC, OF_CONTENTS|OF_LOCATION|OF_EXITS|OF_HOME|OF_OWNER|OF_SIBLINGS}, {"TYPE5", '+', CA_GOD, 0}, {"GARBAGE", '-', CA_PUBLIC, OF_CONTENTS|OF_LOCATION|OF_EXITS|OF_HOME|OF_SIBLINGS}, {"GARBAGE", '#', CA_GOD, 0}, {"GARBAGE", '=', CA_GOD, 0} }; /* --------------------------------------------------------------------------- * init_flagtab: initialize flag hash tables. */ void init_flagtab(void) { char *nbuf = alloc_sbuf("init_flagtab"); for (FLAGNAMEENT *fp = gen_flag_names; fp->pOrigName; fp++) { fp->flagname = (char *)fp->pOrigName; mux_strncpy(nbuf, fp->pOrigName, SBUF_SIZE-1); mux_strlwr(nbuf); if (!hashfindLEN(nbuf, strlen(nbuf), &mudstate.flags_htab)) { hashaddLEN(nbuf, strlen(nbuf), fp, &mudstate.flags_htab); } } free_sbuf(nbuf); } /* --------------------------------------------------------------------------- * display_flags: display available flags. */ void display_flagtab(dbref player) { char *buf, *bp; FLAGNAMEENT *fp; bp = buf = alloc_lbuf("display_flagtab"); safe_str("Flags:", buf, &bp); for (fp = gen_flag_names; fp->flagname; fp++) { FLAGBITENT *fbe = fp->fbe; if ( ( (fbe->listperm & CA_WIZARD) && !Wizard(player)) || ( (fbe->listperm & CA_GOD) && !God(player))) { continue; } safe_chr(' ', buf, &bp); safe_str(fp->flagname, buf, &bp); if (fbe->flaglett != ' ') { safe_chr('(', buf, &bp); if (!fp->bPositive) { safe_chr('!', buf, &bp); } safe_chr(fbe->flaglett, buf, &bp); safe_chr(')', buf, &bp); } } *bp = '\0'; notify(player, buf); free_lbuf(buf); } char *MakeCanonicalFlagName ( const char *pName, int *pnName, bool *pbValid ) { static char buff[SBUF_SIZE]; char *p = buff; int nName = 0; while (*pName && nName < SBUF_SIZE) { *p = mux_tolower(*pName); p++; pName++; nName++; } *p = '\0'; if ( 0 < nName && nName < SBUF_SIZE) { *pnName = nName; *pbValid = true; return buff; } else { *pnName = 0; *pbValid = false; return NULL; } } static FLAGNAMEENT *find_flag(const char *flagname) { // Convert flagname to canonical lowercase format. // int nName; bool bValid; char *pName = MakeCanonicalFlagName(flagname, &nName, &bValid); FLAGNAMEENT *fe = NULL; if (bValid) { fe = (FLAGNAMEENT *)hashfindLEN(pName, nName, &mudstate.flags_htab); } return fe; } // --------------------------------------------------------------------------- // flag_set: Set or clear a specified flag on an object. // void flag_set(dbref target, dbref player, char *flag, int key) { bool bDone = false; do { // Trim spaces, and handle the negation character. // while (mux_isspace(*flag)) { flag++; } bool bNegate = false; if (*flag == '!') { bNegate = true; do { flag++; } while (mux_isspace(*flag)); } // Beginning of flag name is now 'flag'. // char *nflag = flag; while ( *nflag != '\0' && !mux_isspace(*nflag)) { nflag++; } if (*nflag == '\0') { bDone = true; } else { *nflag = '\0'; } // Make sure a flag name was specified. // if (*flag == '\0') { if (bNegate) { notify(player, "You must specify a flag to clear."); } else { notify(player, "You must specify a flag to set."); } } else { FLAGNAMEENT *fp = find_flag(flag); if (!fp) { notify(player, "I do not understand that flag."); } else { FLAGBITENT *fbe = fp->fbe; bool bClearSet = bNegate; if (!fp->bPositive) { bNegate = !bNegate; } // Invoke the flag handler, and print feedback. // if (!fbe->handler(target, player, fbe->flagvalue, fbe->flagflag, bNegate)) { notify(player, NOPERM_MESSAGE); } else if (!(key & SET_QUIET) && !Quiet(player)) { notify(player, (bClearSet ? "Cleared." : "Set.")); } } } flag = nflag + 1; } while (!bDone); } /* * --------------------------------------------------------------------------- * * decode_flags: converts a flags word into corresponding letters. */ char *decode_flags(dbref player, FLAGSET *fs) { char *buf, *bp; buf = bp = alloc_sbuf("decode_flags"); *bp = '\0'; if (!Good_obj(player)) { mux_strncpy(buf, "#-2 ERROR", SBUF_SIZE-1); return buf; } int flagtype = fs->word[FLAG_WORD1] & TYPE_MASK; bool bNeedColon = true; if (object_types[flagtype].lett != ' ') { safe_sb_chr(object_types[flagtype].lett, buf, &bp); bNeedColon = false; } FLAGNAMEENT *fp; for (fp = gen_flag_names; fp->flagname; fp++) { FLAGBITENT *fbe = fp->fbe; if ( !fp->bPositive || fbe->flaglett == ' ') { // Only look at positive-sense entries that have non-space flag // letters. // continue; } if (fs->word[fbe->flagflag] & fbe->flagvalue) { if ( ( (fbe->listperm & CA_STAFF) && !Staff(player)) || ( (fbe->listperm & CA_ADMIN) && !WizRoy(player)) || ( (fbe->listperm & CA_WIZARD) && !Wizard(player)) || ( (fbe->listperm & CA_GOD) && !God(player))) { continue; } // Don't show CONNECT on dark wizards to mortals // if ( flagtype == TYPE_PLAYER && fbe->flagflag == FLAG_WORD2 && fbe->flagvalue == CONNECTED && (fs->word[FLAG_WORD1] & (WIZARD | DARK)) == (WIZARD | DARK) && !See_Hidden(player)) { continue; } if ( bNeedColon && mux_isdigit(fbe->flaglett)) { // We can't allow numerical digits at the beginning. // safe_sb_chr(':', buf, &bp); } safe_sb_chr(fbe->flaglett, buf, &bp); bNeedColon = false; } } *bp = '\0'; return buf; } /* * --------------------------------------------------------------------------- * * has_flag: does object have flag visible to player? */ bool has_flag(dbref player, dbref it, const char *flagname) { FLAGNAMEENT *fp = find_flag(flagname); if (!fp) { return false; } FLAGBITENT *fbe = fp->fbe; if ( ( fp->bPositive && (db[it].fs.word[fbe->flagflag] & fbe->flagvalue)) || ( !fp->bPositive && (db[it].fs.word[fbe->flagflag] & fbe->flagvalue) == 0)) { if ( ( (fbe->listperm & CA_STAFF) && !Staff(player)) || ( (fbe->listperm & CA_ADMIN) && !WizRoy(player)) || ( (fbe->listperm & CA_WIZARD) && !Wizard(player)) || ( (fbe->listperm & CA_GOD) && !God(player))) { return false; } // Don't show CONNECT on dark wizards to mortals // if ( isPlayer(it) && (fbe->flagvalue == CONNECTED) && (fbe->flagflag == FLAG_WORD2) && Hidden(it) && !See_Hidden(player)) { return false; } return true; } return false; } /* * --------------------------------------------------------------------------- * * flag_description: Return an mbuf containing the type and flags on thing. */ char *flag_description(dbref player, dbref target) { // Allocate the return buffer. // int otype = Typeof(target); char *buff = alloc_mbuf("flag_description"); char *bp = buff; // Store the header strings and object type. // safe_mb_str("Type: ", buff, &bp); safe_mb_str(object_types[otype].name, buff, &bp); safe_mb_str(" Flags:", buff, &bp); if (object_types[otype].perm != CA_PUBLIC) { *bp = '\0'; return buff; } // Store the type-invariant flags. // FLAGNAMEENT *fp; for (fp = gen_flag_names; fp->flagname; fp++) { if (!fp->bPositive) { continue; } FLAGBITENT *fbe = fp->fbe; if (db[target].fs.word[fbe->flagflag] & fbe->flagvalue) { if ( ( (fbe->listperm & CA_STAFF) && !Staff(player)) || ( (fbe->listperm & CA_ADMIN) && !WizRoy(player)) || ( (fbe->listperm & CA_WIZARD) && !Wizard(player)) || ( (fbe->listperm & CA_GOD) && !God(player))) { continue; } // Don't show CONNECT on dark wizards to mortals. // if ( isPlayer(target) && (fbe->flagvalue == CONNECTED) && (fbe->flagflag == FLAG_WORD2) && Hidden(target) && !See_Hidden(player)) { continue; } safe_mb_chr(' ', buff, &bp); safe_mb_str(fp->flagname, buff, &bp); } } // Terminate the string, and return the buffer to the caller. // *bp = '\0'; return buff; } /* * --------------------------------------------------------------------------- * * Return an lbuf containing the name and number of an object */ char *unparse_object_numonly(dbref target) { char *buf = alloc_lbuf("unparse_object_numonly"); if (target < 0) { mux_strncpy(buf, aszSpecialDBRefNames[-target], LBUF_SIZE-1); } else if (!Good_obj(target)) { mux_sprintf(buf, LBUF_SIZE, "*ILLEGAL*(#%d)", target); } else { // Leave 100 bytes on the end for the dbref. // size_t vw; size_t nLen = ANSI_TruncateToField(Name(target), LBUF_SIZE-100, buf, LBUF_SIZE, &vw, ANSI_ENDGOAL_NORMAL); char *bp = buf + nLen; safe_str("(#", buf, &bp); safe_ltoa(target, buf, &bp); safe_chr(')', buf, &bp); *bp = '\0'; } return buf; } #if defined(FIRANMUX) static bool AcquireColor(dbref player, dbref target, char SimplifiedCodes[8]) { int aflags; dbref aowner; // Get the value of the object's '@color' attribute (or on a parent). // char *color_attr = alloc_lbuf("AcquireColor.1"); atr_pget_str(color_attr, target, A_COLOR, &aowner, &aflags); if ('\0' == color_attr[0]) { free_lbuf(color_attr); return false; } else { char *AnsiCodes = alloc_lbuf("AcquireColor.2"); char *ac = AnsiCodes; char *cp = color_attr; mux_exec(AnsiCodes, &ac, player, target, target, AttrTrace(aflags, EV_EVAL|EV_TOP|EV_FCHECK), &cp, NULL, 0); *ac = '\0'; free_lbuf(color_attr); SimplifyColorLetters(SimplifiedCodes, AnsiCodes); free_lbuf(AnsiCodes); return true; } } #endif // FIRANMUX /* * --------------------------------------------------------------------------- * * Return an lbuf pointing to the object name and possibly the db# and flags */ char *unparse_object(dbref player, dbref target, bool obey_myopic, bool bAddColor) { char *buf = alloc_lbuf("unparse_object"); if (NOPERM <= target && target < 0) { mux_strncpy(buf, aszSpecialDBRefNames[-target], LBUF_SIZE-1); } else if (!Good_obj(target)) { mux_sprintf(buf, LBUF_SIZE, "*ILLEGAL*(#%d)", target); } else { bool exam; if (obey_myopic) { exam = MyopicExam(player, target); } else { exam = Examinable(player, target); } // Leave and extra 100 bytes for the dbref and flags at the end and // color at the beginning if necessary.. // size_t vw; size_t nLen = ANSI_TruncateToField(Moniker(target), LBUF_SIZE-100, buf, LBUF_SIZE, &vw, ANSI_ENDGOAL_NORMAL); char *bp = buf + nLen; #if defined(FIRANMUX) if ( vw == nLen && bAddColor) { // There is no color in the name, so look for @color, or highlight. // char *buf2 = alloc_lbuf("unparse_object.color"); char *bp2 = buf2; char SimplifiedCodes[8]; if (AcquireColor(player, target, SimplifiedCodes)) { for (int i = 0; SimplifiedCodes[i]; i++) { const char *pColor = ColorTable[(unsigned char)SimplifiedCodes[i]]; if (pColor) { safe_str(pColor, buf2, &bp2); } } } else { safe_str(ANSI_HILITE, buf2, &bp2); } *bp = '\0'; safe_str(buf, buf2, &bp2); safe_str(ANSI_NORMAL, buf2, &bp2); // Swap buffers. // free_lbuf(buf); buf = buf2; bp = bp2; } #else UNUSED_PARAMETER(bAddColor); #endif // FIRANMUX if ( exam || (Flags(target) & (CHOWN_OK | JUMP_OK | LINK_OK | DESTROY_OK)) || (Flags2(target) & ABODE)) { // Show everything. // char *fp = decode_flags(player, &(db[target].fs)); safe_str("(#", buf, &bp); safe_ltoa(target, buf, &bp); safe_str(fp, buf, &bp); safe_chr(')', buf, &bp); free_sbuf(fp); } *bp = '\0'; } return buf; } /* --------------------------------------------------------------------------- * cf_flag_access: Modify who can set a flag. */ CF_HAND(cf_flag_access) { UNUSED_PARAMETER(vp); UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t=,"); char *fstr = mux_strtok_parse(&tts); char *permstr = mux_strtok_parse(&tts); if ( NULL == fstr || '\0' == fstr[0] || NULL == permstr || '\0' == permstr[0]) { return -1; } FLAGNAMEENT *fp; if ((fp = find_flag(fstr)) == NULL) { cf_log_notfound(player, cmd, "No such flag", fstr); return -1; } FLAGBITENT *fbe = fp->fbe; // Don't change the handlers on special things. // if ( (fbe->handler != fh_any) && (fbe->handler != fh_wizroy) && (fbe->handler != fh_wiz) && (fbe->handler != fh_god) && (fbe->handler != fh_restrict_player) && (fbe->handler != fh_privileged)) { STARTLOG(LOG_CONFIGMODS, "CFG", "PERM"); log_text("Cannot change access for flag: "); log_text(fp->flagname); ENDLOG; return -1; } if (!strcmp(permstr, "any")) { fbe->handler = fh_any; } else if (!strcmp(permstr, "royalty")) { fbe->handler = fh_wizroy; } else if (!strcmp(permstr, "wizard")) { fbe->handler = fh_wiz; } else if (!strcmp(permstr, "god")) { fbe->handler = fh_god; } else if (!strcmp(permstr, "restrict_player")) { fbe->handler = fh_restrict_player; } else if (!strcmp(permstr, "privileged")) { fbe->handler = fh_privileged; } else if (!strcmp(permstr, "staff")) { fbe->handler = fh_staff; } else { cf_log_notfound(player, cmd, "Flag access", permstr); return -1; } return 0; } /* * --------------------------------------------------------------------------- * * convert_flags: convert a list of flag letters into its bit pattern. * * Also set the type qualifier if specified and not already set. */ bool convert_flags(dbref player, char *flaglist, FLAGSET *fset, FLAG *p_type) { FLAG type = NOTYPE; FLAGSET flagmask; memset(&flagmask, 0, sizeof(flagmask)); int i; char *s; bool handled; for (s = flaglist; *s; s++) { handled = false; // Check for object type. // for (i = 0; i <= 7 && !handled; i++) { if ( object_types[i].lett == *s && !( ( (object_types[i].perm & CA_STAFF) && !Staff(player)) || ( (object_types[i].perm & CA_ADMIN) && !WizRoy(player)) || ( (object_types[i].perm & CA_WIZARD) && !Wizard(player)) || ( (object_types[i].perm & CA_GOD) && !God(player)))) { if ( type != NOTYPE && type != i) { char *p = tprintf("%c: Conflicting type specifications.", *s); notify(player, p); return false; } type = i; handled = true; } } // Check generic flags. // if (handled) { continue; } FLAGNAMEENT *fp; for (fp = gen_flag_names; fp->flagname && !handled; fp++) { FLAGBITENT *fbe = fp->fbe; if ( !fp->bPositive || fbe->flaglett == ' ') { continue; } if ( fbe->flaglett == *s && !( ( (fbe->listperm & CA_STAFF) && !Staff(player)) || ( (fbe->listperm & CA_ADMIN) && !WizRoy(player)) || ( (fbe->listperm & CA_WIZARD) && !Wizard(player)) || ( (fbe->listperm & CA_GOD) && !God(player)))) { flagmask.word[fbe->flagflag] |= fbe->flagvalue; handled = true; } } if (!handled) { notify(player, tprintf("%c: Flag unknown or not valid for specified object type", *s)); return false; } } // Return flags to search for and type. // *fset = flagmask; *p_type = type; return true; } /* * --------------------------------------------------------------------------- * * decompile_flags: Produce commands to set flags on target. */ void decompile_flags(dbref player, dbref thing, char *thingname) { // Report generic flags. // FLAGNAMEENT *fp; for (fp = gen_flag_names; fp->flagname; fp++) { FLAGBITENT *fbe = fp->fbe; // Only handle positive-sense entries. // Skip if we shouldn't decompile this flag. // Skip if this flag isn't set. // Skip if we can't see this flag. // if ( !fp->bPositive || (fbe->listperm & CA_NO_DECOMP) || (db[thing].fs.word[fbe->flagflag] & fbe->flagvalue) == 0 || !check_access(player, fbe->listperm)) { continue; } // Report this flag. // notify(player, tprintf("@set %s=%s", strip_ansi(thingname), fp->flagname)); } } // do_flag: Rename flags or remove flag aliases. // Based on RhostMUSH code. // static bool flag_rename(char *alias, char *newname) { int nAlias; bool bValidAlias; char *pCheckedAlias = MakeCanonicalFlagName(alias, &nAlias, &bValidAlias); if (!bValidAlias) { return false; } char *pAlias = alloc_sbuf("flag_rename.old"); memcpy(pAlias, pCheckedAlias, nAlias+1); int nNewName; bool bValidNewName; char *pCheckedNewName = MakeCanonicalFlagName(newname, &nNewName, &bValidNewName); if (!bValidNewName) { free_sbuf(pAlias); return false; } char *pNewName = alloc_sbuf("flag_rename.new"); memcpy(pNewName, pCheckedNewName, nNewName+1); FLAGNAMEENT *flag1; flag1 = (FLAGNAMEENT *)hashfindLEN(pAlias, nAlias, &mudstate.flags_htab); if (flag1 != NULL) { FLAGNAMEENT *flag2; flag2 = (FLAGNAMEENT *)hashfindLEN(pNewName, nNewName, &mudstate.flags_htab); if (flag2 == NULL) { hashaddLEN(pNewName, nNewName, flag1, &mudstate.flags_htab); if (flag1->flagname != flag1->pOrigName) { MEMFREE(flag1->flagname); } flag1->flagname = StringCloneLen(pNewName, nNewName); mux_strupr(flag1->flagname); free_sbuf(pAlias); free_sbuf(pNewName); return true; } } free_sbuf(pAlias); free_sbuf(pNewName); return false; } void do_flag(dbref executor, dbref caller, dbref enactor, int key, int nargs, char *flag1, char *flag2) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); if (key & FLAG_REMOVE) { if (nargs == 2) { notify(executor, "Extra argument ignored."); } int nAlias; bool bValidAlias; char *pCheckedAlias = MakeCanonicalFlagName(flag1, &nAlias, &bValidAlias); if (bValidAlias) { FLAGNAMEENT *lookup; lookup = (FLAGNAMEENT *)hashfindLEN(pCheckedAlias, nAlias, &mudstate.flags_htab); if (lookup) { if ( lookup->flagname != lookup->pOrigName && mux_stricmp(lookup->flagname, pCheckedAlias) == 0) { MEMFREE(lookup->flagname); lookup->flagname = (char *)lookup->pOrigName; hashdeleteLEN(pCheckedAlias, nAlias, &mudstate.flags_htab); notify(executor, tprintf("Flag name '%s' removed from the hash table.", pCheckedAlias)); } else { notify(executor, "Error: You can't remove the present flag name from the hash table."); } } } } else { if (nargs < 2) { notify(executor, "You must specify a flag and a name."); return; } if (flag_rename(flag1, flag2)) { notify(executor, "Flag name changed."); } else { notify(executor, "Error: Bad flagname given or flag not found."); } } } /* --------------------------------------------------------------------------- * cf_flag_name: Rename a flag. Counterpart to @flag. */ CF_HAND(cf_flag_name) { UNUSED_PARAMETER(vp); UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); UNUSED_PARAMETER(player); UNUSED_PARAMETER(cmd); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t=,"); char *flagstr = mux_strtok_parse(&tts); char *namestr = mux_strtok_parse(&tts); if ( !flagstr || !*flagstr || !namestr || !*namestr) { return -1; } if (flag_rename(flagstr, namestr)) { return 0; } else { return -1; } } mux2.6/src/stringutil.h0000600000175000017500000002267511025753746015167 0ustar sdennissdennis// stringutil.h -- string utilities. // // $Id: stringutil.h 3051 2007-12-30 06:36:17Z brazilofmux $ // #ifndef STRINGUTIL_H #define STRINGUTIL_H extern const bool mux_isprint[256]; extern const bool mux_isdigit[256]; extern const bool mux_isxdigit[256]; extern const bool mux_isazAZ[256]; extern const bool mux_isalpha[256]; extern const bool mux_isalnum[256]; extern const bool mux_islower[256]; extern const bool mux_isupper[256]; extern const bool mux_isspace[256]; extern bool mux_AttrNameInitialSet[256]; extern bool mux_AttrNameSet[256]; extern const bool mux_ObjectNameSet[256]; extern bool mux_PlayerNameSet[256]; extern const bool mux_issecure[256]; extern const bool mux_isescape[256]; extern const unsigned char mux_hex2dec[256]; extern const unsigned char mux_toupper[256]; extern const unsigned char mux_tolower[256]; extern const unsigned char mux_StripAccents[256]; #define mux_isprint(x) (mux_isprint[(unsigned char)(x)]) #define mux_isdigit(x) (mux_isdigit[(unsigned char)(x)]) #define mux_isxdigit(x)(mux_isxdigit[(unsigned char)(x)]) #define mux_isazAZ(x) (mux_isazAZ[(unsigned char)(x)]) #define mux_isalpha(x) (mux_isalpha[(unsigned char)(x)]) #define mux_isalnum(x) (mux_isalnum[(unsigned char)(x)]) #define mux_islower(x) (mux_islower[(unsigned char)(x)]) #define mux_isupper(x) (mux_isupper[(unsigned char)(x)]) #define mux_isspace(x) (mux_isspace[(unsigned char)(x)]) #define mux_hex2dec(x) (mux_hex2dec[(unsigned char)(x)]) #define mux_toupper(x) (mux_toupper[(unsigned char)(x)]) #define mux_tolower(x) (mux_tolower[(unsigned char)(x)]) #define mux_AttrNameInitialSet(x) (mux_AttrNameInitialSet[(unsigned char)(x)]) #define mux_AttrNameSet(x) (mux_AttrNameSet[(unsigned char)(x)]) #define mux_ObjectNameSet(x) (mux_ObjectNameSet[(unsigned char)(x)]) #define mux_PlayerNameSet(x) (mux_PlayerNameSet[(unsigned char)(x)]) #define mux_issecure(x) (mux_issecure[(unsigned char)(x)]) #define mux_isescape(x) (mux_isescape[(unsigned char)(x)]) #define mux_StripAccents(x) (mux_StripAccents[(unsigned char)(x)]) #define UTF8_SIZE1 1 #define UTF8_SIZE2 2 #define UTF8_SIZE3 3 #define UTF8_SIZE4 4 #define UTF8_CONTINUE 5 #define UTF8_ILLEGAL 6 extern const unsigned char utf8_FirstByte[256]; #define utf8_NextCodePoint(x) (x + utf8_FirstByte[(unsigned char)*x]) int ANSI_lex(size_t nString, const char *pString, size_t *nLengthToken0, size_t *nLengthToken1); #define TOKEN_TEXT_ANSI 0 // Text sequence + optional ANSI sequence. #define TOKEN_ANSI 1 // ANSI sequence. // utf/tr_Color.txt // // 517 code points. // 5 states, 13 columns, 321 bytes // #define TR_COLOR_START_STATE (0) #define TR_COLOR_ACCEPTING_STATES_START (5) extern const unsigned char tr_color_itt[256]; extern const unsigned char tr_color_stt[5][13]; inline int mux_color(const unsigned char *p) { int iState = TR_COLOR_START_STATE; do { unsigned char ch = *p++; iState = tr_color_stt[iState][tr_color_itt[(unsigned char)ch]]; } while (iState < TR_COLOR_ACCEPTING_STATES_START); return iState - TR_COLOR_ACCEPTING_STATES_START; } #define COLOR_NOTCOLOR 0 // utf/tr_utf8_latin1.txt // // 1596 code points. // 74 states, 191 columns, 28524 bytes // #define TR_LATIN1_START_STATE (0) #define TR_LATIN1_ACCEPTING_STATES_START (74) extern const unsigned char tr_latin1_itt[256]; extern const unsigned short tr_latin1_stt[74][191]; char *ConvertToLatin(const UTF8 *pString); UTF8 *convert_color(const UTF8 *pString); typedef struct { char *pString; char aControl[256]; } MUX_STRTOK_STATE; void mux_strtok_src(MUX_STRTOK_STATE *tts, char *pString); void mux_strtok_ctl(MUX_STRTOK_STATE *tts, const char *pControl); char *mux_strtok_parseLEN(MUX_STRTOK_STATE *tts, size_t *pnLen); char *mux_strtok_parse(MUX_STRTOK_STATE *tts); char *RemoveSetOfCharacters(char *pString, const char *pSetToRemove); size_t mux_ltoa(long val, char *buf); char *mux_ltoa_t(long val); void safe_ltoa(long val, char *buff, char **bufc); size_t mux_i64toa(INT64 val, char *buf); char *mux_i64toa_t(INT64 val); void safe_i64toa(INT64 val, char *buff, char **bufc); long mux_atol(const char *pString); INT64 mux_atoi64(const char *pString); double mux_atof(char *szString, bool bStrict = true); char *mux_ftoa(double r, bool bRounded, int frac); bool is_integer(char *, int *); bool is_rational(char *); bool is_real(char *); #pragma pack(1) typedef struct { unsigned char bNormal:1; unsigned char bBlink:1; unsigned char bHighlite:1; unsigned char bInverse:1; unsigned char bUnder:1; unsigned char iForeground:4; unsigned char iBackground:4; } ANSI_ColorState; #pragma pack() struct ANSI_In_Context { ANSI_ColorState m_acs; const char *m_p; size_t m_n; }; struct ANSI_Out_Context { int m_iEndGoal; ANSI_ColorState m_acs; bool m_bDone; // some constraint was met. char *m_p; size_t m_n; size_t m_nMax; size_t m_vw; size_t m_vwMax; }; #define ANSI_ENDGOAL_NORMAL 0 #define ANSI_ENDGOAL_NOBLEED 1 #define ANSI_ENDGOAL_LEAK 2 void ANSI_String_In_Init(struct ANSI_In_Context *pacIn, const char *szString, int iEndGoal); void ANSI_String_Out_Init(struct ANSI_Out_Context *pacOut, char *pField, size_t nField, size_t vwMax, int iEndGoal); void ANSI_String_Skip(struct ANSI_In_Context *pacIn, size_t maxVisualWidth, size_t *pnVisualWidth); void ANSI_String_Copy(struct ANSI_Out_Context *pacOut, struct ANSI_In_Context *pacIn, size_t vwMax); size_t ANSI_String_Finalize(struct ANSI_Out_Context *pacOut, size_t *pnVisualWidth); char *ANSI_TruncateAndPad_sbuf(const char *pString, size_t nMaxVisualWidth, char fill = ' '); size_t ANSI_TruncateToField(const char *szString, size_t nField, char *pField, size_t maxVisual, size_t *nVisualWidth, int iEndGoal); char *strip_ansi(const char *szString, size_t *pnString = 0); char *strip_accents(const char *szString, size_t *pnString = 0); char *normal_to_white(const char *); char *munge_space(const char *); char *trim_spaces(const char *); char *grabto(char **, char); int string_compare(const char *, const char *); int string_prefix(const char *, const char *); const char * string_match(const char * ,const char *); char *replace_string(const char *, const char *, const char *); char *replace_tokens ( const char *s, const char *pBound, const char *pListPlace, const char *pSwitch ); #if 0 int prefix_match(const char *, const char *); char *BufferCloneLen(const char *pBuffer, unsigned int nBuffer); #endif // 0 bool minmatch(const char *str, const char *target, int min); char *StringCloneLen(const char *str, size_t nStr); char *StringClone(const char *str); void safe_copy_str(const char *src, char *buff, char **bufp, int max); void safe_copy_str_lbuf(const char *src, char *buff, char **bufp); size_t safe_copy_buf(const char *src, size_t nLen, char *buff, char **bufp); size_t safe_fill(char *buff, char **bufc, char chFile, size_t nSpaces); void mux_strncpy(char *dest, const char *src, size_t nSizeOfBuffer); bool matches_exit_from_list(char *, const char *); char *translate_string(const char *, bool); int mux_stricmp(const char *a, const char *b); int mux_memicmp(const void *p1_arg, const void *p2_arg, size_t n); void mux_strlwr(char *tp); void mux_strupr(char *a); typedef struct tag_itl { bool bFirst; char chPrefix; char chSep; char *buff; char **bufc; size_t nBufferAvailable; } ITL; void ItemToList_Init(ITL *pContext, char *arg_buff, char **arg_bufc, char arg_chPrefix = 0, char arg_chSep = ' '); bool ItemToList_AddInteger(ITL *pContext, int i); bool ItemToList_AddInteger64(ITL *pContext, INT64 i); bool ItemToList_AddString(ITL *pContext, const char *pStr); bool ItemToList_AddStringLEN(ITL *pContext, size_t nStr, const char *pStr); void ItemToList_Final(ITL *pContext); size_t DCL_CDECL mux_vsnprintf(char *buff, size_t count, const char *fmt, va_list va); void DCL_CDECL mux_sprintf(char *buff, size_t count, const char *fmt, ...); size_t GetLineTrunc(char *Buffer, size_t nBuffer, FILE *fp); typedef struct { size_t m_d[256]; size_t m_skip2; } BMH_State; extern void BMH_Prepare(BMH_State *bmhs, size_t nPat, const char *pPat); extern bool BMH_Execute(BMH_State *bmhs, size_t *pnMatched, size_t nPat, const char *pPat, size_t nSrc, const char *pSrc); extern bool BMH_StringSearch(size_t *pnMatched, size_t nPat, const char *pPat, size_t nSrc, const char *pSrc); extern void BMH_PrepareI(BMH_State *bmhs, size_t nPat, const char *pPat); extern bool BMH_ExecuteI(BMH_State *bmhs, size_t *pnMatched, size_t nPat, const char *pPat, size_t nSrc, const char *pSrc); extern bool BMH_StringSearchI(size_t *pnMatched, size_t nPat, const char *pPat, size_t nSrc, const char *pSrc); struct ArtRuleset { ArtRuleset* m_pNextRule; void* m_pRegexp; void *m_pRegexpStudy; int m_bUseAn; }; typedef struct { int iLeadingSign; int iString; const char *pDigitsA; size_t nDigitsA; const char *pDigitsB; size_t nDigitsB; int iExponentSign; const char *pDigitsC; size_t nDigitsC; const char *pMeat; size_t nMeat; } PARSE_FLOAT_RESULT; extern bool ParseFloat(PARSE_FLOAT_RESULT *pfr, const char *str, bool bStrict = true); class mux_string { private: size_t m_n; char m_ach[LBUF_SIZE]; ANSI_ColorState m_acs[LBUF_SIZE]; public: mux_string(void); void import(size_t n, const char *str); void copy(char *buf, char **bufc); }; #endif // STRINGUTIL_H mux2.6/src/attrcache.h0000600000175000017500000000110611025753746014703 0ustar sdennissdennis// attrcache.h // // $Id: attrcache.h 8 2006-09-05 01:55:58Z brazilofmux $ // #ifndef _ATTRCACHE_H #define _ATTRCACHE_H typedef struct Aname { unsigned int object; unsigned int attrnum; } Aname; extern const char *cache_get(Aname *nam, size_t *pLen); extern bool cache_put(Aname *nam, const char *obj, size_t len); extern int cache_init(const char *game_dir_file, const char *game_pag_file, int nCachePages); extern void cache_close(void); extern void cache_tick(void); extern bool cache_sync(void); extern void cache_del(Aname *nam); #endif // !_ATTRCACHE_H mux2.6/src/wiz.cpp0000600000175000017500000005064311025753746014123 0ustar sdennissdennis// wiz.cpp -- Wizard-only commands. // // $Id: wiz.cpp 3689 2008-05-31 17:36:05Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "file_c.h" #include "powers.h" static void do_teleport_single ( dbref executor, dbref caller, dbref enactor, int key, dbref victim, char *to ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); dbref loc; int hush = 0; // Validate type of victim. // if ( !Good_obj(victim) || isRoom(victim)) { notify_quiet(executor, "You can't teleport that."); return; } // Fail if we don't control the victim or the victim's location. // if ( !Controls(executor, victim) && !Controls(executor, isExit(victim) ? Exits(victim) : Location(victim)) && !Tel_Anything(executor)) { notify_quiet(executor, NOPERM_MESSAGE); return; } // Check for teleporting home // if (!string_compare(to, "home")) { if (isExit(victim)) { notify_quiet(executor, "Bad destination."); } else { move_via_teleport(victim, HOME, enactor, 0); } return; } // Find out where to send the victim. // init_match(executor, to, NOTYPE); match_everything(0); dbref destination = match_result(); switch (destination) { case NOTHING: notify_quiet(executor, "No match."); return; case AMBIGUOUS: notify_quiet(executor, "I don't know which destination you mean!"); return; default: if (victim == destination) { notify_quiet(executor, "Bad destination."); return; } } // If fascist teleport is on, you must control the victim's ultimate // location (after LEAVEing any objects) or it must be JUMP_OK. // if (mudconf.fascist_tport) { if (isExit(victim)) { loc = where_room(Home(victim)); } else { loc = where_room(victim); } if ( !Good_obj(loc) || !isRoom(loc) || !( Controls(executor, loc) || Jump_ok(loc) || Tel_Anywhere(executor))) { notify_quiet(executor, NOPERM_MESSAGE); return; } } if ( isGarbage(destination) || ( Has_location(destination) && isGarbage(Location(destination)))) { // @Teleporting into garbage is never permitted. // notify_quiet(executor, "Bad destination."); return; } else if (Has_contents(destination)) { // You must control the destination OR it must be a JUMP_OK room where // the victim passes its TELEPORT lock (exit victims have the // additional requirement that the destination must be OPEN_OK and // pass the OPEN lock) OR you must be Tel_Anywhere. // // Only God may teleport exits into God. // if ( ( Controls(executor, destination) || Tel_Anywhere(executor) || ( Jump_ok(destination) && could_doit(victim, destination, A_LTPORT) && ( !isExit(victim) || ( Open_ok(destination) && could_doit(executor, destination, A_LOPEN))))) && ( !isExit(victim) || !God(destination) || God(executor))) { // We're OK, do the teleport. // if (key & TELEPORT_QUIET) { hush = HUSH_ENTER | HUSH_LEAVE; } if (move_via_teleport(victim, destination, enactor, hush)) { if (executor != victim) { if (!Quiet(executor)) { notify_quiet(executor, "Teleported."); } } } } else { // Nope, report failure. // if (executor != victim) { notify_quiet(executor, NOPERM_MESSAGE); } did_it(victim, destination, A_TFAIL, "You can't teleport there!", A_OTFAIL, 0, A_ATFAIL, 0, NULL, 0); } } else if (isExit(destination)) { if (isExit(victim)) { if (executor != victim) { notify_quiet(executor, "Bad destination."); } did_it(victim, destination, A_TFAIL, "You can't teleport there!", A_OTFAIL, 0, A_ATFAIL, 0, NULL, 0); return; } else { if (Exits(destination) == Location(victim)) { move_exit(victim, destination, false, "You can't go that way.", 0); } else { notify_quiet(executor, "I can't find that exit."); } } } } void do_teleport ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *arg1, char *arg2 ) { if ( ( Fixed(executor) || Fixed(Owner(executor))) && !Tel_Anywhere(executor)) { notify(executor, mudconf.fixed_tel_msg); return; } // Get victim. // if (nargs == 1) { // Teleport executor to given destination. // do_teleport_single(executor, caller, enactor, key, executor, arg1); } else if (nargs == 2) { // Teleport 3rd part(y/ies) to given destination. // if (key & TELEPORT_LIST) { // We have a space-delimited list of victims. // char *p; MUX_STRTOK_STATE tts; mux_strtok_src(&tts, arg1); mux_strtok_ctl(&tts, " "); for (p = mux_strtok_parse(&tts); p; p = mux_strtok_parse(&tts)) { init_match(executor, p, NOTYPE); match_everything(0); dbref victim = noisy_match_result(); if (Good_obj(victim)) { do_teleport_single(executor, caller, enactor, key, victim, arg2); } } } else { init_match(executor, arg1, NOTYPE); match_everything(0); dbref victim = noisy_match_result(); if (Good_obj(victim)) { do_teleport_single(executor, caller, enactor, key, victim, arg2); } } } } // --------------------------------------------------------------------------- // do_force_prefixed: Interlude to do_force for the # command // void do_force_prefixed( dbref executor, dbref caller, dbref enactor, int eval, int key, char *command, char *args[], int nargs ) { char *cp = parse_to(&command, ' ', 0); if (!command) { return; } while (mux_isspace(*command)) { command++; } if (*command) { do_force(executor, caller, enactor, eval, key, cp, command, args, nargs); } } // --------------------------------------------------------------------------- // do_force: Force an object to do something. // void do_force( dbref executor, dbref caller, dbref enactor, int eval, int key, char *what, char *command, char *args[], int nargs ) { UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); dbref victim = match_controlled(executor, what); if (victim != NOTHING) { // Force victim to do command. // CLinearTimeAbsolute lta; wait_que(victim, caller, executor, eval, false, lta, NOTHING, 0, command, nargs, args, mudstate.global_regs); } } // --------------------------------------------------------------------------- // do_toad: Turn a player into an object. // void do_toad ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *toad, char *newowner ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); dbref victim, recipient, loc, aowner; char *buf; int count, aflags; init_match(executor, toad, TYPE_PLAYER); match_neighbor(); match_absolute(); match_player(); if (!Good_obj(victim = noisy_match_result())) { return; } if (!isPlayer(victim)) { notify_quiet(executor, "Try @destroy instead."); return; } if (No_Destroy(victim)) { notify_quiet(executor, "You can't toad that player."); return; } if ( nargs == 2 && *newowner ) { init_match(executor, newowner, TYPE_PLAYER); match_neighbor(); match_absolute(); match_player(); if ((recipient = noisy_match_result()) == NOTHING) { return; } } else { if (mudconf.toad_recipient == NOTHING) { recipient = executor; } else { recipient = mudconf.toad_recipient; } } STARTLOG(LOG_WIZARD, "WIZ", "TOAD"); log_name_and_loc(victim); log_text(" was @toaded by "); log_name(executor); ENDLOG; // Clear everything out. // if (key & TOAD_NO_CHOWN) { count = -1; } else { // You get it. // count = chown_all(victim, recipient, executor, CHOWN_NOZONE); s_Owner(victim, recipient); s_Zone(victim, NOTHING); } s_Flags(victim, FLAG_WORD1, TYPE_THING | HALT); s_Flags(victim, FLAG_WORD2, 0); s_Flags(victim, FLAG_WORD3, 0); s_Pennies(victim, 1); // Notify people. // loc = Location(victim); buf = alloc_mbuf("do_toad"); const char *pVictimName = Moniker(victim); mux_sprintf(buf, MBUF_SIZE, "%s has been turned into a slimy toad!", pVictimName); notify_except2(loc, executor, victim, executor, buf); mux_sprintf(buf, MBUF_SIZE, "You toaded %s! (%d objects @chowned)", pVictimName, count + 1); notify_quiet(executor, buf); // Zap the name from the name hash table. // mux_sprintf(buf, MBUF_SIZE, "a slimy toad named %s", pVictimName); delete_player_name(victim, pVictimName); s_Name(victim, buf); free_mbuf(buf); // Zap the alias, too. // buf = atr_pget(victim, A_ALIAS, &aowner, &aflags); delete_player_name(victim, buf); free_lbuf(buf); // Boot off. // count = boot_off(victim, "You have been turned into a slimy toad!"); // Release comsys and @mail resources. // ReleaseAllResources(victim); buf = tprintf("%d connection%s closed.", count, (count == 1 ? "" : "s")); notify_quiet(executor, buf); } void do_newpassword ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *password ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nargs); dbref victim = lookup_player(executor, name, false); if (victim == NOTHING) { notify_quiet(executor, "No such player."); return; } const char *pmsg; if ( *password != '\0' && !ok_password(password, &pmsg)) { // Can set null passwords, but not bad passwords. // notify_quiet(executor, pmsg); return; } if (God(victim)) { bool bCan = true; if (God(executor)) { // God can change her own password if it's missing. // int aflags; dbref aowner; char *target = atr_get(executor, A_PASS, &aowner, &aflags); if (target[0] != '\0') { bCan = false; } free_lbuf(target); } else { bCan = false; } if (!bCan) { notify_quiet(executor, "You cannot change that player's password."); return; } } STARTLOG(LOG_WIZARD, "WIZ", "PASS"); log_name(executor); log_text(" changed the password of "); log_name(victim); ENDLOG; // It's ok, do it. // ChangePassword(victim, password); notify_quiet(executor, "Password changed."); char *buf = alloc_lbuf("do_newpassword"); char *bp = buf; safe_tprintf_str(buf, &bp, "Your password has been changed by %s.", Moniker(executor)); notify_quiet(victim, buf); free_lbuf(buf); } void do_boot(dbref executor, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); if (!Can_Boot(executor)) { notify(executor, NOPERM_MESSAGE); return; } dbref victim; int count; if (key & BOOT_PORT) { if (is_integer(name, NULL)) { victim = mux_atol(name); } else { notify_quiet(executor, "That's not a number!"); return; } STARTLOG(LOG_WIZARD, "WIZ", "BOOT"); log_text(tprintf("Port %d", victim)); log_text(" was @booted by "); log_name(executor); ENDLOG; } else { init_match(executor, name, TYPE_PLAYER); match_neighbor(); match_absolute(); match_player(); if ((victim = noisy_match_result()) == NOTHING) { return; } if (God(victim)) { notify_quiet(executor, "You cannot boot that player!"); return; } if ( ( !isPlayer(victim) && !God(executor)) || executor == victim) { notify_quiet(executor, "You can only boot off other players!"); return; } STARTLOG(LOG_WIZARD, "WIZ", "BOOT"); log_name_and_loc(victim); log_text(" was @booted by "); log_name(executor); ENDLOG; notify_quiet(executor, tprintf("You booted %s off!", Moniker(victim))); } const char *buf; if (key & BOOT_QUIET) { buf = NULL; } else { buf = tprintf("%s gently shows you the door.", Moniker(executor)); } if (key & BOOT_PORT) { count = boot_by_port(victim, God(executor), buf); } else { count = boot_off(victim, buf); } notify_quiet(executor, tprintf("%d connection%s closed.", count, (count == 1 ? "" : "s"))); } // --------------------------------------------------------------------------- // do_poor: Reduce the wealth of anyone over a specified amount. // void do_poor(dbref executor, dbref caller, dbref enactor, int eval, int key, char *arg1) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); if (!is_rational(arg1)) { return; } int amt = mux_atol(arg1); int curamt; dbref a; DO_WHOLE_DB(a) { if (isPlayer(a)) { curamt = Pennies(a); if (amt < curamt) { s_Pennies(a, amt); } } } } // --------------------------------------------------------------------------- // do_cut: Chop off a contents or exits chain after the named item. // void do_cut(dbref executor, dbref caller, dbref enactor, int eval, int key, char *thing) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); dbref object = match_controlled(executor, thing); if (Good_obj(object)) { s_Next(object, NOTHING); notify_quiet(executor, "Cut."); } } // -------------------------------------------------------------------------- // do_motd: Wizard-settable message of the day (displayed on connect) // void do_motd(dbref executor, dbref caller, dbref enactor, int eval, int key, char *message) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); bool is_brief = false; if (key & MOTD_BRIEF) { is_brief = true; key = key & ~MOTD_BRIEF; if (key == MOTD_ALL) key = MOTD_LIST; else if (key != MOTD_LIST) key |= MOTD_BRIEF; } switch (key) { case MOTD_ALL: mux_strncpy(mudconf.motd_msg, message, GBUF_SIZE-1); if (!Quiet(executor)) { notify_quiet(executor, "Set: MOTD."); } break; case MOTD_WIZ: mux_strncpy(mudconf.wizmotd_msg, message, GBUF_SIZE-1); if (!Quiet(executor)) { notify_quiet(executor, "Set: Wizard MOTD."); } break; case MOTD_DOWN: mux_strncpy(mudconf.downmotd_msg, message, GBUF_SIZE-1); if (!Quiet(executor)) { notify_quiet(executor, "Set: Down MOTD."); } break; case MOTD_FULL: mux_strncpy(mudconf.fullmotd_msg, message, GBUF_SIZE-1); if (!Quiet(executor)) { notify_quiet(executor, "Set: Full MOTD."); } break; case MOTD_LIST: if (Wizard(executor)) { if (!is_brief) { notify_quiet(executor, "----- motd file -----"); fcache_send(executor, FC_MOTD); notify_quiet(executor, "----- wizmotd file -----"); fcache_send(executor, FC_WIZMOTD); notify_quiet(executor, "----- motd messages -----"); } notify_quiet(executor, tprintf("MOTD: %s", mudconf.motd_msg)); notify_quiet( executor, tprintf("Wizard MOTD: %s", mudconf.wizmotd_msg) ); notify_quiet( executor, tprintf("Down MOTD: %s", mudconf.downmotd_msg) ); notify_quiet( executor, tprintf("Full MOTD: %s", mudconf.fullmotd_msg) ); } else { if (Guest(executor)) { fcache_send(executor, FC_CONN_GUEST); } else { fcache_send(executor, FC_MOTD); } notify_quiet(executor, mudconf.motd_msg); } break; default: notify_quiet(executor, "Illegal combination of switches."); } } // --------------------------------------------------------------------------- // do_enable: enable or disable global control flags // NAMETAB enable_names[] = { {"building", 1, CA_PUBLIC, CF_BUILD}, {"checkpointing", 2, CA_PUBLIC, CF_CHECKPOINT}, {"cleaning", 2, CA_PUBLIC, CF_DBCHECK}, {"dequeueing", 1, CA_PUBLIC, CF_DEQUEUE}, #ifdef MUSH3 {"god_monitoring", 1, CA_PUBLIC, CF_GODMONITOR}, #endif // MUSH3 {"idlechecking", 2, CA_PUBLIC, CF_IDLECHECK}, {"interpret", 2, CA_PUBLIC, CF_INTERP}, {"logins", 3, CA_PUBLIC, CF_LOGIN}, {"guests", 2, CA_PUBLIC, CF_GUEST}, {"eventchecking", 2, CA_PUBLIC, CF_EVENTCHECK}, { NULL, 0, 0, 0} }; void do_global(dbref executor, dbref caller, dbref enactor, int eval, int key, char *flag) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); // Set or clear the indicated flag. // int flagvalue; if (!search_nametab(executor, enable_names, flag, &flagvalue)) { notify_quiet(executor, "I don't know about that flag."); } else if (key == GLOB_ENABLE) { // Check for CF_DEQUEUE // if (flagvalue == CF_DEQUEUE) { scheduler.SetMinPriority(PRIORITY_CF_DEQUEUE_ENABLED); } mudconf.control_flags |= flagvalue; STARTLOG(LOG_CONFIGMODS, "CFG", "GLOBAL"); log_name(executor); log_text(" enabled: "); log_text(flag); ENDLOG; if (!Quiet(executor)) { notify_quiet(executor, "Enabled."); } } else if (key == GLOB_DISABLE) { if (flagvalue == CF_DEQUEUE) { scheduler.SetMinPriority(PRIORITY_CF_DEQUEUE_DISABLED); } mudconf.control_flags &= ~flagvalue; STARTLOG(LOG_CONFIGMODS, "CFG", "GLOBAL"); log_name(executor); log_text(" disabled: "); log_text(flag); ENDLOG; if (!Quiet(executor)) { notify_quiet(executor, "Disabled."); } } else { notify_quiet(executor, "Illegal combination of switches."); } } mux2.6/src/_build.h0000600000175000017500000000100711025753746014203 0ustar sdennissdennis// _build.h // // $Id: _build.h 3727 2008-06-17 15:13:31Z brazilofmux $ // #ifndef MUX_BUILD_NUM extern char szBuildNum[]; #define MUX_BUILD_NUM szBuildNum #endif // MUX_BUILD_NUM #ifndef MUX_BUILD_DATE extern char szBuildDate[]; #define MUX_BUILD_DATE szBuildDate #endif // MUX_BUILD_DATE #define MUX_VERSION "2.6.5.28" // Version number #define MUX_RELEASE_DATE "2008-JUN-17" // Source release date // Define if this release is qualified as ALPHA or BETA. // //#define ALPHA //#define BETA mux2.6/src/comsys.cpp0000600000175000017500000027107711025753746014635 0ustar sdennissdennis/*! \file comsys.cpp * Channel Communication System. * * $Id: comsys.cpp 3052 2007-12-30 06:36:27Z brazilofmux $ * * The functions here manage channels, channel membership, the comsys.db, and * the interaction of players and other objects with channels. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include #include "ansi.h" #include "attrs.h" #include "command.h" #include "comsys.h" #include "functions.h" #include "interface.h" #include "powers.h" static int num_channels; static comsys_t *comsys_table[NUM_COMSYS]; #define DFLT_MAX_LOG 0 #define MIN_RECALL_REQUEST 1 #define DFLT_RECALL_REQUEST 10 #define MAX_RECALL_REQUEST 200 // Return value is a static buffer provided by RemoveSetOfCharacters. // static char *RestrictTitleValue(char *pTitleRequest) { // First, remove all '\r\n\t' from the string. // char *pNewTitle = RemoveSetOfCharacters(pTitleRequest, "\r\n\t"); // Optimize/terminate any ANSI in the string. // char NewTitle_ANSI[MAX_TITLE_LEN+1]; size_t nVisualWidth; size_t nLen = ANSI_TruncateToField(pNewTitle, sizeof(NewTitle_ANSI), NewTitle_ANSI, sizeof(NewTitle_ANSI), &nVisualWidth, ANSI_ENDGOAL_NORMAL); memcpy(pNewTitle, NewTitle_ANSI, nLen+1); return pNewTitle; } static void do_setcomtitlestatus(dbref player, struct channel *ch, bool status) { struct comuser *user = select_user(ch,player); if (ch && user) { user->ComTitleStatus = status; } } static void do_setnewtitle(dbref player, struct channel *ch, char *pValidatedTitle) { struct comuser *user = select_user(ch, player); if (ch && user) { if (user->title) { MEMFREE(user->title); user->title = NULL; } user->title = StringClone(pValidatedTitle); } } void load_comsys_V4(FILE *fp) { char buffer[200]; if ( fgets(buffer, sizeof(buffer), fp) && strcmp(buffer, "*** Begin CHANNELS ***\n") == 0) { load_channels_V4(fp); } else { Log.tinyprintf("Error: Couldn't find Begin CHANNELS." ENDLINE); return; } if ( fgets(buffer, sizeof(buffer), fp) && strcmp(buffer, "*** Begin COMSYS ***\n") == 0) { load_comsystem_V4(fp); } else { Log.tinyprintf("Error: Couldn't find Begin COMSYS." ENDLINE); return; } } void load_comsys_V0123(FILE *fp) { char buffer[200]; if ( fgets(buffer, sizeof(buffer), fp) && strcmp(buffer, "*** Begin CHANNELS ***\n") == 0) { load_channels_V0123(fp); } else { Log.tinyprintf("Error: Couldn't find Begin CHANNELS." ENDLINE); return; } if ( fgets(buffer, sizeof(buffer), fp) && strcmp(buffer, "*** Begin COMSYS ***\n") == 0) { load_comsystem_V0123(fp); } else { Log.tinyprintf("Error: Couldn't find Begin COMSYS." ENDLINE); return; } } void load_comsys(char *filename) { int i; for (i = 0; i < NUM_COMSYS; i++) { comsys_table[i] = NULL; } FILE *fp; if (!mux_fopen(&fp, filename, "rb")) { Log.tinyprintf("Error: Couldn't find %s." ENDLINE, filename); } else { DebugTotalFiles++; Log.tinyprintf("LOADING: %s" ENDLINE, filename); int ch = getc(fp); if (EOF == ch) { Log.tinyprintf("Error: Couldn't read first byte."); } else { ungetc(ch, fp); if ('+' == ch) { // Version 4 or later. // char nbuf1[8]; // Read the version number. // if (fgets(nbuf1, sizeof(nbuf1), fp)) { if (strncmp(nbuf1, "+V4", 3) == 0) { // Started v4 on 2007-MAR-13. // load_comsys_V4(fp); } } } else { load_comsys_V0123(fp); } } if (fclose(fp) == 0) { DebugTotalFiles--; } Log.tinyprintf("LOADING: %s (done)" ENDLINE, filename); } } void save_comsys(char *filename) { char buffer[500]; mux_sprintf(buffer, sizeof(buffer), "%s.#", filename); FILE *fp; if (!mux_fopen(&fp, buffer, "wb")) { Log.tinyprintf("Unable to open %s for writing." ENDLINE, buffer); return; } DebugTotalFiles++; fprintf(fp, "*** Begin CHANNELS ***\n"); save_channels(fp); fprintf(fp, "*** Begin COMSYS ***\n"); save_comsystem(fp); if (fclose(fp) == 0) { DebugTotalFiles--; } ReplaceFile(buffer, filename); } // Aliases must be between 1 and 5 characters. No spaces. No ANSI. // char *MakeCanonicalComAlias ( const char *pAlias, size_t *nValidAlias, bool *bValidAlias ) { static char Buffer[ALIAS_SIZE]; *nValidAlias = 0; *bValidAlias = false; if (!pAlias) { return NULL; } size_t n = 0; while (pAlias[n]) { if ( !mux_isprint(pAlias[n]) || ' ' == pAlias[n]) { return NULL; } n++; } if (n < 1) { return NULL; } else if (MAX_ALIAS_LEN < n) { n = MAX_ALIAS_LEN; } memcpy(Buffer, pAlias, n); Buffer[n] = '\0'; *nValidAlias = n; *bValidAlias = true; return Buffer; } static bool ParseChannelLine(char *pBuffer, char *pAlias5, char **ppChannelName) { // Fetch alias portion. We need to find the first space. // char *p = strchr(pBuffer, ' '); if (!p) { return false; } *p = '\0'; bool bValidAlias; size_t nValidAlias; char *pValidAlias = MakeCanonicalComAlias(pBuffer, &nValidAlias, &bValidAlias); if (!bValidAlias) { return false; } mux_strncpy(pAlias5, pValidAlias, ALIAS_SIZE-1); // Skip any leading space before the channel name. // p++; while (mux_isspace(*p)) { p++; } if (*p == '\0') { return false; } // The rest of the line is the channel name. // *ppChannelName = StringClone(p); return true; } static bool ReadListOfNumbers(FILE *fp, int cnt, int anum[]) { char buffer[200]; if (fgets(buffer, sizeof(buffer), fp)) { char *p = buffer; for (int i = 0; i < cnt; i++) { if ( mux_isdigit(p[0]) || ( '-' == p[0] && mux_isdigit(p[1]))) { anum[i] = mux_atol(p); do { p++; } while (mux_isdigit(*p)); if (' ' == *p) { p++; } } else { return false; } } if ('\n' == *p) { return true; } } return false; } void load_channels_V0123(FILE *fp) { int i, j; int anum[2]; char buffer[LBUF_SIZE]; comsys_t *c; int np = 0; mux_assert(ReadListOfNumbers(fp, 1, &np)); for (i = 0; i < np; i++) { c = create_new_comsys(); c->who = 0; c->numchannels = 0; mux_assert(ReadListOfNumbers(fp, 2, anum)); c->who = anum[0]; c->numchannels = anum[1]; c->maxchannels = c->numchannels; if (c->maxchannels > 0) { c->alias = (char *)MEMALLOC(c->maxchannels * ALIAS_SIZE); ISOUTOFMEMORY(c->alias); c->channels = (char **)MEMALLOC(sizeof(char *) * c->maxchannels); ISOUTOFMEMORY(c->channels); for (j = 0; j < c->numchannels; j++) { size_t n = GetLineTrunc(buffer, sizeof(buffer), fp); if (buffer[n-1] == '\n') { // Get rid of trailing '\n'. // n--; buffer[n] = '\0'; } if (!ParseChannelLine(buffer, c->alias + j * ALIAS_SIZE, c->channels+j)) { c->numchannels--; j--; } } sort_com_aliases(c); } else { c->alias = NULL; c->channels = NULL; } if (Good_obj(c->who)) { add_comsys(c); } else { Log.tinyprintf("Invalid dbref %d." ENDLINE, c->who); } purge_comsystem(); } } void load_channels_V4(FILE *fp) { int i, j; int anum[2]; char buffer[LBUF_SIZE]; comsys_t *c; int np = 0; mux_assert(ReadListOfNumbers(fp, 1, &np)); for (i = 0; i < np; i++) { c = create_new_comsys(); c->who = 0; c->numchannels = 0; mux_assert(ReadListOfNumbers(fp, 2, anum)); c->who = anum[0]; c->numchannels = anum[1]; c->maxchannels = c->numchannels; if (c->maxchannels > 0) { c->alias = (char *)MEMALLOC(c->maxchannels * ALIAS_SIZE); ISOUTOFMEMORY(c->alias); c->channels = (char **)MEMALLOC(sizeof(char *) * c->maxchannels); ISOUTOFMEMORY(c->channels); for (j = 0; j < c->numchannels; j++) { size_t n = GetLineTrunc(buffer, sizeof(buffer), fp); if (buffer[n-1] == '\n') { // Get rid of trailing '\n'. // n--; buffer[n] = '\0'; } // Convert entire line including color codes. // char *pBuffer = (char *)convert_color((UTF8 *)buffer); pBuffer = ConvertToLatin((UTF8 *)pBuffer); if (!ParseChannelLine(pBuffer, c->alias + j * ALIAS_SIZE, c->channels+j)) { c->numchannels--; j--; } } sort_com_aliases(c); } else { c->alias = NULL; c->channels = NULL; } if (Good_obj(c->who)) { add_comsys(c); } else { Log.tinyprintf("Invalid dbref %d." ENDLINE, c->who); } purge_comsystem(); } } void purge_comsystem(void) { #ifdef ABORT_PURGE_COMSYS return; #endif // ABORT_PURGE_COMSYS comsys_t *c; comsys_t *d; int i; for (i = 0; i < NUM_COMSYS; i++) { c = comsys_table[i]; while (c) { d = c; c = c->next; if (d->numchannels == 0) { del_comsys(d->who); continue; } if (isPlayer(d->who)) { continue; } if ( God(Owner(d->who)) && Going(d->who)) { del_comsys(d->who); continue; } } } } void save_channels(FILE *fp) { purge_comsystem(); comsys_t *c; int i, j; int np = 0; for (i = 0; i < NUM_COMSYS; i++) { c = comsys_table[i]; while (c) { np++; c = c->next; } } fprintf(fp, "%d\n", np); for (i = 0; i < NUM_COMSYS; i++) { c = comsys_table[i]; while (c) { fprintf(fp, "%d %d\n", c->who, c->numchannels); for (j = 0; j < c->numchannels; j++) { fprintf(fp, "%s %s\n", c->alias + j * ALIAS_SIZE, c->channels[j]); } c = c->next; } } } comsys_t *create_new_comsys(void) { comsys_t *c = (comsys_t *)MEMALLOC(sizeof(comsys_t)); if (c) { c->who = NOTHING; c->numchannels = 0; c->maxchannels = 0; c->alias = NULL; c->channels = NULL; c->next = NULL; } else { ISOUTOFMEMORY(c); } return c; } static comsys_t *get_comsys(dbref which) { if (which < 0) { return NULL; } comsys_t *c = comsys_table[which % NUM_COMSYS]; while (c && (c->who != which)) c = c->next; if (!c) { c = create_new_comsys(); c->who = which; add_comsys(c); } return c; } void add_comsys(comsys_t *c) { if (c->who < 0 || c->who >= mudstate.db_top) { Log.tinyprintf("add_comsys: dbref %d out of range [0, %d)" ENDLINE, c->who, mudstate.db_top); return; } c->next = comsys_table[c->who % NUM_COMSYS]; comsys_table[c->who % NUM_COMSYS] = c; } void del_comsys(dbref who) { if (who < 0 || who >= mudstate.db_top) { Log.tinyprintf("del_comsys: dbref %d out of range [0, %d)" ENDLINE, who, mudstate.db_top); return; } comsys_t *c = comsys_table[who % NUM_COMSYS]; if (c == NULL) { return; } if (c->who == who) { comsys_table[who % NUM_COMSYS] = c->next; destroy_comsys(c); return; } comsys_t *last = c; c = c->next; while (c) { if (c->who == who) { last->next = c->next; destroy_comsys(c); return; } last = c; c = c->next; } } void destroy_comsys(comsys_t *c) { int i; if (c->alias) { MEMFREE(c->alias); c->alias = NULL; } for (i = 0; i < c->numchannels; i++) { MEMFREE(c->channels[i]); c->channels[i] = NULL; } if (c->channels) { MEMFREE(c->channels); c->channels = NULL; } MEMFREE(c); c = NULL; } void sort_com_aliases(comsys_t *c) { int i; char buffer[10]; char *s; bool cont = true; while (cont) { cont = false; for (i = 0; i < c->numchannels - 1; i++) { if (strcmp(c->alias + i * ALIAS_SIZE, c->alias + (i + 1) * ALIAS_SIZE) > 0) { mux_strncpy(buffer, c->alias + i * ALIAS_SIZE, sizeof(buffer)-1); mux_strncpy(c->alias + i * ALIAS_SIZE, c->alias + (i + 1) * ALIAS_SIZE, ALIAS_SIZE-1); mux_strncpy(c->alias + (i + 1) * ALIAS_SIZE, buffer, ALIAS_SIZE-1); s = c->channels[i]; c->channels[i] = c->channels[i + 1]; c->channels[i + 1] = s; cont = true; } } } } static char *get_channel_from_alias(dbref player, char *alias) { int first, last, current, dir; comsys_t *c = get_comsys(player); current = first = 0; last = c->numchannels - 1; dir = 1; while (dir && (first <= last)) { current = (first + last) / 2; dir = strcmp(alias, c->alias + ALIAS_SIZE * current); if (dir < 0) last = current - 1; else first = current + 1; } if (!dir) { return c->channels[current]; } else { return (char *)""; } } void load_comsystem_V0123(FILE *fp) { int i, j; int ver = 0; struct channel *ch; char temp[LBUF_SIZE]; num_channels = 0; int nc = 0; if (NULL == fgets(temp, sizeof(temp), fp)) { return; } if (!strncmp(temp, "+V", 2)) { // +V2 has colored headers // ver = mux_atol(temp + 2); if (ver < 1 || 3 < ver) { return; } mux_assert(ReadListOfNumbers(fp, 1, &nc)); } else { nc = mux_atol(temp); } num_channels = nc; for (i = 0; i < nc; i++) { int anum[10]; ch = (struct channel *)MEMALLOC(sizeof(struct channel)); ISOUTOFMEMORY(ch); size_t nChannel = GetLineTrunc(temp, sizeof(temp), fp); if (nChannel > MAX_CHANNEL_LEN) { nChannel = MAX_CHANNEL_LEN; } if (temp[nChannel-1] == '\n') { // Get rid of trailing '\n'. // nChannel--; } memcpy(ch->name, temp, nChannel); ch->name[nChannel] = '\0'; if (ver >= 2) { size_t nHeader = GetLineTrunc(temp, sizeof(temp), fp); if (nHeader > MAX_HEADER_LEN) { nHeader = MAX_HEADER_LEN; } if (temp[nHeader-1] == '\n') { nHeader--; } memcpy(ch->header, temp, nHeader); ch->header[nHeader] = '\0'; } ch->on_users = NULL; hashaddLEN(ch->name, nChannel, ch, &mudstate.channel_htab); ch->type = 127; ch->temp1 = 0; ch->temp2 = 0; ch->charge = 0; ch->charge_who = NOTHING; ch->amount_col = 0; ch->num_messages = 0; ch->chan_obj = NOTHING; if (ver >= 1) { mux_assert(ReadListOfNumbers(fp, 8, anum)); ch->type = anum[0]; ch->temp1 = anum[1]; ch->temp2 = anum[2]; ch->charge = anum[3]; ch->charge_who = anum[4]; ch->amount_col = anum[5]; ch->num_messages = anum[6]; ch->chan_obj = anum[7]; } else { mux_assert(ReadListOfNumbers(fp, 10, anum)); ch->type = anum[0]; // anum[1] is not used. ch->temp1 = anum[2]; ch->temp2 = anum[3]; // anum[4] is not used. ch->charge = anum[5]; ch->charge_who = anum[6]; ch->amount_col = anum[7]; ch->num_messages = anum[8]; ch->chan_obj = anum[9]; } if (ver <= 1) { // Build colored header if not +V2 or later db. // if (ch->type & CHANNEL_PUBLIC) { mux_sprintf(temp, sizeof(temp), "%s[%s%s%s%s%s]%s", ANSI_CYAN, ANSI_HILITE, ANSI_BLUE, ch->name, ANSI_NORMAL, ANSI_CYAN, ANSI_NORMAL); } else { mux_sprintf(temp, sizeof(temp), "%s[%s%s%s%s%s]%s", ANSI_MAGENTA, ANSI_HILITE, ANSI_RED, ch->name, ANSI_NORMAL, ANSI_MAGENTA, ANSI_NORMAL); } size_t vwVisual; ANSI_TruncateToField(temp, MAX_HEADER_LEN+1, ch->header, MAX_HEADER_LEN+1, &vwVisual, ANSI_ENDGOAL_NORMAL); } ch->num_users = 0; mux_assert(ReadListOfNumbers(fp, 1, &(ch->num_users))); ch->max_users = ch->num_users; if (ch->num_users > 0) { ch->users = (struct comuser **)calloc(ch->max_users, sizeof(struct comuser *)); ISOUTOFMEMORY(ch->users); int jAdded = 0; for (j = 0; j < ch->num_users; j++) { struct comuser t_user; memset(&t_user, 0, sizeof(t_user)); t_user.who = NOTHING; t_user.bUserIsOn = false; t_user.ComTitleStatus = false; if (ver == 3) { mux_assert(ReadListOfNumbers(fp, 3, anum)); t_user.who = anum[0]; t_user.bUserIsOn = (anum[1] ? true : false); t_user.ComTitleStatus = (anum[2] ? true : false); } else { t_user.ComTitleStatus = true; if (ver) { mux_assert(ReadListOfNumbers(fp, 2, anum)); t_user.who = anum[0]; t_user.bUserIsOn = (anum[1] ? true : false); } else { mux_assert(ReadListOfNumbers(fp, 4, anum)); t_user.who = anum[0]; // anum[1] is not used. // anum[2] is not used. t_user.bUserIsOn = (anum[3] ? true : false); } } // Read Comtitle. // size_t nTitle = GetLineTrunc(temp, sizeof(temp), fp); char *pTitle = temp; if (!Good_dbref(t_user.who)) { Log.tinyprintf("load_comsystem: dbref %d out of range [0, %d)." ENDLINE, t_user.who, mudstate.db_top); } else if (isGarbage(t_user.who)) { Log.tinyprintf("load_comsystem: dbref is GARBAGE." ENDLINE, t_user.who); } else { // Validate comtitle // if (3 < nTitle && temp[0] == 't' && temp[1] == ':') { pTitle = temp+2; nTitle -= 2; if (pTitle[nTitle-1] == '\n') { // Get rid of trailing '\n'. // nTitle--; } if (nTitle <= 0 || MAX_TITLE_LEN < nTitle) { nTitle = 0; pTitle = temp; } } else { nTitle = 0; } struct comuser *user = (struct comuser *)MEMALLOC(sizeof(struct comuser)); ISOUTOFMEMORY(user); memcpy(user, &t_user, sizeof(struct comuser)); user->title = StringCloneLen(pTitle, nTitle); ch->users[jAdded++] = user; if ( !(isPlayer(user->who)) && !(Going(user->who) && (God(Owner(user->who))))) { do_joinchannel(user->who, ch); } user->on_next = ch->on_users; ch->on_users = user; } } ch->num_users = jAdded; sort_users(ch); } else { ch->users = NULL; } } } // Version 4 start on 2007-MAR-17 // // -- Supports UTF-8 and ANSI as code-points. // -- Relies on a version number at the top of the file instead of within // this section. // void load_comsystem_V4(FILE *fp) { int i, j; struct channel *ch; char temp[LBUF_SIZE]; num_channels = 0; int nc = 0; if (NULL == fgets((char *)temp, sizeof(temp), fp)) { return; } nc = mux_atol(temp); num_channels = nc; for (i = 0; i < nc; i++) { int anum[10]; ch = (struct channel *)MEMALLOC(sizeof(struct channel)); ISOUTOFMEMORY(ch); size_t nChannel = GetLineTrunc(temp, sizeof(temp), fp); if (nChannel > MAX_CHANNEL_LEN) { nChannel = MAX_CHANNEL_LEN; } if (temp[nChannel-1] == '\n') { // Get rid of trailing '\n'. // nChannel--; temp[nChannel] = '\0'; } // Convert entire line including color codes. // char *pBuffer = (char *)convert_color((UTF8 *)temp); pBuffer = ConvertToLatin((UTF8 *)pBuffer); nChannel = strlen(pBuffer); if (MAX_CHANNEL_LEN < nChannel) { nChannel = MAX_CHANNEL_LEN; } memcpy(ch->name, pBuffer, nChannel); ch->name[nChannel] = '\0'; size_t nHeader = GetLineTrunc(temp, sizeof(temp), fp); if (temp[nHeader-1] == '\n') { nHeader--; temp[nHeader] = '\0'; } // Convert entire line including color codes. // pBuffer = (char *)convert_color((UTF8 *)temp); pBuffer = ConvertToLatin((UTF8 *)pBuffer); nHeader = strlen(pBuffer); if (MAX_HEADER_LEN < nHeader) { nHeader = MAX_HEADER_LEN; } memcpy(ch->header, pBuffer, nHeader); ch->header[nHeader] = '\0'; ch->on_users = NULL; hashaddLEN(ch->name, nChannel, ch, &mudstate.channel_htab); ch->type = 127; ch->temp1 = 0; ch->temp2 = 0; ch->charge = 0; ch->charge_who = NOTHING; ch->amount_col = 0; ch->num_messages = 0; ch->chan_obj = NOTHING; mux_assert(ReadListOfNumbers(fp, 8, anum)); ch->type = anum[0]; ch->temp1 = anum[1]; ch->temp2 = anum[2]; ch->charge = anum[3]; ch->charge_who = anum[4]; ch->amount_col = anum[5]; ch->num_messages = anum[6]; ch->chan_obj = anum[7]; ch->num_users = 0; mux_assert(ReadListOfNumbers(fp, 1, &(ch->num_users))); ch->max_users = ch->num_users; if (ch->num_users > 0) { ch->users = (struct comuser **)calloc(ch->max_users, sizeof(struct comuser *)); ISOUTOFMEMORY(ch->users); int jAdded = 0; for (j = 0; j < ch->num_users; j++) { struct comuser t_user; memset(&t_user, 0, sizeof(t_user)); t_user.who = NOTHING; t_user.bUserIsOn = false; t_user.ComTitleStatus = false; mux_assert(ReadListOfNumbers(fp, 3, anum)); t_user.who = anum[0]; t_user.bUserIsOn = (anum[1] ? true : false); t_user.ComTitleStatus = (anum[2] ? true : false); // Read Comtitle. // size_t nTitle = GetLineTrunc(temp, sizeof(temp), fp); // Convert entire line including color codes. // char *pTitle = (char *)convert_color((UTF8 *)temp); pTitle = ConvertToLatin((UTF8 *)pTitle); nTitle = strlen(pTitle); if (!Good_dbref(t_user.who)) { Log.tinyprintf("load_comsystem: dbref %d out of range [0, %d)." ENDLINE, t_user.who, mudstate.db_top); } else if (isGarbage(t_user.who)) { Log.tinyprintf("load_comsystem: dbref is GARBAGE." ENDLINE, t_user.who); } else { // Validate comtitle. // if ( 3 < nTitle && pTitle[0] == 't' && pTitle[1] == ':') { pTitle = pTitle+2; nTitle -= 2; if (pTitle[nTitle-1] == '\n') { // Get rid of trailing '\n'. // nTitle--; } if ( nTitle <= 0 || MAX_TITLE_LEN < nTitle) { nTitle = 0; pTitle = pBuffer; } } else { nTitle = 0; } struct comuser *user = (struct comuser *)MEMALLOC(sizeof(struct comuser)); ISOUTOFMEMORY(user); memcpy(user, &t_user, sizeof(struct comuser)); user->title = StringCloneLen(pTitle, nTitle); ch->users[jAdded++] = user; if ( !(isPlayer(user->who)) && !(Going(user->who) && (God(Owner(user->who))))) { do_joinchannel(user->who, ch); } user->on_next = ch->on_users; ch->on_users = user; } } ch->num_users = jAdded; sort_users(ch); } else { ch->users = NULL; } } } void save_comsystem(FILE *fp) { struct channel *ch; struct comuser *user; int j; fprintf(fp, "+V3\n"); fprintf(fp, "%d\n", num_channels); for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab); ch; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab)) { fprintf(fp, "%s\n", ch->name); fprintf(fp, "%s\n", ch->header); fprintf(fp, "%d %d %d %d %d %d %d %d\n", ch->type, ch->temp1, ch->temp2, ch->charge, ch->charge_who, ch->amount_col, ch->num_messages, ch->chan_obj); // Count the number of 'valid' users to dump. // int nUsers = 0; for (j = 0; j < ch->num_users; j++) { user = ch->users[j]; if (user->who >= 0 && user->who < mudstate.db_top) { nUsers++; } } fprintf(fp, "%d\n", nUsers); for (j = 0; j < ch->num_users; j++) { user = ch->users[j]; if (user->who >= 0 && user->who < mudstate.db_top) { user = ch->users[j]; fprintf(fp, "%d %d %d\n", user->who, user->bUserIsOn, user->ComTitleStatus); if (user->title[0] != '\0') { fprintf(fp, "t:%s\n", user->title); } else { fprintf(fp, "t:\n"); } } } } } static void BuildChannelMessage ( bool bSpoof, const char *pHeader, struct comuser *user, char *pPose, char **messNormal, char **messNoComtitle ) { // Allocate necessary buffers. // *messNormal = alloc_lbuf("BCM.messNormal"); *messNoComtitle = NULL; if (!bSpoof) { *messNoComtitle = alloc_lbuf("BCM.messNoComtitle"); } // Comtitle Check // bool hasComTitle = (user->title[0] != '\0'); char *mnptr = *messNormal; // Message without comtitle removal char *mncptr = *messNoComtitle; // Message with comtitle removal safe_str(pHeader, *messNormal, &mnptr); safe_chr(' ', *messNormal, &mnptr); if (!bSpoof) { safe_str(pHeader, *messNoComtitle, &mncptr); safe_chr(' ', *messNoComtitle, &mncptr); } // Don't evaluate a title if there isn't one to parse or evaluation of // comtitles is disabled. // If they're set spoof, ComTitleStatus doesn't matter. if (hasComTitle && (user->ComTitleStatus || bSpoof)) { if (mudconf.eval_comtitle) { // Evaluate the comtitle as code. // char TempToEval[LBUF_SIZE]; mux_strncpy(TempToEval, user->title, LBUF_SIZE-1); char *q = TempToEval; mux_exec(*messNormal, &mnptr, user->who, user->who, user->who, EV_FCHECK | EV_EVAL | EV_TOP, &q, NULL, 0); } else { safe_str(user->title, *messNormal, &mnptr); } if (!bSpoof) { safe_chr(' ', *messNormal, &mnptr); safe_str(Moniker(user->who), *messNormal, &mnptr); safe_str(Moniker(user->who), *messNoComtitle, &mncptr); } } else { safe_str(Moniker(user->who), *messNormal, &mnptr); if (!bSpoof) { safe_str(Moniker(user->who), *messNoComtitle, &mncptr); } } char *saystring = NULL; char *newPose = NULL; switch(pPose[0]) { case ':': pPose++; newPose = modSpeech(user->who, pPose, true, (char *)"channel/pose"); if (newPose) { pPose = newPose; } safe_chr(' ', *messNormal, &mnptr); safe_str(pPose, *messNormal, &mnptr); if (!bSpoof) { safe_chr(' ', *messNoComtitle, &mncptr); safe_str(pPose, *messNoComtitle, &mncptr); } break; case ';': pPose++; newPose = modSpeech(user->who, pPose, true, (char *)"channel/pose"); if (newPose) { pPose = newPose; } safe_str(pPose, *messNormal, &mnptr); if (!bSpoof) { safe_str(pPose, *messNoComtitle, &mncptr); } break; default: newPose = modSpeech(user->who, pPose, true, (char *)"channel"); if (newPose) { pPose = newPose; } saystring = modSpeech(user->who, pPose, false, (char *)"channel"); if (saystring) { safe_chr(' ', *messNormal, &mnptr); safe_str(saystring, *messNormal, &mnptr); safe_str(" \"", *messNormal, &mnptr); } else { safe_str(" says, \"", *messNormal, &mnptr); } safe_str(pPose, *messNormal, &mnptr); safe_chr('"', *messNormal, &mnptr); if (!bSpoof) { if (saystring) { safe_chr(' ', *messNoComtitle, &mncptr); safe_str(saystring, *messNoComtitle, &mncptr); safe_str(" \"", *messNoComtitle, &mncptr); } else { safe_str(" says, \"", *messNoComtitle, &mncptr); } safe_str(pPose, *messNoComtitle, &mncptr); safe_chr('"', *messNoComtitle, &mncptr); } break; } *mnptr = '\0'; if (!bSpoof) { *mncptr = '\0'; } if (newPose) { free_lbuf(newPose); } if (saystring) { free_lbuf(saystring); } } static void do_processcom(dbref player, char *arg1, char *arg2) { if (!*arg2) { raw_notify(player, "No message."); return; } if (3500 < strlen(arg2)) { arg2[3500] = '\0'; } struct channel *ch = select_channel(arg1); if (!ch) { raw_notify(player, tprintf("Unknown channel %s.", arg1)); return; } struct comuser *user = select_user(ch, player); if (!user) { raw_notify(player, "You are not listed as on that channel. Delete this alias and readd."); return; } #if !defined(FIRANMUX) if ( Gagged(player) && !Wizard(player)) { raw_notify(player, "GAGGED players may not speak on channels."); return; } #endif // FIRANMUX if (!strcmp(arg2, "on")) { do_joinchannel(player, ch); } else if (!strcmp(arg2, "off")) { do_leavechannel(player, ch); } else if (!user->bUserIsOn) { raw_notify(player, tprintf("You must be on %s to do that.", arg1)); return; } else if (!strcmp(arg2, "who")) { do_comwho(player, ch); } else if ( !strncmp(arg2, "last", 4) && ( arg2[4] == '\0' || ( arg2[4] == ' ' && is_integer(arg2 + 5, NULL)))) { // Parse optional number after the 'last' command. // int nRecall = DFLT_RECALL_REQUEST; if (arg2[4] == ' ') { nRecall = mux_atol(arg2 + 5); } do_comlast(player, ch, nRecall); } else if (!test_transmit_access(player, ch)) { raw_notify(player, "That channel type cannot be transmitted on."); return; } else { if (!payfor(player, Guest(player) ? 0 : ch->charge)) { notify(player, tprintf("You don't have enough %s.", mudconf.many_coins)); return; } else { ch->amount_col += ch->charge; giveto(ch->charge_who, ch->charge); } // BuildChannelMessage allocates messNormal and messNoComtitle, // SendChannelMessage frees them. // char *messNormal; char *messNoComtitle; BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, user, arg2, &messNormal, &messNoComtitle); SendChannelMessage(player, ch, messNormal, messNoComtitle); } } void SendChannelMessage ( dbref executor, struct channel *ch, char *msgNormal, char *msgNoComtitle ) { bool bSpoof = ((ch->type & CHANNEL_SPOOF) != 0); ch->num_messages++; struct comuser *user; for (user = ch->on_users; user; user = user->on_next) { if ( user->bUserIsOn && test_receive_access(user->who, ch)) { if ( user->ComTitleStatus || bSpoof || msgNoComtitle == NULL) { notify_with_cause_ooc(user->who, executor, msgNormal); } else { notify_with_cause_ooc(user->who, executor, msgNoComtitle); } } } dbref obj = ch->chan_obj; if (Good_obj(obj)) { dbref aowner; int aflags; int logmax = DFLT_MAX_LOG; char *maxbuf; ATTR *pattr = atr_str("MAX_LOG"); if ( pattr && pattr->number) { maxbuf = atr_get(obj, pattr->number, &aowner, &aflags); logmax = mux_atol(maxbuf); free_lbuf(maxbuf); } if (logmax > 0) { if (logmax > MAX_RECALL_REQUEST) { logmax = MAX_RECALL_REQUEST; atr_add(ch->chan_obj, pattr->number, mux_ltoa_t(logmax), GOD, AF_CONST|AF_NOPROG|AF_NOPARSE); } char *p = tprintf("HISTORY_%d", iMod(ch->num_messages, logmax)); int atr = mkattr(GOD, p); if (0 < atr) { atr_add(ch->chan_obj, atr, msgNormal, GOD, AF_CONST|AF_NOPROG|AF_NOPARSE); } } } else if (ch->chan_obj != NOTHING) { ch->chan_obj = NOTHING; } // Since msgNormal and msgNoComTitle are no longer needed, free them here. // if (msgNormal) { free_lbuf(msgNormal); } if ( msgNoComtitle && msgNoComtitle != msgNormal) { free_lbuf(msgNoComtitle); } } void do_joinchannel(dbref player, struct channel *ch) { struct comuser **cu; int i; struct comuser *user = select_user(ch, player); if (!user) { if (ch->num_users >= MAX_USERS_PER_CHANNEL) { raw_notify(player, tprintf("Too many people on channel %s already.", ch->name)); return; } ch->num_users++; if (ch->num_users >= ch->max_users) { ch->max_users = ch->num_users + 10; cu = (struct comuser **)MEMALLOC(sizeof(struct comuser *) * ch->max_users); ISOUTOFMEMORY(cu); for (i = 0; i < (ch->num_users - 1); i++) { cu[i] = ch->users[i]; } MEMFREE(ch->users); ch->users = cu; } user = (struct comuser *)MEMALLOC(sizeof(struct comuser)); ISOUTOFMEMORY(user); for (i = ch->num_users - 1; i > 0 && ch->users[i - 1]->who > player; i--) { ch->users[i] = ch->users[i - 1]; } ch->users[i] = user; user->who = player; user->bUserIsOn = true; user->ComTitleStatus = true; user->title = StringClone(""); // if (Connected(player))&&(isPlayer(player)) // if (UNDEAD(player)) { user->on_next = ch->on_users; ch->on_users = user; } } else if (!user->bUserIsOn) { user->bUserIsOn = true; } else { raw_notify(player, tprintf("You are already on channel %s.", ch->name)); return; } if (!Hidden(player)) { char *messNormal, *messNoComtitle; BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, user, (char *)":has joined this channel.", &messNormal, &messNoComtitle); SendChannelMessage(player, ch, messNormal, messNoComtitle); } } void do_leavechannel(dbref player, struct channel *ch) { struct comuser *user = select_user(ch, player); raw_notify(player, tprintf("You have left channel %s.", ch->name)); if ( user->bUserIsOn && !Hidden(player)) { char *messNormal, *messNoComtitle; BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, user, (char *)":has left this channel.", &messNormal, &messNoComtitle); SendChannelMessage(player, ch, messNormal, messNoComtitle); } user->bUserIsOn = false; } static void do_comwho_line ( dbref player, struct channel *ch, struct comuser *user ) { char *msg; char *buff = NULL; if (user->title[0] != '\0') { // There is a comtitle // if (Staff(player)) { buff = unparse_object(player, user->who, false); if (ch->type & CHANNEL_SPOOF) { msg = tprintf("%s as %s", buff, user->title); } else { msg = tprintf("%s as %s %s", buff, user->title, buff); } } else { if (ch->type & CHANNEL_SPOOF) { msg = user->title; } else { buff = unparse_object(player, user->who, false); msg = tprintf("%s %s", user->title, buff); } } } else { buff = unparse_object(player, user->who, false); msg = buff; } raw_notify(player, msg); if (buff) { free_lbuf(buff); } } void do_comwho(dbref player, struct channel *ch) { struct comuser *user; raw_notify(player, "-- Players --"); for (user = ch->on_users; user; user = user->on_next) { if (isPlayer(user->who)) { if ( Connected(user->who) && ( !Hidden(user->who) || Wizard_Who(player) || See_Hidden(player))) { if (user->bUserIsOn) { do_comwho_line(player, ch, user); } } else if (!Hidden(user->who)) { do_comdisconnectchannel(user->who, ch->name); } } } raw_notify(player, "-- Objects --"); for (user = ch->on_users; user; user = user->on_next) { if (!isPlayer(user->who)) { if ( Going(user->who) && God(Owner(user->who))) { do_comdisconnectchannel(user->who, ch->name); } else if (user->bUserIsOn) { do_comwho_line(player, ch, user); } } } raw_notify(player, tprintf("-- %s --", ch->name)); } void do_comlast(dbref player, struct channel *ch, int arg) { if (!Good_obj(ch->chan_obj)) { raw_notify(player, "Channel does not have an object."); return; } dbref aowner; int aflags; dbref obj = ch->chan_obj; int logmax = MAX_RECALL_REQUEST; ATTR *pattr = atr_str("MAX_LOG"); if ( pattr && (atr_get_info(obj, pattr->number, &aowner, &aflags))) { char *maxbuf = atr_get(obj, pattr->number, &aowner, &aflags); logmax = mux_atol(maxbuf); free_lbuf(maxbuf); } if (logmax < 1) { raw_notify(player, "Channel does not log."); return; } if (arg < MIN_RECALL_REQUEST) { arg = MIN_RECALL_REQUEST; } if (arg > logmax) { arg = logmax; } char *message; int histnum = ch->num_messages - arg; raw_notify(player, "-- Begin Comsys Recall --"); for (int count = 0; count < arg; count++) { histnum++; pattr = atr_str(tprintf("HISTORY_%d", iMod(histnum, logmax))); if (pattr) { message = atr_get(obj, pattr->number, &aowner, &aflags); raw_notify(player, message); free_lbuf(message); } } raw_notify(player, "-- End Comsys Recall --"); } static bool do_chanlog(dbref player, char *channel, char *arg) { UNUSED_PARAMETER(player); int value; if ( !*arg || !is_integer(arg, NULL) || (value = mux_atol(arg)) > MAX_RECALL_REQUEST) { return false; } if (value < 0) { value = 0; } struct channel *ch = select_channel(channel); if (!Good_obj(ch->chan_obj)) { // No channel object has been set. // return false; } int atr = mkattr(GOD, "MAX_LOG"); if (atr <= 0) { return false; } dbref aowner; int aflags; char *oldvalue = atr_get(ch->chan_obj, atr, &aowner, &aflags); if (oldvalue) { int oldnum = mux_atol(oldvalue); if (oldnum > value) { ATTR *hist; for (int count = 0; count <= oldnum; count++) { hist = atr_str(tprintf("HISTORY_%d", count)); if (hist) { atr_clr(ch->chan_obj, hist->number); } } } free_lbuf(oldvalue); } atr_add(ch->chan_obj, atr, mux_ltoa_t(value), GOD, AF_CONST|AF_NOPROG|AF_NOPARSE); return true; } struct channel *select_channel(char *channel) { struct channel *cp = (struct channel *)hashfindLEN(channel, strlen(channel), &mudstate.channel_htab); return cp; } struct comuser *select_user(struct channel *ch, dbref player) { if (!ch) { return NULL; } int first = 0; int last = ch->num_users - 1; int dir = 1; int current = 0; while (dir && (first <= last)) { current = (first + last) / 2; if (ch->users[current] == NULL) { last--; continue; } if (ch->users[current]->who == player) { dir = 0; } else if (ch->users[current]->who < player) { dir = 1; first = current + 1; } else { dir = -1; last = current - 1; } } if (!dir) { return ch->users[current]; } else { return NULL; } } #define MAX_ALIASES_PER_PLAYER 100 void do_addcom ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *arg1, char *channel ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nargs); if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } bool bValidAlias; size_t nValidAlias; char *pValidAlias = MakeCanonicalComAlias(arg1, &nValidAlias, &bValidAlias); if (!bValidAlias) { raw_notify(executor, "You need to specify a valid alias."); return; } if ('\0' == channel[0]) { raw_notify(executor, "You need to specify a channel."); return; } int i, j, where; char *na; char **nc; struct channel *ch = select_channel(channel); char Buffer[MAX_CHANNEL_LEN+1]; if (!ch) { size_t nVisualWidth; ANSI_TruncateToField(channel, sizeof(Buffer), Buffer, sizeof(Buffer), &nVisualWidth, ANSI_ENDGOAL_NORMAL); raw_notify(executor, tprintf("Channel %s does not exist yet.", Buffer)); return; } if (!test_join_access(executor, ch)) { raw_notify(executor, "Sorry, this channel type does not allow you to join."); return; } comsys_t *c = get_comsys(executor); if (c->numchannels >= MAX_ALIASES_PER_PLAYER) { raw_notify(executor, tprintf("Sorry, but you have reached the maximum number of aliases allowed.")); return; } for (j = 0; j < c->numchannels && (strcmp(pValidAlias, c->alias + j * ALIAS_SIZE) > 0); j++) { ; // Nothing. } if (j < c->numchannels && !strcmp(pValidAlias, c->alias + j * ALIAS_SIZE)) { char *p = tprintf("That alias is already in use for channel %s.", c->channels[j]); raw_notify(executor, p); return; } if (c->numchannels >= c->maxchannels) { c->maxchannels = c->numchannels + 10; na = (char *)MEMALLOC(ALIAS_SIZE * c->maxchannels); ISOUTOFMEMORY(na); nc = (char **)MEMALLOC(sizeof(char *) * c->maxchannels); ISOUTOFMEMORY(nc); for (i = 0; i < c->numchannels; i++) { mux_strncpy(na + i * ALIAS_SIZE, c->alias + i * ALIAS_SIZE, ALIAS_SIZE-1); nc[i] = c->channels[i]; } if (c->alias) { MEMFREE(c->alias); c->alias = NULL; } if (c->channels) { MEMFREE(c->channels); c->channels = NULL; } c->alias = na; c->channels = nc; } where = c->numchannels++; for (i = where; i > j; i--) { mux_strncpy(c->alias + i * ALIAS_SIZE, c->alias + (i - 1) * ALIAS_SIZE, ALIAS_SIZE-1); c->channels[i] = c->channels[i - 1]; } where = j; memcpy(c->alias + where * ALIAS_SIZE, pValidAlias, nValidAlias); *(c->alias + where * ALIAS_SIZE + nValidAlias) = '\0'; c->channels[where] = StringClone(channel); if (!select_user(ch, executor)) { do_joinchannel(executor, ch); } raw_notify(executor, tprintf("Channel %s added with alias %s.", channel, pValidAlias)); } void do_delcom(dbref executor, dbref caller, dbref enactor, int eval, int key, char *arg1) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } if (!arg1) { raw_notify(executor, "Need an alias to delete."); return; } comsys_t *c = get_comsys(executor); int i; for (i = 0; i < c->numchannels; i++) { if (!strcmp(arg1, c->alias + i * ALIAS_SIZE)) { int itmp, found = 0; for (itmp = 0;itmp < c->numchannels; itmp++) { if (!strcmp(c->channels[itmp],c->channels[i])) { found++; } } // If we found no other channels, delete it // if (found <= 1) { do_delcomchannel(executor, c->channels[i], false); raw_notify(executor, tprintf("Alias %s for channel %s deleted.", arg1, c->channels[i])); MEMFREE(c->channels[i]); } else { raw_notify(executor, tprintf("Alias %s for channel %s deleted.", arg1, c->channels[i])); } c->channels[i] = NULL; c->numchannels--; for (; i < c->numchannels; i++) { mux_strncpy(c->alias + i * ALIAS_SIZE, c->alias + (i + 1) * ALIAS_SIZE, ALIAS_SIZE-1); c->channels[i] = c->channels[i + 1]; } return; } } raw_notify(executor, "Unable to find that alias."); } void do_delcomchannel(dbref player, char *channel, bool bQuiet) { struct comuser *user; struct channel *ch = select_channel(channel); if (!ch) { raw_notify(player, tprintf("Unknown channel %s.", channel)); } else { int i; int j = 0; for (i = 0; i < ch->num_users && !j; i++) { user = ch->users[i]; if (user->who == player) { do_comdisconnectchannel(player, channel); if (!bQuiet) { if ( user->bUserIsOn && !Hidden(player)) { char *messNormal, *messNoComtitle; BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, user, (char *)":has left this channel.", &messNormal, &messNoComtitle); SendChannelMessage(player, ch, messNormal, messNoComtitle); } raw_notify(player, tprintf("You have left channel %s.", channel)); } if (user->title) { MEMFREE(user->title); user->title = NULL; } MEMFREE(user); user = NULL; j = 1; } } if (j) { ch->num_users--; for (i--; i < ch->num_users; i++) { ch->users[i] = ch->users[i + 1]; } } } } void do_createchannel(dbref executor, dbref caller, dbref enactor, int eval, int key, char *channel) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); if ('\0' == channel[0]) { raw_notify(executor, "You must specify a channel to create."); return; } if (!Comm_All(executor)) { raw_notify(executor, NOPERM_MESSAGE); return; } struct channel *newchannel = (struct channel *)MEMALLOC(sizeof(struct channel)); if (NULL == newchannel) { raw_notify(executor, "Out of memory."); return; } size_t vwChannel; size_t nNameNoANSI; char *pNameNoANSI; char Buffer[MAX_HEADER_LEN]; size_t nChannel = ANSI_TruncateToField(channel, sizeof(Buffer), Buffer, sizeof(Buffer), &vwChannel, ANSI_ENDGOAL_NORMAL); if (nChannel == vwChannel) { // The channel name does not contain ANSI, so first, we add some to // get the header. // const size_t nMax = MAX_HEADER_LEN - (sizeof(ANSI_HILITE)-1) - (sizeof(ANSI_NORMAL)-1) - 2; if (nChannel > nMax) { nChannel = nMax; } Buffer[nChannel] = '\0'; mux_sprintf(newchannel->header, sizeof(newchannel->header), "%s[%s]%s", ANSI_HILITE, Buffer, ANSI_NORMAL); // Then, we use the non-ANSI part for the name. // nNameNoANSI = nChannel; pNameNoANSI = Buffer; } else { // The given channel name does contain ANSI. // memcpy(newchannel->header, Buffer, nChannel+1); pNameNoANSI = strip_ansi(Buffer, &nNameNoANSI); } if (nNameNoANSI > MAX_CHANNEL_LEN) { nNameNoANSI = MAX_CHANNEL_LEN; } memcpy(newchannel->name, pNameNoANSI, nNameNoANSI); newchannel->name[nNameNoANSI] = '\0'; if (select_channel(newchannel->name)) { raw_notify(executor, tprintf("Channel %s already exists.", newchannel->name)); MEMFREE(newchannel); return; } newchannel->type = 127; newchannel->temp1 = 0; newchannel->temp2 = 0; newchannel->charge = 0; newchannel->charge_who = executor; newchannel->amount_col = 0; newchannel->num_users = 0; newchannel->max_users = 0; newchannel->users = NULL; newchannel->on_users = NULL; newchannel->chan_obj = NOTHING; newchannel->num_messages = 0; num_channels++; hashaddLEN(newchannel->name, strlen(newchannel->name), newchannel, &mudstate.channel_htab); // Report the channel creation using non-ANSI name. // raw_notify(executor, tprintf("Channel %s created.", newchannel->name)); } void do_destroychannel(dbref executor, dbref caller, dbref enactor, int eval, int key, char *channel) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); struct channel *ch; int j; if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } ch = (struct channel *)hashfindLEN(channel, strlen(channel), &mudstate.channel_htab); if (!ch) { raw_notify(executor, tprintf("Could not find channel %s.", channel)); return; } else if ( !Comm_All(executor) && !Controls(executor, ch->charge_who)) { raw_notify(executor, NOPERM_MESSAGE); return; } num_channels--; hashdeleteLEN(channel, strlen(channel), &mudstate.channel_htab); for (j = 0; j < ch->num_users; j++) { MEMFREE(ch->users[j]); ch->users[j] = NULL; } MEMFREE(ch->users); ch->users = NULL; MEMFREE(ch); ch = NULL; raw_notify(executor, tprintf("Channel %s destroyed.", channel)); } #if 0 void do_cleanupchannels(void) { struct channel *ch; for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab); ch; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab)) { struct comuser *user, *prevuser = NULL; for (user = ch->on_users; user; ) { if (isPlayer(user->who)) { if (!test_join_access(user->who, ch)) //if (!Connected(user->who)) { // Go looking for user in the array. // bool bFound = false; int iPos; for (iPos = 0; iPos < ch->num_users && !bFound; iPos++) { if (ch->users[iPos] == user) { bFound = true; } } if (bFound) { // Remove user from the array. // ch->num_users--; for (iPos--; iPos < ch->num_users; iPos++) { ch->users[iPos] = ch->users[iPos+1]; } // Save user pointer for later reporting and freeing. // struct comuser *cuVictim = user; // Unlink user from the list, and decide who to look at next. // if (prevuser) { prevuser->on_next = user->on_next; } else { ch->on_users = user->on_next; } user = user->on_next; // Reporting // if (!Hidden(cuVictim->who)) { char *mess = StartBuildChannelMessage(cuVictim->who, (ch->type & CHANNEL_SPOOF) != 0, ch->header, cuVictim->title, Moniker(cuVictim->who), ":is booted off the channel by the system."); do_comsend(ch, mess); EndBuildChannelMessage(mess); } raw_notify(cuVictim->who, tprintf("The system has booted you off channel %s.", ch->name)); // Freeing // if (cuVictim->title) { MEMFREE(cuVictim->title); cuVictim->title = NULL; } MEMFREE(cuVictim); cuVictim = NULL; continue; } } } prevuser = user; user = user->on_next; } } } #endif static void do_listchannels(dbref player) { struct channel *ch; char temp[LBUF_SIZE]; bool perm = Comm_All(player); if (!perm) { raw_notify(player, "Warning: Only public channels and your channels will be shown."); } raw_notify(player, "*** Channel --Flags-- Obj Own Charge Balance Users Messages"); for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab); ch; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab)) { if ( perm || (ch->type & CHANNEL_PUBLIC) || Controls(player, ch->charge_who)) { mux_sprintf(temp, sizeof(temp), "%c%c%c %-13.13s %c%c%c/%c%c%c %7d %7d %8d %8d %6d %10d", (ch->type & CHANNEL_PUBLIC) ? 'P' : '-', (ch->type & CHANNEL_LOUD) ? 'L' : '-', (ch->type & CHANNEL_SPOOF) ? 'S' : '-', ch->name, (ch->type & CHANNEL_PLAYER_JOIN) ? 'J' : '-', (ch->type & CHANNEL_PLAYER_TRANSMIT) ? 'X' : '-', (ch->type & CHANNEL_PLAYER_RECEIVE) ? 'R' : '-', (ch->type & CHANNEL_OBJECT_JOIN) ? 'j' : '-', (ch->type & CHANNEL_OBJECT_TRANSMIT) ? 'x' : '-', (ch->type & CHANNEL_OBJECT_RECEIVE) ? 'r' : '-', (ch->chan_obj != NOTHING) ? ch->chan_obj : -1, ch->charge_who, ch->charge, ch->amount_col, ch->num_users, ch->num_messages); raw_notify(player, temp); } } raw_notify(player, "-- End of list of Channels --"); } void do_comtitle ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *arg1, char *arg2 ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } if (!*arg1) { raw_notify(executor, "Need an alias to do comtitle."); return; } char channel[MAX_CHANNEL_LEN+1]; mux_strncpy(channel, get_channel_from_alias(executor, arg1), MAX_CHANNEL_LEN); if (channel[0] == '\0') { raw_notify(executor, "Unknown alias."); return; } struct channel *ch = select_channel(channel); if (ch) { if (select_user(ch, executor)) { if (key == COMTITLE_OFF) { if ((ch->type & CHANNEL_SPOOF) == 0) { raw_notify(executor, tprintf("Comtitles are now off for channel %s", channel)); do_setcomtitlestatus(executor, ch, false); } else { raw_notify(executor, "You can not turn off comtitles on that channel."); } } else if (key == COMTITLE_ON) { raw_notify(executor, tprintf("Comtitles are now on for channel %s", channel)); do_setcomtitlestatus(executor, ch, true); } else { char *pValidatedTitleValue = RestrictTitleValue(arg2); do_setnewtitle(executor, ch, pValidatedTitleValue); raw_notify(executor, tprintf("Title set to '%s' on channel %s.", pValidatedTitleValue, channel)); } } } else { raw_notify(executor, "Illegal comsys alias, please delete."); } } void do_comlist ( dbref executor, dbref caller, dbref enactor, int eval, int key, char* pattern ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } bool bWild; if ( NULL != pattern && '\0' != *pattern) { bWild = true; } else { bWild = false; } raw_notify(executor, "Alias Channel Status Title"); comsys_t *c = get_comsys(executor); int i; for (i = 0; i < c->numchannels; i++) { struct comuser *user = select_user(select_channel(c->channels[i]), executor); if (user) { if ( !bWild || quick_wild(pattern,c->channels[i])) { char *p = tprintf("%-9.9s %-18.18s %s %s %s", c->alias + i * ALIAS_SIZE, c->channels[i], (user->bUserIsOn ? "on " : "off"), (user->ComTitleStatus ? "con " : "coff"), user->title); raw_notify(executor, p); } } else { raw_notify(executor, tprintf("Bad Comsys Alias: %s for Channel: %s", c->alias + i * ALIAS_SIZE, c->channels[i])); } } raw_notify(executor, "-- End of comlist --"); } void do_channelnuke(dbref player) { struct channel *ch; int j; for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab); ch; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab)) { if (player == ch->charge_who) { num_channels--; hashdeleteLEN(ch->name, strlen(ch->name), &mudstate.channel_htab); if (NULL != ch->users) { for (j = 0; j < ch->num_users; j++) { MEMFREE(ch->users[j]); ch->users[j] = NULL; } MEMFREE(ch->users); ch->users = NULL; } MEMFREE(ch); ch = NULL; } } } void do_clearcom(dbref executor, dbref caller, dbref enactor, int unused2) { UNUSED_PARAMETER(unused2); if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } comsys_t *c = get_comsys(executor); int i; for (i = (c->numchannels) - 1; i > -1; --i) { do_delcom(executor, caller, enactor, 0, 0, c->alias + i * ALIAS_SIZE); } } void do_allcom(dbref executor, dbref caller, dbref enactor, int eval, int key, char *arg1) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(eval); if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } if ( strcmp(arg1, "who") != 0 && strcmp(arg1, "on") != 0 && strcmp(arg1, "off") != 0) { raw_notify(executor, "Only options available are: on, off and who."); return; } comsys_t *c = get_comsys(executor); int i; for (i = 0; i < c->numchannels; i++) { do_processcom(executor, c->channels[i], arg1); if (strcmp(arg1, "who") == 0) { raw_notify(executor, ""); } } } void sort_users(struct channel *ch) { int i; bool done = false; struct comuser *user; int nu = ch->num_users; while (!done) { done = true; for (i = 0; i < (nu - 1); i++) { if (ch->users[i]->who > ch->users[i + 1]->who) { user = ch->users[i]; ch->users[i] = ch->users[i + 1]; ch->users[i + 1] = user; done = false; } } } } void do_channelwho(dbref executor, dbref caller, dbref enactor, int eval, int key, char *arg1) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } char channel[MAX_CHANNEL_LEN+1]; char *s = arg1; char *t = channel; while (*s && *s != '/' && ((t - channel) < MAX_CHANNEL_LEN)) { *t++ = *s++; } *t = 0; bool flag = false; if (*s && *(s + 1)) { flag = (*(s + 1) == 'a'); } struct channel *ch = select_channel(channel); if (!ch) { raw_notify(executor, tprintf("Unknown channel %s.", channel)); return; } if ( !( Comm_All(executor) || Controls(executor,ch->charge_who))) { raw_notify(executor, NOPERM_MESSAGE); return; } raw_notify(executor, tprintf("-- %s --", ch->name)); raw_notify(executor, tprintf("%-29.29s %-6.6s %-6.6s", "Name", "Status", "Player")); struct comuser *user; char *buff; char temp[LBUF_SIZE]; int i; for (i = 0; i < ch->num_users; i++) { user = ch->users[i]; if ( ( flag || UNDEAD(user->who)) && ( !Hidden(user->who) || Wizard_Who(executor) || See_Hidden(executor))) { buff = unparse_object(executor, user->who, false); mux_sprintf(temp, sizeof(temp), "%-29.29s %-6.6s %-6.6s", strip_ansi(buff), user->bUserIsOn ? "on " : "off", isPlayer(user->who) ? "yes" : "no "); raw_notify(executor, temp); free_lbuf(buff); } } raw_notify(executor, tprintf("-- %s --", ch->name)); } static void do_comdisconnectraw_notify(dbref player, char *chan) { struct channel *ch = select_channel(chan); if (!ch) return; struct comuser *cu = select_user(ch, player); if (!cu) return; if ( (ch->type & CHANNEL_LOUD) && cu->bUserIsOn && !Hidden(player)) { char *messNormal, *messNoComtitle; BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, cu, (char *)":has disconnected.", &messNormal, &messNoComtitle); SendChannelMessage(player, ch, messNormal, messNoComtitle); } } static void do_comconnectraw_notify(dbref player, char *chan) { struct channel *ch = select_channel(chan); if (!ch) return; struct comuser *cu = select_user(ch, player); if (!cu) return; if ( (ch->type & CHANNEL_LOUD) && cu->bUserIsOn && !Hidden(player)) { char *messNormal, *messNoComtitle; BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, cu, (char *)":has connected.", &messNormal, &messNoComtitle); SendChannelMessage(player, ch, messNormal, messNoComtitle); } } static void do_comconnectchannel(dbref player, char *channel, char *alias, int i) { struct comuser *user; struct channel *ch = select_channel(channel); if (ch) { for (user = ch->on_users; user && user->who != player; user = user->on_next) ; if (!user) { user = select_user(ch, player); if (user) { user->on_next = ch->on_users; ch->on_users = user; } else { raw_notify(player, tprintf("Bad Comsys Alias: %s for Channel: %s", alias + i * ALIAS_SIZE, channel)); } } } else { raw_notify(player, tprintf("Bad Comsys Alias: %s for Channel: %s", alias + i * ALIAS_SIZE, channel)); } } void do_comdisconnect(dbref player) { comsys_t *c = get_comsys(player); int i; for (i = 0; i < c->numchannels; i++) { char *CurrentChannel = c->channels[i]; bool bFound = false; int j; for (j = 0; j < i; j++) { if (strcmp(c->channels[j], CurrentChannel) == 0) { bFound = true; break; } } if (!bFound) { do_comdisconnectchannel(player, CurrentChannel); do_comdisconnectraw_notify(player, CurrentChannel); } } } void do_comconnect(dbref player) { comsys_t *c = get_comsys(player); int i; for (i = 0; i < c->numchannels; i++) { char *CurrentChannel = c->channels[i]; bool bFound = false; int j; for (j = 0; j < i; j++) { if (strcmp(c->channels[j], CurrentChannel) == 0) { bFound = true; break; } } if (!bFound) { do_comconnectchannel(player, CurrentChannel, c->alias, i); do_comconnectraw_notify(player, CurrentChannel); } } } void do_comdisconnectchannel(dbref player, char *channel) { struct channel *ch = select_channel(channel); if (!ch) { return; } struct comuser *prevuser = NULL; struct comuser *user; for (user = ch->on_users; user;) { if (user->who == player) { if (prevuser) { prevuser->on_next = user->on_next; } else { ch->on_users = user->on_next; } return; } else { prevuser = user; user = user->on_next; } } } void do_editchannel ( dbref executor, dbref caller, dbref enactor, int flag, int nargs, char *arg1, char *arg2 ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } struct channel *ch = select_channel(arg1); if (!ch) { raw_notify(executor, tprintf("Unknown channel %s.", arg1)); return; } if ( !( Comm_All(executor) || Controls(executor, ch->charge_who))) { raw_notify(executor, NOPERM_MESSAGE); return; } bool add_remove = true; char *s = arg2; if (*s == '!') { add_remove = false; s++; } switch (flag) { case 0: { dbref who = lookup_player(executor, arg2, true); if (Good_obj(who)) { ch->charge_who = Owner(who); raw_notify(executor, "Set."); } else { raw_notify(executor, "Invalid player."); } } break; case 1: { int c_charge = mux_atol(arg2); if ( 0 <= c_charge && c_charge <= MAX_COST) { ch->charge = c_charge; raw_notify(executor, "Set."); } else { raw_notify(executor, "That is not a reasonable cost."); } } break; case 3: { int access = 0; if (strcmp(s, "join") == 0) { access = CHANNEL_PLAYER_JOIN; } else if (strcmp(s, "receive") == 0) { access = CHANNEL_PLAYER_RECEIVE; } else if (strcmp(s, "transmit") == 0) { access = CHANNEL_PLAYER_TRANSMIT; } else { raw_notify(executor, "@cpflags: Unknown Flag."); } if (access) { if (add_remove) { ch->type |= access; raw_notify(executor, "@cpflags: Set."); } else { ch->type &= ~access; raw_notify(executor, "@cpflags: Cleared."); } } } break; case 4: { int access = 0; if (strcmp(s, "join") == 0) { access = CHANNEL_OBJECT_JOIN; } else if (strcmp(s, "receive") == 0) { access = CHANNEL_OBJECT_RECEIVE; } else if (strcmp(s, "transmit") == 0) { access = CHANNEL_OBJECT_TRANSMIT; } else { raw_notify(executor, "@coflags: Unknown Flag."); } if (access) { if (add_remove) { ch->type |= access; raw_notify(executor, "@coflags: Set."); } else { ch->type &= ~access; raw_notify(executor, "@coflags: Cleared."); } } } break; } } bool test_join_access(dbref player, struct channel *chan) { if (Comm_All(player)) { return true; } int access; if (isPlayer(player)) { access = CHANNEL_PLAYER_JOIN; } else { access = CHANNEL_OBJECT_JOIN; } return ( (chan->type & access) != 0 || could_doit(player, chan->chan_obj, A_LOCK)); } bool test_transmit_access(dbref player, struct channel *chan) { if (Comm_All(player)) { return true; } int access; if (isPlayer(player)) { access = CHANNEL_PLAYER_TRANSMIT; } else { access = CHANNEL_OBJECT_TRANSMIT; } return ( (chan->type & access) != 0 || could_doit(player, chan->chan_obj, A_LUSE)); } bool test_receive_access(dbref player, struct channel *chan) { if (Comm_All(player)) { return true; } int access; if (isPlayer(player)) { access = CHANNEL_PLAYER_RECEIVE; } else { access = CHANNEL_OBJECT_RECEIVE; } return ( (chan->type & access) != 0 || could_doit(player, chan->chan_obj, A_LENTER)); } // true means continue, false means stop // bool do_comsystem(dbref who, char *cmd) { char *t = strchr(cmd, ' '); if ( !t || t - cmd > MAX_ALIAS_LEN || t[1] == '\0') { // doesn't fit the pattern of "alias message" return true; } char alias[ALIAS_SIZE]; memcpy(alias, cmd, t - cmd); alias[t - cmd] = '\0'; char *ch = get_channel_from_alias(who, alias); if (ch[0] == '\0') { // not really an alias after all return true; } t++; do_processcom(who, ch, t); return false; } void do_cemit ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *chan, char *text ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } struct channel *ch = select_channel(chan); if (!ch) { raw_notify(executor, tprintf("Channel %s does not exist.", chan)); return; } if ( !Controls(executor, ch->charge_who) && !Comm_All(executor)) { raw_notify(executor, NOPERM_MESSAGE); return; } char *text2 = alloc_lbuf("do_cemit"); if (key == CEMIT_NOHEADER) { mux_strncpy(text2, text, LBUF_SIZE-1); } else { mux_strncpy(text2, tprintf("%s %s", ch->header, text), LBUF_SIZE-1); } SendChannelMessage(executor, ch, text2, text2); } void do_chopen ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *chan, char *value ) { UNUSED_PARAMETER(nargs); if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } if (key == CSET_LIST) { do_chanlist(executor, caller, enactor, 0, 1, NULL); return; } const char *msg = NULL; struct channel *ch = select_channel(chan); if (!ch) { msg = tprintf("@cset: Channel %s does not exist.", chan); raw_notify(executor, msg); return; } if ( !Controls(executor, ch->charge_who) && !Comm_All(executor)) { raw_notify(executor, NOPERM_MESSAGE); return; } char *buff; dbref thing; switch (key) { case CSET_PUBLIC: ch->type |= CHANNEL_PUBLIC; msg = tprintf("@cset: Channel %s placed on the public listings.", chan); break; case CSET_PRIVATE: ch->type &= ~CHANNEL_PUBLIC; msg = tprintf("@cset: Channel %s taken off the public listings." ,chan); break; case CSET_LOUD: ch->type |= CHANNEL_LOUD; msg = tprintf("@cset: Channel %s now sends connect/disconnect msgs.", chan); break; case CSET_QUIET: ch->type &= ~CHANNEL_LOUD; msg = tprintf("@cset: Channel %s connect/disconnect msgs muted.", chan); break; case CSET_SPOOF: ch->type |= CHANNEL_SPOOF; msg = tprintf("@cset: Channel %s set spoofable.", chan); break; case CSET_NOSPOOF: ch->type &= ~CHANNEL_SPOOF; msg = tprintf("@cset: Channel %s set unspoofable.", chan); break; case CSET_OBJECT: init_match(executor, value, NOTYPE); match_everything(0); thing = match_result(); if (thing == NOTHING) { ch->chan_obj = thing; msg = tprintf("Channel %s is now disassociated from any channel object.", ch->name); } else if (Good_obj(thing)) { ch->chan_obj = thing; buff = unparse_object(executor, thing, false); msg = tprintf("Channel %s is now using %s as channel object.", ch->name, buff); free_lbuf(buff); } else { msg = tprintf("%d is not a valid channel object.", thing); } break; case CSET_HEADER: do_cheader(executor, chan, value); msg = "Set."; break; case CSET_LOG: if (do_chanlog(executor, chan, value)) { msg = tprintf("@cset: Channel %s maximum history set.", chan); } else { msg = tprintf("@cset: Maximum history must be a number less than or equal to %d.", MAX_RECALL_REQUEST); } break; } raw_notify(executor, msg); } void do_chboot ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *channel, char *victim ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); // I sure hope it's not going to be that long. // if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } struct channel *ch = select_channel(channel); if (!ch) { raw_notify(executor, "@cboot: Unknown channel."); return; } struct comuser *user = select_user(ch, executor); if (!user) { raw_notify(executor, "@cboot: You are not on that channel."); return; } if ( !Controls(executor, ch->charge_who) && !Comm_All(executor)) { raw_notify(executor, "@cboot: You can't do that!"); return; } dbref thing = match_thing(executor, victim); if (!Good_obj(thing)) { return; } struct comuser *vu = select_user(ch, thing); if (!vu) { raw_notify(executor, tprintf("@cboot: %s is not on the channel.", Moniker(thing))); return; } raw_notify(executor, tprintf("You boot %s off channel %s.", Moniker(thing), ch->name)); raw_notify(thing, tprintf("%s boots you off channel %s.", Moniker(thing), ch->name)); if (!(key & CBOOT_QUIET)) { char *mess1, *mess1nct; char *mess2, *mess2nct; BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, ch->header, user, (char *)":boots", &mess1, &mess1nct); BuildChannelMessage((ch->type & CHANNEL_SPOOF) != 0, 0, vu, (char *)":off the channel.", &mess2, &mess2nct); char *messNormal = alloc_lbuf("do_chboot.messnormal"); char *messNoComtitle = alloc_lbuf("do_chboot.messnocomtitle"); char *mnp = messNormal; char *mnctp = messNoComtitle; if (mess1) { safe_str(mess1, messNormal, &mnp); free_lbuf(mess1); } if (mess2) { safe_str(mess2, messNormal, &mnp); free_lbuf(mess2); } *mnp = '\0'; if (mess1nct) { safe_str(mess1nct, messNoComtitle, &mnctp); free_lbuf(mess1nct); } if (mess2nct) { safe_str(mess2nct, messNoComtitle, &mnctp); free_lbuf(mess2nct); } *mnctp = '\0'; SendChannelMessage(executor, ch, messNormal, messNoComtitle); do_delcomchannel(thing, channel, false); } else { do_delcomchannel(thing, channel, true); } } void do_cheader(dbref player, char *channel, char *header) { struct channel *ch = select_channel(channel); if (!ch) { raw_notify(player, "That channel does not exist."); return; } if ( !Controls(player, ch->charge_who) && !Comm_All(player)) { raw_notify(player, NOPERM_MESSAGE); return; } char *p = RemoveSetOfCharacters(header, "\r\n\t"); // Optimize/terminate any ANSI in the string. // char NewHeader_ANSI[MAX_HEADER_LEN+1]; size_t nVisualWidth; size_t nLen = ANSI_TruncateToField(p, sizeof(NewHeader_ANSI), NewHeader_ANSI, sizeof(NewHeader_ANSI), &nVisualWidth, ANSI_ENDGOAL_NORMAL); memcpy(ch->header, NewHeader_ANSI, nLen+1); } struct chanlist_node { char * name; struct channel * ptr; }; static int DCL_CDECL chanlist_comp(const void* a, const void* b) { chanlist_node* ca = (chanlist_node*)a; chanlist_node* cb = (chanlist_node*)b; return mux_stricmp(ca->name, cb->name); } void do_chanlist ( dbref executor, dbref caller, dbref enactor, int eval, int key, char *pattern ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); if (!mudconf.have_comsys) { raw_notify(executor, "Comsys disabled."); return; } if (key & CLIST_FULL) { do_listchannels(executor); return; } dbref owner; struct channel *ch; int flags = 0; char *atrstr; char *temp = alloc_mbuf("do_chanlist_temp"); char *buf = alloc_mbuf("do_chanlist_buf"); if (key & CLIST_HEADERS) { raw_notify(executor, "*** Channel Owner Header"); } else { raw_notify(executor, "*** Channel Owner Description"); } bool bWild; if ( NULL != pattern && '\0' != *pattern) { bWild = true; } else { bWild = false; } #define MAX_SUPPORTED_NUM_ENTRIES 10000 unsigned int entries = mudstate.channel_htab.GetEntryCount(); if (MAX_SUPPORTED_NUM_ENTRIES < entries) { // Nobody should have so many channels. // entries = MAX_SUPPORTED_NUM_ENTRIES; } if (0 < entries) { struct chanlist_node* charray = (chanlist_node*)MEMALLOC(sizeof(chanlist_node)*entries); if (charray) { // Arrayify all the channels // size_t actualEntries = 0; for ( ch = (struct channel *)hash_firstentry(&mudstate.channel_htab); ch && actualEntries < entries; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab)) { if ( !bWild || quick_wild(pattern, ch->name)) { charray[actualEntries].name = ch->name; charray[actualEntries].ptr = ch; actualEntries++; } } if (0 < actualEntries) { qsort(charray, actualEntries, sizeof(struct chanlist_node), chanlist_comp); for (size_t i = 0; i < actualEntries; i++) { ch = charray[i].ptr; if ( Comm_All(executor) || (ch->type & CHANNEL_PUBLIC) || Controls(executor, ch->charge_who)) { char *pBuffer; if (key & CLIST_HEADERS) { pBuffer = ch->header; } else { atrstr = atr_pget(ch->chan_obj, A_DESC, &owner, &flags); if ( NOTHING == ch->chan_obj || !*atrstr) { mux_strncpy(buf, "No description.", MBUF_SIZE-1); } else { mux_sprintf(buf, MBUF_SIZE, "%-54.54s", atrstr); } free_lbuf(atrstr); pBuffer = buf; } char *ownername_ansi = ANSI_TruncateAndPad_sbuf(Moniker(ch->charge_who), 15); mux_sprintf(temp, MBUF_SIZE, "%c%c%c %-13.13s %s %-45.45s", (ch->type & (CHANNEL_PUBLIC)) ? 'P' : '-', (ch->type & (CHANNEL_LOUD)) ? 'L' : '-', (ch->type & (CHANNEL_SPOOF)) ? 'S' : '-', ch->name, ownername_ansi, pBuffer); free_sbuf(ownername_ansi); raw_notify(executor, temp); } } } MEMFREE(charray); } } free_mbuf(temp); free_mbuf(buf); raw_notify(executor, "-- End of list of Channels --"); } // Returns a player's comtitle for a named channel. // FUNCTION(fun_comtitle) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!mudconf.have_comsys) { safe_str("#-1 COMSYS DISABLED", buff, bufc); return; } dbref victim = lookup_player(executor, fargs[0], true); if (!Good_obj(victim)) { init_match(executor, fargs[0], TYPE_THING); match_everything(0); victim = match_result(); if (!Good_obj(victim)) { safe_str("#-1 OBJECT DOES NOT EXIST", buff, bufc); return; } } struct channel *chn = select_channel(fargs[1]); if (!chn) { safe_str("#-1 CHANNEL DOES NOT EXIST", buff, bufc); return; } comsys_t *c = get_comsys(executor); struct comuser *user; int i; bool onchannel = false; if (Wizard(executor)) { onchannel = true; } else { for (i = 0; i < c->numchannels; i++) { user = select_user(chn, executor); if (user) { onchannel = true; break; } } } if (!onchannel) { safe_noperm(buff, bufc); return; } for (i = 0; i < c->numchannels; i++) { user = select_user(chn, victim); if (user) { // Do we want this function to evaluate the comtitle or not? #if 0 char *nComTitle = GetComtitle(user); safe_str(nComTitle, buff, bufc); FreeComtitle(nComTitle); return; #else safe_str(user->title, buff, bufc); return; #endif } } safe_str("#-1 OBJECT NOT ON THAT CHANNEL", buff, bufc); } // Returns a player's comsys alias for a named channel. // FUNCTION(fun_comalias) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!mudconf.have_comsys) { safe_str("#-1 COMSYS DISABLED", buff, bufc); return; } dbref victim = lookup_player(executor, fargs[0], true); if (!Good_obj(victim)) { init_match(executor, fargs[0], TYPE_THING); match_everything(0); victim = match_result(); if (!Good_obj(victim)) { safe_str("#-1 OBJECT DOES NOT EXIST", buff, bufc); return; } } struct channel *chn = select_channel(fargs[1]); if (!chn) { safe_str("#-1 CHANNEL DOES NOT EXIST", buff, bufc); return; } // Wizards can get the comalias for anyone. Players and objects can check // for themselves. Objects that Inherit can check for their owners. // if ( !Wizard(executor) && executor != victim && ( Owner(executor) != victim || !Inherits(executor))) { safe_noperm(buff, bufc); return; } comsys_t *cc = get_comsys(victim); for (int i = 0; i < cc->numchannels; i++) { if (!strcmp(fargs[1], cc->channels[i])) { safe_str(cc->alias + i * ALIAS_SIZE, buff, bufc); return; } } safe_str("#-1 OBJECT NOT ON THAT CHANNEL", buff, bufc); } // Returns a list of channels. // FUNCTION(fun_channels) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!mudconf.have_comsys) { safe_str("#-1 COMSYS DISABLED", buff, bufc); return; } dbref who = NOTHING; if (nfargs >= 1) { who = lookup_player(executor, fargs[0], true); if ( who == NOTHING && mux_stricmp(fargs[0], "all") != 0) { safe_str("#-1 PLAYER NOT FOUND", buff, bufc); return; } } ITL itl; ItemToList_Init(&itl, buff, bufc); struct channel *chn; for (chn = (struct channel *)hash_firstentry(&mudstate.channel_htab); chn; chn = (struct channel *)hash_nextentry(&mudstate.channel_htab)) { if ( ( Comm_All(executor) || (chn->type & CHANNEL_PUBLIC) || Controls(executor, chn->charge_who)) && ( who == NOTHING || Controls(who, chn->charge_who)) && !ItemToList_AddString(&itl, chn->name)) { break; } } } mux2.6/src/log.cpp0000600000175000017500000002117111025753746014065 0ustar sdennissdennis// log.cpp -- Logging routines. // // $Id: log.cpp 2734 2007-10-28 23:02:55Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include #include "command.h" NAMETAB logdata_nametab[] = { {"flags", 1, 0, LOGOPT_FLAGS}, {"location", 1, 0, LOGOPT_LOC}, {"owner", 1, 0, LOGOPT_OWNER}, {"timestamp", 1, 0, LOGOPT_TIMESTAMP}, { NULL, 0, 0, 0} }; NAMETAB logoptions_nametab[] = { {"accounting", 2, 0, LOG_ACCOUNTING}, {"all_commands", 2, 0, LOG_ALLCOMMANDS}, {"bad_commands", 2, 0, LOG_BADCOMMANDS}, {"buffer_alloc", 3, 0, LOG_ALLOCATE}, {"bugs", 3, 0, LOG_BUGS}, {"checkpoints", 2, 0, LOG_DBSAVES}, {"config_changes", 2, 0, LOG_CONFIGMODS}, {"create", 2, 0, LOG_PCREATES}, {"killing", 1, 0, LOG_KILLS}, {"logins", 1, 0, LOG_LOGIN}, {"network", 1, 0, LOG_NET}, {"problems", 1, 0, LOG_PROBLEMS}, {"security", 2, 0, LOG_SECURITY}, {"shouts", 2, 0, LOG_SHOUTS}, {"startup", 2, 0, LOG_STARTUP}, {"suspect", 2, 0, LOG_SUSPECTCMDS}, {"time_usage", 1, 0, LOG_TIMEUSE}, {"wizard", 1, 0, LOG_WIZARD}, { NULL, 0, 0, 0} }; /* --------------------------------------------------------------------------- * start_log: see if it is OK to log something, and if so, start writing the * log entry. */ bool start_log(const char *primary, const char *secondary) { mudstate.logging++; if ( 1 <= mudstate.logging && mudstate.logging <= 2) { if (!mudstate.bStandAlone) { // Format the timestamp. // char buffer[256]; buffer[0] = '\0'; if (mudconf.log_info & LOGOPT_TIMESTAMP) { CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); FIELDEDTIME ft; ltaNow.ReturnFields(&ft); mux_sprintf(buffer, sizeof(buffer), "%d.%02d%02d:%02d%02d%02d ",ft.iYear, ft.iMonth, ft.iDayOfMonth, ft.iHour, ft.iMinute, ft.iSecond); } // Write the header to the log. // if ( secondary && *secondary) { Log.tinyprintf("%s%s %3s/%-5s: ", buffer, mudconf.mud_name, primary, secondary); } else { Log.tinyprintf("%s%s %-9s: ", buffer, mudconf.mud_name, primary); } } // If a recursive call, log it and return indicating no log. // if (mudstate.logging == 1) { return true; } Log.WriteString("Recursive logging request." ENDLINE); } mudstate.logging--; return false; } /* --------------------------------------------------------------------------- * end_log: Finish up writing a log entry */ void end_log(void) { Log.WriteString(ENDLINE); Log.Flush(); mudstate.logging--; } /* --------------------------------------------------------------------------- * log_perror: Write perror message to the log */ void log_perror(const char *primary, const char *secondary, const char *extra, const char *failing_object) { start_log(primary, secondary); if (extra && *extra) { log_text("("); log_text(extra); log_text(") "); } // : // Log.WriteString(failing_object); Log.WriteString(": "); Log.WriteString(mux_strerror(errno)); #ifndef WIN32 Log.WriteString(ENDLINE); #endif // !WIN32 Log.Flush(); mudstate.logging--; } /* --------------------------------------------------------------------------- * log_text, log_number: Write text or number to the log file. */ void log_text(const char *text) { Log.WriteString(strip_ansi(text)); } void log_number(int num) { Log.WriteInteger(num); } void DCL_CDECL log_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); char aTempBuffer[SIZEOF_LOG_BUFFER]; size_t nString = mux_vsnprintf(aTempBuffer, SIZEOF_LOG_BUFFER, fmt, ap); va_end(ap); Log.WriteBuffer(nString, aTempBuffer); } /* --------------------------------------------------------------------------- * log_name: write the name, db number, and flags of an object to the log. * If the object does not own itself, append the name, db number, and flags * of the owner. */ void log_name(dbref target) { if (mudstate.bStandAlone) { Log.tinyprintf("%s(#%d)", Name(target), target); } else { char *tp; if (mudconf.log_info & LOGOPT_FLAGS) { tp = unparse_object(GOD, target, false); } else { tp = unparse_object_numonly(target); } Log.WriteString(strip_ansi(tp)); free_lbuf(tp); if ( (mudconf.log_info & LOGOPT_OWNER) && target != Owner(target)) { if (mudconf.log_info & LOGOPT_FLAGS) { tp = unparse_object(GOD, Owner(target), false); } else { tp = unparse_object_numonly(Owner(target)); } Log.tinyprintf("[%s]", strip_ansi(tp)); free_lbuf(tp); } } } /* --------------------------------------------------------------------------- * log_name_and_loc: Log both the name and location of an object */ void log_name_and_loc(dbref player) { log_name(player); if ( (mudconf.log_info & LOGOPT_LOC) && Has_location(player)) { log_text(" in "); log_name(Location(player)); } return; } static const char *OBJTYP(dbref thing) { if (!Good_dbref(thing)) { return "??OUT-OF-RANGE??"; } switch (Typeof(thing)) { case TYPE_PLAYER: return "PLAYER"; case TYPE_THING: return "THING"; case TYPE_ROOM: return "ROOM"; case TYPE_EXIT: return "EXIT"; case TYPE_GARBAGE: return "GARBAGE"; default: return "??ILLEGAL??"; } } void log_type_and_name(dbref thing) { char nbuf[16]; log_text(OBJTYP(thing)); mux_sprintf(nbuf, sizeof(nbuf), " #%d(", thing); log_text(nbuf); if (Good_obj(thing)) { log_text(Name(thing)); } log_text(")"); return; } void do_log ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *whichlog, char *logtext ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nargs); bool bValid = true; // Strip the filename of all ANSI. // char *pFilename = strip_ansi(whichlog); // Restrict filename to a subdirectory to reduce the possibility // of a security hole. // char *temp_ptr = strrchr(pFilename, '/'); if (temp_ptr) { pFilename = ++temp_ptr; } temp_ptr = strrchr(pFilename, '\\'); if (temp_ptr) { pFilename = ++temp_ptr; } // Check for and disallow leading periods, empty strings // and filenames over 30 characters. // size_t n = strlen(pFilename); if ( n == 0 || n > 30) { bValid = false; } else { unsigned int i; for (i = 0; i < n; i++) { if (!mux_isalnum(pFilename[i])) { bValid = false; break; } } } char *pFullName = NULL; const char *pMessage = ""; if (bValid) { pFullName = alloc_lbuf("do_log_filename"); mux_sprintf(pFullName, LBUF_SIZE, "logs/M-%s.log", pFilename); // Strip the message of all ANSI. // pMessage = strip_ansi(logtext); // Check for and disallow empty messages. // if (pMessage[0] == '\0') { bValid = false; } } if (!bValid) { if (pFullName) { free_lbuf(pFullName); } notify(executor, "Syntax: @log file=message"); return; } FILE *hFile; if (mux_fopen(&hFile, pFullName, "r")) { fclose(hFile); if (mux_fopen(&hFile, pFullName, "a")) { // Okay, at this point, the file exists. // free_lbuf(pFullName); fprintf(hFile, "%s" ENDLINE, pMessage); fclose(hFile); return; } } free_lbuf(pFullName); notify(executor, "Not a valid log file."); return; } mux2.6/src/timeutil.h0000600000175000017500000001723211025753746014610 0ustar sdennissdennis// timeutil.h -- CLinearTimeAbsolute, and CLinearTimeDelta modules. // // $Id: timeutil.h 2734 2007-10-28 23:02:55Z brazilofmux $ // // Date/Time code based on algorithms presented in "Calendrical Calculations", // Cambridge Press, 1998. // #ifndef TIMEUTIL_H #define TIMEUTIL_H typedef struct { short iYear; // 1900 would be stored as 1900. unsigned short iMonth; // January is 1. December is 12. unsigned short iDayOfWeek; // 0 is Sunday, 1 is Monday, etc. unsigned short iDayOfMonth; // Day of Month, 1..31 unsigned short iDayOfYear; // January 1st is 1, etc. unsigned short iHour; unsigned short iMinute; unsigned short iSecond; unsigned short iMillisecond; // Milliseconds less than a second. unsigned short iMicrosecond; // Microseconds less than a Millisecond. unsigned short iNanosecond; // Nanoseconds less than a Microsecond. } FIELDEDTIME; class CLinearTimeDelta; class CLinearTimeAbsolute { friend class CLinearTimeDelta; friend bool operator<(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb); friend bool operator>(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb); friend bool operator==(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb); friend bool operator<=(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb); friend CLinearTimeAbsolute operator+(const CLinearTimeAbsolute& lta, const CLinearTimeDelta& ltd); friend CLinearTimeAbsolute operator-(const CLinearTimeAbsolute& lta, const CLinearTimeDelta& ltd); friend CLinearTimeDelta operator-(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb); private: INT64 m_tAbsolute; static int m_nCount; static char m_Buffer[204]; public: //CLinearTimeAbsolute(int tInitial); CLinearTimeAbsolute(void); CLinearTimeAbsolute(const CLinearTimeAbsolute& ltaOrigin, const CLinearTimeDelta& ltdOffset); CLinearTimeAbsolute(const CLinearTimeAbsolute& lta); void operator=(const CLinearTimeAbsolute& lta); void operator+=(const CLinearTimeDelta& ltdOffset); void operator-=(const CLinearTimeDelta& ltdOffset); void GetUTC(void); void GetLocal(void); void ReturnUniqueString(char *buffer, size_t nBuffer); char *ReturnDateString(int nFracDigits = 0); bool ReturnFields(FIELDEDTIME *arg_tStruct); INT64 ReturnSeconds(void); char *ReturnSecondsString(int nFracDigits = 0); INT64 Return100ns(void); void SetSeconds(INT64 arg_tSeconds); bool SetSecondsString(char *arg_szSeconds); bool SetFields(FIELDEDTIME *arg_tStruct); bool SetString(const char *arg_tBuffer); void Set100ns(INT64 arg_t100ns); void UTC2Local(void); void Local2UTC(void); }; bool FieldedTimeToLinearTime(FIELDEDTIME *ft, INT64 *plt); bool LinearTimeToFieldedTime(INT64 lt, FIELDEDTIME *ft); class CLinearTimeDelta { friend class CLinearTimeAbsolute; friend bool operator<(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb); friend bool operator>(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb); friend bool operator==(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb); friend bool operator<=(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb); friend bool operator!=(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb); friend CLinearTimeDelta operator-(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb); friend CLinearTimeDelta operator-(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb); friend int operator/(const CLinearTimeDelta& ltdA, const CLinearTimeDelta& ltdB); friend CLinearTimeDelta operator*(const CLinearTimeDelta& ltdA, int nScaler); friend CLinearTimeAbsolute operator+(const CLinearTimeAbsolute& ltdA, const CLinearTimeDelta& ltdB); friend CLinearTimeAbsolute operator-(const CLinearTimeAbsolute& lta, const CLinearTimeDelta& ltd); private: INT64 m_tDelta; static char m_Buffer[204]; public: CLinearTimeDelta(void); CLinearTimeDelta(INT64 arg_t100ns); CLinearTimeDelta(CLinearTimeAbsolute, CLinearTimeAbsolute); void ReturnTimeValueStruct(struct timeval *tv); #ifdef HAVE_NANOSLEEP void ReturnTimeSpecStruct(struct timespec *ts); #endif long ReturnMilliseconds(void); INT64 ReturnMicroseconds(void); long ReturnDays(void); long ReturnSeconds(void); char *ReturnSecondsString(int nFracDigits = 0); INT64 Return100ns(void); void SetTimeValueStruct(struct timeval *tv); void SetMilliseconds(unsigned long arg_dwMilliseconds); void SetSeconds(INT64 arg_tSeconds); void SetSecondsString(char *arg_szSeconds); void Set100ns(INT64 arg_t100ns); void operator+=(const CLinearTimeDelta& ltd); }; class CMuxAlarm { private: bool bAlarmSet; #ifdef WIN32 HANDLE hThread; #endif public: bool bAlarmed; #ifdef WIN32 volatile HANDLE hSemAlarm; volatile DWORD dwWait; ~CMuxAlarm(); #endif CMuxAlarm(void); void Sleep(CLinearTimeDelta ltd); void SurrenderSlice(void); void Set(CLinearTimeDelta ltdDeadline); void Clear(void); #ifndef WIN32 void Signal(void); #endif }; extern CMuxAlarm MuxAlarm; #define FACTOR_NANOSECONDS_PER_100NS 100 #define FACTOR_100NS_PER_MICROSECOND 10 #define FACTOR_100NS_PER_MILLISECOND 10000 #ifdef WIN32 #define EPOCH_OFFSET 116444736000000000i64 #define EARLIEST_VALID_DATE (-9106391088000000000i64) #define LATEST_VALID_DATE ( 9222834959999999999i64) #define TIMEUTIL_TIME_T_MIN_VALUE (-922283539200i64) #define TIMEUTIL_TIME_T_MAX_VALUE ( 910638979199i64) #else // WIN32 #define EPOCH_OFFSET 116444736000000000ll #define EARLIEST_VALID_DATE (-9106391088000000000ll) #define LATEST_VALID_DATE ( 9222834959999999999ll) #define TIMEUTIL_TIME_T_MIN_VALUE (-922283539200ll) #define TIMEUTIL_TIME_T_MAX_VALUE ( 910638979199ll) #endif // WIN32 extern const INT64 FACTOR_100NS_PER_SECOND; extern const INT64 FACTOR_100NS_PER_MINUTE; extern const INT64 FACTOR_100NS_PER_HOUR; extern const INT64 FACTOR_100NS_PER_DAY; extern const INT64 FACTOR_100NS_PER_WEEK; const CLinearTimeDelta time_200us = 200*FACTOR_100NS_PER_MICROSECOND; const CLinearTimeDelta time_5ms = 5*FACTOR_100NS_PER_MILLISECOND; const CLinearTimeDelta time_250ms = 250*FACTOR_100NS_PER_MILLISECOND; const CLinearTimeDelta time_1s = FACTOR_100NS_PER_SECOND; const CLinearTimeDelta time_5s = 5*FACTOR_100NS_PER_SECOND; const CLinearTimeDelta time_15s = 15*FACTOR_100NS_PER_SECOND; const CLinearTimeDelta time_30s = 30*FACTOR_100NS_PER_SECOND; const CLinearTimeDelta time_45s = 45*FACTOR_100NS_PER_SECOND; const CLinearTimeDelta time_15m = 15*FACTOR_100NS_PER_MINUTE; const CLinearTimeDelta time_30m = 30*FACTOR_100NS_PER_MINUTE; const CLinearTimeDelta time_1w = FACTOR_100NS_PER_WEEK; extern void TIME_Initialize(void); #ifdef SMALLEST_INT_GTE_NEG_QUOTIENT INT64 i64Mod(INT64 x, INT64 y); INT64 i64FloorDivision(INT64 x, INT64 y); DCL_INLINE INT64 i64Division(INT64 x, INT64 y) { return x / y; } DCL_INLINE INT64 i64Remainder(INT64 x, INT64 y) { return x % y; } int iFloorDivisionMod(int x, int y, int *piMod); #else // SMALLEST_INT_GTE_NEG_QUOTIENT DCL_INLINE INT64 i64Mod(INT64 x, INT64 y) { return x % y; } DCL_INLINE INT64 i64FloorDivision(INT64 x, INT64 y) { return x / y; } INT64 i64Division(INT64 x, INT64 y); INT64 i64Remainder(INT64 x, INT64 y); int DCL_INLINE iFloorDivisionMod(int x, int y, int *piMod) \ { \ *piMod = x % y; \ return x / y; \ } #endif // SMALLEST_INT_GTE_NEG_QUOTIENT extern bool ParseDate(CLinearTimeAbsolute <a, char *pDateString, bool *pbZoneSpecified); extern bool isLeapYear(long iYear); extern const char *monthtab[12]; extern const char *DayOfWeekString[7]; extern int iMod(int x, int y); #endif // TIMEUTIL_H mux2.6/src/htab.cpp0000600000175000017500000003105411025753746014223 0ustar sdennissdennis/*! \file htab.cpp * Table hashing routines. * * $Id: htab.cpp 2734 2007-10-28 23:02:55Z brazilofmux $ * * The functions here outsource most of their work to CHashTable. There are * several reasons to use the functions here instead of using CHashTable * directly: 1) they are briefer to use, 2) this interface predates * CHashTable, 3) there are many references to these functions throughout the * code, and 4) MUSH hardcoders are generally more familiar with this * interface than with the CHashTable interface. * * To replace them all would require rexamining the assumptions near every * reference. * * CHashTable is not aware of Keys -- only hashes of Keys. In fact, CHashTable * could not tell you anything about the Keys kept within its records. It * will give you all the records stored under a specific hash, but it leaves * to its callers the small chore of looking in each record for a desired Key. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" /*! \brief Reset hash table statistics. * * Each Hash Table maintains certain statistics regarding the type and * number of requests they receive as well as the hash table's performance * in responding to those requests. The hashreset() function allows callers * to reset these statistics. Typically, this is done when the caller knows * future access patterns are of more interest than past access paterns. * * \param htab Hash Table. * \return None. */ void hashreset(CHashTable *htab) { htab->ResetStats(); } /*! \brief Staging area for reads and writes into CHashTable. * * The htab_rec structure is a fixed size, but only part of htab_rec is used. * Since requests use variable-sized Keys, the portion of htab_rec used on * any particular request is also variable-sized. pData is always present, * but aKey may occupy as little as a single byte. */ #pragma pack(1) static struct { void *pData; char aKey[LBUF_SIZE+125]; } htab_rec; #pragma pack() /*! \brief Look for a previously-added (Key, Data) pair in a hash table, and * return its data pointer. * * Given a variable-sized Key, hashfindLEN() uses the associations previously * created with hashaddLEN() to find and return the corresponding 'Data' part * of a (Key, Data) pair, if it exists. * * NULL is returned if the request is not valid or if the (Key, Data) pair * is not found. * * \param pKey Pointer to Key to find. * \param nKey Size (in bytes) of the above Key. * \param htab Hash Table. * \return pData or NULL. */ void *hashfindLEN(const void *pKey, size_t nKey, CHashTable *htab) { if ( pKey == NULL || nKey <= 0) { return NULL; } UINT32 nHash = HASH_ProcessBuffer(0, pKey, nKey); UINT32 iDir = HF_FIND_FIRST; iDir = htab->FindFirstKey(nHash); while (iDir != HF_FIND_END) { HP_HEAPLENGTH nRecord; htab->Copy(iDir, &nRecord, &htab_rec); size_t nTarget = nRecord - sizeof(int *); if ( nTarget == nKey && memcmp(pKey, htab_rec.aKey, nKey) == 0) { return htab_rec.pData; } iDir = htab->FindNextKey(iDir, nHash); } return NULL; } /*! \brief Add a new (Key, Data) pair to a hash table. * * hashaddLEN() associates a variable-sized key with a pointer using a hash * table. The pointer, pData, given to hashaddLEN() may be obtained again * later by presenting the the same key to hashfindLEN(). The data given in * (pKey, nKey) is saved, so the caller is free to reuse the Key buffer. * While the value of pData is also saved, the data that pData points to is * not. * * This function requires that the Key does not already exist in the hash * table. It may be necessary to use hashfindLEN() to insure this. * * \param pKey Pointer to Key of (Key, Data) pair to add. * \param nKey Size (in bytes) of the above Key. * \param pData Pointer to Data part of (Key, Data) pair. * \param htab Hash Table. * \return false for failure. true for success. */ bool hashaddLEN(const void *pKey, size_t nKey, void *pData, CHashTable *htab) { if ( pKey == NULL || nKey <= 0) { return false; } UINT32 nHash = HASH_ProcessBuffer(0, pKey, nKey); htab_rec.pData = pData; memcpy(htab_rec.aKey, pKey, nKey); size_t nRecord = nKey + sizeof(void *); htab->Insert((HP_HEAPLENGTH)nRecord, nHash, &htab_rec); return true; } /*! \brief Removes a (Key, Data) pair from a hash table. * * hashdeleteLEN() disassociates a variable-sized Key from its Data pointer * by removing the (Key, Data) pair from the hash table and freeing any * related storage. However, it is the caller's responsibility to free any * memory that Data points to. * * \param pKey The Key to remove. * \param nKey Size (in bytes) of the above Key. * \param htab Hash Table. * \return None. */ void hashdeleteLEN(const void *pKey, size_t nKey, CHashTable *htab) { if ( pKey == NULL || nKey <= 0) { return; } UINT32 nHash = HASH_ProcessBuffer(0, pKey, nKey); UINT32 iDir = htab->FindFirstKey(nHash); while (iDir != HF_FIND_END) { HP_HEAPLENGTH nRecord; htab->Copy(iDir, &nRecord, &htab_rec); size_t nTarget = nRecord - sizeof(int *); if ( nTarget == nKey && memcmp(pKey, htab_rec.aKey, nKey) == 0) { htab->Remove(iDir); } iDir = htab->FindNextKey(iDir, nHash); } } /*! \brief Removes all (Key, Data) entries in a hash table. * * The Hash Table is re-initialized from scratch and all storage is * reclaimed. The resulting Hash Table is empty. * * \param htab Hash Table. * \return None. */ void hashflush(CHashTable *htab) { htab->Reset(); } /* * --------------------------------------------------------------------------- * * hashreplLEN: replace the data part of a hash entry. */ bool hashreplLEN(const void *str, size_t nStr, void *pData, CHashTable *htab) { if ( str == NULL || nStr <= 0) { return false; } UINT32 nHash = HASH_ProcessBuffer(0, str, nStr); UINT32 iDir = htab->FindFirstKey(nHash); while (iDir != HF_FIND_END) { HP_HEAPLENGTH nRecord; htab->Copy(iDir, &nRecord, &htab_rec); size_t nTarget = nRecord - sizeof(int *); if ( nTarget == nStr && memcmp(str, htab_rec.aKey, nStr) == 0) { htab_rec.pData = pData; htab->Update(iDir, nRecord, &htab_rec); return true; } iDir = htab->FindNextKey(iDir, nHash); } return false; } void hashreplall(const void *old, void *new0, CHashTable *htab) { HP_HEAPLENGTH nRecord; for ( UINT32 iDir = htab->FindFirst(&nRecord, &htab_rec); iDir != HF_FIND_END; iDir = htab->FindNext(&nRecord, &htab_rec)) { if (htab_rec.pData == old) { htab_rec.pData = new0; htab->Update(iDir, nRecord, &htab_rec); } } } /* * Returns the key for the first hash entry in 'htab'. */ void *hash_firstentry(CHashTable *htab) { HP_HEAPLENGTH nRecord; UINT32 iDir = htab->FindFirst(&nRecord, &htab_rec); if (iDir != HF_FIND_END) { return htab_rec.pData; } return NULL; } void *hash_nextentry(CHashTable *htab) { HP_HEAPLENGTH nRecord; UINT32 iDir = htab->FindNext(&nRecord, &htab_rec); if (iDir != HF_FIND_END) { return htab_rec.pData; } return NULL; } void *hash_firstkey(CHashTable *htab, int *nKeyLength, char **pKey) { HP_HEAPLENGTH nRecord; UINT32 iDir = htab->FindFirst(&nRecord, &htab_rec); if (iDir != HF_FIND_END) { *nKeyLength = nRecord-sizeof(int *); *pKey = htab_rec.aKey; return htab_rec.pData; } *nKeyLength = 0; *pKey = NULL; return NULL; } void *hash_nextkey(CHashTable *htab, int *nKeyLength, char **pKey) { HP_HEAPLENGTH nRecord; UINT32 iDir = htab->FindNext(&nRecord, &htab_rec); if (iDir != HF_FIND_END) { *nKeyLength = nRecord-sizeof(int *); *pKey = htab_rec.aKey; return htab_rec.pData; } *nKeyLength = 0; *pKey = NULL; return NULL; } /* * --------------------------------------------------------------------------- * * search_nametab: Search a name table for a match and return the flag value. */ bool search_nametab(dbref player, NAMETAB *ntab, char *flagname, int *pflag) { NAMETAB *nt; for (nt = ntab; nt->name; nt++) { if (minmatch(flagname, nt->name, nt->minlen)) { if (check_access(player, nt->perm)) { *pflag = nt->flag; return true; } else { *pflag = -2; return false; } } } *pflag = -1; return false; } /* * --------------------------------------------------------------------------- * * find_nametab_ent: Search a name table for a match and return a pointer to it. */ NAMETAB *find_nametab_ent(dbref player, NAMETAB *ntab, char *flagname) { NAMETAB *nt; for (nt = ntab; nt->name; nt++) { if (minmatch(flagname, nt->name, nt->minlen)) { if (check_access(player, nt->perm)) { return nt; } } } return NULL; } /* * --------------------------------------------------------------------------- * * display_nametab: Print out the names of the entries in a name table. */ void display_nametab(dbref player, NAMETAB *ntab, const char *prefix, bool list_if_none) { NAMETAB *nt; bool got_one = false; char *buf = alloc_lbuf("display_nametab"); char *bp = buf; safe_str(prefix, buf, &bp); for (nt = ntab; nt->name; nt++) { if ( God(player) || check_access(player, nt->perm)) { safe_chr(' ', buf, &bp); safe_str(nt->name, buf, &bp); got_one = true; } } *bp = '\0'; if ( got_one || list_if_none) { notify(player, buf); } free_lbuf(buf); } /* --------------------------------------------------------------------------- * interp_nametab: Print values for flags defined in name table. */ void interp_nametab(dbref player, NAMETAB *ntab, int flagword, const char *prefix, const char *true_text, const char *false_text) { bool bFirst = true; char *buf = alloc_lbuf("interp_nametab"); char *bp = buf; safe_str(prefix, buf, &bp); for (NAMETAB *nt = ntab; nt->name; nt++) { if ( God(player) || check_access(player, nt->perm)) { if (!bFirst) { safe_chr(';', buf, &bp); bFirst = false; } safe_chr(' ', buf, &bp); safe_str(nt->name, buf, &bp); safe_str("...", buf, &bp); if ((flagword & nt->flag) != 0) { safe_str(true_text, buf, &bp); } else { safe_str(false_text, buf, &bp); } } } *bp = '\0'; notify(player, buf); free_lbuf(buf); } /* --------------------------------------------------------------------------- * listset_nametab: Print values for flags defined in name table. */ void listset_nametab(dbref player, NAMETAB *ntab, int flagword, char *prefix, bool list_if_none) { char *buf = alloc_lbuf("listset_nametab"); char *bp = buf; safe_str(prefix, buf, &bp); NAMETAB *nt = ntab; bool got_one = false; while (nt->name) { if ( ((flagword & nt->flag) != 0) && ( God(player) || check_access(player, nt->perm))) { safe_chr(' ', buf, &bp); safe_str(nt->name, buf, &bp); got_one = true; } nt++; } *bp = '\0'; if ( got_one || list_if_none) { notify(player, buf); } free_lbuf(buf); } /* --------------------------------------------------------------------------- * cf_ntab_access: Change the access on a nametab entry. */ CF_HAND(cf_ntab_access) { NAMETAB *np; char *ap; for (ap = str; *ap && !mux_isspace(*ap); ap++) { ; // Nothing. } if (*ap) { *ap++ = '\0'; } while (mux_isspace(*ap)) { ap++; } for (np = (NAMETAB *) vp; np->name; np++) { if (minmatch(str, np->name, np->minlen)) { return cf_modify_bits(&(np->perm), ap, pExtra, nExtra, player, cmd); } } cf_log_notfound(player, cmd, "Entry", str); return -1; } mux2.6/src/db.cpp0000600000175000017500000026622411025753746013703 0ustar sdennissdennis// db.cpp // // $Id: db.cpp 2734 2007-10-28 23:02:55Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "comsys.h" #include "interface.h" #include "powers.h" #include "vattr.h" #include "ansi.h" #ifndef O_ACCMODE #define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) #endif // O_ACCMODE OBJ *db = NULL; typedef struct atrcount ATRCOUNT; struct atrcount { dbref thing; int count; }; // list of attributes // ATTR AttrTable[] = { {"Aahear", A_AAHEAR, AF_ODARK | AF_NOPROG}, {"Aclone", A_ACLONE, AF_ODARK | AF_NOPROG}, {"Aconnect", A_ACONNECT, AF_ODARK | AF_NOPROG}, {"Adesc", A_ADESC, AF_ODARK | AF_NOPROG}, {"Adfail", A_ADFAIL, AF_ODARK | AF_NOPROG}, {"Adisconnect", A_ADISCONNECT, AF_ODARK | AF_NOPROG}, {"Adrop", A_ADROP, AF_ODARK | AF_NOPROG}, {"Aefail", A_AEFAIL, AF_ODARK | AF_NOPROG}, {"Aenter", A_AENTER, AF_ODARK | AF_NOPROG}, {"Afail", A_AFAIL, AF_ODARK | AF_NOPROG}, {"Agfail", A_AGFAIL, AF_ODARK | AF_NOPROG}, {"Ahear", A_AHEAR, AF_ODARK | AF_NOPROG}, {"Akill", A_AKILL, AF_ODARK | AF_NOPROG}, {"Aleave", A_ALEAVE, AF_ODARK | AF_NOPROG}, {"Alfail", A_ALFAIL, AF_ODARK | AF_NOPROG}, {"Alias", A_ALIAS, AF_NOPROG | AF_NOCMD | AF_NOCLONE | AF_PRIVATE | AF_CONST | AF_VISUAL}, {"Allowance", A_ALLOWANCE, AF_MDARK | AF_NOPROG | AF_WIZARD}, {"Amail", A_AMAIL, AF_ODARK | AF_NOPROG}, {"Amhear", A_AMHEAR, AF_ODARK | AF_NOPROG}, {"Amove", A_AMOVE, AF_ODARK | AF_NOPROG}, {"Apay", A_APAY, AF_ODARK | AF_NOPROG}, {"Arfail", A_ARFAIL, AF_ODARK | AF_NOPROG}, {"Asucc", A_ASUCC, AF_ODARK | AF_NOPROG}, {"Atfail", A_ATFAIL, AF_ODARK | AF_NOPROG}, {"Atport", A_ATPORT, AF_ODARK | AF_NOPROG}, {"Atofail", A_ATOFAIL, AF_ODARK | AF_NOPROG}, {"Aufail", A_AUFAIL, AF_ODARK | AF_NOPROG}, {"Ause", A_AUSE, AF_ODARK | AF_NOPROG}, {"Away", A_AWAY, AF_ODARK | AF_NOPROG}, {"Charges", A_CHARGES, AF_ODARK | AF_NOPROG}, {"CmdCheck", A_CMDCHECK, AF_DARK | AF_NOPROG | AF_NOCMD | AF_NOCLONE | AF_PRIVATE | AF_CONST}, {"Comment", A_COMMENT, AF_MDARK | AF_WIZARD}, {"ConFormat", A_CONFORMAT, AF_ODARK | AF_NOPROG}, {"Cost", A_COST, AF_ODARK | AF_NOPROG}, {"Created", A_CREATED, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_NOCLONE | AF_GOD}, {"Daily", A_DAILY, AF_ODARK | AF_NOPROG}, {"Desc", A_DESC, AF_VISUAL | AF_NOPROG}, {"DefaultLock", A_LOCK, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"DescFormat", A_DESCFORMAT, AF_ODARK | AF_NOPROG}, {"Destroyer", A_DESTROYER, AF_MDARK | AF_WIZARD | AF_NOPROG}, {"Dfail", A_DFAIL, AF_ODARK | AF_NOPROG}, {"Drop", A_DROP, AF_ODARK | AF_NOPROG}, {"DropLock", A_LDROP, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Ealias", A_EALIAS, AF_ODARK | AF_NOPROG}, {"Efail", A_EFAIL, AF_ODARK | AF_NOPROG}, {"Enter", A_ENTER, AF_ODARK | AF_NOPROG}, {"EnterLock", A_LENTER, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"ExitFormat", A_EXITFORMAT, AF_ODARK | AF_NOPROG}, {"ExitTo", A_EXITVARDEST, AF_ODARK | AF_NOPROG | AF_WIZARD}, {"Fail", A_FAIL, AF_ODARK | AF_NOPROG}, {"Filter", A_FILTER, AF_ODARK | AF_NOPROG}, {"Forwardlist", A_FORWARDLIST, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_CONST}, {"GetFromLock", A_LGET, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Gfail", A_GFAIL, AF_ODARK | AF_NOPROG}, {"GiveLock", A_LGIVE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Idesc", A_IDESC, AF_ODARK | AF_NOPROG}, {"Idle", A_IDLE, AF_ODARK | AF_NOPROG}, {"IdleTimeout", A_IDLETMOUT, AF_ODARK | AF_NOPROG}, {"Infilter", A_INFILTER, AF_ODARK | AF_NOPROG}, {"Inprefix", A_INPREFIX, AF_ODARK | AF_NOPROG}, {"Kill", A_KILL, AF_ODARK | AF_NOPROG}, {"Lalias", A_LALIAS, AF_ODARK | AF_NOPROG}, {"Last", A_LAST, AF_WIZARD | AF_NOCMD | AF_NOPROG | AF_NOCLONE}, {"Lastpage", A_LASTPAGE, AF_INTERNAL | AF_NOCMD | AF_NOPROG | AF_GOD | AF_PRIVATE}, {"Lastsite", A_LASTSITE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_NOCLONE | AF_GOD}, {"LastIP", A_LASTIP, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_GOD}, {"Leave", A_LEAVE, AF_ODARK | AF_NOPROG}, {"LeaveLock", A_LLEAVE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Lfail", A_LFAIL, AF_ODARK | AF_NOPROG}, {"LinkLock", A_LLINK, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Listen", A_LISTEN, AF_ODARK | AF_NOPROG}, {"Logindata", A_LOGINDATA, AF_MDARK | AF_NOPROG | AF_NOCMD | AF_CONST}, {"Mailcurf", A_MAILCURF, AF_MDARK | AF_WIZARD | AF_NOPROG | AF_NOCLONE}, {"Mailflags", A_MAILFLAGS, AF_MDARK | AF_WIZARD | AF_NOPROG | AF_NOCLONE}, {"Mailfolders", A_MAILFOLDERS, AF_MDARK | AF_WIZARD | AF_NOPROG | AF_NOCLONE}, {"MailLock", A_LMAIL, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Mailmsg", A_MAILMSG, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL}, {"Mailsub", A_MAILSUB, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL}, {"Mailsucc", A_MAIL, AF_ODARK | AF_NOPROG}, {"Mailto", A_MAILTO, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL}, {"Mfail", A_MFAIL, AF_ODARK | AF_NOPROG}, {"Modified", A_MODIFIED, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_NOCLONE | AF_GOD}, {"Moniker", A_MONIKER, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_CONST}, {"Move", A_MOVE, AF_ODARK | AF_NOPROG}, {"Name", A_NAME, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL}, {"NameFormat", A_NAMEFORMAT, AF_ODARK | AF_NOPROG | AF_WIZARD}, {"Odesc", A_ODESC, AF_ODARK | AF_NOPROG}, {"Odfail", A_ODFAIL, AF_ODARK | AF_NOPROG}, {"Odrop", A_ODROP, AF_ODARK | AF_NOPROG}, {"Oefail", A_OEFAIL, AF_ODARK | AF_NOPROG}, {"Oenter", A_OENTER, AF_ODARK | AF_NOPROG}, {"Ofail", A_OFAIL, AF_ODARK | AF_NOPROG}, {"Ogfail", A_OGFAIL, AF_ODARK | AF_NOPROG}, {"Okill", A_OKILL, AF_ODARK | AF_NOPROG}, {"Oleave", A_OLEAVE, AF_ODARK | AF_NOPROG}, {"Olfail", A_OLFAIL, AF_ODARK | AF_NOPROG}, {"Omove", A_OMOVE, AF_ODARK | AF_NOPROG}, {"Opay", A_OPAY, AF_ODARK | AF_NOPROG}, {"OpenLock", A_LOPEN, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Orfail", A_ORFAIL, AF_ODARK | AF_NOPROG}, {"Osucc", A_OSUCC, AF_ODARK | AF_NOPROG}, {"Otfail", A_OTFAIL, AF_ODARK | AF_NOPROG}, {"Otport", A_OTPORT, AF_ODARK | AF_NOPROG}, {"Otofail", A_OTOFAIL, AF_ODARK | AF_NOPROG}, {"Oufail", A_OUFAIL, AF_ODARK | AF_NOPROG}, {"Ouse", A_OUSE, AF_ODARK | AF_NOPROG}, {"Oxenter", A_OXENTER, AF_ODARK | AF_NOPROG}, {"Oxleave", A_OXLEAVE, AF_ODARK | AF_NOPROG}, {"Oxtport", A_OXTPORT, AF_ODARK | AF_NOPROG}, {"PageLock", A_LPAGE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"ParentLock", A_LPARENT, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Pay", A_PAY, AF_ODARK | AF_NOPROG}, {"Prefix", A_PREFIX, AF_ODARK | AF_NOPROG}, {"ProgCmd", A_PROGCMD, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL}, {"QueueMax", A_QUEUEMAX, AF_MDARK | AF_WIZARD | AF_NOPROG}, {"Quota", A_QUOTA, AF_MDARK | AF_NOPROG | AF_GOD | AF_NOCMD | AF_NOCLONE}, {"ReceiveLock", A_LRECEIVE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Reject", A_REJECT, AF_ODARK | AF_NOPROG}, {"Rfail", A_RFAIL, AF_ODARK | AF_NOPROG}, {"Rquota", A_RQUOTA, AF_MDARK | AF_NOPROG | AF_GOD | AF_NOCMD | AF_NOCLONE}, {"Runout", A_RUNOUT, AF_ODARK | AF_NOPROG}, {"SayString", A_SAYSTRING, AF_ODARK | AF_NOPROG}, {"Semaphore", A_SEMAPHORE, AF_ODARK | AF_NOPROG | AF_WIZARD | AF_NOCMD | AF_NOCLONE}, {"Sex", A_SEX, AF_VISUAL | AF_NOPROG}, {"Signature", A_SIGNATURE, AF_ODARK | AF_NOPROG}, {"SpeechMod", A_SPEECHMOD, AF_ODARK | AF_NOPROG}, {"SpeechLock", A_LSPEECH, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Startup", A_STARTUP, AF_ODARK | AF_NOPROG}, {"Succ", A_SUCC, AF_ODARK | AF_NOPROG}, {"TeloutLock", A_LTELOUT, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Tfail", A_TFAIL, AF_ODARK | AF_NOPROG}, {"Timeout", A_TIMEOUT, AF_MDARK | AF_NOPROG | AF_WIZARD}, {"Tport", A_TPORT, AF_ODARK | AF_NOPROG}, {"TportLock", A_LTPORT, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"Tofail", A_TOFAIL, AF_ODARK | AF_NOPROG}, {"Ufail", A_UFAIL, AF_ODARK | AF_NOPROG}, {"Use", A_USE, AF_ODARK | AF_NOPROG}, {"UseLock", A_LUSE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"UserLock", A_LUSER, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK}, {"VA", A_VA, AF_ODARK}, {"VB", A_VA + 1, AF_ODARK}, {"VC", A_VA + 2, AF_ODARK}, {"VD", A_VA + 3, AF_ODARK}, {"VE", A_VA + 4, AF_ODARK}, {"VF", A_VA + 5, AF_ODARK}, {"VG", A_VA + 6, AF_ODARK}, {"VH", A_VA + 7, AF_ODARK}, {"VI", A_VA + 8, AF_ODARK}, {"VJ", A_VA + 9, AF_ODARK}, {"VK", A_VA + 10, AF_ODARK}, {"VL", A_VA + 11, AF_ODARK}, {"VM", A_VA + 12, AF_ODARK}, {"VN", A_VA + 13, AF_ODARK}, {"VO", A_VA + 14, AF_ODARK}, {"VP", A_VA + 15, AF_ODARK}, {"VQ", A_VA + 16, AF_ODARK}, {"VR", A_VA + 17, AF_ODARK}, {"VS", A_VA + 18, AF_ODARK}, {"VT", A_VA + 19, AF_ODARK}, {"VU", A_VA + 20, AF_ODARK}, {"VV", A_VA + 21, AF_ODARK}, {"VW", A_VA + 22, AF_ODARK}, {"VX", A_VA + 23, AF_ODARK}, {"VY", A_VA + 24, AF_ODARK}, {"VZ", A_VA + 25, AF_ODARK}, {"VRML_URL", A_VRML_URL, AF_ODARK | AF_NOPROG}, {"HTDesc", A_HTDESC, AF_NOPROG}, {"Reason", A_REASON, AF_PRIVATE | AF_MDARK | AF_NOPROG | AF_NOCMD | AF_GOD}, #ifdef GAME_DOOFERMUX {"RegInfo", A_REGINFO, AF_PRIVATE | AF_MDARK | AF_NOPROG | AF_NOCMD | AF_WIZARD}, #endif // GAME_DOOFERMUX {"ConnInfo", A_CONNINFO, AF_PRIVATE | AF_MDARK | AF_NOPROG | AF_NOCMD | AF_GOD}, {"*Password", A_PASS, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL}, {"*Privileges", A_PRIVS, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL}, {"*Money", A_MONEY, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL}, #ifdef REALITY_LVLS {"Rlevel", A_RLEVEL, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL}, #endif // REALITY_LVLS #if defined(FIRANMUX) {"Color", A_COLOR, AF_ODARK}, {"Alead", A_ALEAD, AF_ODARK | AF_WIZARD}, {"Lead", A_LEAD, AF_ODARK | AF_NOPROG | AF_WIZARD}, {"Olead", A_OLEAD, AF_ODARK | AF_NOPROG | AF_WIZARD}, #endif // FIRANMUX {NULL, 0, 0} }; const char *aszSpecialDBRefNames[1-NOPERM] = { "", "*NOTHING*", "*AMBIGUOUS*", "*HOME*", "*NOPERMISSION*" }; /* --------------------------------------------------------------------------- * fwdlist_set, fwdlist_clr: Manage cached forwarding lists */ void fwdlist_set(dbref thing, FWDLIST *ifp) { // If fwdlist is null, clear. // if ( NULL == ifp || ifp->count <= 0) { fwdlist_clr(thing); return; } // Copy input forwardlist to a correctly-sized buffer. // FWDLIST *fp = NULL; try { fp = new FWDLIST; } catch (...) { ; // Nothing. } if (NULL != fp) { fp->data = NULL; try { fp->data = new dbref[ifp->count]; } catch (...) { ; // Nothing. } if (NULL != fp->data) { for (int i = 0; i < ifp->count; i++) { fp->data[i] = ifp->data[i]; } fp->count = ifp->count; // Replace an existing forwardlist, or add a new one. // bool bDone = false; FWDLIST *xfp = fwdlist_get(thing); if (xfp) { if (xfp->data) { delete [] xfp->data; } delete xfp; xfp = NULL; bDone = hashreplLEN(&thing, sizeof(thing), fp, &mudstate.fwdlist_htab); } else { bDone = hashaddLEN(&thing, sizeof(thing), fp, &mudstate.fwdlist_htab); } // If addition or replacement failed, don't leak new forward list. // if (!bDone) { if (fp->data) { delete [] fp->data; } delete fp; } } else { ISOUTOFMEMORY(fp->data); } } else { ISOUTOFMEMORY(fp); } } void fwdlist_clr(dbref thing) { // If a forwardlist exists, delete it // FWDLIST *xfp = fwdlist_get(thing); if (xfp) { if (xfp->data) { delete [] xfp->data; } delete xfp; xfp = NULL; hashdeleteLEN(&thing, sizeof(thing), &mudstate.fwdlist_htab); } } /* --------------------------------------------------------------------------- * fwdlist_load: Load text into a forwardlist. */ FWDLIST *fwdlist_load(dbref player, char *atext) { FWDLIST *fp = NULL; try { fp = new FWDLIST; } catch (...) { ; // Nothing. } if (NULL != fp) { fp->count = 0; fp->data = NULL; try { fp->data = new dbref[LBUF_SIZE/2]; } catch (...) { ; // Nothing. } if (NULL != fp->data) { char *tp = alloc_lbuf("fwdlist_load.str"); char *bp = tp; mux_strncpy(tp, atext, LBUF_SIZE-1); int count = 0; do { // Skip spaces. // for (; mux_isspace(*bp); bp++) { ; // Nothing. } // Remember string. // char *dp; for (dp = bp; *bp && !mux_isspace(*bp); bp++) { ; // Nothing. } // Terminate string. // if (*bp) { *bp++ = '\0'; } if ( *dp++ == '#' && mux_isdigit(*dp)) { bool fail; dbref target = mux_atol(dp); if (mudstate.bStandAlone) { fail = !Good_obj(target); } else { fail = ( !Good_obj(target) || ( !God(player) && !Controls(player, target) && ( !Link_ok(target) || !could_doit(player, target, A_LLINK)))); } if (fail) { if (!mudstate.bStandAlone) { notify(player, tprintf("Cannot forward to #%d: Permission denied.", target)); } } else { fp->data[count++] = target; } } } while (*bp); free_lbuf(tp); if (0 < count) { fp->count = count; } else { delete [] fp->data; delete fp; fp = NULL; } } else { delete fp; fp = NULL; } } return fp; } /* --------------------------------------------------------------------------- * fwdlist_rewrite: Generate a text string from a FWDLIST buffer. */ int fwdlist_rewrite(FWDLIST *fp, char *atext) { int count = 0; atext[0] = '\0'; if ( fp && fp->count) { char *bp = atext; ITL pContext; ItemToList_Init(&pContext, atext, &bp, '#'); for (int i = 0; i < fp->count; i++) { if ( Good_obj(fp->data[i]) && ItemToList_AddInteger(&pContext, fp->data[i])) { count++; } } ItemToList_Final(&pContext); } return count; } /* --------------------------------------------------------------------------- * fwdlist_ck: Check a list of dbref numbers to forward to for AUDIBLE */ bool fwdlist_ck(dbref player, dbref thing, int anum, char *atext) { UNUSED_PARAMETER(anum); if (mudstate.bStandAlone) { return true; } FWDLIST *fp = NULL; if ( NULL != atext && '\0' != atext[0]) { fp = fwdlist_load(player, atext); } // Set the cached forwardlist. // fwdlist_set(thing, fp); int count = fwdlist_rewrite(fp, atext); if (NULL != fp) { if (NULL != fp->data) { delete [] fp->data; } delete fp; fp = NULL; } return ( count > 0 || NULL == atext || '\0' == atext[0]); } FWDLIST *fwdlist_get(dbref thing) { static FWDLIST *fp = NULL; if (mudstate.bStandAlone) { dbref aowner; int aflags; char *tp = atr_get(thing, A_FORWARDLIST, &aowner, &aflags); fp = fwdlist_load(GOD, tp); free_lbuf(tp); } else { fp = (FWDLIST *) hashfindLEN(&thing, sizeof(thing), &mudstate.fwdlist_htab); } return fp; } // --------------------------------------------------------------------------- // Name, PureName, Moniker, s_Moniker, and s_Name: Get or set object's // various names. // const char *Name(dbref thing) { if (thing < 0) { return aszSpecialDBRefNames[-thing]; } dbref aowner; int aflags; #ifdef MEMORY_BASED static char tbuff[LBUF_SIZE]; atr_get_str(tbuff, thing, A_NAME, &aowner, &aflags); return tbuff; #else // MEMORY_BASED if (!db[thing].name) { size_t len; char *pName = atr_get_LEN(thing, A_NAME, &aowner, &aflags, &len); db[thing].name = StringCloneLen(pName, len); free_lbuf(pName); } return db[thing].name; #endif // MEMORY_BASED } const char *PureName(dbref thing) { if (thing < 0) { return aszSpecialDBRefNames[-thing]; } dbref aowner; int aflags; char *pName, *pPureName; if (mudconf.cache_names) { if (!db[thing].purename) { size_t nName; size_t nPureName; #ifdef MEMORY_BASED pName = atr_get_LEN(thing, A_NAME, &aowner, &aflags, &nName); pPureName = strip_ansi(pName, &nPureName); free_lbuf(pName); db[thing].purename = StringCloneLen(pPureName, nPureName); #else // MEMORY_BASED if (!db[thing].name) { pName = atr_get_LEN(thing, A_NAME, &aowner, &aflags, &nName); db[thing].name = StringCloneLen(pName, nName); free_lbuf(pName); } else { nName = strlen(db[thing].name); } pName = db[thing].name; pPureName = strip_ansi(pName, &nPureName); if (nPureName == nName) { db[thing].purename = pName; } else { db[thing].purename = StringCloneLen(pPureName, nPureName); } #endif // MEMORY_BASED } return db[thing].purename; } pName = atr_get(thing, A_NAME, &aowner, &aflags); pPureName = strip_ansi(pName); free_lbuf(pName); return pPureName; } const char *Moniker(dbref thing) { if (thing < 0) { return aszSpecialDBRefNames[-thing]; } if (db[thing].moniker) { return db[thing].moniker; } // Compare accent-stripped, ansi-stripped version of @moniker against // accent-stripped, ansi-stripped version of @name. // const char *pPureName = strip_accents(PureName(thing)); char *pPureNameCopy = StringClone(pPureName); size_t nMoniker; dbref aowner; int aflags; char *pMoniker = atr_get_LEN(thing, A_MONIKER, &aowner, &aflags, &nMoniker); char *pPureMoniker = strip_accents(strip_ansi(pMoniker)); const char *pReturn = NULL; static char tbuff[LBUF_SIZE]; if (strcmp(pPureNameCopy, pPureMoniker) == 0) { // The stripped version of @moniker is the same as the stripped // version of @name, so (possibly cache and) use the unstripped // version of @moniker. // if (mudconf.cache_names) { #ifdef MEMORY_BASED db[thing].moniker = StringCloneLen(pMoniker, nMoniker); #else // MEMORY_BASED if (strcmp(pMoniker, Name(thing)) == 0) { db[thing].moniker = db[thing].name; } else { db[thing].moniker = StringCloneLen(pMoniker, nMoniker); } #endif // MEMORY_BASED pReturn = db[thing].moniker; } else { memcpy(tbuff, pMoniker, nMoniker+1); pReturn = tbuff; } } else { // @moniker can't be used, so instead reflect @name (whether it // contains ANSI color and accents or not). // #ifdef MEMORY_BASED if (mudconf.cache_names) { db[thing].moniker = StringClone(Name(thing)); pReturn = db[thing].moniker; } else { pReturn = Name(thing); } #else // MEMORY_BASED if (mudconf.cache_names) { db[thing].moniker = db[thing].name; pReturn = db[thing].moniker; } else { pReturn = Name(thing); } #endif // MEMORY_BASED } free_lbuf(pMoniker); MEMFREE(pPureNameCopy); return pReturn; } void s_Name(dbref thing, const char *s) { atr_add_raw(thing, A_NAME, s); #ifndef MEMORY_BASED if (db[thing].name) { if (mudconf.cache_names) { if (db[thing].name == db[thing].purename) { db[thing].purename = NULL; } if (db[thing].name == db[thing].moniker) { db[thing].moniker = NULL; } } MEMFREE(db[thing].name); db[thing].name = NULL; } if (s) { db[thing].name = StringClone(s); } #endif // !MEMORY_BASED if (mudconf.cache_names) { if (db[thing].purename) { MEMFREE(db[thing].purename); db[thing].purename = NULL; } if (db[thing].moniker) { MEMFREE(db[thing].moniker); db[thing].moniker = NULL; } } } void s_Moniker(dbref thing, const char *s) { atr_add_raw(thing, A_MONIKER, s); if (mudconf.cache_names) { #ifndef MEMORY_BASED if (db[thing].name == db[thing].moniker) { db[thing].moniker = NULL; } #endif // !MEMORY_BASED if (db[thing].moniker) { MEMFREE(db[thing].moniker); db[thing].moniker = NULL; } } } void s_Pass(dbref thing, const char *s) { atr_add_raw(thing, A_PASS, s); } /* --------------------------------------------------------------------------- * do_attrib: Manage user-named attributes. */ void do_attribute ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *aname, char *value ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); // Look up the user-named attribute we want to play with. // size_t nName; bool bValid = false; ATTR *va = NULL; char *pName = MakeCanonicalAttributeName(aname, &nName, &bValid); if (bValid) { va = (ATTR *)vattr_find_LEN(pName, nName); } if (NULL == va) { notify(executor, "No such user-named attribute."); return; } int f; char *sp; ATTR *va2; bool negate, success; switch (key) { case ATTRIB_ACCESS: // Modify access to user-named attribute // mux_strupr(value); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, value); mux_strtok_ctl(&tts, " "); sp = mux_strtok_parse(&tts); success = false; while (sp != NULL) { // Check for negation. // negate = false; if (*sp == '!') { negate = true; sp++; } // Set or clear the appropriate bit. // if (search_nametab(executor, attraccess_nametab, sp, &f)) { success = true; if (negate) { va->flags &= ~f; } else { va->flags |= f; } } else { notify(executor, tprintf("Unknown permission: %s.", sp)); } // Get the next token. // sp = mux_strtok_parse(&tts); } if (success && !Quiet(executor)) notify(executor, "Attribute access changed."); break; case ATTRIB_RENAME: { // Save the old name for use later. // char OldName[SBUF_SIZE]; char *pOldName = OldName; safe_sb_str(pName, OldName, &pOldName); *pOldName = '\0'; size_t nOldName = pOldName - OldName; // Make sure the new name doesn't already exist. This checks // the built-in and user-defined data structures. // va2 = atr_str(value); if (va2) { notify(executor, "An attribute with that name already exists."); return; } pName = MakeCanonicalAttributeName(value, &nName, &bValid); if (!bValid || vattr_rename_LEN(OldName, nOldName, pName, nName) == NULL) notify(executor, "Attribute rename failed."); else notify(executor, "Attribute renamed."); } break; case ATTRIB_DELETE: // Remove the attribute. // vattr_delete_LEN(pName, nName); notify(executor, "Attribute deleted."); break; } } /* --------------------------------------------------------------------------- * do_fixdb: Directly edit database fields */ void do_fixdb ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *arg1, char *arg2 ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); init_match(executor, arg1, NOTYPE); match_everything(0); dbref thing = noisy_match_result(); if (thing == NOTHING) { return; } dbref res = NOTHING; switch (key) { case FIXDB_OWNER: case FIXDB_LOC: case FIXDB_CON: case FIXDB_EXITS: case FIXDB_NEXT: init_match(executor, arg2, NOTYPE); match_everything(0); res = noisy_match_result(); break; case FIXDB_PENNIES: res = mux_atol(arg2); break; } char *pValidName; switch (key) { case FIXDB_OWNER: s_Owner(thing, res); if (!Quiet(executor)) notify(executor, tprintf("Owner set to #%d", res)); break; case FIXDB_LOC: s_Location(thing, res); if (!Quiet(executor)) notify(executor, tprintf("Location set to #%d", res)); break; case FIXDB_CON: s_Contents(thing, res); if (!Quiet(executor)) notify(executor, tprintf("Contents set to #%d", res)); break; case FIXDB_EXITS: s_Exits(thing, res); if (!Quiet(executor)) notify(executor, tprintf("Exits set to #%d", res)); break; case FIXDB_NEXT: s_Next(thing, res); if (!Quiet(executor)) notify(executor, tprintf("Next set to #%d", res)); break; case FIXDB_PENNIES: s_Pennies(thing, res); if (!Quiet(executor)) notify(executor, tprintf("Pennies set to %d", res)); break; case FIXDB_NAME: if (isPlayer(thing)) { if (!ValidatePlayerName(arg2)) { notify(executor, "That's not a good name for a player."); return; } pValidName = arg2; if (lookup_player(NOTHING, pValidName, false) != NOTHING) { notify(executor, "That name is already in use."); return; } STARTLOG(LOG_SECURITY, "SEC", "CNAME"); log_name(thing), log_text(" renamed to "); log_text(pValidName); ENDLOG; if (Suspect(executor)) { raw_broadcast(WIZARD, "[Suspect] %s renamed to %s", Name(thing), pValidName); } delete_player_name(thing, Name(thing)); s_Name(thing, pValidName); add_player_name(thing, pValidName); } else { size_t nTmp; bool bValid; pValidName = MakeCanonicalObjectName(arg2, &nTmp, &bValid); if (!bValid) { notify(executor, "That is not a reasonable name."); return; } s_Name(thing, pValidName); } if (!Quiet(executor)) { notify(executor, tprintf("Name set to %s", pValidName)); } break; } } // MakeCanonicalAttributeName // // See stringutil.cpp for valid characters used here.. // // We truncate the attribute name to a length of SBUF_SIZE-1, if // necessary, but we will validate the remaining characters anyway. // // NOTE: Refer to init_attrtab() where it directly manipulates // mux_AttrNameSet to allow the attribute name: "*Password". // char *MakeCanonicalAttributeName(const char *pName, size_t *pnName, bool *pbValid) { static char Buffer[SBUF_SIZE]; if ( !pName || !mux_AttrNameInitialSet(*pName)) { *pnName = 0; *pbValid = false; return NULL; } int nLeft = SBUF_SIZE-1; char *p = Buffer; while (*pName && nLeft) { if (!mux_AttrNameSet(*pName)) { *pnName = 0; *pbValid = false; return Buffer; } *p = mux_toupper(*pName); p++; pName++; nLeft--; } *p = '\0'; // Continue to validate remaining characters even though // we aren't going to use them. This helps to ensure that // softcode will run in the future if we increase the // size of SBUF_SIZE. // while (*pName) { if (!mux_AttrNameSet(*pName)) { *pnName = 0; *pbValid = false; return Buffer; } pName++; } // Length of truncated result. // *pnName = p - Buffer; *pbValid = true; return Buffer; } // MakeCanonicalAttributeCommand // char *MakeCanonicalAttributeCommand(const char *pName, size_t *pnName, bool *pbValid) { if (!pName) { *pnName = 0; *pbValid = false; return NULL; } static char Buffer[SBUF_SIZE]; int nLeft = SBUF_SIZE-2; char *p = Buffer; *p++ = '@'; while (*pName && nLeft) { *p = mux_tolower(*pName); p++; pName++; nLeft--; } *p = '\0'; // Length of result. // *pnName = p - Buffer; // Is the result valid? // *pbValid = (*pnName > 1); // Pointer to result // return Buffer; } /* --------------------------------------------------------------------------- * init_attrtab: Initialize the attribute hash tables. */ void init_attrtab(void) { ATTR *a; // We specifically allow the '*' character at server // initialization because it's part of the A_PASS attribute // name. // const unsigned char star = '*'; mux_AttrNameSet[star] = true; mux_AttrNameInitialSet[star] = true; for (a = AttrTable; a->number; a++) { size_t nLen; bool bValid; char *buff = MakeCanonicalAttributeName(a->name, &nLen, &bValid); if (!bValid) { continue; } anum_extend(a->number); anum_set(a->number, a); hashaddLEN(buff, nLen, a, &mudstate.attr_name_htab); } mux_AttrNameInitialSet[star] = false; mux_AttrNameSet[star] = false; } /* --------------------------------------------------------------------------- * atr_str: Look up an attribute by name. */ ATTR *atr_str(const char *s) { // Make attribute name canonical. // size_t nBuffer; bool bValid; char *buff = MakeCanonicalAttributeName(s, &nBuffer, &bValid); if (!bValid) { return NULL; } // Look for a predefined attribute. // ATTR *a = (ATTR *)hashfindLEN(buff, nBuffer, &mudstate.attr_name_htab); if (a != NULL) { return a; } // Nope, look for a user attribute. // a = vattr_find_LEN(buff, nBuffer); return a; } int GrowFiftyPercent(int x, int low, int high) { if (x < 0) { x = 0; } // Calcuate 150% of x clipping goal at INT_MAX. // int half = x >> 1; int goal; if (INT_MAX - half <= x) { goal = INT_MAX; } else { goal = x + half; } // Clip result between requested boundaries. // if (goal < low) { goal = low; } else if (high < goal) { goal = high; } return goal; } /* --------------------------------------------------------------------------- * anum_extend: Grow the attr num lookup table. */ ATTR **anum_table = NULL; int anum_alc_top = -1; void anum_extend(int newtop) { if (newtop <= anum_alc_top) { return; } int delta; if (mudstate.bStandAlone) { delta = 1000; } else { delta = mudconf.init_size; } int h = GrowFiftyPercent(anum_alc_top, delta, INT_MAX); if (newtop < h) { newtop = h; } int i; ATTR **anum_table2 = (ATTR **) MEMALLOC((newtop + 1) * sizeof(ATTR *)); if (NULL != anum_table2) { for (i = anum_alc_top + 1; i <= newtop; i++) { anum_table2[i] = NULL; } if (NULL != anum_table) { for (i = 0; i <= anum_alc_top; i++) { anum_table2[i] = anum_table[i]; } MEMFREE((char *)anum_table); } anum_table = anum_table2; } else { ISOUTOFMEMORY(anum_table2); } anum_alc_top = newtop; } // -------------------------------------------------------------------------- // atr_num: Look up an attribute by number. // ATTR *atr_num(int anum) { if ( anum < 0 || anum_alc_top < anum) { return NULL; } return anum_get(anum); } static void SetupThrottle(dbref executor) { CLinearTimeAbsolute tNow; CLinearTimeDelta ltdHour; ltdHour.SetSeconds(60*60); tNow.GetUTC(); db[executor].tThrottleExpired = tNow + ltdHour; s_ThAttrib(executor, mudconf.vattr_per_hour); s_ThMail(executor, mudconf.mail_per_hour); } static void SetupGlobalThrottle(void) { CLinearTimeAbsolute tNow; CLinearTimeDelta ltdHour; ltdHour.SetSeconds(60*60); tNow.GetUTC(); mudstate.tThrottleExpired = tNow + ltdHour; mudstate.pcreates_this_hour = mudconf.pcreate_per_hour; } bool ThrottlePlayerCreate(void) { if (0 < mudstate.pcreates_this_hour) { mudstate.pcreates_this_hour--; return false; } CLinearTimeAbsolute tNow; tNow.GetUTC(); if (mudstate.tThrottleExpired <= tNow) { SetupGlobalThrottle(); return false; } return true; } bool ThrottleAttributeNames(dbref executor) { if (0 < ThAttrib(executor)) { s_ThAttrib(executor, ThAttrib(executor)-1); return false; } CLinearTimeAbsolute tNow; tNow.GetUTC(); if (db[executor].tThrottleExpired <= tNow) { SetupThrottle(executor); return false; } return true; } bool ThrottleMail(dbref executor) { if (0 < ThMail(executor)) { s_ThMail(executor, ThMail(executor)-1); return false; } CLinearTimeAbsolute tNow; tNow.GetUTC(); if (db[executor].tThrottleExpired <= tNow) { SetupThrottle(executor); return false; } return true; } /* --------------------------------------------------------------------------- * mkattr: Lookup attribute by name, creating if needed. */ int mkattr(dbref executor, const char *buff) { ATTR *ap = atr_str(buff); if (!ap) { // Unknown attribute name, create a new one. // size_t nName; bool bValid; char *pName = MakeCanonicalAttributeName(buff, &nName, &bValid); ATTR *va; if (bValid) { if ( !Wizard(executor) && ThrottleAttributeNames(executor)) { return -1; } int aflags = mudconf.vattr_flags; if (pName[0] == '_') { // An attribute that begins with an underline is // hidden from mortals and only changeable by // WIZARDs. // aflags |= AF_MDARK | AF_WIZARD; } va = vattr_alloc_LEN(pName, nName, aflags); if (va && va->number) { return va->number; } } return -1; } else if (ap->number) { return ap->number; } return -1; } #ifndef MEMORY_BASED /* --------------------------------------------------------------------------- * al_decode: Fetch an attribute number from an alist. */ static int al_decode(char **app) { char *ap = *app; int atrnum = 0, atrshft = 0; for (;;) { int ch = *ap++; int bits = ch & 0x7F; if (atrshft > 0) atrnum |= (bits << atrshft); else atrnum = bits; if ((ch & 0x80) == 0) { *app = ap; return atrnum; } atrshft += 7; } } // --------------------------------------------------------------------------- // al_code: Store an attribute number in an alist // // Because A_LIST are attributes, too. We cannot generate a '\0', otherwise // the size of an A_LIST cannot be determined with strlen(). Fortunately, the // following routine only generates a '\0' if atrnum == 0 (which is // never used). // static char *al_code(char *ap, unsigned int atrnum) { int i; unsigned int bits; for (i = 0; i < ATR_BUF_INCR - 1; i++) { bits = atrnum & 0x7F; if (atrnum <= 0x7F) { ap[i] = (char)bits; break; } atrnum >>= 7; ap[i] = (char)(bits | 0x80); } return ap + i + 1; } #endif // MEMORY_BASED /* --------------------------------------------------------------------------- * Commer: check if an object has any $-commands in its attributes. */ bool Commer(dbref thing) { if (mudstate.bfNoCommands.IsSet(thing)) { // We already know that there are no commands on this thing. // return false; } else if (mudstate.bfCommands.IsSet(thing)) { // We already know that there are definitely commands on this thing. // return true; } bool bFoundListens = false; char *as; atr_push(); char *buff = alloc_lbuf("Commer"); for (int atr = atr_head(thing, &as); atr; atr = atr_next(&as)) { ATTR *ap = atr_num(atr); if ( !ap || (ap->flags & AF_NOPROG)) { continue; } int aflags; dbref aowner; atr_get_str(buff, thing, atr, &aowner, &aflags); if (aflags & AF_NOPROG) { continue; } if ( AMATCH_CMD != buff[0] && AMATCH_LISTEN != buff[0]) { continue; } // Search for unescaped ':' // char *s = strchr(buff+1, ':'); if (!s) { continue; } if (AMATCH_CMD == buff[0]) { free_lbuf(buff); atr_pop(); mudstate.bfCommands.Set(thing); if (bFoundListens) { mudstate.bfListens.Set(thing); mudstate.bfNoListens.Clear(thing); } return true; } else // AMATCH_LISTEN == buff[0] { bFoundListens = true; } } free_lbuf(buff); atr_pop(); mudstate.bfNoCommands.Set(thing); if (bFoundListens) { mudstate.bfListens.Set(thing); mudstate.bfNoListens.Clear(thing); } else { mudstate.bfNoListens.Set(thing); mudstate.bfListens.Clear(thing); } return false; } // routines to handle object attribute lists // #ifndef MEMORY_BASED /* --------------------------------------------------------------------------- * al_fetch, al_store, al_add, al_delete: Manipulate attribute lists */ // al_extend: Get more space for attributes, if needed // static void al_extend(char **buffer, size_t *bufsiz, size_t len, bool copy) { if (len > *bufsiz) { size_t newsize = len + ATR_BUF_CHUNK; char *tbuff = (char *)MEMALLOC(newsize); ISOUTOFMEMORY(tbuff); if (*buffer) { if (copy) { memcpy(tbuff, *buffer, *bufsiz); } MEMFREE(*buffer); *buffer = NULL; } *buffer = tbuff; *bufsiz = newsize; } } // al_store: Write modified attribute list // void al_store(void) { if (mudstate.mod_al_id != NOTHING) { if (mudstate.mod_alist_len) { atr_add_raw_LEN(mudstate.mod_al_id, A_LIST, mudstate.mod_alist, mudstate.mod_alist_len); } else { atr_clr(mudstate.mod_al_id, A_LIST); } } mudstate.mod_al_id = NOTHING; } // al_fetch: Load attribute list // static char *al_fetch(dbref thing) { // We only need fetch if we change things. // if (mudstate.mod_al_id == thing) { return mudstate.mod_alist; } // Save old list, then fetch and set up the attribute list. // al_store(); size_t len; const char *astr = atr_get_raw_LEN(thing, A_LIST, &len); if (astr) { al_extend(&mudstate.mod_alist, &mudstate.mod_size, len+1, false); memcpy(mudstate.mod_alist, astr, len+1); mudstate.mod_alist_len = len; } else { al_extend(&mudstate.mod_alist, &mudstate.mod_size, 1, false); *mudstate.mod_alist = '\0'; mudstate.mod_alist_len = 0; } mudstate.mod_al_id = thing; return mudstate.mod_alist; } // al_add: Add an attribute to an attribute list // static bool al_add(dbref thing, int attrnum) { char *abuf = al_fetch(thing); char *cp = abuf; int anum; // See if attr is in the list. If so, exit (need not do anything). // while (*cp) { anum = al_decode(&cp); if (anum == attrnum) { return true; } } // The attribute isn't there, so we need to try to add it. // size_t iPosition = cp - abuf; // If we are too large for an attribute // if (iPosition + ATR_BUF_INCR >= LBUF_SIZE) { return false; } // Extend it. // al_extend(&mudstate.mod_alist, &mudstate.mod_size, (iPosition + ATR_BUF_INCR), true); if (mudstate.mod_alist != abuf) { // extend returned different buffer, re-position the end // cp = mudstate.mod_alist + iPosition; } // Add the new attribute on to the end. // cp = al_code(cp, attrnum); *cp = '\0'; mudstate.mod_alist_len = cp - mudstate.mod_alist; return true; } // al_delete: Remove an attribute from an attribute list // static void al_delete(dbref thing, int attrnum) { int anum; char *abuf, *cp, *dp; // If trying to modify List attrib, return. Otherwise, get the attribute list. // if (attrnum == A_LIST) { return; } abuf = al_fetch(thing); if (!abuf) { return; } cp = abuf; while (*cp) { dp = cp; anum = al_decode(&cp); if (anum == attrnum) { while (*cp) { anum = al_decode(&cp); dp = al_code(dp, anum); } *dp = '\0'; mudstate.mod_alist_len = dp - mudstate.mod_alist; return; } } return; } static DCL_INLINE void makekey(dbref thing, int atr, Aname *abuff) { abuff->object = thing; abuff->attrnum = atr; return; } #endif // !MEMORY_BASED /* --------------------------------------------------------------------------- * atr_encode: Encode an attribute string. */ static char *atr_encode(char *iattr, dbref thing, dbref owner, int flags, int atr) { UNUSED_PARAMETER(atr); // If using the default owner and flags (almost all attributes will), // just store the string. // if (((owner == Owner(thing)) || (owner == NOTHING)) && !flags) return iattr; // Encode owner and flags into the attribute text. // if (owner == NOTHING) owner = Owner(thing); return tprintf("%c%d:%d:%s", ATR_INFO_CHAR, owner, flags, iattr); } // atr_decode_flags_owner: Decode the owner and flags (if present) and // return a pointer to the attribute text. // static const char *atr_decode_flags_owner(const char *iattr, dbref *owner, int *flags) { // See if the first char of the attribute is the special character // *flags = 0; if (*iattr != ATR_INFO_CHAR) { return iattr; } // It has the special character, crack the attr apart. // const char *cp = iattr + 1; // Get the attribute owner // bool neg = false; if (*cp == '-') { neg = true; cp++; } int tmp_owner = 0; unsigned int ch = *cp; while (mux_isdigit(ch)) { cp++; tmp_owner = 10*tmp_owner + (ch-'0'); ch = *cp; } if (neg) { tmp_owner = -tmp_owner; } // If delimiter is not ':', just return attribute // if (*cp++ != ':') { return iattr; } // Get the attribute flags. // int tmp_flags = 0; ch = *cp; while (mux_isdigit(ch)) { cp++; tmp_flags = 10*tmp_flags + (ch-'0'); ch = *cp; } // If delimiter is not ':', just return attribute. // if (*cp++ != ':') { return iattr; } // Get the attribute text. // if (tmp_owner != NOTHING) { *owner = tmp_owner; } *flags = tmp_flags; return cp; } // --------------------------------------------------------------------------- // atr_decode: Decode an attribute string. // static void atr_decode_LEN(const char *iattr, size_t nLen, char *oattr, dbref thing, dbref *owner, int *flags, size_t *pLen) { // Default the owner // *owner = Owner(thing); // Parse for owner and flags // const char *cp = atr_decode_flags_owner(iattr, owner, flags); // Get the attribute text. // *pLen = nLen - (cp - iattr); if (oattr) { memcpy(oattr, cp, (*pLen) + 1); } } /* --------------------------------------------------------------------------- * atr_clr: clear an attribute in the list. */ void atr_clr(dbref thing, int atr) { #ifdef MEMORY_BASED if ( !db[thing].nALUsed || !db[thing].pALHead) { return; } mux_assert(0 <= db[thing].nALUsed); // Binary search for the attribute. // int lo = 0; int mid; int hi = db[thing].nALUsed - 1; ATRLIST *list = db[thing].pALHead; while (lo <= hi) { mid = ((hi - lo) >> 1) + lo; if (list[mid].number > atr) { hi = mid - 1; } else if (list[mid].number < atr) { lo = mid + 1; } else // (list[mid].number == atr) { MEMFREE(list[mid].data); list[mid].data = NULL; db[thing].nALUsed--; if (mid != db[thing].nALUsed) { memmove( list + mid, list + mid + 1, (db[thing].nALUsed - mid) * sizeof(ATRLIST)); } break; } } #else // MEMORY_BASED Aname okey; makekey(thing, atr, &okey); cache_del(&okey); al_delete(thing, atr); #endif // MEMORY_BASED switch (atr) { case A_STARTUP: db[thing].fs.word[FLAG_WORD1] &= ~HAS_STARTUP; break; case A_DAILY: db[thing].fs.word[FLAG_WORD2] &= ~HAS_DAILY; break; case A_FORWARDLIST: db[thing].fs.word[FLAG_WORD2] &= ~HAS_FWDLIST; if (!mudstate.bStandAlone) { // We should clear the hashtable, too. // fwdlist_clr(thing); } break; case A_LISTEN: db[thing].fs.word[FLAG_WORD2] &= ~HAS_LISTEN; break; case A_TIMEOUT: desc_reload(thing); break; case A_QUEUEMAX: pcache_reload(thing); break; default: // Since this could overwrite an existing ^-Command or $-Command, we // longer assert that the object has one. // mudstate.bfListens.Clear(thing); mudstate.bfCommands.Clear(thing); break; } } /* --------------------------------------------------------------------------- * atr_add_raw, atr_add: add attribute of type atr to list */ void atr_add_raw_LEN(dbref thing, int atr, const char *szValue, size_t nValue) { if ( !szValue || '\0' == szValue[0]) { atr_clr(thing, atr); return; } #ifdef MEMORY_BASED ATRLIST *list = db[thing].pALHead; char *text = StringCloneLen(szValue, nValue); if (!list) { db[thing].nALAlloc = INITIAL_ATRLIST_SIZE; list = (ATRLIST *)MEMALLOC(db[thing].nALAlloc*sizeof(ATRLIST)); ISOUTOFMEMORY(list); db[thing].pALHead = list; db[thing].nALUsed = 1; list[0].number = atr; list[0].data = text; list[0].size = nValue + 1; } else { // If this atr is newly allocated, or it comes from the flatfile, it // will experience worst-case performance with a binary search, so we // perform a quick check to see if it goes on the end. // int lo; int hi = db[thing].nALUsed - 1; if (list[hi].number < atr) { // Attribute should be appended to the end of the list. // lo = hi + 1; } else { // Binary search for the attribute // lo = 0; while (lo <= hi) { int mid = ((hi - lo) >> 1) + lo; if (list[mid].number > atr) { hi = mid - 1; } else if (list[mid].number < atr) { lo = mid + 1; } else // if (list[mid].number == atr) { MEMFREE(list[mid].data); list[mid].data = text; list[mid].size = nValue + 1; goto FoundAttribute; } } } // We didn't find it, and lo == hi + 1. The attribute should be // inserted between (0,hi) and (lo,nALUsed-1) where hi may be -1 // and lo may be nALUsed. // if (db[thing].nALUsed < db[thing].nALAlloc) { if (lo < db[thing].nALUsed) { memmove( list + lo + 1, list + lo, (db[thing].nALUsed - lo) * sizeof(ATRLIST)); } } else { // Double the size of the list. // db[thing].nALAlloc = GrowFiftyPercent(db[thing].nALAlloc, INITIAL_ATRLIST_SIZE, INT_MAX); list = (ATRLIST *)MEMALLOC(db[thing].nALAlloc * sizeof(ATRLIST)); ISOUTOFMEMORY(list); // Copy bottom part. // if (lo > 0) { memcpy(list, db[thing].pALHead, lo * sizeof(ATRLIST)); } // Copy top part. // if (lo < db[thing].nALUsed) { memcpy( list + lo + 1, db[thing].pALHead + lo, (db[thing].nALUsed - lo) * sizeof(ATRLIST)); } MEMFREE(db[thing].pALHead); db[thing].pALHead = list; } db[thing].nALUsed++; list[lo].data = text; list[lo].number = atr; list[lo].size = nValue + 1; } FoundAttribute: #else // MEMORY_BASED if (nValue > LBUF_SIZE-1) { nValue = LBUF_SIZE-1; } Aname okey; makekey(thing, atr, &okey); if (atr == A_LIST) { // A_LIST is never compressed and it's never listed within itself. // cache_put(&okey, szValue, nValue+1); } else { if (!al_add(thing, atr)) { return; } cache_put(&okey, szValue, nValue+1); } #endif // MEMORY_BASED switch (atr) { case A_STARTUP: db[thing].fs.word[FLAG_WORD1] |= HAS_STARTUP; break; case A_DAILY: db[thing].fs.word[FLAG_WORD2] |= HAS_DAILY; break; case A_FORWARDLIST: db[thing].fs.word[FLAG_WORD2] |= HAS_FWDLIST; break; case A_LISTEN: db[thing].fs.word[FLAG_WORD2] |= HAS_LISTEN; break; case A_TIMEOUT: desc_reload(thing); break; case A_QUEUEMAX: pcache_reload(thing); break; } } void atr_add_raw(dbref thing, int atr, const char *szValue) { atr_add_raw_LEN(thing, atr, szValue, szValue ? strlen(szValue) : 0); } void atr_add(dbref thing, int atr, char *buff, dbref owner, int flags) { set_modified(thing); if (!buff || !*buff) { atr_clr(thing, atr); } else { switch (buff[0]) { case AMATCH_LISTEN: // Since this could be a ^-Command, we no longer assert that the // object has none. // mudstate.bfNoListens.Clear(thing); break; case AMATCH_CMD: // Since this could be a $-Command, we no longer assert that the // object has none. // mudstate.bfNoCommands.Clear(thing); break; } // Since this could overwrite an existing ^-Command or $-Command, we // longer assert that the object has one. // mudstate.bfListens.Clear(thing); mudstate.bfCommands.Clear(thing); char *tbuff = atr_encode(buff, thing, owner, flags, atr); atr_add_raw(thing, atr, tbuff); } } void atr_set_flags(dbref thing, int atr, dbref flags) { dbref aowner; int aflags; char *buff = atr_get(thing, atr, &aowner, &aflags); atr_add(thing, atr, buff, aowner, flags); free_lbuf(buff); } /* --------------------------------------------------------------------------- * get_atr,atr_get_raw, atr_get_str, atr_get: Get an attribute from the database. */ int get_atr(const char *name) { ATTR *ap = atr_str(name); if (!ap) return 0; if (!(ap->number)) return -1; return ap->number; } #ifdef MEMORY_BASED const char *atr_get_raw_LEN(dbref thing, int atr, size_t *pLen) { if (!Good_obj(thing)) { return NULL; } // Binary search for the attribute. // ATRLIST *list = db[thing].pALHead; if (!list) { return NULL; } int lo = 0; int hi = db[thing].nALUsed - 1; int mid; while (lo <= hi) { mid = ((hi - lo) >> 1) + lo; if (list[mid].number > atr) { hi = mid - 1; } else if (list[mid].number < atr) { lo = mid + 1; } else // if (list[mid].number == atr) { *pLen = list[mid].size - 1; return list[mid].data; } } *pLen = 0; return NULL; } #else // MEMORY_BASED const char *atr_get_raw_LEN(dbref thing, int atr, size_t *pLen) { Aname okey; makekey(thing, atr, &okey); size_t nLen; const char *a = cache_get(&okey, &nLen); nLen = a ? (nLen-1) : 0; *pLen = nLen; return a; } #endif // MEMORY_BASED const char *atr_get_raw(dbref thing, int atr) { size_t Len; return atr_get_raw_LEN(thing, atr, &Len); } char *atr_get_str_LEN(char *s, dbref thing, int atr, dbref *owner, int *flags, size_t *pLen) { const char *buff = atr_get_raw_LEN(thing, atr, pLen); if (!buff) { *owner = Owner(thing); *flags = 0; *pLen = 0; *s = '\0'; } else { atr_decode_LEN(buff, *pLen, s, thing, owner, flags, pLen); } return s; } char *atr_get_str(char *s, dbref thing, int atr, dbref *owner, int *flags) { size_t nLen; return atr_get_str_LEN(s, thing, atr, owner, flags, &nLen); } char *atr_get_LEN(dbref thing, int atr, dbref *owner, int *flags, size_t *pLen) { char *buff = alloc_lbuf("atr_get"); return atr_get_str_LEN(buff, thing, atr, owner, flags, pLen); } char *atr_get_real(dbref thing, int atr, dbref *owner, int *flags, const char *file, const int line) { size_t nLen; char *buff = pool_alloc_lbuf("atr_get", file, line); return atr_get_str_LEN(buff, thing, atr, owner, flags, &nLen); } bool atr_get_info(dbref thing, int atr, dbref *owner, int *flags) { size_t nLen; const char *buff = atr_get_raw_LEN(thing, atr, &nLen); if (!buff) { *owner = Owner(thing); *flags = 0; return false; } atr_decode_LEN(buff, nLen, NULL, thing, owner, flags, &nLen); return true; } char *atr_pget_str_LEN(char *s, dbref thing, int atr, dbref *owner, int *flags, size_t *pLen) { dbref parent; int lev; ATTR *ap; const char *buff; ITER_PARENTS(thing, parent, lev) { buff = atr_get_raw_LEN(parent, atr, pLen); if (buff && *buff) { atr_decode_LEN(buff, *pLen, s, thing, owner, flags, pLen); if ( lev == 0 || !(*flags & AF_PRIVATE)) { return s; } } if ( lev == 0 && Good_obj(Parent(parent))) { ap = atr_num(atr); if (!ap || ap->flags & AF_PRIVATE) { break; } } } *owner = Owner(thing); *flags = 0; *s = '\0'; *pLen = 0; return s; } char *atr_pget_str(char *s, dbref thing, int atr, dbref *owner, int *flags) { size_t nLen; return atr_pget_str_LEN(s, thing, atr, owner, flags, &nLen); } char *atr_pget_LEN(dbref thing, int atr, dbref *owner, int *flags, size_t *pLen) { char *buff = alloc_lbuf("atr_pget"); return atr_pget_str_LEN(buff, thing, atr, owner, flags, pLen); } char *atr_pget_real(dbref thing, int atr, dbref *owner, int *flags, const char *file, const int line) { size_t nLen; char *buff = pool_alloc_lbuf("atr_pget", file, line); return atr_pget_str_LEN(buff, thing, atr, owner, flags, &nLen); } bool atr_pget_info(dbref thing, int atr, dbref *owner, int *flags) { dbref parent; int lev; ATTR *ap; ITER_PARENTS(thing, parent, lev) { size_t nLen; const char *buff = atr_get_raw_LEN(parent, atr, &nLen); if (buff && *buff) { atr_decode_LEN(buff, nLen, NULL, thing, owner, flags, &nLen); if ((lev == 0) || !(*flags & AF_PRIVATE)) { return true; } } if ((lev == 0) && Good_obj(Parent(parent))) { ap = atr_num(atr); if (!ap || ap->flags & AF_PRIVATE) break; } } *owner = Owner(thing); *flags = 0; return false; } /* --------------------------------------------------------------------------- * atr_free: Reset all attributes of an object. */ void atr_free(dbref thing) { #ifdef MEMORY_BASED if (db[thing].pALHead) { MEMFREE(db[thing].pALHead); } db[thing].pALHead = NULL; db[thing].nALAlloc = 0; db[thing].nALUsed = 0; #else // MEMORY_BASED char *as; atr_push(); for (int atr = atr_head(thing, &as); atr; atr = atr_next(&as)) { atr_clr(thing, atr); } atr_pop(); if (mudstate.mod_al_id == thing) { al_store(); // remove from cache } atr_clr(thing, A_LIST); #endif // MEMORY_BASED mudstate.bfCommands.Clear(thing); mudstate.bfNoCommands.Set(thing); mudstate.bfListens.Clear(thing); mudstate.bfNoListens.Set(thing); } /* --------------------------------------------------------------------------- * atr_cpy: Copy all attributes from one object to another. */ void atr_cpy(dbref dest, dbref source, bool bInternal) { dbref owner = Owner(dest); char *as; atr_push(); for (int atr = atr_head(source, &as); atr; atr = atr_next(&as)) { int aflags; dbref aowner; char *buf = atr_get(source, atr, &aowner, &aflags); if (!(aflags & AF_LOCK)) { // Change owner. // aowner = owner; } ATTR *at = atr_num(atr); if ( atr && at) { if ( !(at->flags & (AF_INTERNAL|AF_NOCLONE)) && ( bInternal || God(owner) || ( !God(dest) && !(aflags & AF_LOCK) && ( ( Controls(owner, dest) && !(at->flags & (AF_WIZARD|AF_GOD)) && !(aflags & (AF_WIZARD|AF_GOD))) || ( Wizard(owner) && !(at->flags & AF_GOD)))))) { // Only set attrs that owner has perm to set. // atr_add(dest, atr, buf, aowner, aflags); } } free_lbuf(buf); } atr_pop(); } /* --------------------------------------------------------------------------- * atr_chown: Change the ownership of the attributes of an object to the * current owner if they are not locked. */ void atr_chown(dbref obj) { dbref owner = Owner(obj); char *as; atr_push(); for (int atr = atr_head(obj, &as); atr; atr = atr_next(&as)) { int aflags; dbref aowner; char *buf = atr_get(obj, atr, &aowner, &aflags); if ( aowner != owner && !(aflags & AF_LOCK)) { atr_add(obj, atr, buf, owner, aflags); } free_lbuf(buf); } atr_pop(); } /* --------------------------------------------------------------------------- * atr_next: Return next attribute in attribute list. */ int atr_next(char **attrp) { #ifdef MEMORY_BASED ATRCOUNT *atr; if (!attrp || !*attrp) { return 0; } else { atr = (ATRCOUNT *) * attrp; if (atr->count >= db[atr->thing].nALUsed) { MEMFREE(atr); atr = NULL; return 0; } atr->count++; return db[atr->thing].pALHead[atr->count - 1].number; } #else // MEMORY_BASED if (!*attrp || !**attrp) { return 0; } else { return al_decode(attrp); } #endif // MEMORY_BASED } /* --------------------------------------------------------------------------- * atr_push, atr_pop: Push and pop attr lists. */ void atr_push(void) { #ifndef MEMORY_BASED ALIST *new_alist = (ALIST *) alloc_sbuf("atr_push"); new_alist->data = mudstate.iter_alist.data; new_alist->len = mudstate.iter_alist.len; new_alist->next = mudstate.iter_alist.next; mudstate.iter_alist.data = NULL; mudstate.iter_alist.len = 0; mudstate.iter_alist.next = new_alist; #endif // !MEMORY_BASED } void atr_pop(void) { #ifndef MEMORY_BASED ALIST *old_alist = mudstate.iter_alist.next; if (mudstate.iter_alist.data) { MEMFREE(mudstate.iter_alist.data); mudstate.iter_alist.data = NULL; } if (old_alist) { mudstate.iter_alist.data = old_alist->data; mudstate.iter_alist.len = old_alist->len; mudstate.iter_alist.next = old_alist->next; char *cp = (char *)old_alist; free_sbuf(cp); } else { mudstate.iter_alist.data = NULL; mudstate.iter_alist.len = 0; mudstate.iter_alist.next = NULL; } #endif // !MEMORY_BASED } /* --------------------------------------------------------------------------- * atr_head: Returns the head of the attr list for object 'thing' */ int atr_head(dbref thing, char **attrp) { #ifdef MEMORY_BASED if (db[thing].nALUsed) { ATRCOUNT *atr = (ATRCOUNT *) MEMALLOC(sizeof(ATRCOUNT)); ISOUTOFMEMORY(atr); atr->thing = thing; atr->count = 1; *attrp = (char *)atr; return db[thing].pALHead[0].number; } return 0; #else // MEMORY_BASED const char *astr; size_t alen; // Get attribute list. Save a read if it is in the modify atr list // if (thing == mudstate.mod_al_id) { astr = mudstate.mod_alist; alen = mudstate.mod_alist_len; } else { astr = atr_get_raw_LEN(thing, A_LIST, &alen); } // If no list, return nothing. // if (!alen) { return 0; } // Set up the list and return the first entry. // al_extend(&mudstate.iter_alist.data, &mudstate.iter_alist.len, alen+1, false); memcpy(mudstate.iter_alist.data, astr, alen+1); *attrp = mudstate.iter_alist.data; return atr_next(attrp); #endif // MEMORY_BASED } /* --------------------------------------------------------------------------- * db_grow: Extend the struct database. */ #define SIZE_HACK 1 // So mistaken refs to #-1 won't die. static void initialize_objects(dbref first, dbref last) { dbref thing; for (thing = first; thing < last; thing++) { s_Owner(thing, GOD); s_Flags(thing, FLAG_WORD1, (TYPE_GARBAGE | GOING)); s_Powers(thing, 0); s_Powers2(thing, 0); s_Location(thing, NOTHING); s_Contents(thing, NOTHING); s_Exits(thing, NOTHING); s_Link(thing, NOTHING); s_Next(thing, NOTHING); s_Zone(thing, NOTHING); s_Parent(thing, NOTHING); #ifdef DEPRECATED s_Stack(thing, NULL); #endif // DEPRECATED db[thing].cpu_time_used.Set100ns(0); db[thing].tThrottleExpired.Set100ns(0); s_ThAttrib(thing, 0); s_ThMail(thing, 0); #ifdef MEMORY_BASED db[thing].pALHead = NULL; db[thing].nALAlloc = 0; db[thing].nALUsed = 0; #else db[thing].name = NULL; #endif // MEMORY_BASED db[thing].purename = NULL; db[thing].moniker = NULL; } } void db_grow(dbref newtop) { mudstate.bfCommands.Resize(newtop); mudstate.bfNoCommands.Resize(newtop); mudstate.bfListens.Resize(newtop); mudstate.bfNoListens.Resize(newtop); int delta; if (mudstate.bStandAlone) { delta = 1000; } else { delta = mudconf.init_size; } // Determine what to do based on requested size, current top and size. // Make sure we grow in reasonable-sized chunks to prevent frequent // reallocations of the db array. // // If requested size is smaller than the current db size, ignore it. // if (newtop <= mudstate.db_top) { return; } // If requested size is greater than the current db size but smaller // than the amount of space we have allocated, raise the db size and // initialize the new area. // if (newtop <= mudstate.db_size) { initialize_objects(mudstate.db_top, newtop); mudstate.db_top = newtop; return; } // Grow by a minimum of delta objects // int newsize = newtop; int nMinimumGrowth = mudstate.db_size + delta; if (newtop <= nMinimumGrowth) { newsize = nMinimumGrowth; } // Enforce minimum database size // if (newsize < mudstate.min_size) { newsize = mudstate.min_size; } // Grow the db array // // NOTE: There is always one copy of 'db' around that isn't freed even // just before the process terminates. We rely (quite safely) on the OS // to reclaim the memory. // OBJ *newdb = (OBJ *)MEMALLOC((newsize + SIZE_HACK) * sizeof(OBJ)); ISOUTOFMEMORY(newdb); if (db) { // An old struct database exists. Copy it to the new buffer. // db -= SIZE_HACK; memcpy(newdb, db, (mudstate.db_top + SIZE_HACK) * sizeof(OBJ)); MEMFREE(db); } else { // Creating a brand new struct database. Fill in the 'reserved' area // in case it is referenced. // db = newdb; initialize_objects(0, SIZE_HACK); } db = newdb + SIZE_HACK; newdb = NULL; initialize_objects(mudstate.db_top, newtop); mudstate.db_top = newtop; mudstate.db_size = newsize; // Grow the db mark buffer. // int marksize = (newsize + 7) >> 3; MARKBUF *newmarkbuf = (MARKBUF *)MEMALLOC(marksize); ISOUTOFMEMORY(newmarkbuf); memset(newmarkbuf, 0, marksize); if (mudstate.markbits) { marksize = (newtop + 7) >> 3; memcpy(newmarkbuf, mudstate.markbits, marksize); MEMFREE(mudstate.markbits); } mudstate.markbits = newmarkbuf; } void db_free(void) { char *cp; if (db != NULL) { db -= SIZE_HACK; cp = (char *)db; MEMFREE(cp); cp = NULL; db = NULL; } mudstate.db_top = 0; mudstate.db_size = 0; mudstate.freelist = NOTHING; } void db_make_minimal(void) { db_free(); db_grow(1); s_Name(0, "Limbo"); s_Flags(0, FLAG_WORD1, TYPE_ROOM); s_Flags(0, FLAG_WORD2, 0); s_Flags(0, FLAG_WORD3, 0); s_Powers(0, 0); s_Powers2(0, 0); s_Location(0, NOTHING); s_Exits(0, NOTHING); s_Link(0, NOTHING); s_Parent(0, NOTHING); s_Zone(0, NOTHING); s_Pennies(0, 0); s_Owner(0, 1); // should be #1 // load_player_names(); const char *pmsg; dbref obj = create_player("Wizard", "potrzebie", NOTHING, false, &pmsg); s_Flags(obj, FLAG_WORD1, Flags(obj) | WIZARD); s_Powers(obj, 0); s_Powers2(obj, 0); s_Pennies(obj, 1000); // Manually link to Limbo, just in case // s_Location(obj, 0); s_Next(obj, NOTHING); s_Contents(0, obj); s_Link(obj, 0); } dbref parse_dbref(const char *s) { // Enforce completely numeric dbrefs // const char *p = s; if (p[0]) { do { if (!mux_isdigit(*p)) { return NOTHING; } p++; } while (*p); } else { return NOTHING; } int x = mux_atol(s); return ((x >= 0) ? x : NOTHING); } void putref(FILE *f, dbref ref) { char buf[SBUF_SIZE]; size_t n = mux_ltoa(ref, buf); buf[n] = '\n'; fwrite(buf, sizeof(char), n+1, f); } // Code 0 - Any byte. // Code 1 - NUL (0x00) // Code 2 - '"' (0x22) // Code 3 - '\\' (0x5C) // Code 4 - 'e' (0x65) or 'E' (0x45) // Code 5 - 'n' (0x6E) or 'N' (0x4E) // Code 6 - 'r' (0x72) or 'R' (0x52) // Code 7 - 't' (0x74) or 'T' (0x54) // static const unsigned char decode_table[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 1, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, // 4 0, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, // 5 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, // 6 0, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; #define STATE_START 0 #define STATE_HAVE_ESC 1 // Action 0 - Emit X. // Action 1 - Get a Buffer. // Action 2 - Emit X. Move to START state. // Action 3 - Terminate parse. // Action 4 - Move to ESC state. // Action 5 - Emit ESC (0x1B). Move to START state. // Action 6 - Emit LF (0x0A). Move to START state. // Action 7 - Emit CR (0x0D). Move to START state. // Action 8 - Emit TAB (0x09). Move to START state. // static const int action_table[2][8] = { // Any '\0' '"' '\\' 'e' 'n' 'r' 't' { 0, 1, 3, 4, 0, 0, 0, 0}, // STATE_START { 2, 1, 2, 2, 5, 6, 7, 8} // STATE_HAVE_ESC }; char *getstring_noalloc(FILE *f, bool new_strings, size_t *pnBuffer) { static char buf[2*LBUF_SIZE + 20]; int c = fgetc(f); if ( new_strings && c == '"') { size_t nBufferLeft = sizeof(buf)-10; int iState = STATE_START; char *pOutput = buf; for (;;) { // Fetch up to and including the next LF. // char *pInput = pOutput + 6; if (fgets(pInput, static_cast(nBufferLeft), f) == NULL) { // EOF or ERROR. // *pOutput = 0; if (pnBuffer) { *pnBuffer = pOutput - buf; } return buf; } size_t nOutput = 0; // De-escape this data. removing the '\\' prefixes. // Terminate when you hit a '"'. // for (;;) { char ch = *pInput++; if (iState == STATE_START) { if (decode_table[(unsigned char)ch] == 0) { // As long as decode_table[*p] is 0, just keep copying the characters. // char *p = pOutput; do { *pOutput++ = ch; ch = *pInput++; } while (decode_table[(unsigned char)ch] == 0); nOutput = pOutput - p; } } int iAction = action_table[iState][decode_table[(unsigned char)ch]]; if (iAction <= 2) { if (1 == iAction) { // Get Buffer and remain in the current state. // break; } else { // 2 == iAction // Emit X and move to START state. // *pOutput++ = ch; nOutput++; iState = STATE_START; } } else if (3 == iAction) { // Terminate parsing. // *pOutput = 0; if (pnBuffer) { *pnBuffer = pOutput - buf; } return buf; } else if (4 == iAction) { // Move to ESC state. // iState = STATE_HAVE_ESC; } else if (5 == iAction) { *pOutput++ = ESC_CHAR; nOutput++; iState = STATE_START; } else if (6 == iAction) { *pOutput++ = '\n'; nOutput++; iState = STATE_START; } else if (7 == iAction) { *pOutput++ = '\r'; nOutput++; iState = STATE_START; } else { // if (8 == iAction) *pOutput++ = '\t'; nOutput++; iState = STATE_START; } } nBufferLeft -= nOutput; // Do we have any more room? // if (nBufferLeft <= 0) { *pOutput = 0; if (pnBuffer) { *pnBuffer = pOutput - buf; } return buf; } } } else { ungetc(c, f); char *p = buf; for (;;) { // Fetch up to and including the next LF. // if (fgets(p, LBUF_SIZE, f) == NULL) { // EOF or ERROR. // p[0] = '\0'; } else { // How much data did we fetch? // size_t nLine = strlen(p); if (nLine >= 2) { if (p[nLine-2] == '\r') { // Line is continued on the next line. // p += nLine; continue; } // Eat '\n' // p[nLine-1] = '\0'; } } if (pnBuffer) { *pnBuffer = p - buf; } return buf; } } } // Code 0 - Any byte. // Code 1 - NUL (0x00) // Code 2 - '"' (0x22) // Code 3 - '\\' (0x5C) // Code 4 - ESC (0x1B) // Code 5 - LF (0x0A) // Code 6 - CR' (0x0D) // Code 7 - TAB (0x09) // static const unsigned char encode_table[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 5, 0, 0, 6, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, // 1 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; void putstring(FILE *f, const char *pRaw) { static char aBuffer[2*LBUF_SIZE+4]; char *pBuffer = aBuffer; // Always leave room for four characters. One at the beginning and // three on the end. '\\"\n' or '\""\n' // *pBuffer++ = '"'; if (pRaw) { for (;;) { char ch; while ((ch = encode_table[(unsigned char)*pRaw]) == 0) { *pBuffer++ = *pRaw++; } if (1 == ch) { break; } pRaw++; switch (ch) { case 2: ch = '"'; break; case 3: ch = '\\'; break; case 4: ch = 'e'; break; case 5: ch = 'n'; break; case 6: ch = 'r'; break; case 7: ch = 't'; break; } *pBuffer++ = '\\'; *pBuffer++ = ch; } } *pBuffer++ = '"'; *pBuffer++ = '\n'; fwrite(aBuffer, sizeof(char), pBuffer - aBuffer, f); } int getref(FILE *f) { static char buf[SBUF_SIZE]; if (NULL != fgets(buf, sizeof(buf), f)) { return mux_atol(buf); } else { return 0; } } void free_boolexp(BOOLEXP *b) { if (b == TRUE_BOOLEXP) return; switch (b->type) { case BOOLEXP_AND: case BOOLEXP_OR: free_boolexp(b->sub1); free_boolexp(b->sub2); free_bool(b); break; case BOOLEXP_NOT: case BOOLEXP_CARRY: case BOOLEXP_IS: case BOOLEXP_OWNER: case BOOLEXP_INDIR: free_boolexp(b->sub1); free_bool(b); break; case BOOLEXP_CONST: free_bool(b); break; case BOOLEXP_ATR: case BOOLEXP_EVAL: MEMFREE(b->sub1); b->sub1 = NULL; free_bool(b); break; } } static BOOLEXP *dup_bool(BOOLEXP *b) { if (b == TRUE_BOOLEXP) return (TRUE_BOOLEXP); BOOLEXP *r = alloc_bool("dup_bool"); switch (r->type = b->type) { case BOOLEXP_AND: case BOOLEXP_OR: r->sub2 = dup_bool(b->sub2); case BOOLEXP_NOT: case BOOLEXP_CARRY: case BOOLEXP_IS: case BOOLEXP_OWNER: case BOOLEXP_INDIR: r->sub1 = dup_bool(b->sub1); case BOOLEXP_CONST: r->thing = b->thing; break; case BOOLEXP_EVAL: case BOOLEXP_ATR: r->thing = b->thing; r->sub1 = (BOOLEXP *)StringClone((char *)b->sub1); break; default: Log.WriteString("Bad bool type!" ENDLINE); return TRUE_BOOLEXP; } return (r); } #ifndef MEMORY_BASED int init_dbfile(char *game_dir_file, char *game_pag_file, int nCachePages) { if (mudstate.bStandAlone) { Log.tinyprintf("Opening (%s,%s)" ENDLINE, game_dir_file, game_pag_file); } int cc = cache_init(game_dir_file, game_pag_file, nCachePages); if (cc != HF_OPEN_STATUS_ERROR) { if (mudstate.bStandAlone) { Log.tinyprintf("Done opening (%s,%s)." ENDLINE, game_dir_file, game_pag_file); } else { STARTLOG(LOG_ALWAYS, "INI", "LOAD"); Log.tinyprintf("Using game db files: (%s,%s).", game_dir_file, game_pag_file); ENDLOG; } db_free(); } return cc; } #endif // !MEMORY_BASED // check_zone - checks back through a zone tree for control. // bool check_zone_handler(dbref player, dbref thing, bool bPlayerCheck) { mudstate.zone_nest_num++; if ( !mudconf.have_zones || !Good_obj(Zone(thing)) || mudstate.zone_nest_num >= mudconf.zone_nest_lim || isPlayer(thing) != bPlayerCheck) { mudstate.zone_nest_num = 0; return false; } // If the zone doesn't have an enterlock, DON'T allow control. // if ( atr_get_raw(Zone(thing), A_LENTER) && could_doit(player, Zone(thing), A_LENTER)) { mudstate.zone_nest_num = 0; return true; } else if (thing == Zone(thing)) { return false; } return check_zone_handler(player, Zone(thing), false); } // This function releases: // // 1. comsys resources associated with an object. // 2. @mail resources associated with an object. // void ReleaseAllResources(dbref obj) { if (mudconf.have_comsys) { do_comdisconnect(obj); do_clearcom(obj, obj, obj, 0); do_channelnuke(obj); del_comsys(obj); } if (mudconf.have_mailer) { do_mail_clear(obj, NULL); do_mail_purge(obj); malias_cleanup(obj); } } #ifndef WIN32 /* --------------------------------------------------------------------------- * dump_restart_db: Writes out socket information. */ void dump_restart_db(void) { FILE *f; DESC *d; int version = 2; mux_assert(mux_fopen(&f, "restart.db", "wb")); fprintf(f, "+V%d\n", version); putref(f, nMainGamePorts); for (int i = 0; i < nMainGamePorts; i++) { putref(f, aMainGamePorts[i].port); putref(f, aMainGamePorts[i].socket); } putref(f, mudstate.start_time.ReturnSeconds()); putstring(f, mudstate.doing_hdr); putref(f, mudstate.record_players); DESC_ITER_ALL(d) { putref(f, d->descriptor); putref(f, d->flags); putref(f, d->connected_at.ReturnSeconds()); putref(f, d->command_count); putref(f, d->timeout); putref(f, d->host_info); putref(f, d->player); putref(f, d->last_time.ReturnSeconds()); putref(f, d->raw_input_state); putref(f, d->nvt_sga_him_state); putref(f, d->nvt_sga_us_state); putref(f, d->nvt_eor_him_state); putref(f, d->nvt_eor_us_state); putref(f, d->nvt_naws_him_state); putref(f, d->nvt_naws_us_state); putref(f, d->height); putref(f, d->width); putstring(f, d->output_prefix); putstring(f, d->output_suffix); putstring(f, d->addr); putstring(f, d->doing); putstring(f, d->username); } putref(f, 0); fclose(f); } void load_restart_db(void) { FILE *f; if (!mux_fopen(&f, "restart.db", "rb")) { mudstate.restarting = false; return; } DebugTotalFiles++; mudstate.restarting = true; char buf[8]; fgets(buf, 3, f); mux_assert(strncmp(buf, "+V", 2) == 0); int version = getref(f); if ( 1 == version || 2 == version) { // Version 1 started on 2001-DEC-03 // Version 2 started on 2005-NOV-08 // nMainGamePorts = getref(f); for (int i = 0; i < nMainGamePorts; i++) { aMainGamePorts[i].port = getref(f); mux_assert(aMainGamePorts[i].port > 0); aMainGamePorts[i].socket = getref(f); if (maxd <= aMainGamePorts[i].socket) { maxd = aMainGamePorts[i].socket + 1; } } } else { // The restart file, restart.db, has a version other than 1. You // cannot @restart from the previous version to the new version. Use // @shutdown instead. // mux_assert(0); } DebugTotalSockets += nMainGamePorts; mudstate.start_time.SetSeconds(getref(f)); size_t nBuffer; char *pBuffer = getstring_noalloc(f, true, &nBuffer); memcpy(mudstate.doing_hdr, pBuffer, nBuffer+1); mudstate.record_players = getref(f); if (mudconf.reset_players) { mudstate.record_players = 0; } int val; DESC *d; while ((val = getref(f)) != 0) { ndescriptors++; DebugTotalSockets++; d = alloc_desc("restart"); d->descriptor = val; d->flags = getref(f); d->connected_at.SetSeconds(getref(f)); d->command_count = getref(f); d->timeout = getref(f); d->host_info = getref(f); d->player = getref(f); d->last_time.SetSeconds(getref(f)); if (2 == version) { d->raw_input_state = getref(f); d->nvt_sga_him_state = getref(f); d->nvt_sga_us_state = getref(f); d->nvt_eor_him_state = getref(f); d->nvt_eor_us_state = getref(f); d->nvt_naws_him_state = getref(f); d->nvt_naws_us_state = getref(f); d->height = getref(f); d->width = getref(f); } else { d->raw_input_state = NVT_IS_NORMAL; d->nvt_sga_him_state = OPTION_NO; d->nvt_sga_us_state = OPTION_NO; d->nvt_eor_him_state = OPTION_NO; d->nvt_eor_us_state = OPTION_NO; d->nvt_naws_him_state = OPTION_NO; d->nvt_naws_us_state = OPTION_NO; d->height = 24; d->width = 78; } size_t nBuffer; char *temp = getstring_noalloc(f, true, &nBuffer); if ('\0' != temp[0]) { d->output_prefix = alloc_lbuf("set_userstring"); memcpy(d->output_prefix, temp, nBuffer+1); } else { d->output_prefix = NULL; } temp = getstring_noalloc(f, true, &nBuffer); if ('\0' != temp[0]) { d->output_suffix = alloc_lbuf("set_userstring"); memcpy(d->output_suffix, temp, nBuffer+1); } else { d->output_suffix = NULL; } temp = getstring_noalloc(f, true, &nBuffer); memcpy(d->addr, temp, nBuffer+1); temp = getstring_noalloc(f, true, &nBuffer); memcpy(d->doing, temp, nBuffer+1); temp = getstring_noalloc(f, true, &nBuffer); memcpy(d->username, temp, nBuffer+1); d->output_size = 0; d->output_tot = 0; d->output_lost = 0; d->output_head = NULL; d->output_tail = NULL; d->input_head = NULL; d->input_tail = NULL; d->input_size = 0; d->input_tot = 0; d->input_lost = 0; d->raw_input = NULL; d->raw_input_at = NULL; d->nOption = 0; d->quota = mudconf.cmd_quota_max; d->program_data = NULL; d->hashnext = NULL; if (descriptor_list) { DESC *p; for (p = descriptor_list; p->next; p = p->next) { ; // Nothing. } d->prev = &p->next; p->next = d; d->next = NULL; } else { d->next = descriptor_list; d->prev = &descriptor_list; descriptor_list = d; } if (maxd <= d->descriptor) { maxd = d->descriptor + 1; } desc_addhash(d); if (isPlayer(d->player)) { s_Connected(d->player); } } DESC_ITER_CONN(d) { if (!isPlayer(d->player)) { shutdownsock(d, R_QUIT); } } if (fclose(f) == 0) { DebugTotalFiles--; } remove("restart.db"); raw_broadcast(0, "GAME: Restart finished."); } #endif // !WIN32 #ifdef WIN32 int ReplaceFile(char *old_name, char *new_name) { DeleteFile(new_name); if (MoveFile(old_name, new_name)) { return 0; } else { Log.tinyprintf("MoveFile %s to %s fails with GetLastError() of %d" ENDLINE, old_name, new_name, GetLastError()); } return -1; } void RemoveFile(char *name) { DeleteFile(name); } #else // WIN32 int ReplaceFile(char *old_name, char *new_name) { if (rename(old_name, new_name) == 0) { return 0; } else { Log.tinyprintf("rename %s to %s fails with errno of %s(%d)" ENDLINE, old_name, new_name, strerror(errno), errno); } return -1; } void RemoveFile(char *name) { unlink(name); } #endif // WIN32 mux2.6/src/funmath.h0000600000175000017500000000351711025753746014417 0ustar sdennissdennis// funmath.h -- declarations for math-related functions. // // $Id: funmath.h 8 2006-09-05 01:55:58Z brazilofmux $ // #include "copyright.h" #ifndef __FUNMATH_H #define __FUNMATH_H XFUNCTION(fun_add); XFUNCTION(fun_ladd); XFUNCTION(fun_iadd); XFUNCTION(fun_sub); XFUNCTION(fun_isub); XFUNCTION(fun_mul); XFUNCTION(fun_imul); XFUNCTION(fun_gt); XFUNCTION(fun_gte); XFUNCTION(fun_lt); XFUNCTION(fun_lte); XFUNCTION(fun_eq); XFUNCTION(fun_neq); XFUNCTION(fun_max); XFUNCTION(fun_min); XFUNCTION(fun_sign); XFUNCTION(fun_isign); XFUNCTION(fun_shl); XFUNCTION(fun_shr); XFUNCTION(fun_inc); XFUNCTION(fun_dec); XFUNCTION(fun_trunc); XFUNCTION(fun_fdiv); XFUNCTION(fun_idiv); XFUNCTION(fun_floordiv); XFUNCTION(fun_mod); XFUNCTION(fun_remainder); XFUNCTION(fun_abs); XFUNCTION(fun_iabs); XFUNCTION(fun_dist2d); XFUNCTION(fun_dist3d); XFUNCTION(fun_vadd); XFUNCTION(fun_vsub); XFUNCTION(fun_vmul); XFUNCTION(fun_vdot); XFUNCTION(fun_vcross); XFUNCTION(fun_vmag); XFUNCTION(fun_vunit); XFUNCTION(fun_floor); XFUNCTION(fun_ceil); XFUNCTION(fun_round); XFUNCTION(fun_pi); XFUNCTION(fun_e); XFUNCTION(fun_ctu); XFUNCTION(fun_sin); XFUNCTION(fun_cos); XFUNCTION(fun_tan); XFUNCTION(fun_asin); XFUNCTION(fun_acos); XFUNCTION(fun_atan); XFUNCTION(fun_exp); XFUNCTION(fun_power); XFUNCTION(fun_fmod); XFUNCTION(fun_ln); XFUNCTION(fun_log); XFUNCTION(fun_sqrt); XFUNCTION(fun_isnum); XFUNCTION(fun_israt); XFUNCTION(fun_isint); XFUNCTION(fun_and); XFUNCTION(fun_or); XFUNCTION(fun_andbool); XFUNCTION(fun_orbool); XFUNCTION(fun_cand); XFUNCTION(fun_cor); XFUNCTION(fun_candbool); XFUNCTION(fun_corbool); XFUNCTION(fun_xor); XFUNCTION(fun_not); XFUNCTION(fun_t); XFUNCTION(fun_spellnum); XFUNCTION(fun_roman); XFUNCTION(fun_land); XFUNCTION(fun_lor); XFUNCTION(fun_band); XFUNCTION(fun_bor); XFUNCTION(fun_bnand); XFUNCTION(fun_bxor); XFUNCTION(fun_crc32); XFUNCTION(fun_sha1); #endif mux2.6/src/externs.h0000600000175000017500000012552511025753746014451 0ustar sdennissdennis// externs.h -- Prototypes for externs not defined elsewhere. // // $Id: externs.h 3049 2007-12-30 06:35:41Z brazilofmux $ // #ifndef EXTERNS_H #define EXTERNS_H #include "db.h" #include "match.h" #include "mudconf.h" #include "svdrand.h" // From bsd.cpp. // void boot_slave(dbref executor, dbref caller, dbref enactor, int key); void close_sockets(bool emergency, const char *message); void CleanUpSlaveSocket(void); void CleanUpSlaveProcess(void); #ifdef QUERY_SLAVE void CleanUpSQLSlaveSocket(void); void CleanUpSQLSlaveProcess(void); #endif // QUERY_SLAVE #ifdef WIN32 extern HANDLE CompletionPort; // IOs are queued up on this port extern CRITICAL_SECTION csDescriptorList; #endif // WIN32 #ifdef QUERY_SLAVE void boot_sqlslave(dbref executor, dbref caller, dbref enactor, int key); #endif // QUERY_SLAVE extern NAMETAB sigactions_nametab[]; // From conf.cpp // void cf_log_notfound(dbref, const char *, const char *, const char *); int cf_modify_bits(int *, char *, void *, UINT32, dbref, char *); void DCL_CDECL cf_log_syntax(dbref player, char *cmd, const char *fmt, ...); void ValidateConfigurationDbrefs(void); int cf_read(void); void cf_init(void); void cf_list(dbref, char *, char **); void cf_display(dbref, char *, char *, char **); void list_cf_access(dbref); int cf_set(char *, char *, dbref); CF_HAND(cf_cf_access); CF_HAND(cf_access); CF_HAND(cf_cmd_alias); CF_HAND(cf_acmd_access); CF_HAND(cf_attr_access); CF_HAND(cf_func_access); CF_HAND(cf_flag_access); CF_HAND(cf_flag_name); CF_HAND(cf_art_rule); // From local.cpp. // void local_startup(void); void local_presync_database(void); void local_presync_database_sigsegv(void); void local_dump_database(int); void local_dump_complete_signal(void); void local_shutdown(void); void local_dbck(void); void local_connect(dbref, int, int); void local_disconnect(dbref, int); void local_data_create(dbref); void local_data_clone(dbref, dbref); void local_data_free(dbref); const char **local_get_info_table(void); // From mail.cpp. // void load_mail(FILE *); int dump_mail(FILE *); struct mail *mail_fetch(dbref, int); char *MakeCanonicalMailAlias ( char *pMailAlias, size_t *pnValidMailAlias, bool *pbValidMailAlias ); char *MakeCanonicalMailAliasDesc ( char *pMailAliasDesc, size_t *pnValidMailAliasDesc, bool *pbValidMailAliasDesc, size_t *pnVisualWidth ); #if defined(FIRANMUX) const char *MessageFetch(int number); size_t MessageFetchSize(int number); #endif // FIRANMUX // From netcommon.cpp. // void DCL_CDECL raw_broadcast(int, const char *, ...); void list_siteinfo(dbref); void logged_out0(dbref executor, dbref caller, dbref enactor, int key); void logged_out1(dbref executor, dbref caller, dbref enactor, int eval, int key, char *arg); void init_logout_cmdtab(void); void desc_reload(dbref); void make_portlist(dbref, dbref, char *, char **); char *MakeCanonicalDoing(char *pDoing, size_t *pnValidDoing, bool *pbValidDoing); /* From cque.cpp */ int nfy_que(dbref, int, int, int); int halt_que(dbref, dbref); void wait_que(dbref executor, dbref caller, dbref enactor, int, bool, CLinearTimeAbsolute&, dbref, int, char *, int, char *[], reg_ref *[]); #ifndef WIN32 extern "C" char *crypt(const char *inptr, const char *inkey); #endif // WIN32 extern bool break_called; /* From eval.cpp */ void tcache_init(void); char *parse_to(char **, char, int); char *parse_arglist(dbref executor, dbref caller, dbref enactor, char *, char, int, char *[], int, char*[], int, int *); int get_gender(dbref); void mux_exec(char *buff, char **bufc, dbref executor, dbref caller, dbref enactor, int eval, char **dstr, char *cargs[], int ncargs); DCL_INLINE void BufAddRef(lbuf_ref *lbufref) { if (NULL != lbufref) { lbufref->refcount++; } } DCL_INLINE void BufRelease(lbuf_ref *lbufref) { if (NULL != lbufref) { lbufref->refcount--; if (0 == lbufref->refcount) { free_lbuf(lbufref->lbuf_ptr); lbufref->lbuf_ptr = NULL; free_lbufref(lbufref); } } } DCL_INLINE void RegAddRef(reg_ref *regref) { if (NULL != regref) { regref->refcount++; } } DCL_INLINE void RegRelease(reg_ref *regref) { if (NULL != regref) { regref->refcount--; if (0 == regref->refcount) { BufRelease(regref->lbuf); regref->lbuf = NULL; regref->reg_ptr = NULL; regref->reg_len = 0; free_regref(regref); } } } void RegAssign(reg_ref **regref, size_t nLength, const char *ptr); void save_global_regs(reg_ref *preserve[]); void save_and_clear_global_regs(reg_ref *preserve[]); void restore_global_regs(reg_ref *preserve[]); char **PushPointers(int nNeeded); void PopPointers(char **p, int nNeeded); reg_ref **PushRegisters(int nNeeded); void PopRegisters(reg_ref **p, int nNeeded); extern const signed char mux_RegisterSet[256]; extern const char *ColorTable[256]; #if defined(FIRANMUX) char *linewrap_desc(char *); char *linewrap_general(char *, int, const char *, const char *); #endif // FIRANMUX /* From game.cpp */ #define notify(p,m) notify_check(p,p,m, MSG_PUP_ALWAYS|MSG_ME_ALL|MSG_F_DOWN) #define notify_saypose(p,m) notify_check(p,p,m, MSG_PUP_ALWAYS|MSG_ME_ALL|MSG_F_DOWN|MSG_SAYPOSE) #define notify_html(p,m) notify_check(p,p,m, MSG_PUP_ALWAYS|MSG_ME_ALL|MSG_F_DOWN|MSG_HTML) #define notify_quiet(p,m) notify_check(p,p,m, MSG_PUP_ALWAYS|MSG_ME) #define notify_with_cause(p,c,m) notify_check(p,c,m, MSG_PUP_ALWAYS|MSG_ME_ALL|MSG_F_DOWN) #define notify_with_cause_ooc(p,c,m) notify_check(p,c,m, MSG_PUP_ALWAYS|MSG_ME_ALL|MSG_F_DOWN|MSG_OOC) #define notify_with_cause_html(p,c,m) notify_check(p,c,m, MSG_PUP_ALWAYS|MSG_ME_ALL|MSG_F_DOWN|MSG_HTML) #define notify_quiet_with_cause(p,c,m) notify_check(p,c,m, MSG_PUP_ALWAYS|MSG_ME) //#define notify_puppet(p,c,m) notify_check(p,c,m, MSG_ME_ALL|MSG_F_DOWN) //#define notify_quiet_puppet(p,c,m) notify_check(p,c,m, MSG_ME) #define notify_all(p,c,m) notify_check(p,c,m, MSG_ME_ALL|MSG_NBR_EXITS|MSG_F_UP|MSG_F_CONTENTS) #define notify_all_from_inside(p,c,m) notify_check(p,c,m, MSG_ME_ALL|MSG_NBR_EXITS_A|MSG_F_UP|MSG_F_CONTENTS|MSG_S_INSIDE) #define notify_all_from_inside_saypose(p,c,m) notify_check(p,c,m, MSG_ME_ALL|MSG_NBR_EXITS_A|MSG_F_UP|MSG_F_CONTENTS|MSG_S_INSIDE|MSG_SAYPOSE) #define notify_all_from_inside_html(p,c,m) notify_check(p,c,m, MSG_ME_ALL|MSG_NBR_EXITS_A|MSG_F_UP|MSG_F_CONTENTS|MSG_S_INSIDE|MSG_HTML) //#define notify_all_from_outside(p,c,m) notify_check(p,c,m, MSG_ME_ALL|MSG_NBR_EXITS|MSG_F_UP|MSG_F_CONTENTS|MSG_S_OUTSIDE) void notify_except(dbref, dbref, dbref, const char *, int key); void notify_except2(dbref, dbref, dbref, dbref, const char *); void notify_check(dbref, dbref, const char *, int); bool Hearer(dbref); void report(void); bool atr_match ( dbref thing, dbref player, char type, char *str, char *raw_str, bool check_parents ); bool regexp_match ( char *pattern, char *str, int case_opt, char *args[], int nargs ); bool list_check ( dbref thing, dbref player, char type, char *str, char *raw_str, bool check_parent ); bool html_escape(const char *src, char *dest, char **destp); #define DUMP_I_NORMAL 0 // OUTPUT to the outdb through a temporary file. #define DUMP_I_PANIC 1 // UNLOAD to a crashdb #define DUMP_I_RESTART 2 // OUTPUT to the inputdb #define DUMP_I_FLAT 3 // UNLOAD to a .FLAT file #define DUMP_I_SIGNAL 4 // UNLOAD to a .FLAT file from signal. #define NUM_DUMP_TYPES 5 void dump_database_internal(int); void fork_and_dump(int key); #define MUX_OPEN_INVALID_HANDLE_VALUE (-1) bool mux_fopen(FILE **pFile, const char *filename, const char *mode); bool mux_open(int *pfh, const char *filename, int oflag); const char *mux_strerror(int errnum); /* From help.cpp */ void helpindex_clean(int); void helpindex_load(dbref); void helpindex_init(void); void help_helper(dbref executor, int iHelpfile, char *topic_arg, char *buff, char **bufc); /* From htab.cpp */ int cf_ntab_access(int *, char *, void *, UINT32, dbref, char *); /* From log.cpp */ #ifdef WIN32 #define ENDLINE "\r\n" #else // WIN32 #define ENDLINE "\n" #endif // WIN32 bool start_log(const char *primary, const char *secondary); void end_log(void); void log_perror(const char *, const char *,const char *, const char *); void log_text(const char *); void log_number(int); void DCL_CDECL log_printf(const char *fmt, ...); void log_name(dbref); void log_name_and_loc(dbref); void log_type_and_name(dbref); /* From look.cpp */ void look_in(dbref,dbref, int); void show_vrml_url(dbref, dbref); #define NUM_ATTRIBUTE_CODES 12 size_t decode_attr_flags(int aflags, char buff[NUM_ATTRIBUTE_CODES+1]); void decode_attr_flag_names(int aflags, char *buf, char **bufc); /* From move.cpp */ void move_object(dbref, dbref); void move_via_generic(dbref, dbref, dbref, int); bool move_via_teleport(dbref, dbref, dbref, int); void move_exit(dbref, dbref, bool, const char *, int); void do_enter_internal(dbref, dbref, bool); /* From object.cpp */ dbref start_home(void); dbref default_home(void); bool can_set_home(dbref, dbref, dbref); dbref new_home(dbref); dbref clone_home(dbref, dbref); void divest_object(dbref); dbref create_obj(dbref, int, const char *, int); void destroy_obj(dbref); void empty_obj(dbref); /* From player.cpp */ dbref create_player(const char *name, const char *pass, dbref executor, bool isrobot, const char **pmsg); void AddToPublicChannel(dbref player); bool add_player_name(dbref, const char *); bool delete_player_name(dbref, const char *); dbref lookup_player(dbref, char *, bool); void load_player_names(void); void badname_add(char *); void badname_remove(char *); bool badname_check(char *); void badname_list(dbref, const char *); void ChangePassword(dbref player, const char *szPassword); const char *mux_crypt(const char *szPassword, const char *szSalt, int *piType); int QueueMax(dbref); int a_Queue(dbref, int); void pcache_reload(dbref); void pcache_init(void); /* From predicates.cpp */ char * DCL_CDECL tprintf(const char *, ...); void DCL_CDECL safe_tprintf_str(char *, char **, const char *, ...); dbref insert_first(dbref, dbref); dbref remove_first(dbref, dbref); dbref reverse_list(dbref); bool member(dbref, dbref); bool could_doit(dbref, dbref, int); bool can_see(dbref, dbref, bool); void add_quota(dbref, int); bool canpayfees(dbref, dbref, int, int); void giveto(dbref,int); bool payfor(dbref,int); char *MakeCanonicalObjectName(const char *pName, size_t *pnName, bool *pbValid); char *MakeCanonicalExitName(const char *pName, size_t *pnName, bool *pbValid); bool ValidatePlayerName(const char *pName); bool ok_password(const char *szPassword, const char **pmsg); void handle_ears(dbref, bool, bool); dbref match_possessed(dbref, dbref, char *, dbref, bool); void parse_range(char **, dbref *, dbref *); bool parse_thing_slash(dbref, char *, char **, dbref *); bool get_obj_and_lock(dbref, char *, dbref *, ATTR **, char *, char **); dbref where_is(dbref); dbref where_room(dbref); bool locatable(dbref, dbref, dbref); bool nearby(dbref, dbref); bool exit_visible(dbref, dbref, int); bool exit_displayable(dbref, dbref, int); void did_it(dbref player, dbref thing, int what, const char *def, int owhat, const char *odef, int awhat, int ctrl_flags, char *args[], int nargs); bool bCanReadAttr(dbref executor, dbref target, ATTR *tattr, bool bParentCheck); bool bCanSetAttr(dbref executor, dbref target, ATTR *tattr); bool bCanLockAttr(dbref executor, dbref target, ATTR *tattr); /* From set.cpp */ bool parse_attrib(dbref, char *, dbref *, ATTR **); bool parse_attrib_wild(dbref, char *, dbref *, bool, bool, bool); void edit_string(char *, char **, char *, char *); dbref match_controlled_handler(dbref player, const char *name, bool bQuiet); #define match_controlled(player,name) match_controlled_handler(player, name, false) #define match_controlled_quiet(player,name) match_controlled_handler(player, name, true) void set_modified(dbref thing); void TranslateFlags_Clone ( FLAG aClearFlags[3], dbref executor, int key ); void TranslateFlags_Chown ( FLAG aClearFlags[3], FLAG aSetFlags[3], bool *bClearPowers, dbref executor, int key ); void SetClearFlags(dbref thing, FLAG aClearFlags[3], FLAG aSetFlags[3]); /* From boolexp.cpp */ bool eval_boolexp(dbref, dbref, dbref, BOOLEXP *); BOOLEXP *parse_boolexp(dbref, const char *, bool); bool eval_boolexp_atr(dbref, dbref, dbref, char *); /* From functions.cpp */ bool xlate(char *); #define IEEE_MAKE_NAN 1 #define IEEE_MAKE_IND 2 #define IEEE_MAKE_PINF 3 #define IEEE_MAKE_NINF 4 double MakeSpecialFloat(int iWhich); /* From unparse.cpp */ char *unparse_boolexp(dbref, BOOLEXP *); char *unparse_boolexp_quiet(dbref, BOOLEXP *); char *unparse_boolexp_decompile(dbref, BOOLEXP *); char *unparse_boolexp_function(dbref, BOOLEXP *); /* From walkdb.cpp */ int chown_all(dbref from_player, dbref to_player, dbref acting_player, int key); void olist_push(void); void olist_pop(void); void olist_add(dbref); dbref olist_first(void); dbref olist_next(void); /* From wild.cpp */ bool wild(char *, char *, char *[], int); bool wild_match(char *, const char *); bool quick_wild(const char *, const char *); /* From command.cpp */ bool check_access(dbref player, int mask); void set_prefix_cmds(void); char *process_command(dbref executor, dbref caller, dbref enactor, int, bool, char *, char *[], int); size_t LeftJustifyString(char *field, size_t nWidth, const char *value); size_t RightJustifyNumber(char *field, size_t nWidth, INT64 value, char chFill); #define Protect(f) (cmdp->perms & f) #define Invalid_Objtype(x) \ ((Protect(CA_LOCATION) && !Has_location(x)) || \ (Protect(CA_CONTENTS) && !Has_contents(x)) || \ (Protect(CA_PLAYER) && !isPlayer(x))) /* from db.cpp */ bool Commer(dbref); void s_Pass(dbref, const char *); void s_Name(dbref, const char *); void s_Moniker(dbref thing, const char *s); const char *Name(dbref thing); const char *PureName(dbref thing); const char *Moniker(dbref thing); FWDLIST *fwdlist_load(dbref player, char *atext); void fwdlist_set(dbref, FWDLIST *); void fwdlist_clr(dbref); int fwdlist_rewrite(FWDLIST *, char *); FWDLIST *fwdlist_get(dbref); void atr_push(void); void atr_pop(void); int atr_head(dbref, char **); int atr_next(char **); int init_dbfile(char *game_dir_file, char *game_pag_file, int nCachePages); void atr_cpy(dbref dest, dbref source, bool bInternal); void atr_chown(dbref); void atr_clr(dbref, int); void atr_add_raw_LEN(dbref, int, const char *, size_t n); void atr_add_raw(dbref, int, const char *); void atr_add(dbref, int, char *, dbref, int); void atr_set_flags(dbref, int, int); const char *atr_get_raw_LEN(dbref, int, size_t *); const char *atr_get_raw(dbref, int); char *atr_get_LEN(dbref, int, dbref *, int *, size_t *); char *atr_get_real(dbref, int, dbref *, int *, const char *, const int); #define atr_get(t,a,o,f) atr_get_real(t,a,o,f, __FILE__, __LINE__) char *atr_pget_LEN(dbref, int, dbref *, int *, size_t *); char *atr_pget_real(dbref, int, dbref *, int *, const char *, const int); #define atr_pget(t,a,o,f) atr_pget_real(t,a,o,f, __FILE__, __LINE__) char *atr_get_str_LEN(char *s, dbref, int, dbref *, int *, size_t *); char *atr_get_str(char *, dbref, int, dbref *, int *); char *atr_pget_str_LEN(char *, dbref, int, dbref *, int *, size_t *); char *atr_pget_str(char *, dbref, int, dbref *, int *); bool atr_get_info(dbref, int, dbref *, int *); bool atr_pget_info(dbref, int, dbref *, int *); void atr_free(dbref); bool check_zone_handler(dbref player, dbref thing, bool bPlayerCheck); #define check_zone(player, thing) check_zone_handler(player, thing, false) void ReleaseAllResources(dbref obj); bool fwdlist_ck(dbref player, dbref thing, int anum, char *atext); extern int anum_alc_top; /* Command handler keys */ #define ATTRIB_ACCESS 1 /* Change access to attribute */ #define ATTRIB_RENAME 2 /* Rename attribute */ #define ATTRIB_DELETE 4 /* Delete attribute */ #define ATTRIB_INFO 8 /* Info (number, flags) about attribute */ #define BOOT_QUIET 1 /* Inhibit boot message to victim */ #define BOOT_PORT 2 /* Boot by port number */ #define CEMIT_NOHEADER 1 /* Channel emit without header */ #define CHOWN_ONE 1 /* item = new_owner */ #define CHOWN_ALL 2 /* old_owner = new_owner */ #define CHOWN_NOSTRIP 4 /* Don't strip (most) flags from object */ #define CHOWN_NOZONE 8 /* Strip zones from objects */ #define CLIST_FULL 1 /* Full listing of channels */ #define CLIST_HEADERS 2 /* Lists channel headers, like "[Public]" */ #define CLONE_LOCATION 0 /* Create cloned object in my location */ #define CLONE_INHERIT 1 /* Keep INHERIT bit if set */ #define CLONE_PRESERVE 2 /* Preserve the owner of the object */ #define CLONE_INVENTORY 4 /* Create cloned object in my inventory */ #define CLONE_SET_COST 8 /* ARG2 is cost of cloned object */ #define CLONE_SET_LOC 16 /* ARG2 is location of cloned object */ #define CLONE_SET_NAME 32 /* ARG2 is alternate name of cloned object */ #define CLONE_FROM_PARENT 64 /* Set parent on obj instd of cloning attrs */ #define CLONE_NOSTRIP 128 // Don't strip (most) flags from object. #define CBOOT_QUIET 1 // Cboot without a message #define COMTITLE_ON 1 // Turn Comtitles on. #define COMTITLE_OFF 2 // Turn Comtitles off. #define CRE_INVENTORY 0 /* Create object in my inventory */ #define CRE_LOCATION 1 /* Create object in my location */ #define CRE_SET_LOC 2 /* ARG2 is location of new object */ #define CSET_PUBLIC 0 /* Sets a channel public */ #define CSET_PRIVATE 1 /* Sets a channel private (default) */ #define CSET_LOUD 2 /* Channel shows connects and disconnects */ #define CSET_QUIET 3 /* Channel doesn't show connects/disconnects */ #define CSET_LIST 4 /* Lists channels */ #define CSET_OBJECT 5 /* Sets the channel object for the channel */ #define CSET_SPOOF 6 /* Sets the channel spoofable */ #define CSET_NOSPOOF 7 /* Sets the channel non-spoofable */ #define CSET_HEADER 8 /* Sets the channel header, like "[Public]" */ #define CSET_LOG 9 // Set maximum number of messages to log. #define DBCK_DEFAULT 1 /* Get default tests too */ #define DBCK_FULL 2 /* Do all tests */ #define DECOMP_DBREF 1 /* decompile by dbref */ //#define DECOMP_PRETTY 2 /* pretty-format output */ #define DEST_ONE 1 /* object */ #define DEST_OVERRIDE 4 /* override Safe() */ #define DEST_INSTANT 8 /* instantly destroy */ #define DIG_TELEPORT 1 /* teleport to room after @digging */ #define DOLIST_SPACE 0 /* expect spaces as delimiter */ #define DOLIST_DELIMIT 1 /* expect custom delimiter */ #define DOLIST_NOTIFY 2 /* Send an @notify after the @dolist is completed */ #define DOING_MESSAGE 0 /* Set my DOING message */ #define DOING_HEADER 1 /* Set the DOING header */ #define DOING_POLL 2 /* List DOING header */ #define DOING_UNIQUE 3 // Set DOING message for current port only #define DOING_MASK 15 // Lower four bits form non-SW_MULTIPLE part. #define DOING_QUIET 16 // Set DOING messages without 'Set.' message. #define DROP_QUIET 1 /* Don't do odrop/adrop if control */ #define DUMP_STRUCT 1 /* Dump flat structure file */ #define DUMP_TEXT 2 /* Dump to external attribute database. */ #define DUMP_FLATFILE 4 /* Dump .FLAT file */ #define EXAM_DEFAULT 0 /* Default */ #define EXAM_BRIEF 1 /* Nonowner sees just owner */ #define EXAM_LONG 2 /* Nonowner sees public attrs too */ #define EXAM_DEBUG 4 /* Display more info for finding db problems */ #define EXAM_PARENT 8 /* Get attr from parent when exam obj/attr */ //#define EXAM_PRETTY 16 /* Pretty-format output */ //#define EXAM_PAIRS 32 /* Print paren matches in color */ #define FIXDB_OWNER 1 /* Fix OWNER field */ #define FIXDB_LOC 2 /* Fix LOCATION field */ #define FIXDB_CON 4 /* Fix CONTENTS field */ #define FIXDB_EXITS 8 /* Fix EXITS field */ #define FIXDB_NEXT 16 /* Fix NEXT field */ #define FIXDB_PENNIES 32 /* Fix PENNIES field */ #define FIXDB_ZONE 64 /* Fix ZONE field */ #define FIXDB_LINK 128 /* Fix LINK field */ #define FIXDB_PARENT 256 /* Fix PARENT field */ #define FIXDB_NAME 2048 /* Set NAME attribute */ #define FLAG_REMOVE 1 // Remove a flag alias #define GET_QUIET 1 /* Don't do osucc/asucc if control */ #define GIVE_QUIET 64 /* Inhibit give messages */ #define GLOB_ENABLE 1 /* key to enable */ #define GLOB_DISABLE 2 /* key to disable */ //#define GLOB_LIST 3 /* key to list */ #define HALT_ALL 1 /* halt everything */ #define HOOK_BEFORE 1 /* BEFORE hook */ #define HOOK_AFTER 2 /* AFTER hook */ #define HOOK_PERMIT 4 /* PERMIT hook */ #define HOOK_IGNORE 8 /* IGNORE hook */ #define HOOK_IGSWITCH 16 /* BFAIL hook */ #define HOOK_AFAIL 32 /* AFAIL hook */ #define HOOK_CLEAR 64 /* CLEAR hook */ #define HOOK_LIST 128 /* LIST hooks */ #define ICMD_DISABLE 0 #define ICMD_IGNORE 1 #define ICMD_ON 2 #define ICMD_OFF 4 #define ICMD_CLEAR 8 #define ICMD_CHECK 16 #define ICMD_DROOM 32 #define ICMD_IROOM 64 #define ICMD_CROOM 128 #define ICMD_LROOM 256 #define ICMD_LALLROOM 512 #define KILL_KILL 1 /* gives victim insurance */ #define KILL_SLAY 2 /* no insurance */ #define LOOK_LOOK 1 /* list desc (and succ/fail if room) */ #define LOOK_OUTSIDE 8 /* look for object in container of player */ #define MAIL_STATS 1 /* Mail stats */ #define MAIL_DSTATS 2 /* More mail stats */ #define MAIL_FSTATS 3 /* Even more mail stats */ #define MAIL_DEBUG 4 /* Various debugging options */ #define MAIL_NUKE 5 /* Nuke the post office */ #define MAIL_FOLDER 6 /* Do folder stuff */ #define MAIL_LIST 7 /* List @mail by time */ #define MAIL_READ 8 /* Read @mail message */ #define MAIL_CLEAR 9 /* Clear @mail message */ #define MAIL_UNCLEAR 10 /* Unclear @mail message */ #define MAIL_PURGE 11 /* Purge cleared @mail messages */ #define MAIL_FILE 12 /* File @mail in folders */ #define MAIL_TAG 13 /* Tag @mail messages */ #define MAIL_UNTAG 14 /* Untag @mail messages */ #define MAIL_FORWARD 15 /* Forward @mail messages */ #define MAIL_SEND 16 /* Send @mail messages in progress */ #define MAIL_EDIT 17 /* Edit @mail messages in progress */ #define MAIL_URGENT 18 /* Sends a @mail message as URGENT */ #define MAIL_ALIAS 19 /* Creates an @mail alias */ #define MAIL_ALIST 20 /* Lists @mail aliases */ #define MAIL_PROOF 21 /* Proofs @mail messages in progress */ #define MAIL_ABORT 22 /* Aborts @mail messages in progress */ #define MAIL_QUICK 23 /* Sends a quick @mail message */ #define MAIL_REVIEW 24 /* Reviews @mail sent to a player */ #define MAIL_RETRACT 25 /* Retracts @mail sent to a player */ #define MAIL_CC 26 /* Carbon copy */ #define MAIL_SAFE 27 /* Defines a piece of mail as safe. */ #define MAIL_REPLY 28 /* Replies to a message. */ #define MAIL_REPLYALL 29 /* Replies to all recipients of msg */ #define MAIL_BCC 30 // Blind Carbon Copy. Don't show the recipient list to these. #define MAIL_QUOTE 0x100 /* Quote back original in the reply? */ #define MALIAS_DESC 1 /* Describes a mail alias */ #define MALIAS_CHOWN 2 /* Changes a mail alias's owner */ #define MALIAS_ADD 3 /* Adds a player to an alias */ #define MALIAS_REMOVE 4 /* Removes a player from an alias */ #define MALIAS_DELETE 5 /* Deletes a mail alias */ #define MALIAS_RENAME 6 /* Renames a mail alias */ #define MALIAS_LIST 8 /* Lists mail aliases */ #define MALIAS_STATUS 9 /* Status of mail aliases */ #define MARK_SET 0 /* Set mark bits */ #define MARK_CLEAR 1 /* Clear mark bits */ #define MOTD_ALL 0 /* login message for all */ #define MOTD_WIZ 1 /* login message for wizards */ #define MOTD_DOWN 2 /* login message when logins disabled */ #define MOTD_FULL 4 /* login message when too many players on */ #define MOTD_LIST 8 /* Display current login messages */ #define MOTD_BRIEF 16 /* Suppress motd file display for wizards */ #define MOVE_QUIET 1 /* Dont do osucc/ofail/asucc/afail if ctrl */ #define NFY_NFY 0 /* Notify first waiting command */ #define NFY_NFYALL 1 /* Notify all waiting commands */ #define NFY_DRAIN 2 /* Delete waiting commands */ #define NFY_QUIET 3 /* Suppress "Notified." message */ #define OPEN_LOCATION 0 /* Open exit in my location */ #define OPEN_INVENTORY 1 /* Open exit in me */ #define PCRE_PLAYER 1 /* create new player */ #define PCRE_ROBOT 2 /* create robot player */ #define PEMIT_PEMIT 1 /* emit to named player */ #define PEMIT_OEMIT 2 /* emit to all in current room except named */ #define PEMIT_WHISPER 3 /* whisper to player in current room */ #define PEMIT_FSAY 4 /* force controlled obj to say */ #define PEMIT_FEMIT 5 /* force controlled obj to emit */ #define PEMIT_FPOSE 6 /* force controlled obj to pose */ #define PEMIT_FPOSE_NS 7 /* force controlled obj to pose w/o space */ #define PEMIT_CONTENTS 8 /* Send to contents (additive) */ #define PEMIT_HERE 16 /* Send to location (@femit, additive) */ #define PEMIT_ROOM 32 /* Send to containing rm (@femit, additive) */ #define PEMIT_LIST 64 /* Send to a list */ #define PEMIT_HTML 128 /* HTML escape, and no newline */ #define PS_BRIEF 0 /* Short PS report */ #define PS_LONG 1 /* Long PS report */ #define PS_SUMM 2 /* Queue counts only */ #define PS_ALL 4 /* List entire queue */ #define QUERY_SQL 1 /* SQL query */ #define QUEUE_KICK 1 /* Process commands from queue */ #define QUEUE_WARP 2 /* Advance or set back wait queue clock */ #define QUOTA_SET 1 /* Set a quota */ #define QUOTA_FIX 2 /* Repair a quota */ #define QUOTA_TOT 4 /* Operate on total quota */ #define QUOTA_REM 8 /* Operate on remaining quota */ #define QUOTA_ALL 16 /* Operate on all players */ //#define QUOTA_ROOM 32 /* Room quota set */ //#define QUOTA_EXIT 64 /* Exit quota set */ //#define QUOTA_THING 128 /* Thing quota set */ //#define QUOTA_PLAYER 256 /* Player quota set */ #define SAY_SAY 1 /* say in current room */ #define SAY_NOSPACE 1 /* OR with xx_EMIT to get nospace form */ #define SAY_POSE 2 /* pose in current room */ #define SAY_POSE_NOSPC 3 /* pose w/o space in current room */ #define SAY_PREFIX 4 /* first char indicates formatting */ #define SAY_EMIT 5 /* emit in current room */ #define SAY_NOEVAL 8 // Don't eval message #define SHOUT_SHOUT 1 /* shout to all logged-in players */ #define SHOUT_WALLPOSE 2 /* Pose to all logged-in players */ #define SHOUT_WALLEMIT 3 /* Emit to all logged-in players */ #define SHOUT_WIZSHOUT 4 /* shout to all logged-in wizards */ #define SHOUT_WIZPOSE 5 /* Pose to all logged-in wizards */ #define SHOUT_WIZEMIT 6 /* Emit to all logged-in wizards */ #define SHOUT_ADMINSHOUT 7 /* Emit to all wizards or royalty */ //#define SAY_GRIPE 16 /* Complain to management */ //#define SAY_NOTE 17 /* Comment to log for wizards */ #define SAY_NOTAG 32 /* Don't put Broadcast: in front (additive) */ #define SAY_HERE 64 /* Output to current location */ #define SAY_ROOM 128 /* Output to containing room */ #define SAY_HTML 256 /* Don't output a newline */ #define SET_QUIET 1 /* Don't display 'Set.' message. */ #define SHOUT_DEFAULT 0 /* Default @wall message */ #define SHOUT_WIZARD 1 /* @wizwall */ #define SHOUT_ADMIN 2 /* @wall/admin */ #define SHUTDN_NORMAL 0 /* Normal shutdown */ #define SHUTDN_PANIC 1 /* Write a panic dump file */ #define SHUTDN_EXIT 2 /* Exit from shutdown code */ #define SHUTDN_COREDUMP 4 /* Produce a coredump */ #define SRCH_SEARCH 1 /* Do a normal search */ #define SRCH_MARK 2 /* Set mark bit for matches */ #define SRCH_UNMARK 3 /* Clear mark bit for matches */ #define STAT_PLAYER 0 /* Display stats for one player or tot objs */ #define STAT_ALL 1 /* Display global stats */ #define STAT_ME 2 /* Display stats for me */ #define SWITCH_DEFAULT 0 /* Use the configured default for switch */ #define SWITCH_ANY 1 /* Execute all cases that match */ #define SWITCH_ONE 2 /* Execute only first case that matches */ #define SWITCH_MASK 3 /* Includes lower 2 bits */ #define SWITCH_NOTIFY 4 /* Send a @notify after the @switch is completed */ #define SWEEP_ME 1 /* Check my inventory */ #define SWEEP_HERE 2 /* Check my location */ #define SWEEP_COMMANDS 4 /* Check for $-commands */ #define SWEEP_LISTEN 8 /* Check for @listen-ers */ #define SWEEP_PLAYER 16 /* Check for players and puppets */ #define SWEEP_CONNECT 32 /* Search for connected players/puppets */ #define SWEEP_EXITS 64 /* Search the exits for audible flags */ #define SWEEP_SCAN 128 /* Scan for pattern matching */ #define SWEEP_VERBOSE 256 /* Display what pattern matches */ #define TELEPORT_DEFAULT 1 /* Emit all messages */ #define TELEPORT_QUIET 2 /* Teleport in quietly */ #define TELEPORT_LIST 4 /* Teleport a list of items */ #define TIMECHK_RESET 1 /* Reset all counters to zero */ #define TIMECHK_SCREEN 2 /* Write info to screen */ #define TIMECHK_LOG 4 /* Write info to log */ #define TOAD_NO_CHOWN 1 /* Don't change ownership */ #define TRIG_QUIET 1 /* Don't display 'Triggered.' message. */ #define TRIG_NOTIFY 2 /* Send a @notify after the @trigger is completed. */ #define TWARP_QUEUE 1 /* Warp the wait and sem queues */ #define TWARP_DUMP 2 /* Warp the dump interval */ #define TWARP_CLEAN 4 /* Warp the cleaning interval */ #define TWARP_IDLE 8 /* Warp the idle check interval */ /* empty 16 */ #define TWARP_EVENTS 32 /* Warp the events checking interval */ #define VERB_NONAME 1 // Do not preprend name to odefault. #define WAIT_UNTIL 1 // Absolute UTC seconds instead of delta. /* Hush codes for movement messages */ #define HUSH_ENTER 1 /* xENTER/xEFAIL */ #define HUSH_LEAVE 2 /* xLEAVE/xLFAIL */ #define HUSH_EXIT 4 /* xSUCC/xDROP/xFAIL from exits */ /* Evaluation directives */ #define EV_FIGNORE 0x00000000 /* Don't look for func if () found */ #define EV_FMAND 0x00000100 /* Text before () must be func name */ #define EV_FCHECK 0x00000200 /* Check text before () for function */ #define EV_STRIP_CURLY 0x00000400 /* Strip one level of brackets */ #define EV_EVAL 0x00000800 /* Evaluate results before returning */ #define EV_STRIP_TS 0x00001000 /* Strip trailing spaces */ #define EV_STRIP_LS 0x00002000 /* Strip leading spaces */ #define EV_STRIP_ESC 0x00004000 /* Strip one level of \ characters */ #define EV_STRIP_AROUND 0x00008000 /* Strip {} only at ends of string */ #define EV_TOP 0x00010000 /* This is a toplevel call to eval() */ #define EV_NOTRACE 0x00020000 /* Don't trace this call to eval */ #define EV_NO_COMPRESS 0x00040000 /* Don't compress spaces. */ #define EV_NO_LOCATION 0x00080000 /* Supresses %l */ #define EV_NOFCHECK 0x00100000 /* Do not evaluate functions! */ #define EV_TRACE 0x00200000 /* Request a trace of this call to eval */ /* Message forwarding directives */ #define MSG_PUP_ALWAYS 0x00000001UL /* Always forward msg to puppet owner */ #define MSG_INV 0x00000002UL /* Forward msg to contents */ #define MSG_INV_L 0x00000004UL /* ... only if msg passes my @listen */ #define MSG_INV_EXITS 0x00000008UL /* Forward through my audible exits */ #define MSG_NBR 0x00000010UL /* Forward msg to neighbors */ #define MSG_NBR_A 0x00000020UL /* ... only if I am audible */ #define MSG_NBR_EXITS 0x00000040UL /* Also forward to neighbor exits */ #define MSG_NBR_EXITS_A 0x00000080UL /* ... only if I am audible */ #define MSG_LOC 0x00000100UL /* Send to my location */ #define MSG_LOC_A 0x00000200UL /* ... only if I am audible */ #define MSG_FWDLIST 0x00000400UL /* Forward to my fwdlist members if aud */ #define MSG_ME 0x00000800UL /* Send to me */ #define MSG_S_INSIDE 0x00001000UL /* Originator is inside target */ #define MSG_S_OUTSIDE 0x00002000UL /* Originator is outside target */ #define MSG_HTML 0x00004000UL /* Don't send \r\n */ #define MSG_OOC 0x00008000UL /* Overide visibility rules because it's OOC */ #define MSG_SAYPOSE 0x00010000UL /* Indicates that the message is speech. */ #define MSG_ME_ALL (MSG_ME|MSG_INV_EXITS|MSG_FWDLIST) #define MSG_F_CONTENTS (MSG_INV) #define MSG_F_UP (MSG_NBR_A|MSG_LOC_A) #define MSG_F_DOWN (MSG_INV_L) /* Look primitive directives */ #define LK_IDESC 0x0001 #define LK_OBEYTERSE 0x0002 #define LK_SHOWATTR 0x0004 #define LK_SHOWEXIT 0x0008 #define LK_SHOWVRML 0x0010 /* Quota types */ //#define QTYPE_ALL 0 //#define QTYPE_ROOM 1 //#define QTYPE_EXIT 2 //#define QTYPE_THING 3 //#define QTYPE_PLAYER 4 /* Exit visibility precalculation codes */ #define VE_LOC_XAM 0x01 /* Location is examinable */ #define VE_LOC_DARK 0x02 /* Location is dark */ #define VE_LOC_LIGHT 0x04 /* Location is light */ //#define VE_BASE_XAM 0x08 /* Base location (pre-parent) is examinable */ #define VE_BASE_DARK 0x10 /* Base location (pre-parent) is dark */ //#define VE_BASE_LIGHT 0x20 /* Base location (pre-parent) is light */ /* Signal handling directives */ #define SA_EXIT 1 /* Exit, and dump core */ #define SA_DFLT 2 /* Try to restart on a fatal error */ #define STARTLOG(key,p,s) \ if ((((key) & mudconf.log_options) != 0) && start_log(p, s)) { #define ENDLOG \ end_log(); } #define LOG_SIMPLE(key,p,s,m) \ STARTLOG(key,p,s) \ log_text(m); \ ENDLOG extern const char *NOMATCH_MESSAGE; extern const char *AMBIGUOUS_MESSAGE; extern const char *NOPERM_MESSAGE; extern const char *FUNC_FAIL_MESSAGE; extern const char *FUNC_NOMATCH_MESSAGE; extern const char *OUT_OF_RANGE; extern const char *FUNC_NOT_FOUND; extern const char *FUNC_AMBIGUOUS; extern const char *FUNC_NOPERM_MESSAGE; #define safe_nothing(b,p) safe_copy_buf(FUNC_FAIL_MESSAGE,3,(b),(p)) #define safe_noperm(b,p) safe_copy_buf(FUNC_NOPERM_MESSAGE,21,(b),(p)) #define safe_nomatch(b,p) safe_copy_buf(FUNC_NOMATCH_MESSAGE,12,(b),(p)) #define safe_range(b,p) safe_copy_buf(OUT_OF_RANGE,16,(b),(p)) #define safe_ambiguous(b,p) safe_copy_buf(FUNC_AMBIGUOUS,13,(b),(p)) #define safe_notfound(b,p) safe_copy_buf(FUNC_NOT_FOUND,13,(b),(p)) int ReplaceFile(char *old_name, char *new_name); void RemoveFile(char *name); void destroy_player(dbref agent, dbref victim); void do_pemit_list ( dbref player, int key, bool bDoContents, int pemit_flags, char *list, int chPoseType, char *message ); void do_pemit_single ( dbref player, int key, bool bDoContents, int pemit_flags, char *recipient, int chPoseType, char *message ); void do_say(dbref executor, dbref caller, dbref enactor, int eval, int key, char *message); int boot_off(dbref player, const char *message); void do_mail_clear(dbref player, char *msglist); void do_mail_purge(dbref player); void malias_cleanup(dbref player); void count_mail(dbref player, int folder, int *rcount, int *ucount, int *ccount); void check_mail_expiration(void); void check_mail(dbref player, int folder, bool silent); const char *mail_fetch_message(dbref player, int num); int mail_fetch_from(dbref player, int num); void raw_notify_html(dbref player, const char *msg); void do_lock(dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *keytext); void check_events(void); void list_system_resources(dbref player); #if defined(WOD_REALMS) || defined(REALITY_LVLS) #define ACTION_IS_STATIONARY 0 #define ACTION_IS_MOVING 1 #define ACTION_IS_TALKING 2 #define NUMBER_OF_ACTIONS 3 // A count, n, of the number of possible actions 0...n-1 #define REALM_DO_NORMALLY_SEEN 1 #define REALM_DO_HIDDEN_FROM_YOU 2 #define REALM_DO_SHOW_OBFDESC 3 #define REALM_DO_SHOW_WRAITHDESC 4 #define REALM_DO_SHOW_UMBRADESC 5 #define REALM_DO_SHOW_MATRIXDESC 6 #define REALM_DO_SHOW_FAEDESC 7 #define REALM_DO_MASK 7 #define REALM_DISABLE_ADESC 0x00000008L int DoThingToThingVisibility(dbref looker, dbref lookee, int action_state); #endif // WOD_REALMS typedef struct { int port; SOCKET socket; } PortInfo; #define MAX_LISTEN_PORTS 10 extern PortInfo aMainGamePorts[MAX_LISTEN_PORTS]; extern int nMainGamePorts; #ifdef WIN32 extern bool bUseCompletionPorts;; #else // WIN32 extern int maxd; #endif // WIN32 extern unsigned int ndescriptors; extern long DebugTotalFiles; extern long DebugTotalSockets; #ifdef WIN32 extern int game_pid; extern long DebugTotalThreads; extern long DebugTotalSemaphores; extern HANDLE hGameProcess; typedef BOOL __stdcall FCANCELIO(HANDLE hFile); typedef BOOL __stdcall FGETPROCESSTIMES(HANDLE hProcess, LPFILETIME pftCreate, LPFILETIME pftExit, LPFILETIME pftKernel, LPFILETIME pftUser); extern FCANCELIO *fpCancelIo; extern FGETPROCESSTIMES *fpGetProcessTimes; #else // WIN32 extern pid_t game_pid; #endif // WIN32 // From timer.cpp // void init_timer(void); #ifdef WIN32 void Task_FreeDescriptor(void *arg_voidptr, int arg_Integer); void Task_DeferredClose(void *arg_voidptr, int arg_Integer); #endif void dispatch_DatabaseDump(void *pUnused, int iUnused); void dispatch_FreeListReconstruction(void *pUnused, int iUnused); void dispatch_IdleCheck(void *pUnused, int iUnused); void dispatch_CheckEvents(void *pUnused, int iUnused); #ifndef MEMORY_BASED void dispatch_CacheTick(void *pUnused, int iUnused); #endif // Using a heap as the data structure for representing this priority // has some attributes which we depend on: // // 1. Most importantly, actions scheduled for the same time (i.e., // immediately) keep the order that they were inserted into the // heap. // // If you ever re-implement this object using another data structure, // please remember to maintain this property. // typedef void FTASK(void *, int); typedef struct { CLinearTimeAbsolute ltaWhen; int iPriority; int m_Ticket; // This is the order in which the task was scheduled. FTASK *fpTask; void *arg_voidptr; int arg_Integer; int m_iVisitedMark; } TASK_RECORD, *PTASK_RECORD; #define PRIORITY_SYSTEM 100 #define PRIORITY_PLAYER 200 #define PRIORITY_OBJECT 300 #define PRIORITY_SUSPEND 400 // CF_DEQUEUE driven minimum priority levels. // #define PRIORITY_CF_DEQUEUE_ENABLED PRIORITY_OBJECT #define PRIORITY_CF_DEQUEUE_DISABLED (PRIORITY_PLAYER-1) typedef int SCHCMP(PTASK_RECORD, PTASK_RECORD); typedef int SCHLOOK(PTASK_RECORD); class CTaskHeap { private: int m_nAllocated; int m_nCurrent; PTASK_RECORD *m_pHeap; int m_iVisitedMark; bool Grow(void); void SiftDown(int, SCHCMP *); void SiftUp(int, SCHCMP *); PTASK_RECORD Remove(int, SCHCMP *); void Update(int iNode, SCHCMP *pfCompare); void Sort(SCHCMP *pfCompare); void Remake(SCHCMP *pfCompare); public: CTaskHeap(); ~CTaskHeap(); void Shrink(void); bool Insert(PTASK_RECORD, SCHCMP *); PTASK_RECORD PeekAtTopmost(void); PTASK_RECORD RemoveTopmost(SCHCMP *); void CancelTask(FTASK *fpTask, void *arg_voidptr, int arg_Integer); #define IU_DONE 0 #define IU_NEXT_TASK 1 #define IU_REMOVE_TASK 2 #define IU_UPDATE_TASK 3 int TraverseUnordered(SCHLOOK *pfLook, SCHCMP *pfCompare); int TraverseOrdered(SCHLOOK *pfLook, SCHCMP *pfCompare); }; class CScheduler { private: CTaskHeap m_WhenHeap; CTaskHeap m_PriorityHeap; int m_Ticket; int m_minPriority; public: void TraverseUnordered(SCHLOOK *pfLook); void TraverseOrdered(SCHLOOK *pfLook); CScheduler(void) { m_Ticket = 0; m_minPriority = PRIORITY_CF_DEQUEUE_ENABLED; } void DeferTask(const CLinearTimeAbsolute& ltWhen, int iPriority, FTASK *fpTask, void *arg_voidptr, int arg_Integer); void DeferImmediateTask(int iPriority, FTASK *fpTask, void *arg_voidptr, int arg_Integer); bool WhenNext(CLinearTimeAbsolute *); int RunTasks(int iCount); int RunAllTasks(void); int RunTasks(const CLinearTimeAbsolute& tNow); void ReadyTasks(const CLinearTimeAbsolute& tNow); void CancelTask(FTASK *fpTask, void *arg_voidptr, int arg_Integer); void Shrink(void); void SetMinPriority(int arg_minPriority); int GetMinPriority(void) { return m_minPriority; } }; extern CScheduler scheduler; int fetch_cmds(dbref target); void fetch_ConnectionInfoFields(dbref target, long anFields[4]); long fetch_ConnectionInfoField(dbref target, int iField); void put_ConnectionInfoFields ( dbref target, long anFields[4], CLinearTimeAbsolute <aLogout ); // Added by D.Piper (del@doofer.org) 2000-APR // // In order: // // Total online time // Longest connection duration // Duration of last connection // Total number of connections. // time (time_t) of last logout. // #define CIF_TOTALTIME 0 #define CIF_LONGESTCONNECT 1 #define CIF_LASTCONNECT 2 #define CIF_NUMCONNECTS 3 #define fetch_totaltime(t) (fetch_ConnectionInfoField((t), CIF_TOTALTIME)) #define fetch_longestconnect(t) (fetch_ConnectionInfoField((t), CIF_LONGESTCONNECT)) #define fetch_lastconnect(t) (fetch_ConnectionInfoField((t), CIF_LASTCONNECT)) #define fetch_numconnections(t) (fetch_ConnectionInfoField((t), CIF_NUMCONNECTS)) CLinearTimeAbsolute fetch_logouttime(dbref target); // From strtod.cpp // void FLOAT_Initialize(void); void mux_FPInit(); void mux_FPSet(); void mux_FPRestore(); double ulp(double); double mux_strtod(const char *s00, char **se); char *mux_dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve); // From wiz.cpp // extern NAMETAB enable_names[]; // From version.cpp // void build_version(void); void init_version(void); // From player_c.cpp // void pcache_sync(void); void pcache_trim(void); // From attrcache.cpp // void cache_redirect(void); void cache_pass2(void); void cache_cleanup(void); extern CLinearTimeAbsolute cs_ltime; // From speech.cpp // char *modSpeech(dbref player, char *message, bool bWhich, char *command); // From funceval.cpp // #ifdef DEPRECATED void stack_clr(dbref obj); #endif // DEPRECATED bool parse_and_get_attrib(dbref, char *[], char **, dbref *, dbref *, int *, char *, char **); void SimplifyColorLetters(char Out[8], char *pIn); #endif // EXTERNS_H mux2.6/src/svdreport.h0000600000175000017500000000016011025753746014774 0ustar sdennissdennis// Report.h -- Aggregate User Statistics module. // // $Id: svdreport.h 8 2006-09-05 01:55:58Z brazilofmux $ // mux2.6/src/set.cpp0000600000175000017500000014411711025753746014105 0ustar sdennissdennis// set.cpp -- Commands which set parameters. // // $Id: set.cpp 571 2006-12-27 17:56:12Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "ansi.h" #include "attrs.h" #include "command.h" #include "powers.h" void set_modified(dbref thing) { CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); atr_add_raw(thing, A_MODIFIED, ltaNow.ReturnDateString(7)); } dbref match_controlled_handler(dbref executor, const char *name, bool bQuiet) { dbref mat; init_match(executor, name, NOTYPE); match_everything(MAT_EXIT_PARENTS); if (bQuiet) { mat = match_result(); } else { mat = noisy_match_result(); } if (!Good_obj(mat)) { return mat; } if (Controls(executor, mat)) { return mat; } if (!bQuiet) { notify_quiet(executor, NOPERM_MESSAGE); } return NOTHING; } void do_chzone ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *newobj ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nargs); if (!mudconf.have_zones) { notify(executor, "Zones disabled."); return; } init_match(executor, name, NOTYPE); match_everything(0); dbref thing = noisy_match_result(); if (thing == NOTHING) { return; } dbref zone; if ( newobj[0] == '\0' || !mux_stricmp(newobj, "none")) { zone = NOTHING; } else { init_match(executor, newobj, NOTYPE); match_everything(0); zone = noisy_match_result(); if (zone == NOTHING) { return; } if ( !isThing(zone) && !isRoom(zone)) { notify(executor, "Invalid zone object type."); return; } } if ( !Wizard(executor) && !Controls(executor, thing) && !check_zone_handler(executor, thing, true) && db[executor].owner != db[thing].owner) { notify(executor, "You don't have the power to shift reality."); return; } // A player may change an object's zone to NOTHING or to an object he owns. // if ( zone != NOTHING && !Wizard(executor) && !Controls(executor, zone) && db[executor].owner != db[zone].owner) { notify(executor, "You cannot move that object to that zone."); return; } // Only rooms may be zoned to other rooms. // if ( zone != NOTHING && isRoom(zone) && !isRoom(thing)) { notify(executor, "Only rooms may be zoned to other rooms."); return; } // Everything is okay, do the change. // db[thing].zone = zone; if (!isPlayer(thing)) { // If the object is a player, resetting these flags is rather // inconvenient -- although this may pose a bit of a security risk. Be // careful when @chzone'ing wizard or royal players. // SetClearFlags(thing, mudconf.stripped_flags.word, NULL); // Wipe out all powers. // Powers(thing) = 0; Powers2(thing) = 0; } notify(executor, "Zone changed."); } void do_name ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *newname ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); dbref thing = match_controlled(executor, name); if (thing == NOTHING) { return; } // Check for bad name. // if ( nargs < 2 || newname[0] == '\0') { notify_quiet(executor, "Give it what new name?"); return; } // Check for renaming a player. // if (isPlayer(thing)) { char *buff = trim_spaces(newname); if ( !ValidatePlayerName(buff) || !badname_check(buff)) { notify_quiet(executor, "You can't use that name."); free_lbuf(buff); return; } else if ( string_compare(buff, Name(thing)) && lookup_player(NOTHING, buff, false) != NOTHING) { // string_compare allows changing foo to Foo, etc. // notify_quiet(executor, "That name is already in use."); free_lbuf(buff); return; } // Everything ok, notify. // STARTLOG(LOG_SECURITY, "SEC", "CNAME"); log_name(thing), log_text(" renamed to "); log_text(buff); ENDLOG; if (Suspect(thing)) { raw_broadcast(WIZARD, "[Suspect] %s renamed to %s", Name(thing), buff); } delete_player_name(thing, Name(thing)); s_Name(thing, buff); set_modified(thing); add_player_name(thing, Name(thing)); if (!Quiet(executor) && !Quiet(thing)) { notify_quiet(executor, "Name set."); } free_lbuf(buff); return; } else { size_t nValidName; bool bValid; char *pValidName; if (isExit(thing)) { pValidName = MakeCanonicalExitName(newname, &nValidName, &bValid); } else { pValidName = MakeCanonicalObjectName(newname, &nValidName, &bValid); } if (!bValid) { notify_quiet(executor, "That is not a reasonable name."); return; } // Everything ok, change the name. // s_Name(thing, pValidName); set_modified(thing); if (!Quiet(executor) && !Quiet(thing)) { notify_quiet(executor, "Name set."); } } } /* * --------------------------------------------------------------------------- * * do_alias: Make an alias for a player or object. */ void do_alias ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *alias ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nargs); dbref thing = match_controlled(executor, name); if (thing == NOTHING) { return; } // Check for renaming a player. // dbref aowner; int aflags; ATTR *ap = atr_num(A_ALIAS); if (isPlayer(thing)) { // Fetch the old alias. // char *oldalias = atr_pget(thing, A_ALIAS, &aowner, &aflags); char *trimalias = trim_spaces(alias); if (!Controls(executor, thing)) { // Make sure we have rights to do it. We can't do the // normal Set_attr check because ALIAS is only // writable by GOD and we want to keep people from // doing &ALIAS and bypassing the player name checks. // notify_quiet(executor, NOPERM_MESSAGE); } else if (!*trimalias) { // New alias is null, just clear it. // delete_player_name(thing, oldalias); atr_clr(thing, A_ALIAS); if (!Quiet(executor)) { notify_quiet(executor, "Alias removed."); } } else if (lookup_player(NOTHING, trimalias, false) != NOTHING) { // Make sure new alias isn't already in use. // notify_quiet(executor, "That name is already in use."); } else if ( !(badname_check(trimalias) && ValidatePlayerName(trimalias))) { notify_quiet(executor, "That's a silly name for a player!"); } else { // Remove the old name and add the new name. // delete_player_name(thing, oldalias); atr_add(thing, A_ALIAS, trimalias, Owner(executor), aflags); if (add_player_name(thing, trimalias)) { if (!Quiet(executor)) { notify_quiet(executor, "Alias set."); } } else { notify_quiet(executor, "That name is already in use or is illegal, alias cleared."); atr_clr(thing, A_ALIAS); } } free_lbuf(trimalias); free_lbuf(oldalias); } else { atr_pget_info(thing, A_ALIAS, &aowner, &aflags); // Make sure we have rights to do it. // if (!bCanSetAttr(executor, thing, ap)) { notify_quiet(executor, NOPERM_MESSAGE); } else { atr_add(thing, A_ALIAS, alias, Owner(executor), aflags); if (!Quiet(executor)) { notify_quiet(executor, "Set."); } } } } // --------------------------------------------------------------------------- // do_forwardlist: Set a forwardlist. // --------------------------------------------------------------------------- void do_forwardlist ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *target, char *newlist ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nargs); dbref thing = match_controlled(executor, target); if (thing == NOTHING) { return; } dbref aowner, aflags; atr_pget_info(thing, A_FORWARDLIST, &aowner, &aflags); if (!Controls(executor, thing)) { notify_quiet(executor, NOPERM_MESSAGE); return; } else if (!*newlist) { // New forwardlist is null, just clear it. // atr_clr(thing, A_FORWARDLIST); set_modified(thing); if (!Quiet(executor)) { notify_quiet(executor, "Forwardlist removed."); } } else if (!fwdlist_ck(executor, thing, A_FORWARDLIST, newlist)) { notify_quiet(executor, "Invalid forwardlist."); return; } else { atr_add(thing, A_FORWARDLIST, newlist, Owner(executor), aflags); if (!Quiet(executor)) { notify_quiet(executor, "Set."); } } } /* * --------------------------------------------------------------------------- * * do_lock: Set a lock on an object or attribute. */ void do_lock ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *keytext ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); dbref thing; ATTR *ap; if ( parse_attrib(executor, name, &thing, &ap) && ap) { dbref aowner; int aflags; if (!atr_get_info(thing, ap->number, &aowner, &aflags)) { notify_quiet(executor, "Attribute not present on object."); return; } if (bCanLockAttr(executor, thing, ap)) { aflags |= AF_LOCK; atr_set_flags(thing, ap->number, aflags); if ( !Quiet(executor) && !Quiet(thing)) { notify_quiet(executor, "Attribute locked."); } } else { notify_quiet(executor, NOPERM_MESSAGE); } return; } init_match(executor, name, NOTYPE); match_everything(MAT_EXIT_PARENTS); thing = match_result(); switch (thing) { case NOTHING: notify_quiet(executor, "I don't see what you want to lock!"); return; case AMBIGUOUS: notify_quiet(executor, "I don't know which one you want to lock!"); return; default: if (!Controls(executor, thing)) { notify_quiet(executor, "You can't lock that!"); return; } } char *pRestrictedKeyText = RemoveSetOfCharacters(keytext, "\r\n\t"); struct boolexp *okey = parse_boolexp(executor, pRestrictedKeyText, false); if (okey == TRUE_BOOLEXP) { notify_quiet(executor, "I don't understand that key."); } else { // Everything ok, do it. // if (!key) { key = A_LOCK; } atr_add_raw(thing, key, unparse_boolexp_quiet(executor, okey)); if ( !Quiet(executor) && !Quiet(thing)) { notify_quiet(executor, "Locked."); } } free_boolexp(okey); } /* * --------------------------------------------------------------------------- * * Remove a lock from an object of attribute. */ void do_unlock(dbref executor, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); dbref thing; ATTR *ap; if ( parse_attrib(executor, name, &thing, &ap) && ap) { // We have been asked to unlock an attribute. // dbref aowner; int aflags; if (!atr_get_info(thing, ap->number, &aowner, &aflags)) { notify_quiet(executor, "Attribute not present on object."); return; } if (bCanLockAttr(executor, thing, ap)) { aflags &= ~AF_LOCK; atr_set_flags(thing, ap->number, aflags); if ( !Quiet(executor) && !Quiet(thing)) { notify_quiet(executor, "Attribute unlocked."); } } else { notify_quiet(executor, NOPERM_MESSAGE); } return; } // We have been asked to change the ownership of an object. // if (!key) { key = A_LOCK; } thing = match_controlled(executor, name); if (thing != NOTHING) { atr_clr(thing, key); set_modified(thing); if (!Quiet(executor) && !Quiet(thing)) { notify_quiet(executor, "Unlocked."); } } } /* * --------------------------------------------------------------------------- * * do_unlink: Unlink an exit from its destination or remove a dropto. */ void do_unlink(dbref executor, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(eval); dbref exit; init_match(executor, name, TYPE_EXIT); match_everything(0); exit = match_result(); switch (exit) { case NOTHING: notify_quiet(executor, "Unlink what?"); break; case AMBIGUOUS: notify_quiet(executor, "I don't know which one you mean!"); break; default: if (!Controls(executor, exit)) { notify_quiet(executor, NOPERM_MESSAGE); } else { switch (Typeof(exit)) { case TYPE_EXIT: s_Location(exit, NOTHING); if (!Quiet(executor)) { notify_quiet(executor, "Unlinked."); } giveto(Owner(exit), mudconf.linkcost); break; case TYPE_ROOM: s_Dropto(exit, NOTHING); if (!Quiet(executor)) { notify_quiet(executor, "Dropto removed."); } break; default: notify_quiet(executor, "You can't unlink that!"); break; } } } } void TranslateFlags_Clone ( FLAG aClearFlags[3], dbref executor, int key ) { if (key & CLONE_NOSTRIP) { if (God(executor)) { // #1 using /nostrip causes nothing to be stripped. // aClearFlags[FLAG_WORD1] = 0; } else { // With #1 powers, /nostrip still strips the WIZARD bit. // aClearFlags[FLAG_WORD1] = WIZARD; } aClearFlags[FLAG_WORD2] = 0; aClearFlags[FLAG_WORD3] = 0; } else { if ( (key & CLONE_INHERIT) && Inherits(executor)) { // The /inherit switch specifically allows INHERIT powers through. // aClearFlags[FLAG_WORD1] = (WIZARD | mudconf.stripped_flags.word[FLAG_WORD1]) & ~(INHERIT); } else { // Normally WIZARD and the other stripped_flags are removed. // aClearFlags[FLAG_WORD1] = WIZARD | mudconf.stripped_flags.word[FLAG_WORD1]; } aClearFlags[FLAG_WORD2] = mudconf.stripped_flags.word[FLAG_WORD2]; aClearFlags[FLAG_WORD3] = mudconf.stripped_flags.word[FLAG_WORD3]; } } void TranslateFlags_Chown ( FLAG aClearFlags[3], FLAG aSetFlags[3], bool *bClearPowers, dbref executor, int key ) { if (key & CHOWN_NOSTRIP) { if (God(executor)) { // #1 using /nostrip only clears CHOWN_OK and sets HALT. // aClearFlags[FLAG_WORD1] = CHOWN_OK; *bClearPowers = false; } else { // With /nostrip, CHOWN_OK and WIZARD are cleared, HALT is // set, and powers are cleared. // aClearFlags[FLAG_WORD1] = CHOWN_OK | WIZARD; *bClearPowers = true; } aClearFlags[FLAG_WORD2] = 0; aClearFlags[FLAG_WORD3] = 0; } else { // Without /nostrip, CHOWN_OK, WIZARD, and stripped_flags are // cleared, HALT is set, powers are cleared. // aClearFlags[FLAG_WORD1] = CHOWN_OK | WIZARD | mudconf.stripped_flags.word[FLAG_WORD1]; aClearFlags[FLAG_WORD2] = mudconf.stripped_flags.word[FLAG_WORD2]; aClearFlags[FLAG_WORD3] = mudconf.stripped_flags.word[FLAG_WORD3]; *bClearPowers = true; } aSetFlags[FLAG_WORD1] = HALT; aSetFlags[FLAG_WORD2] = 0; aSetFlags[FLAG_WORD3] = 0; } void SetClearFlags ( dbref thing, FLAG aClearFlags[3], FLAG aSetFlags[3] ) { int j; for (j = FLAG_WORD1; j <= FLAG_WORD3; j++) { if (NULL != aClearFlags) { db[thing].fs.word[j] &= ~aClearFlags[j]; } if (NULL != aSetFlags) { db[thing].fs.word[j] |= aSetFlags[j]; } } } /* * --------------------------------------------------------------------------- * * do_chown: Change ownership of an object or attribute. */ void do_chown ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *newown ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); dbref nOwnerOrig, nOwnerNew, thing; bool bDoit; ATTR *ap; if ( parse_attrib(executor, name, &thing, &ap) && ap && See_attr(executor, thing, ap)) { // An attribute was given, so we worry about changing the owner of the // attribute. // nOwnerOrig = Owner(thing); if (!*newown) { nOwnerNew = nOwnerOrig; } else if (!string_compare(newown, "me")) { nOwnerNew = Owner(executor); } else { nOwnerNew = lookup_player(executor, newown, true); } // You may chown an attr to yourself if you own the object and the attr // is not locked. You may chown an attr to the owner of the object if // you own the attribute. To do anything else you must be a wizard. // Only #1 can chown attributes on #1. // dbref aowner; int aflags; if (!atr_get_info(thing, ap->number, &aowner, &aflags)) { notify_quiet(executor, "Attribute not present on object."); return; } bDoit = false; if (nOwnerNew == NOTHING) { notify_quiet(executor, "I couldn't find that player."); } else if ( God(thing) && !God(executor)) { notify_quiet(executor, NOPERM_MESSAGE); } else if (Wizard(executor)) { bDoit = true; } else if (nOwnerNew == Owner(executor)) { // Chown to me: only if I own the obj and !locked // if ( !Controls(executor, thing) || (aflags & AF_LOCK)) { notify_quiet(executor, NOPERM_MESSAGE); } else { bDoit = true; } } else if (nOwnerNew == nOwnerOrig) { // chown to obj owner: only if I own attr and !locked // if ( Owner(executor) != aowner || (aflags & AF_LOCK)) { notify_quiet(executor, NOPERM_MESSAGE); } else { bDoit = true; } } else { notify_quiet(executor, NOPERM_MESSAGE); } if (!bDoit) { return; } if (!bCanSetAttr(executor, executor, ap)) { notify_quiet(executor, NOPERM_MESSAGE); return; } char *buff = atr_get(thing, ap->number, &aowner, &aflags); atr_add(thing, ap->number, buff, nOwnerNew, aflags); free_lbuf(buff); if (!Quiet(executor)) { notify_quiet(executor, "Attribute owner changed."); } return; } // An attribute was not specified, so we are being asked to change the // owner of the object. // init_match(executor, name, TYPE_THING); match_possession(); match_here(); match_exit(); match_me(); if (Chown_Any(executor)) { match_player(); match_absolute(); } switch (thing = match_result()) { case NOTHING: notify_quiet(executor, "You don't have that!"); return; case AMBIGUOUS: notify_quiet(executor, "I don't know which you mean!"); return; } nOwnerOrig = Owner(thing); if (!*newown || !(string_compare(newown, "me"))) { nOwnerNew = Owner(executor); } else { nOwnerNew = lookup_player(executor, newown, true); } int cost = 1, quota = 1; switch (Typeof(thing)) { case TYPE_ROOM: cost = mudconf.digcost; quota = mudconf.room_quota; break; case TYPE_THING: cost = OBJECT_DEPOSIT(Pennies(thing)); quota = mudconf.thing_quota; break; case TYPE_EXIT: cost = mudconf.opencost; quota = mudconf.exit_quota; break; case TYPE_PLAYER: cost = mudconf.robotcost; quota = mudconf.player_quota; break; } bool bPlayerControlsThing = Controls(executor, thing); if ( isGarbage(thing) && bPlayerControlsThing) { notify_quiet(executor, "You shouldn't be rummaging through the garbage."); } else if (nOwnerNew == NOTHING) { notify_quiet(executor, "I couldn't find that player."); } else if ( isPlayer(thing) && !God(executor)) { notify_quiet(executor, "Players always own themselves."); } else if ( ( !bPlayerControlsThing && !Chown_Any(executor) && !Chown_ok(thing)) || ( isThing(thing) && Location(thing) != executor && !Chown_Any(executor)) || !Controls(executor, nOwnerNew) || God(thing)) { notify_quiet(executor, NOPERM_MESSAGE); } else if (canpayfees(executor, nOwnerNew, cost, quota)) { giveto(nOwnerOrig, cost); if (mudconf.quotas) { add_quota(nOwnerOrig, quota); } if (!God(executor)) { nOwnerNew = Owner(nOwnerNew); } s_Owner(thing, nOwnerNew); atr_chown(thing); FLAGSET clearflags; FLAGSET setflags; bool bClearPowers; TranslateFlags_Chown(clearflags.word, setflags.word, &bClearPowers, executor, key); SetClearFlags(thing, clearflags.word, setflags.word); if (bClearPowers) { s_Powers(thing, 0); s_Powers2(thing, 0); } // Always halt the queue. // halt_que(NOTHING, thing); // Warn if ROYALTY is left set. // if (ROYALTY & db[thing].fs.word[FLAG_WORD1]) { notify_quiet(executor, tprintf("Warning: @chown/nostrip on %s(#%d) leaves ROYALTY priviledge intact.", Moniker(thing), thing)); } // Warn if INHERIT is left set. // if (INHERIT & db[thing].fs.word[FLAG_WORD1]) { notify_quiet(executor, tprintf("Warning: @chown/nostrip on %s(#%d) leaves INHERIT priviledge intact.", Moniker(thing), thing)); } if (!Quiet(executor)) { char *buff = alloc_lbuf("do_chown.notify"); char *bp = buff; char *p; p = tprintf("Owner of %s(#%d) changed from ", Moniker(thing), thing); safe_str(p, buff, &bp); p = tprintf("%s(#%d) to ", Moniker(nOwnerOrig), nOwnerOrig); safe_str(p, buff, &bp); p = tprintf("%s(#%d).", Moniker(nOwnerNew), nOwnerNew); safe_str(p, buff, &bp); *bp = '\0'; notify_quiet(executor, buff); free_lbuf(buff); } } } /* * --------------------------------------------------------------------------- * * do_set: Set flags or attributes on objects, or flags on attributes. */ static void set_attr_internal(dbref player, dbref thing, int attrnum, char *attrtext, int key) { dbref aowner; int aflags; ATTR *pattr = atr_num(attrnum); atr_pget_info(thing, attrnum, &aowner, &aflags); if ( pattr && bCanSetAttr(player, thing, pattr)) { bool could_hear = Hearer(thing); atr_add(thing, attrnum, attrtext, Owner(player), aflags); handle_ears(thing, could_hear, Hearer(thing)); if ( !(key & SET_QUIET) && !Quiet(player) && !Quiet(thing)) { notify_quiet(player, "Set."); } } else { notify_quiet(player, NOPERM_MESSAGE); } } void do_set ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *flagname ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); dbref thing, aowner; int aflags; ATTR *pattr; // See if we have the / form, which is how you set // attribute flags. // if (parse_attrib(executor, name, &thing, &pattr)) { if ( pattr && See_attr(executor, thing, pattr)) { // You must specify a flag name. // if ( !flagname || flagname[0] == '\0') { notify_quiet(executor, "I don't know what you want to set!"); return; } // Check for clearing. // bool clear = false; if (flagname[0] == NOT_TOKEN) { flagname++; clear = true; } // Make sure player specified a valid attribute flag. // int flagvalue; if (!search_nametab(executor, indiv_attraccess_nametab, flagname, &flagvalue)) { notify_quiet(executor, "You can't set that!"); return; } // Make sure the object has the attribute present. // if (!atr_get_info(thing, pattr->number, &aowner, &aflags)) { notify_quiet(executor, "Attribute not present on object."); return; } // Make sure we can write to the attribute. // if (!bCanSetAttr(executor, thing, pattr)) { notify_quiet(executor, NOPERM_MESSAGE); return; } // Go do it. // if (clear) { aflags &= ~flagvalue; } else { aflags |= flagvalue; } bool could_hear = Hearer(thing); atr_set_flags(thing, pattr->number, aflags); // Tell the player about it. // handle_ears(thing, could_hear, Hearer(thing)); if ( !(key & SET_QUIET) && !Quiet(executor) && !Quiet(thing)) { if (clear) { notify_quiet(executor, "Cleared."); } else { notify_quiet(executor, "Set."); } } return; } } // Find thing. // thing = match_controlled(executor, name); if (!Good_obj(thing)) { return; } // Check for attribute set first. // char *p; for (p = flagname; *p && (*p != ':'); p++) { ; // Nothing. } if (*p) { *p++ = 0; int atr = mkattr(executor, flagname); if (atr <= 0) { notify_quiet(executor, "Couldn't create attribute."); return; } pattr = atr_num(atr); if (!pattr) { notify_quiet(executor, NOPERM_MESSAGE); return; } if (!bCanSetAttr(executor, thing, pattr)) { notify_quiet(executor, NOPERM_MESSAGE); return; } char *buff = alloc_lbuf("do_set"); // Check for _ // if (*p == '_') { ATTR *pattr2; dbref thing2; mux_strncpy(buff, p + 1, LBUF_SIZE-1); if (!( parse_attrib(executor, p + 1, &thing2, &pattr2) && pattr2)) { notify_quiet(executor, "No match."); free_lbuf(buff); return; } p = buff; atr_pget_str(buff, thing2, pattr2->number, &aowner, &aflags); if (!See_attr(executor, thing2, pattr2)) { notify_quiet(executor, NOPERM_MESSAGE); free_lbuf(buff); return; } } // Go set it. // set_attr_internal(executor, thing, atr, p, key); free_lbuf(buff); return; } // Set or clear a flag. // flag_set(thing, executor, flagname, key); } void do_power ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *flag ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); if ( !flag || !*flag) { notify_quiet(executor, "I don't know what you want to set!"); return; } // Find thing. // dbref thing = match_controlled(executor, name); if (thing == NOTHING) { return; } power_set(thing, executor, flag, key); } void do_setattr ( dbref executor, dbref caller, dbref enactor, int attrnum, int nargs, char *name, char *attrtext ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); init_match(executor, name, NOTYPE); match_everything(MAT_EXIT_PARENTS); dbref thing = noisy_match_result(); if (!Good_obj(thing)) { return; } set_attr_internal(executor, thing, attrnum, attrtext, 0); } void do_cpattr(dbref executor, dbref caller, dbref enactor, int eval, int key, char *oldpair, char *newpair[], int nargs) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); int i; char *oldthing, *oldattr, *newthing, *newattr; if ( !*oldpair || !**newpair || !oldpair || !*newpair || nargs < 1) { return; } oldattr = oldpair; oldthing = parse_to(&oldattr, '/', 1); for (i = 0; i < nargs; i++) { newattr = newpair[i]; newthing = parse_to(&newattr, '/', 1); if (!oldattr) { if (!newattr) { do_set(executor, caller, enactor, 0, 2, newthing, tprintf("%s:_%s/%s", oldthing, "me", oldthing)); } else { do_set(executor, caller, enactor, 0, 2, newthing, tprintf("%s:_%s/%s", newattr, "me", oldthing)); } } else { if (!newattr) { do_set(executor, caller, enactor, 0, 2, newthing, tprintf("%s:_%s/%s", oldattr, oldthing, oldattr)); } else { do_set(executor, caller, enactor, 0, 2, newthing, tprintf("%s:_%s/%s", newattr, oldthing, oldattr)); } } } } void do_mvattr(dbref executor, dbref caller, dbref enactor, int eval, int key, char *what, char *args[], int nargs) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); // Make sure we have something to do. // if (nargs < 2) { notify_quiet(executor, "Nothing to do."); return; } // Find and make sure we control the target object. // dbref thing = match_controlled(executor, what); if (thing == NOTHING) { return; } // Look up the source attribute. If it either doesn't exist or isn't // readable, use an empty string. // int in_anum = -1; char *astr = alloc_lbuf("do_mvattr"); ATTR *in_attr = atr_str(args[0]); int aflags = 0; if (in_attr == NULL) { *astr = '\0'; } else { dbref aowner; atr_get_str(astr, thing, in_attr->number, &aowner, &aflags); if (See_attr(executor, thing, in_attr)) { in_anum = in_attr->number; } else { *astr = '\0'; } } // Copy the attribute to each target in turn. // bool bCanDelete = true; int nCopied = 0; for (int i = 1; i < nargs; i++) { int anum = mkattr(executor, args[i]); if (anum <= 0) { notify_quiet(executor, tprintf("%s: That's not a good name for an attribute.", args[i])); continue; } ATTR *out_attr = atr_num(anum); if (!out_attr) { notify_quiet(executor, tprintf("%s: Permission denied.", args[i])); } else if (out_attr->number == in_anum) { // It doesn't make sense to delete a source attribute if it's also // included as a destination. // bCanDelete = false; } else { if (!bCanSetAttr(executor, thing, out_attr)) { notify_quiet(executor, tprintf("%s: Permission denied.", args[i])); } else { nCopied++; atr_add(thing, out_attr->number, astr, Owner(executor), aflags); if (!Quiet(executor)) { notify_quiet(executor, tprintf("%s: Set.", out_attr->name)); } } } } // Remove the source attribute if we were able to copy it successfully to // even one destination object. // if (nCopied <= 0) { if (in_attr) { notify_quiet(executor, tprintf("%s: Not copied anywhere. Not cleared.", in_attr->name)); } else { notify_quiet(executor, "Not copied anywhere. Non-existent attribute."); } } else if ( in_anum > 0 && bCanDelete) { in_attr = atr_num(in_anum); if (in_attr) { if (bCanSetAttr(executor, thing, in_attr)) { atr_clr(thing, in_attr->number); if (!Quiet(executor)) { notify_quiet(executor, tprintf("%s: Cleared.", in_attr->name)); } } else { notify_quiet(executor, tprintf("%s: Could not remove old attribute. Permission denied.", in_attr->name)); } } else { notify_quiet(executor, "Could not remove old attribute. Non-existent attribute."); } } free_lbuf(astr); } /* * --------------------------------------------------------------------------- * * parse_attrib, parse_attrib_wild: parse / tokens. */ bool parse_attrib(dbref player, char *str, dbref *thing, ATTR **attr) { ATTR *tattr = NULL; *thing = NOTHING; if (!str) { *attr = tattr; return false; } // Break apart string into obj and attr. // char *buff = alloc_lbuf("parse_attrib"); mux_strncpy(buff, str, LBUF_SIZE-1); char *AttrName; bool retval = parse_thing_slash(player, buff, &AttrName, thing); // Get the named attribute from the object if we can. // if (retval) { tattr = atr_str(AttrName); } free_lbuf(buff); *attr = tattr; return retval; } static void find_wild_attrs(dbref player, dbref thing, char *str, bool check_exclude, bool hash_insert, bool get_locks) { ATTR *pattr; char *as; dbref aowner; int ca, ok, aflags; // Walk the attribute list of the object. // atr_push(); for (ca = atr_head(thing, &as); ca; ca = atr_next(&as)) { pattr = atr_num(ca); // Discard bad attributes and ones we've seen before. // if (!pattr) { continue; } if ( check_exclude && ( (pattr->flags & AF_PRIVATE) || hashfindLEN(&ca, sizeof(ca), &mudstate.parent_htab))) { continue; } // If we aren't the top level remember this attr so we exclude it in // any parents. // atr_get_info(thing, ca, &aowner, &aflags); if ( check_exclude && (aflags & AF_PRIVATE)) { continue; } if (get_locks) { ok = bCanReadAttr(player, thing, pattr, false); } else { ok = See_attr(player, thing, pattr); } mudstate.wild_invk_ctr = 0; if ( ok && quick_wild(str, pattr->name)) { olist_add(ca); if (hash_insert) { hashaddLEN(&ca, sizeof(ca), pattr, &mudstate.parent_htab); } } } atr_pop(); } bool parse_attrib_wild(dbref player, char *str, dbref *thing, bool check_parents, bool get_locks, bool df_star) { if (!str) { return false; } dbref parent; int lev; bool check_exclude, hash_insert; char *buff = alloc_lbuf("parse_attrib_wild"); mux_strncpy(buff, str, LBUF_SIZE-1); // Separate name and attr portions at the first /. // if (!parse_thing_slash(player, buff, &str, thing)) { // Not in obj/attr format, return if not defaulting to. // if (!df_star) { free_lbuf(buff); return false; } // Look for the object, return failure if not found. // init_match(player, buff, NOTYPE); match_everything(MAT_EXIT_PARENTS); *thing = match_result(); if (!Good_obj(*thing)) { free_lbuf(buff); return false; } str = (char *)"*"; } // Check the object (and optionally all parents) for attributes. // if (check_parents) { check_exclude = false; hash_insert = check_parents; hashflush(&mudstate.parent_htab); ITER_PARENTS(*thing, parent, lev) { if (!Good_obj(Parent(parent))) { hash_insert = false; } find_wild_attrs(player, parent, str, check_exclude, hash_insert, get_locks); check_exclude = true; } } else { find_wild_attrs(player, *thing, str, false, false, get_locks); } free_lbuf(buff); return true; } /* * --------------------------------------------------------------------------- * * edit_string, edit_string_ansi, do_edit: Modify attributes. */ void edit_string(char *src, char **dst, char *from, char *to) { char *cp; // Do the substitution. Idea for prefix/suffix from R'nice@TinyTIM. // if (!strcmp(from, "^")) { // Prepend 'to' to string. // *dst = alloc_lbuf("edit_string.^"); cp = *dst; safe_str(to, *dst, &cp); safe_str(src, *dst, &cp); *cp = '\0'; } else if (!strcmp(from, "$")) { // Append 'to' to string. // *dst = alloc_lbuf("edit_string.$"); cp = *dst; safe_str(src, *dst, &cp); safe_str(to, *dst, &cp); *cp = '\0'; } else { // Replace all occurances of 'from' with 'to'. Handle the special // cases of from = \$ and \^. // if ( ( from[0] == '\\' || from[0] == '%') && ( from[1] == '$' || from[1] == '^') && from[2] == '\0') { from++; } *dst = replace_string(from, to, src); } } static void edit_string_ansi(char *src, char **dst, char **returnstr, char *from, char *to) { char *cp, *rp; // Do the substitution. Idea for prefix/suffix from R'nice@TinyTIM // if (!strcmp(from, "^")) { // Prepend 'to' to string. // *dst = alloc_lbuf("edit_string.^"); cp = *dst; safe_str(to, *dst, &cp); safe_str(src, *dst, &cp); *cp = '\0'; // Do the ansi string used to notify. // *returnstr = alloc_lbuf("edit_string_ansi.^"); rp = *returnstr; safe_str(ANSI_HILITE, *returnstr, &rp); safe_str(to, *returnstr, &rp); safe_str(ANSI_NORMAL, *returnstr, &rp); safe_str(src, *returnstr, &rp); *rp = '\0'; } else if (!strcmp(from, "$")) { // Append 'to' to string // *dst = alloc_lbuf("edit_string.$"); cp = *dst; safe_str(src, *dst, &cp); safe_str(to, *dst, &cp); *cp = '\0'; // Do the ansi string used to notify. // *returnstr = alloc_lbuf("edit_string_ansi.$"); rp = *returnstr; safe_str(src, *returnstr, &rp); safe_str(ANSI_HILITE, *returnstr, &rp); safe_str(to, *returnstr, &rp); safe_str(ANSI_NORMAL, *returnstr, &rp); *rp = '\0'; } else { // Replace all occurances of 'from' with 'to'. Handle the special // cases of from = \$ and \^. // if ( ((from[0] == '\\') || (from[0] == '%')) && ((from[1] == '$') || (from[1] == '^')) && ( from[2] == '\0')) { from++; } *dst = replace_string(from, to, src); *returnstr = replace_string(from, tprintf("%s%s%s", ANSI_HILITE, to, ANSI_NORMAL), src); } } void do_edit(dbref executor, dbref caller, dbref enactor, int eval, int key, char *it, char *args[], int nargs) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); dbref thing, aowner; int atr, aflags; bool bGotOne; char *from, *to, *result, *returnstr, *atext; ATTR *ap; // Make sure we have something to do. // if ( nargs < 1 || !*args[0]) { notify_quiet(executor, "Nothing to do."); return; } from = args[0]; to = (nargs >= 2) ? args[1] : (char *)""; // Look for the object and get the attribute (possibly wildcarded) // olist_push(); if ( !it || !*it || !parse_attrib_wild(executor, it, &thing, false, false, false)) { notify_quiet(executor, "No match."); return; } // Iterate through matching attributes, performing edit. // bGotOne = 0; atext = alloc_lbuf("do_edit.atext"); bool could_hear = Hearer(thing); for (atr = olist_first(); atr != NOTHING; atr = olist_next()) { ap = atr_num(atr); if (ap) { // Get the attr and make sure we can modify it. // atr_get_str(atext, thing, ap->number, &aowner, &aflags); if (bCanSetAttr(executor, thing, ap)) { // Do the edit and save the result // bGotOne = true; edit_string_ansi(atext, &result, &returnstr, from, to); atr_add(thing, ap->number, result, Owner(executor), aflags); if (!Quiet(executor)) { notify_quiet(executor, tprintf("Set - %s: %s", ap->name, returnstr)); } free_lbuf(result); free_lbuf(returnstr); } else { // No rights to change the attr. // notify_quiet(executor, tprintf("%s: Permission denied.", ap->name)); } } } // Clean up. // free_lbuf(atext); olist_pop(); if (!bGotOne) { notify_quiet(executor, "No matching attributes."); } else { handle_ears(thing, could_hear, Hearer(thing)); } } void do_wipe(dbref executor, dbref caller, dbref enactor, int eval, int key, char *it) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); dbref thing; olist_push(); if ( !it || !*it || !parse_attrib_wild(executor, it, &thing, false, false, true)) { notify_quiet(executor, "No match."); return; } if ( mudconf.safe_wipe && has_flag(NOTHING, thing, "SAFE")) { notify_quiet(executor, "SAFE objects may not be @wiped."); return; } // Iterate through matching attributes, zapping the writable ones // int atr; ATTR *ap; bool bGotOne = false, could_hear = Hearer(thing); for (atr = olist_first(); atr != NOTHING; atr = olist_next()) { ap = atr_num(atr); if (ap) { // Get the attr and make sure we can modify it. // if (bCanSetAttr(executor, thing, ap)) { atr_clr(thing, ap->number); bGotOne = true; } } } // Clean up // olist_pop(); if (!bGotOne) { notify_quiet(executor, "No matching attributes."); } else { set_modified(thing); handle_ears(thing, could_hear, Hearer(thing)); if (!Quiet(executor)) { notify_quiet(executor, "Wiped."); } } } void do_trigger(dbref executor, dbref caller, dbref enactor, int eval, int key, char *object, char *argv[], int nargs) { dbref thing; ATTR *pattr; if (!( parse_attrib(executor, object, &thing, &pattr) && pattr)) { notify_quiet(executor, "No match."); return; } if (!Controls(executor, thing)) { notify_quiet(executor, NOPERM_MESSAGE); return; } did_it(executor, thing, 0, NULL, 0, NULL, pattr->number, 0, argv, nargs); if (key & TRIG_NOTIFY) { char *tbuf = alloc_lbuf("trigger.notify_cmd"); mux_strncpy(tbuf, "@notify/quiet me", LBUF_SIZE-1); CLinearTimeAbsolute lta; wait_que(executor, caller, enactor, eval, false, lta, NOTHING, A_SEMAPHORE, tbuf, 0, NULL, mudstate.global_regs); free_lbuf(tbuf); } if ( !(key & TRIG_QUIET) && !Quiet(executor)) { notify_quiet(executor, "Triggered."); } } void do_use(dbref executor, dbref caller, dbref enactor, int eval, int key, char *object) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); char *df_use, *df_ouse, *temp; dbref thing, aowner; int aflags; init_match(executor, object, NOTYPE); match_neighbor(); match_possession(); if (Wizard(executor)) { match_absolute(); match_player(); } match_me(); match_here(); thing = noisy_match_result(); if (thing == NOTHING) return; // Make sure player can use it. // if (!could_doit(executor, thing, A_LUSE)) { did_it(executor, thing, A_UFAIL, "You can't figure out how to use that.", A_OUFAIL, NULL, A_AUFAIL, 0, NULL, 0); return; } temp = alloc_lbuf("do_use"); bool doit = false; if (*atr_pget_str(temp, thing, A_USE, &aowner, &aflags)) { doit = true; } else if (*atr_pget_str(temp, thing, A_OUSE, &aowner, &aflags)) { doit = true; } else if (*atr_pget_str(temp, thing, A_AUSE, &aowner, &aflags)) { doit = true; } free_lbuf(temp); if (doit) { df_use = alloc_lbuf("do_use.use"); df_ouse = alloc_lbuf("do_use.ouse"); mux_sprintf(df_use, LBUF_SIZE, "You use %s", Moniker(thing)); mux_sprintf(df_ouse, LBUF_SIZE, "uses %s", Moniker(thing)); did_it(executor, thing, A_USE, df_use, A_OUSE, df_ouse, A_AUSE, 0, NULL, 0); free_lbuf(df_use); free_lbuf(df_ouse); } else { notify_quiet(executor, "You can't figure out how to use that."); } } /* * --------------------------------------------------------------------------- * * do_setvattr: Set a user-named (or possibly a predefined) attribute. */ void do_setvattr ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *arg1, char *arg2 ) { UNUSED_PARAMETER(key); UNUSED_PARAMETER(nargs); char *s; int anum; // Skip the '&' // arg1++; // Take to the space // for (s = arg1; *s && !mux_isspace(*s); s++) { ; // Nothing. } // Split it // if (*s) { *s++ = '\0'; } // Get or make attribute // anum = mkattr(executor, arg1); if (anum <= 0) { notify_quiet(executor, "That's not a good name for an attribute."); return; } do_setattr(executor, caller, enactor, anum, 2, s, arg2); } mux2.6/src/alloc.h0000600000175000017500000000601511025753746014043 0ustar sdennissdennis// alloc.h -- External definitions for memory allocation subsystem. // // $Id: alloc.h 366 2006-11-05 13:43:16Z brazilofmux $ // #ifndef M_ALLOC_H #define M_ALLOC_H #define POOL_LBUF 0 #define POOL_SBUF 1 #define POOL_MBUF 2 #define POOL_BOOL 3 #define POOL_DESC 4 #define POOL_QENTRY 5 #define POOL_PCACHE 6 #define POOL_LBUFREF 7 #define POOL_REGREF 8 #define NUM_POOLS 9 #ifdef FIRANMUX #define LBUF_SIZE 16000 // Large #else #define LBUF_SIZE 8000 // Large #endif #define GBUF_SIZE 1024 // Generic #define MBUF_SIZE 400 // Medium #define PBUF_SIZE 128 // Pathname #define SBUF_SIZE 64 // Small extern void pool_init(int, int); extern char *pool_alloc(int, const char *, const char *, int); extern char *pool_alloc_lbuf(const char *, const char *, int); extern void pool_free(int, char *, const char *, int); extern void pool_free_lbuf(char *, const char *, int); extern void list_bufstats(dbref); extern void list_buftrace(dbref); extern void pool_reset(void); #define alloc_lbuf(s) pool_alloc_lbuf(s, __FILE__, __LINE__) #define free_lbuf(b) pool_free_lbuf((char *)(b), __FILE__, __LINE__) #define alloc_mbuf(s) pool_alloc(POOL_MBUF,s, __FILE__, __LINE__) #define free_mbuf(b) pool_free(POOL_MBUF,(char *)(b), __FILE__, __LINE__) #define alloc_sbuf(s) pool_alloc(POOL_SBUF,s, __FILE__, __LINE__) #define free_sbuf(b) pool_free(POOL_SBUF,(char *)(b), __FILE__, __LINE__) #define alloc_bool(s) (struct boolexp *)pool_alloc(POOL_BOOL,s, __FILE__, __LINE__) #define free_bool(b) pool_free(POOL_BOOL,(char *)(b), __FILE__, __LINE__) #define alloc_qentry(s) (BQUE *)pool_alloc(POOL_QENTRY,s, __FILE__, __LINE__) #define free_qentry(b) pool_free(POOL_QENTRY,(char *)(b), __FILE__, __LINE__) #define alloc_pcache(s) (PCACHE *)pool_alloc(POOL_PCACHE,s, __FILE__, __LINE__) #define free_pcache(b) pool_free(POOL_PCACHE,(char *)(b), __FILE__, __LINE__) #define alloc_lbufref(s) (lbuf_ref *)pool_alloc(POOL_LBUFREF,s, __FILE__, __LINE__) #define free_lbufref(b) pool_free(POOL_LBUFREF,(char *)(b), __FILE__, __LINE__) #define alloc_regref(s) (reg_ref *)pool_alloc(POOL_REGREF,s, __FILE__, __LINE__) #define free_regref(b) pool_free(POOL_REGREF,(char *)(b), __FILE__, __LINE__) #define safe_copy_chr(src, buff, bufp, nSizeOfBuffer) \ { \ if ((size_t)(*bufp - buff) < nSizeOfBuffer) \ { \ **bufp = src; \ (*bufp)++; \ } \ } #define safe_str(s,b,p) safe_copy_str_lbuf(s,b,p) #define safe_chr(c,b,p) safe_copy_chr((unsigned char)(c),b,p,(LBUF_SIZE-1)) #define safe_bool(c,b,p) safe_chr(((c) ? '1' : '0'),b,p) #define safe_sb_str(s,b,p) safe_copy_str(s,b,p,(SBUF_SIZE-1)) #define safe_sb_chr(c,b,p) safe_copy_chr(c,b,p,(SBUF_SIZE-1)) #define safe_mb_str(s,b,p) safe_copy_str(s,b,p,(MBUF_SIZE-1)) #define safe_mb_chr(c,b,p) safe_copy_chr(c,b,p,(MBUF_SIZE-1)) struct lbuf_ref { int refcount; char *lbuf_ptr; }; struct reg_ref { int refcount; lbuf_ref *lbuf; size_t reg_len; char *reg_ptr; }; #endif // M_ALLOC_H mux2.6/src/autoconf.h.in0000600000175000017500000002265611025753746015205 0ustar sdennissdennis/* autoconf.h.in -- System-dependent configuration information */ #ifndef AUTOCONF_H #define AUTOCONF_H #include "copyright.h" /* --------------------------------------------------------------------------- * Configuration section: * * These defines are written by the configure script. * Change them if need be */ /* Define if we have stdlib.h et al */ #undef STDC_HEADERS /* Define if we have unistd.h */ #undef HAVE_UNISTD_H /* Define if we have memory.h and need it to get memcmp et al */ #undef NEED_MEMORY_H /* Decl for pid_t */ #undef pid_t /* signal() return type */ #define RETSIGTYPE void /* Define if struct tm is not in time.h */ #undef TM_IN_SYS_TIME /* Define if struct tm has a timezone member */ #undef HAVE_TM_ZONE /* Define if tzname[] exists */ #undef HAVE_TZNAME /* Define if setrlimit exists */ #undef HAVE_SETRLIMIT /* Define if getrusage exists */ #undef HAVE_GETRUSAGE /* Define if getdtablesize exists */ #undef HAVE_GETDTABLESIZE /* Define if getpagesize exists */ #undef HAVE_GETPAGESIZE /* Define if gettimeofday exists */ #undef HAVE_GETTIMEOFDAY /* Define if usleep exists */ #undef HAVE_USLEEP /* Define if nanosleep exists */ #undef HAVE_NANOSLEEP /* Define if setitimer exists */ #undef HAVE_SETITIMER /* Define if localtime_r exists */ #undef HAVE_LOCALTIME_R /* Define if sys_siglist[] exists */ #undef SYS_SIGLIST_DECLARED /* Define if sys_signame[] exists */ #undef HAVE_SYS_SIGNAME /* Define if index/rindex/mem??? are defined in string.h */ #undef INDEX_IN_STRING_H /* Define if malloc/realloc/free are defined in stdlib.h */ #undef MALLOC_IN_STDLIB_H /* Define if calling signal with SIGCHLD when handling SIGCHLD blows chow */ #undef SIGNAL_SIGCHLD_BRAINDAMAGE /* Define if errno.h exists */ #undef HAVE_ERRNO_H /* Define if malloc.h exists */ #undef HAVE_MALLOC_H /* Define if sys/wait.h exists */ #undef HAVE_SYS_WAIT_H /* Define if sys/select.h exists */ #undef HAVE_SYS_SELECT_H /* Define if sys/rusage.h exists */ #undef HAVE_SYS_RUSAGE_H /* Define if Big Endian */ #undef WORDS_BIGENDIAN /* Define if Little Endian */ #undef WORDS_LITTLEENDIAN /* Define if Unknown Endian */ #undef WORDS_UNKNOWN /* Define if const is broken */ #undef const /* sizeof(short) */ #undef SIZEOF_SHORT /* sizeof(unsigned short) */ #undef SIZEOF_UNSIGNED_SHORT /* sizeof(int) */ #undef SIZEOF_INT /* sizeof(unsigned int) */ #undef SIZEOF_UNSIGNED_INT /* sizeof(long) */ #undef SIZEOF_LONG /* sizeof(unsigned long) */ #undef SIZEOF_UNSIGNED_LONG /* Define if unaligned short access is allowed. */ #undef CAN_UNALIGN_SHORT /* Define if unaligned int access is allowed. */ #undef CAN_UNALIGN_INT /* Define if unaligned long access is allowed. */ #undef CAN_UNALIGN_LONG /* Define if unaligned long long access is allowed. */ #undef CAN_UNALIGN_LONGLONG /* Define if inline keyword is broken or nonstandard */ #undef inline /* Define if we need to redef index/bcopy et al to their SYSV counterparts */ #undef NEED_INDEX_DCL /* Define if we need to declare malloc et al */ #undef NEED_MALLOC_DCL /* Define if you need to declare vsprintf yourself */ #undef NEED_VSPRINTF_DCL /* Define if you need to declare sys_errlist yourself */ #undef NEED_SYS_ERRLIST_DCL /* Define if you need to declare _sys_errlist yourself */ #undef NEED_SYS__ERRLIST_DCL /* Define if you need to declare sprintf yourself */ #undef NEED_SPRINTF_DCL /* Define if you need to declare getrlimit yourself */ #undef NEED_GETRLIMIT_DCL /* Define if you need to declare getrusage yourself */ #undef NEED_GETRUSAGE_DCL /* Define if struct linger is defined */ #undef HAVE_LINGER /* Define if signal handlers have a struct sigcontext as their third arg */ #undef HAVE_STRUCT_SIGCONTEXT /* Define if stdio.h defines lots of extra functions */ #undef EXTENDED_STDIO_DCLS /* Define if sys/socket.h defines lots of extra functions */ #undef EXTENDED_SOCKET_DCLS /* Define if socklen_t is defined */ #undef SOCKLEN_T_DCL /* Define if we may safely include both time.h and sys/time.h */ #undef TIME_WITH_SYS_TIME /* Define if sys/time.h exists */ #undef HAVE_SYS_TIME_H /* Define if you need to declare gettimeofday yourself */ #undef NEED_GETTIMEOFDAY_DCL /* Define if you need to declare getpagesize yourself */ #undef NEED_GETPAGESIZE_DCL /* Define if you have IEEE floating-point formatted numbers */ #undef HAVE_IEEE_FP_FORMAT /* Define if your IEEE floating-point library can generate NaN */ #undef HAVE_IEEE_FP_SNAN /* Define if your platform computes the integer quotient as the smallest */ /* integer greater than or or equal to the algebraic quotient. For */ /* example, -9/5 gives -1 */ #undef SMALLEST_INT_GTE_NEG_QUOTIENT /* Define if the character special file /dev/urandom is present */ #undef HAVE_DEV_URANDOM /* Define if fpu_config.h is available. */ #undef HAVE_FPU_CONTROL_H /* Define if ieeefp.h is available. */ #undef HAVE_IEEEFP_H /* Define if ieeefp.h is useable. */ #undef IEEEFP_H_USEABLE /* Define if fenv.h is available. */ #undef HAVE_FENV_H /* Define if fegetprec is available. */ #undef HAVE_FEGETPREC /* Define if fesetprec is available. */ #undef HAVE_FESETPREC /* Define if your system has the in_addr_t type */ #undef HAVE_IN_ADDR_T /* Define if fcntl.h exists */ #undef HAVE_FCNTL_H /* Define if crypt library exists */ #undef HAVE_LIBCRYPT /* Define if crypt exists */ #undef HAVE_CRYPT /* Define if pread exists */ #undef HAVE_PREAD /* Define if pwrite exists */ #undef HAVE_PWRITE /* --------------------------------------------------------------------------- * Setup section: * * Load system-dependent header files. */ #if !defined(STDC_HEADERS) #error MUX requires standard headers. #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_UNISTD_H #include #endif // HAVE_UNISTD_H #include #include #include #ifdef NEED_MEMORY_H #include #endif #include #ifdef NEED_INDEX_DCL #define index strchr #define rindex strrchr #define bcopy(s,d,n) memmove(d,s,n) #endif #ifdef TIME_WITH_SYS_TIME #include #include #else #ifdef HAVE_SYS_TIME_H #include #else #include #endif #endif #if defined(HAVE_SETRLIMIT) || defined(HAVE_GETRUSAGE) #include #ifdef NEED_GETRUSAGE_DCL extern int getrusage(int, struct rusage *); #endif #ifdef NEED_GETRLIMIT_DCL extern int getrlimit(int, struct rlimit *); extern int setrlimit(int, struct rlimit *); #endif #endif #ifdef HAVE_SYS_FILE_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_GETTIMEOFDAY #ifdef NEED_GETTIMEOFDAY_DCL extern int gettimeofday(struct timeval *, struct timezone *); #endif #endif #ifdef HAVE_GETDTABLESIZE extern int getdtablesize(void); #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_GETPAGESIZE #ifdef NEED_GETPAGESIZE_DECL extern int getpagesize(void); #endif // NEED_GETPAGESIZE_DECL #else // HAVE_GETPAGESIZE #ifdef _SC_PAGESIZE #define getpagesize() sysconf(_SC_PAGESIZE) #else // _SC_PAGESIZE #include #ifdef EXEC_PAGESIZE #define getpagesize() EXEC_PAGESIZE #else // EXEC_PAGESIZE #ifdef NBPG #ifndef CLSIZE #define CLSIZE 1 #endif // CLSIZE #define getpagesize() NBPG * CLSIZE #else // NBPG #ifdef PAGESIZE #define getpagesize() PAGESIZE #else // PAGESIZE #ifdef NBPC #define getpagesize() NBPC #else // NBPC #define getpagesize() 0 #endif // NBPC #endif // PAGESIZE #endif // NBPG #endif // EXEC_PAGESIZE #endif // _SC_PAGESIZE #endif // HAVE_GETPAGESIZE #ifdef HAVE_ERRNO_H #include #else extern int errno; #endif // Assure that malloc, realloc, and free are defined. // #if !defined(MALLOC_IN_STDLIB_H) #if defined(HAVE_MALLOC_H) #include #elif defined(NEED_MALLOC_DCL) extern char *malloc(int); extern char *realloc(char *, int); extern int free(char *); #endif #endif #ifdef NEED_SYS_ERRLIST_DCL extern char *sys_errlist[]; #endif #include #include #include #ifdef NEED_SPRINTF_DCL extern char *sprintf(char *, const char *, ...); #endif #ifndef EXTENDED_STDIO_DCLS extern int fprintf(FILE *, const char *, ...); extern int printf(const char *, ...); extern int sscanf(const char *, const char *, ...); extern int close(int); extern int fclose(FILE *); extern int fflush(FILE *); extern int fgetc(FILE *); extern int fputc(int, FILE *); extern int fputs(const char *, FILE *); extern int fread(void *, size_t, size_t, FILE *); extern int fseek(FILE *, long, int); extern int fwrite(void *, size_t, size_t, FILE *); extern pid_t getpid(void); extern int pclose(FILE *); extern int rename(char *, char *); extern time_t time(time_t *); extern int ungetc(int, FILE *); extern int unlink(const char *); #endif #include #ifndef EXTENDED_SOCKET_DCLS extern int accept(int, struct sockaddr *, int *); extern int bind(int, struct sockaddr *, int); extern int listen(int, int); extern int sendto(int, void *, int, unsigned int, struct sockaddr *, int); extern int setsockopt(int, int, int, void *, int); extern int shutdown(int, int); extern int socket(int, int, int); extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); #endif typedef int dbref; typedef int FLAG; typedef int POWER; #ifdef REALITY_LVLS typedef unsigned int RLEVEL; #endif // REALITY_LVLS typedef char boolexp_type; typedef char IBUF[16]; #define UNUSED_PARAMETER(x) ((void)(x)) #endif // AUTOCONF_H mux2.6/src/plusemail.cpp0000600000175000017500000004456511025753746015313 0ustar sdennissdennis// plusmail.cpp -- Quicky module implementing Firan-like @email function. // // $Id: plusemail.cpp 2475 2007-09-15 16:18:35Z brazilofmux $ // // Rachel Blackman // // Config options: // mail_server SMTP server to use (mail.bar.com) // mail_ehlo ehlo server (my.baz.com) // mail_sendaddr return address (foo@bar.com) // mail_sendname RFC822 'name' (FooMUSH) // mail_subject Defaults subject link (FooMUSH Mail) // #include "autoconf.h" #include "config.h" #include "_build.h" #ifndef WIN32 #include #endif #include "externs.h" // Encode mail body such that CRLF.CRLF only appears at the end of the // message. Here are some example transforms. // // . --> .. // . --> .. // --> . // --> . // // and are only allowed to occur as the pair -- never alone. // // Code 0 - Any byte. // Code 1 - NUL (0x00) // Code 2 - LF (0x0A) // Code 3 - CR (0x0D) // Code 4 - '.' (0x2E) // Code 5 - non-ASCII // static const unsigned char BodyClasses[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 3, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 8 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 9 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // A 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // B 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // C 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // D 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // E 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 // F }; #define STATE_NOTHING 0 #define STATE_BOM 1 #define STATE_HAVE_CR 2 #define STATE_HAVE_CRLF 3 #define STATE_HAVE_CRLF_DOT 4 #define STATE_HAVE_CRLF_DOT_CR 5 #define STATE_HAVE_DOT 6 #define STATE_HAVE_DOT_CR 7 // Action 0 - Remain in current state. // Action 1 - Emit ch and remain in current state. // Action 2 - Emit ch and move to STATE_NOTHING. // Action 3 - Emit CRLF.CRLF and terminate. // Action 4 - Move to STATE_HAVE_CR. // Action 5 - Move to STATE_HAVE_DOT. // Action 6 - Move to STATE_HAVE_CRLF. // Action 7 - Emit CRLF+ch and move to STATE_NOTHING. // Action 8 - Emit CRLF and move to STATE_HAVE_CR. // Action 9 - Move to STATE_HAVE_CRLF_DOT. // Action 10 - Emit CRLF..+ch and move to STATE_NOTHING. // Action 11 - Emit CRLF..CRLF.CRLF and terminate. // Action 12 - Move to STATE_HAVE_CRLF_DOT_CR. // Action 13 - Emit CRLF.. and move to STATE_HAVE_CRLF. // Action 14 - Emit ..+ch and move to STATE_NOTHING. // Action 15 - Emit ..CRLF.CRLF and terminate. // Action 16 - Move to STATE_HAVE_DOT_CR. // Action 17 - Emit .. and move to STATE_HAVE_CRLF. // static const int BodyActions[8][6] = { // Any '\0' LF CR '.' Non { 1, 3, 0, 4, 1, 0}, // STATE_NOTHING { 2, 3, 0, 4, 5, 0}, // STATE_BOM { 2, 3, 6, 0, 5, 0}, // STATE_HAVE_CR { 7, 3, 0, 8, 9, 0}, // STATE_HAVE_CRLF { 10, 11, 0, 12, 10, 0}, // STATE_HAVE_CRLF_DOT { 10, 11, 13, 0, 10, 0}, // STATE_HAVE_CRLF_DOT_CR { 14, 15, 0, 16, 14, 0}, // STATE_HAVE_DOT { 14, 15, 17, 0, 14, 0} // STATE_HAVE_DOT_CR }; char *EncodeBody(char *pBody) { static char buf[2*LBUF_SIZE]; char *bp = buf; int iState = STATE_BOM; for (;;) { char ch = *pBody++; int iAction = BodyActions[iState][BodyClasses[(unsigned char)ch]]; switch (iAction) { case 0: // Action 0 - Remain in current state. // break; case 1: // Action 1 - Emit ch and remain in current state. // *bp++ = ch; break; case 2: // Action 2 - Emit ch and move to STATE_NOTHING. // *bp++ = ch; iState = STATE_NOTHING; break; case 3: // Action 3 - Emit CRLF.CRLF and terminate. // *bp++ = '\r'; *bp++ = '\n'; *bp++ = '.'; *bp++ = '\r'; *bp++ = '\n'; *bp++ = '\0'; return buf; break; case 4: // Action 4 - Move to STATE_HAVE_CR. // iState = STATE_HAVE_CR; break; case 5: // Action 5 - Move to STATE_HAVE_DOT. // iState = STATE_HAVE_DOT; break; case 6: // Action 6 - Move to STATE_HAVE_CRLF. // iState = STATE_HAVE_CRLF; break; case 7: // Action 7 - Emit CRLF+ch and move to STATE_NOTHING. // *bp++ = '\r'; *bp++ = '\n'; *bp++ = ch; iState = STATE_NOTHING; break; case 8: // Action 8 - Emit CRLF and move to STATE_HAVE_CR. // *bp++ = '\r'; *bp++ = '\n'; iState = STATE_HAVE_CR; break; case 9: // Action 9 - Move to STATE_HAVE_CRLF_DOT. // iState = STATE_HAVE_CRLF_DOT; break; case 10: // Action 10 - Emit CRLF..+ch and move to STATE_NOTHING. // *bp++ = '\r'; *bp++ = '\n'; *bp++ = '.'; *bp++ = '.'; *bp++ = ch; iState = STATE_NOTHING; break; case 11: // Action 11 - Emit CRLF..CRLF.CRLF and terminate. // *bp++ = '\r'; *bp++ = '\n'; *bp++ = '.'; *bp++ = '.'; *bp++ = '\r'; *bp++ = '\n'; *bp++ = '.'; *bp++ = '\r'; *bp++ = '\n'; *bp++ = '\0'; return buf; break; case 12: // Action 12 - Move to STATE_HAVE_CRLF_DOT_CR. // iState = STATE_HAVE_CRLF_DOT_CR; break; case 13: // Action 13 - Emit CRLF.. and move to STATE_HAVE_CRLF. // *bp++ = '\r'; *bp++ = '\n'; *bp++ = '.'; *bp++ = '.'; iState = STATE_HAVE_CRLF; break; case 14: // Action 14 - Emit ..+ch and move to STATE_NOTHING. // *bp++ = '.'; *bp++ = '.'; *bp++ = ch; iState = STATE_NOTHING; break; case 15: // Action 15 - Emit ..CRLF.CRLF and terminate. // *bp++ = '.'; *bp++ = '.'; *bp++ = '\r'; *bp++ = '\n'; *bp++ = '.'; *bp++ = '\r'; *bp++ = '\n'; *bp++ = '\0'; return buf; break; case 16: // Action 16 - Move to STATE_HAVE_DOT_CR. // iState = STATE_HAVE_DOT_CR; break; case 17: // Action 17 - Emit .. and move to STATE_HAVE_CRLF. // *bp++ = '.'; *bp++ = '.'; iState = STATE_HAVE_CRLF; break; } } } // Transform CRLF runs to a space. // char *ConvertCRLFtoSpace(const char *pString) { static char buf[LBUF_SIZE]; char *bp = buf; // Skip any leading CRLF as well as non-ASCII. // while ( '\r' == *pString || '\n' == *pString || (0x80 & *pString) == 0x80) { pString++; } bool bFirst = true; while (*pString) { if (!bFirst) { safe_chr(' ', buf, &bp); } else { bFirst = false; } while ( *pString && '\r' != *pString && '\n' != *pString && (0x80 & *pString) == 0x00) { safe_chr(*pString, buf, &bp); pString++; } // Skip any CRLF. // while ( '\r' == *pString || '\n' == *pString || 0x80 == (0x80 & *pString)) { pString++; } } *bp = '\0'; return buf; } // Write a formatted string to a socket. // static int DCL_CDECL mod_email_sock_printf(SOCKET sock, const char *format, ...) { va_list vargs; char mybuf[2*LBUF_SIZE]; if (IS_INVALID_SOCKET(sock)) { return 0; } va_start(vargs, format); mux_vsnprintf(mybuf, sizeof(mybuf), format, vargs); va_end(vargs); return SOCKET_WRITE(sock, &mybuf[0], strlen(mybuf), 0); } // Read a line of input from the socket. // static int mod_email_sock_readline(SOCKET sock, char *buffer, int maxlen) { buffer[0] = '\0'; if (IS_INVALID_SOCKET(sock)) { return 0; } fd_set read_fds; FD_ZERO(&read_fds); FD_SET(sock, &read_fds); // Wait up to 1 second. // struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; // Check for data before giving up. // if (IS_SOCKET_ERROR(select(sock+1, &read_fds, NULL, NULL, &tv))) { return 0; } if (!FD_ISSET(sock, &read_fds)) { return 0; } bool done = false; bool possible_close = false; int pos = 0; while ( !done && pos < maxlen) { char getme[2]; int numread = SOCKET_READ(sock, &getme[0], 1, 0); if ( IS_SOCKET_ERROR(numread) || 0 == numread) { if (possible_close) { done = true; } else { FD_ZERO(&read_fds); FD_SET(sock, &read_fds); // Wait up to 1 second. // tv.tv_sec = 1; tv.tv_usec = 0; // Check for data before giving up. // if (IS_SOCKET_ERROR(select(sock+1, &read_fds, NULL, NULL, &tv))) { done = true; } if (FD_ISSET(sock, &read_fds)) { possible_close = true; } } } else { possible_close = false; if (getme[0] != '\n') { buffer[pos++] = getme[0]; } else { done = true; } } } buffer[pos] = '\0'; return pos; } // Open a socket to a specific host/port. // static int mod_email_sock_open(const char *conhostname, int port, SOCKET *sock) { struct hostent *conhost; struct sockaddr_in name; int addr_len; conhost = gethostbyname(conhostname); if (0 == conhost) { return -1; } name.sin_port = htons(port); name.sin_family = AF_INET; memcpy((char *)&name.sin_addr, (char *)conhost->h_addr, conhost->h_length); SOCKET mysock = socket(AF_INET, SOCK_STREAM, 0); addr_len = sizeof(name); if (connect(mysock, (struct sockaddr *)&name, addr_len) == -1) { return -2; } *sock = mysock; return 0; } static int mod_email_sock_close(SOCKET sock) { return SOCKET_CLOSE(sock); } void do_plusemail(dbref executor, dbref cause, dbref enactor, int key, int nfargs, char *arg1, char *arg2) { UNUSED_PARAMETER(cause); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nfargs); char inputline[LBUF_SIZE]; if ('\0' == mudconf.mail_server[0]) { notify(executor, "@email: Not configured"); return; } if (!arg1 || !*arg1) { notify(executor, "@email: I don't know who you want to e-mail!"); return; } if (!arg2 || !*arg2) { notify(executor, "@email: Not sending an empty e-mail!"); return; } char *addy = alloc_lbuf("mod_email_do_email.headers"); char *bp = addy; safe_str(arg1, addy, &bp); *bp = '\0'; char *subject = strchr(addy, '/'); if (subject) { *subject = '\0'; subject++; } else { subject = mudconf.mail_subject; } char *pMailServer = ConvertCRLFtoSpace(mudconf.mail_server); SOCKET mailsock = INVALID_SOCKET; int result = mod_email_sock_open(pMailServer, 25, &mailsock); if (-1 == result) { notify(executor, tprintf("@email: Unable to resolve hostname %s!", pMailServer)); free_lbuf(addy); return; } else if (-2 == result) { // Periodically, we get a failed connect, for reasons which elude me. // In almost every case, an immediate retry works. Therefore, we give // it one more shot, before we give up. // result = mod_email_sock_open(pMailServer, 25, &mailsock); if (0 != result) { notify(executor, "@email: Unable to connect to mailserver, aborting!"); free_lbuf(addy); return; } } char *body = alloc_lbuf("mod_email_do_email.body"); char *bodyptr = body; char *bodysrc = arg2; mux_exec(body, &bodyptr, executor, executor, executor, EV_TOP | EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &bodysrc, NULL, 0); *bodyptr = '\0'; do { result = mod_email_sock_readline(mailsock, inputline, LBUF_SIZE - 1); } while ( 0 == result || ( 3 < result && '-' == inputline[3])); if (-1 == result) { mod_email_sock_close(mailsock); notify(executor, "@email: Connection to mailserver lost."); free_lbuf(body); free_lbuf(addy); return; } if ('2' != inputline[0]) { mod_email_sock_close(mailsock); notify(executor, tprintf("@email: Invalid mailserver greeting (%s)", inputline)); } mod_email_sock_printf(mailsock, "EHLO %s\r\n", ConvertCRLFtoSpace(mudconf.mail_ehlo)); do { result = mod_email_sock_readline(mailsock, inputline, LBUF_SIZE - 1); } while ( 0 == result || ( 3 < result && '-' == inputline[3])); if (-1 == result) { mod_email_sock_close(mailsock); notify(executor, "@email: Connection to mailserver lost."); free_lbuf(body); free_lbuf(addy); return; } if ('2' != inputline[0]) { notify(executor, tprintf("@email: Error response on EHLO (%s)", inputline)); } mod_email_sock_printf(mailsock, "MAIL FROM:<%s>\r\n", ConvertCRLFtoSpace(mudconf.mail_sendaddr)); do { result = mod_email_sock_readline(mailsock, inputline, LBUF_SIZE - 1); } while ( 0 == result || ( 3 < result && '-' == inputline[3])); if (-1 == result) { mod_email_sock_close(mailsock); notify(executor, "@email: Connection to mailserver lost."); free_lbuf(body); free_lbuf(addy); return; } if ('2' != inputline[0]) { notify(executor, tprintf("@email: Error response on MAIL FROM (%s)", inputline)); } mod_email_sock_printf(mailsock, "RCPT TO:<%s>\r\n", ConvertCRLFtoSpace(addy)); do { result = mod_email_sock_readline(mailsock, inputline, LBUF_SIZE - 1); } while ( 0 == result || ( 3 < result && '-' == inputline[3])); if (-1 == result) { mod_email_sock_close(mailsock); notify(executor, "@email: Connection to mailserver lost."); free_lbuf(body); free_lbuf(addy); return; } if ('2' != inputline[0]) { notify(executor, tprintf("@email: Error response on RCPT TO (%s)", inputline)); free_lbuf(body); free_lbuf(addy); return; } mod_email_sock_printf(mailsock, "DATA\r\n"); do { result = mod_email_sock_readline(mailsock, inputline, LBUF_SIZE - 1); } while ( 0 == result || ( 3 < result && '-' == inputline[3])); if (-1 == result) { mod_email_sock_close(mailsock); notify(executor, "@email: Connection to mailserver lost."); free_lbuf(body); free_lbuf(addy); return; } if ('3' != inputline[0]) { notify(executor, tprintf("@email: Error response on DATA (%s)", inputline)); free_lbuf(body); free_lbuf(addy); return; } char *pSendName = StringClone(ConvertCRLFtoSpace(mudconf.mail_sendname)); mod_email_sock_printf(mailsock, "From: %s <%s>\r\n", pSendName, ConvertCRLFtoSpace(mudconf.mail_sendaddr)); MEMFREE(pSendName); mod_email_sock_printf(mailsock, "To: %s\r\n", ConvertCRLFtoSpace(addy)); mod_email_sock_printf(mailsock, "X-Mailer: TinyMUX %s\r\n", mudstate.short_ver); mod_email_sock_printf(mailsock, "Subject: %s\r\n\r\n", ConvertCRLFtoSpace(subject)); // The body is encoded to include the CRLF.CRLF at the end. // mod_email_sock_printf(mailsock, "%s", EncodeBody(body)); do { result = mod_email_sock_readline(mailsock, inputline, LBUF_SIZE - 1); // Remove trailing CR and LF characters. // while ( 0 < result && ( '\n' == inputline[result-1] || '\r' == inputline[result-1])) { result--; inputline[result] = '\0'; } } while ( 0 == result || ( 3 < result && '-' == inputline[3])); if (-1 == result) { mod_email_sock_close(mailsock); notify(executor, "@email: Connection to mailserver lost."); free_lbuf(body); free_lbuf(addy); return; } if ('2' != inputline[0]) { notify(executor, tprintf("@email: Message rejected (%s)",inputline)); } else { notify(executor, tprintf("@email: Mail sent to %s (%s)", ConvertCRLFtoSpace(addy), &inputline[4])); } mod_email_sock_printf(mailsock, "QUIT\n"); mod_email_sock_close(mailsock); free_lbuf(body); free_lbuf(addy); } mux2.6/src/config.h0000600000175000017500000001751311025753746014223 0ustar sdennissdennis// config.h // // $Id: config.h 3050 2007-12-30 06:36:06Z brazilofmux $ // #ifndef CONFIG_H #define CONFIG_H /* Compile time options */ #define SIDE_EFFECT_FUNCTIONS /* Those neat funcs that should be commands */ #define PLAYER_NAME_LIMIT 22 /* Max length for player names */ #define NUM_ENV_VARS 10 /* Number of env vars (%0 et al) */ #define MAX_ARG 100 /* max # args from command processor */ #define MAX_GLOBAL_REGS 36 /* r() registers */ #define OUTPUT_BLOCK_SIZE 16384 /* --------------------------------------------------------------------------- * Database R/W flags. */ #define MANDFLAGS_V2 (V_LINK|V_PARENT|V_XFLAGS|V_ZONE|V_POWERS|V_3FLAGS|V_QUOTED) #define OFLAGS_V2 (V_DATABASE|V_ATRKEY|V_ATRNAME|V_ATRMONEY) #define MANDFLAGS_V3 (V_LINK|V_PARENT|V_XFLAGS|V_ZONE|V_POWERS|V_3FLAGS|V_QUOTED|V_ATRKEY) #define OFLAGS_V3 (V_DATABASE|V_ATRNAME|V_ATRMONEY) #define OUTPUT_VERSION 2 #ifdef MEMORY_BASED #define OUTPUT_FLAGS (MANDFLAGS_V2) #else // MEMORY_BASED #define OUTPUT_FLAGS (MANDFLAGS_V2|OFLAGS_V2) #endif // MEMORY_BASED #define UNLOAD_VERSION 2 #define UNLOAD_FLAGS (MANDFLAGS_V2) #define MIN_SUPPORTED_VERSION 1 #define MAX_SUPPORTED_VERSION 3 /* magic lock cookies */ #define NOT_TOKEN '!' #define AND_TOKEN '&' #define OR_TOKEN '|' #define LOOKUP_TOKEN '*' #define NUMBER_TOKEN '#' #define INDIR_TOKEN '@' /* One of these two should go. */ #define CARRY_TOKEN '+' /* One of these two should go. */ #define IS_TOKEN '=' #define OWNER_TOKEN '$' /* matching attribute tokens */ #define AMATCH_CMD '$' #define AMATCH_LISTEN '^' /* delimiters for various things */ #define EXIT_DELIMITER ';' #define ARG_DELIMITER '=' #define ARG_LIST_DELIM ',' /* This token is used to denote a null output delimiter. */ #define NULL_DELIM_VAR "@@" /* This is used to indent output from pretty-printing. */ #define INDENT_STR " " /* amount of object endowment, based on cost */ #define OBJECT_ENDOWMENT(cost) (((cost)/mudconf.sacfactor) + mudconf.sacadjust) /* !!! added for recycling, return value of object */ #define OBJECT_DEPOSIT(pennies) \ (((pennies) - mudconf.sacadjust)* mudconf.sacfactor) #ifdef WIN32 #define DCL_CDECL __cdecl #define DCL_INLINE __inline typedef __int64 INT64; typedef unsigned __int64 UINT64; #define INT64_MAX_VALUE 9223372036854775807i64 #define INT64_MIN_VALUE (-9223372036854775807i64 - 1) #define UINT64_MAX_VALUE 0xffffffffffffffffui64 #define LOCALTIME_TIME_T_MIN_VALUE 0 #if (_MSC_VER >= 1400) // 1400 is Visual C++ 2005 #define LOCALTIME_TIME_T_MAX_VALUE 32535215999ui64 #define MUX_ULONG_PTR ULONG_PTR #define MUX_PULONG_PTR PULONG_PTR #elif (_MSC_VER >= 1200) // 1310 is Visual C++ .NET 2003 // 1300 is Visual C++ .NET 2002 // 1200 is Visual C++ 6.0 #define MUX_ULONG_PTR DWORD #define MUX_PULONG_PTR LPDWORD #elif #error TinyMUX Requires at least version 6.0 of Visual C++. #endif #define SIZEOF_PATHNAME (_MAX_PATH + 1) #define SOCKET_WRITE(s,b,n,f) send(s,b,static_cast(n),f) #define SOCKET_READ(s,b,n,f) recv(s,b,static_cast(n),f) #define SOCKET_CLOSE(s) closesocket(s) #define IS_SOCKET_ERROR(cc) ((cc) == SOCKET_ERROR) #define IS_INVALID_SOCKET(s) ((s) == INVALID_SOCKET) #define SOCKET_LAST_ERROR (WSAGetLastError()) #define SOCKET_EINTR (WSAEINTR) #define SOCKET_EWOULDBLOCK (WSAEWOULDBLOCK) #define SOCKET_EBADF (WSAEBADF) #define popen _popen #define pclose _pclose #define mux_tzset _tzset #define mux_getpid _getpid #define mux_close _close #define mux_read _read #define mux_write _write #define mux_lseek _lseek #else // WIN32 #define DCL_CDECL #define DCL_INLINE inline #ifndef O_BINARY #define O_BINARY 0 #endif // O_BINARY typedef int HANDLE; typedef long long INT64; typedef unsigned long long UINT64; #define INT64_MAX_VALUE 9223372036854775807LL #define INT64_MIN_VALUE (-9223372036854775807LL - 1) #define UINT64_MAX_VALUE 0xffffffffffffffffULL typedef int SOCKET; #ifdef PATH_MAX #define SIZEOF_PATHNAME (PATH_MAX + 1) #else // PATH_MAX #define SIZEOF_PATHNAME (4095 + 1) #endif // PATH_MAX #define SOCKET_WRITE(s,b,n,f) mux_write(s,b,n) #define SOCKET_READ(s,b,n,f) mux_read(s,b,n) #define SOCKET_CLOSE(s) mux_close(s) #define IS_SOCKET_ERROR(cc) ((cc) < 0) #define IS_INVALID_SOCKET(s) ((s) < 0) #define SOCKET_LAST_ERROR (errno) #define SOCKET_EINTR (EINTR) #define SOCKET_EWOULDBLOCK (EWOULDBLOCK) #ifdef EAGAIN #define SOCKET_EAGAIN (EAGAIN) #endif // EAGAIN #define SOCKET_EBADF (EBADF) #define INVALID_SOCKET (-1) #define SD_BOTH (2) #define mux_tzset tzset #define mux_getpid getpid #define mux_close close #define mux_read read #define mux_write write #define mux_lseek lseek #endif // WIN32 #define isTRUE(x) ((x) != 0) // Find the minimum-sized integer type that will hold 32-bits. // Promote to 64-bits if necessary. // #if SIZEOF_INT == 4 typedef int INT32; typedef unsigned int UINT32; #ifdef CAN_UNALIGN_INT #define UNALIGNED32 #endif #elif SIZEOF_LONG == 4 typedef long INT32; typedef unsigned long UINT32; #ifdef CAN_UNALIGN_LONG #define UNALIGNED32 #endif #elif SIZEOF_SHORT == 4 typedef short INT32; typedef unsigned short UINT32; #ifdef CAN_UNALIGN_SHORT #define UNALIGNED32 #endif #else typedef INT64 INT32; typedef UINT64 UINT32; #ifdef CAN_UNALIGN_LONGLONG #define UNALIGNED32 #endif #endif // SIZEOF INT32 #define INT32_MIN_VALUE (-2147483647 - 1) #define INT32_MAX_VALUE 2147483647 #define UINT32_MAX_VALUE 0xFFFFFFFFU // Find the minimum-sized integer type that will hold 16-bits. // Promote to 32-bits if necessary. // #if SIZEOF_INT == 2 typedef int INT16; typedef unsigned int UINT16; #ifdef CAN_UNALIGN_INT #define UNALIGNED16 #endif #elif SIZEOF_LONG == 2 typedef long INT16; typedef unsigned long UINT16; #ifdef CAN_UNALIGN_LONG #define UNALIGNED16 #endif #elif SIZEOF_SHORT == 2 typedef short INT16; typedef unsigned short UINT16; #ifdef CAN_UNALIGN_SHORT #define UNALIGNED16 #endif #else typedef INT32 INT16; typedef UINT32 UINT16; #ifdef UNALIGNED32 #define UNALIGNED16 #endif #endif // SIZEOF INT16 #define INT16_MIN_VALUE (-32768) #define INT16_MAX_VALUE 32767 #define UINT16_MAX_VALUE 0xFFFFU typedef signed char INT8; typedef unsigned char UINT8; typedef UINT8 UTF8; typedef UINT8 *PUTF8; #ifndef HAVE_IN_ADDR_T typedef UINT32 in_addr_t; #endif #ifndef SMALLEST_INT_GTE_NEG_QUOTIENT #define LARGEST_INT_LTE_NEG_QUOTIENT #endif // !SMALLEST_INT_GTE_NEG_QUOTIENT extern bool AssertionFailed(const char *SourceFile, unsigned int LineNo); #define mux_assert(exp) (void)( (exp) || (AssertionFailed(__FILE__, __LINE__), 0) ) extern void OutOfMemory(const char *SourceFile, unsigned int LineNo); #define ISOUTOFMEMORY(exp) {if (!(exp)) { OutOfMemory(__FILE__, __LINE__); }} //#define MEMORY_ACCOUNTING // Memory Allocation Accounting // #ifdef MEMORY_ACCOUNTING extern void *MemAllocate(size_t n, const char *f, int l); extern void MemFree(void *p, const char *f, int l); extern void *MemRealloc(void *p, size_t n, const char *f, int l); #define MEMALLOC(n) MemAllocate((n), __FILE__, __LINE__) #define MEMFREE(p) MemFree((p), __FILE__, __LINE__) #define MEMREALLOC(p, n) MemRealloc((p), (n), __FILE__, __LINE__) #else // MEMORY_ACCOUNTING #define MEMALLOC(n) malloc((n)) #define MEMFREE(p) free((p)) #define MEMREALLOC(p, n) realloc((p),(n)) #endif // MEMORY_ACCOUNTING // If it's Hewlett Packard, then getrusage is provided a different // way. // #ifdef hpux #define HAVE_GETRUSAGE 1 #include #define getrusage(x,p) syscall(SYS_GETRUSAGE,x,p) #endif // hpux #if defined(__INTEL_COMPILER) extern "C" unsigned int __intel_cpu_indicator; #endif #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) void init_rlimit(void); #endif // HAVE_SETRLIMIT RLIMIT_NOFILE #endif // !CONFIG_H mux2.6/src/quota.cpp0000600000175000017500000001542111025753746014436 0ustar sdennissdennis// quota.cpp -- Quota Management Commands. // // $Id: quota.cpp 115 2006-09-14 17:15:09Z alierak $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "functions.h" #include "powers.h" // --------------------------------------------------------------------------- // count_quota, mung_quota, show_quota, do_quota: Manage quotas. // static int count_quota(dbref player) { if (Owner(player) != player) { return 0; } int q = 0 - mudconf.player_quota; dbref i; DO_WHOLE_DB(i) { if (Owner(i) != player) { continue; } if (Going(i) && (!isRoom(i))) { continue; } switch (Typeof(i)) { case TYPE_EXIT: q += mudconf.exit_quota; break; case TYPE_ROOM: q += mudconf.room_quota; break; case TYPE_THING: q += mudconf.thing_quota; break; case TYPE_PLAYER: q += mudconf.player_quota; break; } } return q; } static void mung_quotas(dbref player, int key, int value) { dbref aowner; int aq, rq, xq, aflags; char *buff; if (key & QUOTA_FIX) { // Get value of stuff owned and good value, set other value from that. // xq = count_quota(player); if (key & QUOTA_TOT) { buff = atr_get(player, A_RQUOTA, &aowner, &aflags); aq = mux_atol(buff) + xq; atr_add_raw(player, A_QUOTA, mux_ltoa_t(aq)); free_lbuf(buff); } else { buff = atr_get(player, A_QUOTA, &aowner, &aflags); rq = mux_atol(buff) - xq; atr_add_raw(player, A_RQUOTA, mux_ltoa_t(rq)); free_lbuf(buff); } } else { // Obtain (or calculate) current relative and absolute quota. // buff = atr_get(player, A_QUOTA, &aowner, &aflags); if (!*buff) { free_lbuf(buff); buff = atr_get(player, A_RQUOTA, &aowner, &aflags); rq = mux_atol(buff); free_lbuf(buff); aq = rq + count_quota(player); } else { aq = mux_atol(buff); free_lbuf(buff); buff = atr_get(player, A_RQUOTA, &aowner, &aflags); rq = mux_atol(buff); free_lbuf(buff); } // Adjust values. // if (key & QUOTA_REM) { aq += (value - rq); rq = value; } else { rq += (value - aq); aq = value; } // Set both abs and relative quota. // atr_add_raw(player, A_QUOTA, mux_ltoa_t(aq)); atr_add_raw(player, A_RQUOTA, mux_ltoa_t(rq)); } } static void show_quota(dbref player, dbref victim) { dbref aowner; int aq, rq, aflags; char *buff; buff = atr_get(victim, A_QUOTA, &aowner, &aflags); aq = mux_atol(buff); free_lbuf(buff); buff = atr_get(victim, A_RQUOTA, &aowner, &aflags); rq = aq - mux_atol(buff); free_lbuf(buff); if (!Free_Quota(victim)) { buff = tprintf("%-16s Quota: %9d Used: %9d", Name(victim), aq, rq); } else { buff = tprintf("%-16s Quota: UNLIMITED Used: %9d", Name(victim), rq); } notify_quiet(player, buff); } void do_quota ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *arg1, char *arg2 ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); if (!(mudconf.quotas || Quota(executor))) { notify_quiet(executor, "Quotas are not enabled."); return; } if ((key & QUOTA_TOT) && (key & QUOTA_REM)) { notify_quiet(executor, "Illegal combination of switches."); return; } dbref who; int value = 0, i; bool set = false; // Show or set all quotas if requested. // if (key & QUOTA_ALL) { if (arg1 && *arg1) { value = mux_atol(arg1); set = true; } else if (key & (QUOTA_SET | QUOTA_FIX)) { value = 0; set = true; } if (set) { STARTLOG(LOG_WIZARD, "WIZ", "QUOTA"); log_name(executor); log_text(" changed everyone's quota"); ENDLOG; } DO_WHOLE_DB(i) { if (isPlayer(i)) { if (set) { mung_quotas(i, key, value); } show_quota(executor, i); } } return; } // Find out whose quota to show or set. // if (!arg1 || *arg1 == '\0') { who = Owner(executor); } else { who = lookup_player(executor, arg1, true); if (!Good_obj(who)) { notify_quiet(executor, "Not found."); return; } } // Make sure we have permission to do it. // if (!Quota(executor)) { if (arg2 && *arg2) { notify_quiet(executor, NOPERM_MESSAGE); return; } if (Owner(executor) != who) { notify_quiet(executor, NOPERM_MESSAGE); return; } } if (arg2 && *arg2) { set = true; value = mux_atol(arg2); } else if (key & QUOTA_FIX) { set = true; value = 0; } if (set) { STARTLOG(LOG_WIZARD, "WIZ", "QUOTA"); log_name(executor); log_text(" changed the quota of "); log_name(who); ENDLOG; mung_quotas(who, key, value); } show_quota(executor, who); } FUNCTION(fun_hasquota) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!mudconf.quotas) { safe_str("#-1 Quotas are not enabled.", buff, bufc); return; } // Find out whose quota to show. // dbref who = lookup_player(executor, fargs[0], true); if (!Good_obj(who)) { safe_str("#-1 NOT FOUND", buff, bufc); return; } // Make sure we have permission to do it. // if ( Owner(executor) != who && !Quota(executor)) { safe_str(NOPERM_MESSAGE, buff, bufc); return; } bool bResult = true; if (!Free_Quota(who)) { int aflags; dbref aowner; char *quota = atr_get(who, A_RQUOTA, &aowner, &aflags); int rq = mux_atol(quota); free_lbuf(quota); bResult = (rq >= mux_atol(fargs[1])); } safe_bool(bResult, buff, bufc); } mux2.6/src/svdrand.cpp0000600000175000017500000002066711025753746014756 0ustar sdennissdennis// svdrand.cpp -- Random Numbers. // // $Id: svdrand.cpp 289 2006-10-21 01:43:33Z brazilofmux $ // // Random Numbers from Makoto Matsumoto and Takuji Nishimura. // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "timeutil.h" #include "svdhash.h" #ifdef WIN32 #include typedef BOOL WINAPI FCRYPTACQUIRECONTEXT(HCRYPTPROV *, LPCTSTR, LPCTSTR, DWORD, DWORD); typedef BOOL WINAPI FCRYPTRELEASECONTEXT(HCRYPTPROV, DWORD); typedef BOOL WINAPI FCRYPTGENRANDOM(HCRYPTPROV, DWORD, BYTE *); #else // WIN32 #include #include #include #include #endif // WIN32 // Seed the generator. // static void sgenrand(UINT32); static void sgenrand_from_array(UINT32 *, int); // Returns a random 32-bit integer. // static UINT32 genrand(void); #define NUM_RANDOM_UINT32 1024 bool bCryptoAPI = false; static bool bSeeded = false; void SeedRandomNumberGenerator(void) { if (bSeeded) return; bSeeded = true; UINT32 aRandomSystemBytes[NUM_RANDOM_UINT32]; unsigned int nRandomSystemBytes = 0; #ifdef HAVE_DEV_URANDOM // Try to seed the PRNG from /dev/urandom // If it doesn't work, just seed the normal way // int fd; if (mux_open(&fd, "/dev/urandom", O_RDONLY)) { int len = mux_read(fd, aRandomSystemBytes, sizeof aRandomSystemBytes); mux_close(fd); if (len > 0) { nRandomSystemBytes = len/sizeof(UINT32); } } #endif // HAVE_DEV_URANDOM #ifdef WIN32 // The Cryto API became available on Windows with Win95 OSR2. Using Crypto // API as follows lets us to fallback gracefully when running on pre-OSR2 // Win95. // bCryptoAPI = false; HINSTANCE hAdvAPI32 = LoadLibrary("advapi32"); if (hAdvAPI32) { FCRYPTACQUIRECONTEXT *fpCryptAcquireContext; FCRYPTRELEASECONTEXT *fpCryptReleaseContext; FCRYPTGENRANDOM *fpCryptGenRandom; // Find the entry points for CryptoAcquireContext, CrytpoGenRandom, // and CryptoReleaseContext. // fpCryptAcquireContext = (FCRYPTACQUIRECONTEXT *) GetProcAddress(hAdvAPI32, "CryptAcquireContextA"); fpCryptReleaseContext = (FCRYPTRELEASECONTEXT *) GetProcAddress(hAdvAPI32, "CryptReleaseContext"); fpCryptGenRandom = (FCRYPTGENRANDOM *) GetProcAddress(hAdvAPI32, "CryptGenRandom"); if ( fpCryptAcquireContext && fpCryptReleaseContext && fpCryptGenRandom) { HCRYPTPROV hProv; if ( fpCryptAcquireContext(&hProv, NULL, NULL, PROV_DSS, 0) || fpCryptAcquireContext(&hProv, NULL, NULL, PROV_DSS, CRYPT_NEWKEYSET)) { if (fpCryptGenRandom(hProv, sizeof aRandomSystemBytes, (BYTE *)aRandomSystemBytes)) { nRandomSystemBytes = NUM_RANDOM_UINT32; bCryptoAPI = true; } fpCryptReleaseContext(hProv, 0); } } FreeLibrary(hAdvAPI32); } #endif // WIN32 if (nRandomSystemBytes >= sizeof(UINT32)) { unsigned int i; for (i = 0; i < nRandomSystemBytes; i++) { aRandomSystemBytes[i] &= 0xFFFFFFFFUL; } sgenrand_from_array(aRandomSystemBytes, nRandomSystemBytes); return; } // Determine the initial seed. // CLinearTimeAbsolute lsaNow; lsaNow.GetUTC(); INT64 i64Seed = lsaNow.Return100ns(); int pid = mux_getpid(); UINT32 nSeed = CRC32_ProcessBuffer(0, &i64Seed, sizeof(INT64)); nSeed = CRC32_ProcessBuffer(nSeed, &pid, sizeof(pid)); if (nSeed <= 1000) { nSeed += 22261048; } // ASSERT: 1000 < nSeed sgenrand(nSeed); } // RandomINT32 -- return a long on the interval [lLow, lHigh] // INT32 RandomINT32(INT32 lLow, INT32 lHigh) { // Validate parameters // if (lHigh < lLow) { return -1; } else if (lHigh == lLow) { return lLow; } UINT32 x = lHigh-lLow; if (INT32_MAX_VALUE < x) { return -1; } x++; // We can now look for an random number on the interval [0,x-1]. // // In order to be perfectly conservative about not introducing any // further sources of statistical bias, we're going to call genrand() // until we get a number less than the greatest representable // multiple of x. We'll then return n mod x. // // N.B. This loop happens in randomized constant time, and pretty // damn fast randomized constant time too, since // // P(UINT32_MAX_VALUE - n < UINT32_MAX_VALUE % x) < 0.5, for any x. // // So even for the least desireable x, the average number of times // we will call genrand() is less than 2. // UINT32 n; UINT32 nLimit = UINT32_MAX_VALUE - (UINT32_MAX_VALUE%x); do { n = genrand(); } while (n >= nLimit); return lLow + (n % x); } /* A C-program for MT19937, with initialization improved 2002/2/10.*/ /* Coded by Takuji Nishimura and Makoto Matsumoto. */ /* This is a faster version by taking Shawn Cokus's optimization, */ /* Matthe Bellew's simplification, Isaku Wada's real version. */ /* Before using, initialize the state by using init_genrand(seed) */ /* or init_by_array(init_key, key_length). */ /* This library is free software. */ /* 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. */ /* Copyright (C) 1997, 2002 Makoto Matsumoto and Takuji Nishimura. */ /* Any feedback is very welcome. */ /* http://www.math.keio.ac.jp/matumoto/emt.html */ /* email: matumoto@math.keio.ac.jp */ #define N 624 #define M 397 #define MATRIX_A 0x9908b0dfUL #define UMASK 0x80000000UL // most significant w-r bits #define LMASK 0x7fffffffUL // least significant r bits #define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) ) #define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL)) static UINT32 mt[N]; static int left = 1; static UINT32 *next; // initializes mt[N] with a seed. // static void sgenrand(UINT32 nSeed) { int j; mt[0] = nSeed & 0xffffffffUL; for (j = 1; j < N; j++) { // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. // In the previous versions, MSBs of the seed affect // only MSBs of the array mt[]. // 2002/01/09 modified by Makoto Matsumoto. // mt[j] = 1812433253UL * (mt[j-1] ^ (mt[j-1] >> 30)) + j; mt[j] &= 0xffffffffUL; // for >32 bit machines. } left = 1; } // initialize by an array with array-length // init_key is the array for initializing keys // key_length is its length // static void sgenrand_from_array(UINT32 *init_key, int key_length) { sgenrand(19650218UL); int i = 1; int j = 0; int k = (N > key_length ? N : key_length); for (; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; mt[i] &= 0xffffffffUL; // for > 32-bit machines. i++; j++; if (i >= N) { mt[0] = mt[N-1]; i = 1; } if (j >= key_length) { j = 0; } } for (k = N-1; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i; mt[i] &= 0xffffffffUL; // for > 32-bit machines. i++; if (i >= N) { mt[0] = mt[N-1]; i = 1; } } mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ left = 1; } static void next_state(void) { UINT32 *p = mt; int j; if (!bSeeded) { SeedRandomNumberGenerator(); } for (j = N-M+1; --j; p++) { *p = p[M] ^ TWIST(p[0], p[1]); } for (j = M; --j; p++) { *p = p[M-N] ^ TWIST(p[0], p[1]); } *p = p[M-N] ^ TWIST(p[0], mt[0]); left = N; next = mt; } // generates a random number on the interval [0,0xffffffff] // static UINT32 genrand(void) { UINT32 y; if (--left == 0) { next_state(); } y = *next++; // Tempering. // y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } mux2.6/src/muxcli.h0000600000175000017500000000106511025753746014252 0ustar sdennissdennis// muxcli.h // // $Id: muxcli.h 2475 2007-09-15 16:18:35Z brazilofmux $ // #define CLI_USER 0 // The following control whether an option is allowed/required. // #define CLI_NONE 0 #define CLI_OPTIONAL 1 #define CLI_REQUIRED 2 typedef struct { const char *m_Flag; int m_ArgControl; int m_Unique; } CLI_OptionEntry; typedef void CLI_CALLBACKFUNC(CLI_OptionEntry *pOption, const char *Value); void CLI_Process ( int argc, char *argv[], CLI_OptionEntry *aOptionTable, int nOptionTable, CLI_CALLBACKFUNC *pFunc ); mux2.6/src/copyright.h0000600000175000017500000002227011025753746014762 0ustar sdennissdennis/* copyright.h */ /* -*-C-*- */ /* $Id: copyright.h 8 2006-09-05 01:55:58Z brazilofmux $ */ /* * MUX Source Code (version 2.0 through 2.6). * Copyright (C) 1999-2004 by Solid Vertical Domains, Ltd. * Copyright (C) 2005-2006 Stephen Dennis * * TinyMUX Source Code (versions 1.0 through 1.6) * Copyright (c) 1995, 1996, 1997, 1998, 1999, David Passmore. * * TinyMUSH 2.2 Source Code * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, Lydia Leong, * Jean Marie Diaz, and Deborah Wilson-Hooker. * * TinyMUSH 2.0 Source code * Copyright (c) 1991, Joseph Traub and Glenn Crocker. All rights reserved. * * Based on TinyMUD code * Copyright (c) 1995, David Applegate, James Aspnes, Timothy Freeman, * and Bennet Yee. All rights reserved. * (Modified by these authors from the original 1989, 1990 TinyMUD copyright.) * * * TinyMUX 2.0 is a derivation of TinyMUX 1.6 which is a derivation of * TinyMUSH 2.0.10 patchlevel 6. TinyMUSH 2.0 is dervived from TinyMUD. * * There are also portions of source code derived from PennMUSH 1.50. * * The TinyMUD copyright follows below. PennMUSH, TinyMUSH 2.0 and * TinyMUX 1.6 are now released under the OSI-standard Artistic License. * * * Revised TinyMUD copyright: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, * and (2) distributions including binary code include the above copyright * notice and this paragraph in its entirety in the documentation or other * materials provided with the distribution. The names of the copyright * holders may not be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * TinyMUX 2.6 Copyright: The Artistic License * * Preamble * * The intent of this document is to state the conditions under which a * Package may be copied, such that the Copyright Holder maintains some * semblance of artistic control over the development of the package, * while giving the users of the package the right to use and distribute * the Package in a more-or-less customary fashion, plus the right to * make reasonable modifications. * * Definitions: * - "Package" refers to the collection of files distributed by the * Copyright Holder, and derivatives of that collection of files * created through textual modification. * - "Standard Version" refers to such a Package if it has not been * modified, or has been modified in accordance with the wishes of * the Copyright Holder. * - "Copyright Holder" is whoever is named in the copyright or * copyrights for the package. * - "You" is you, if you're thinking about copying or distributing * this Package. * - "Reasonable copying fee" is whatever you can justify on the basis * of media cost, duplication charges, time of people involved, and * so on. (You will not be required to justify it to the Copyright * Holder, but only to the computing community at large as a market * that must bear the fee.) * - "Freely Available" means that no fee is charged for the item * itself, though there may be fees involved in handling the item. It * also means that recipients of the item may redistribute it under * the same conditions they received it. * * 1. You may make and give away verbatim copies of the source form of * the Standard Version of this Package without restriction, provided * that you duplicate all of the original copyright notices and * associated disclaimers. * * 2. You may apply bug fixes, portability fixes and other modifications * derived from the Public Domain or from the Copyright Holder. A Package * modified in such a way shall still be considered the Standard Version. * * 3. You may otherwise modify your copy of this Package in any way, * provided that you insert a prominent notice in each changed file * stating how and when you changed that file, and provided that you do * at least ONE of the following: * * a) place your modifications in the Public Domain or otherwise make * them Freely Available, such as by posting said modifications to * Usenet or an equivalent medium, or placing the modifications on a * major archive site such as ftp.uu.net, or by allowing the Copyright * Holder to include your modifications in the Standard Version of the * Package. * * b) use the modified Package only within your corporation or * organization. * * c) rename any non-standard executables so the names do not conflict * with standard executables, which must also be provided, and provide * a separate manual page for each non-standard executable that * clearly documents how it differs from the Standard Version. * d) make other distribution arrangements with the Copyright Holder. * * 4. You may distribute the programs of this Package in object code or * executable form, provided that you do at least ONE of the following: * * a) distribute a Standard Version of the executables and library * files, together with instructions (in the manual page or * equivalent) on where to get the Standard Version. * * b) accompany the distribution with the machine-readable source of * the Package with your modifications. * * c) accompany any non-standard executables with their corresponding * Standard Version executables, giving the non-standard executables * non-standard names, and clearly documenting the differences in * manual pages (or equivalent), together with instructions on where * to get the Standard Version. * * d) make other distribution arrangements with the Copyright Holder. * * 5. You may charge a reasonable copying fee for any distribution of * this Package. You may charge any fee you choose for support of this * Package. You may not charge a fee for this Package itself. However, * you may distribute this Package in aggregate with other (possibly * commercial) programs as part of a larger (possibly commercial) * software distribution provided that you do not advertise this Package * as a product of your own. * * 6. The scripts and library files supplied as input to or produced as * output from the programs of this Package do not automatically fall * under the copyright of this Package, but belong to whomever generated * them, and may be sold commercially, and may be aggregated with this * Package. * * 7. C or perl subroutines supplied by you and linked into this Package * shall not be considered part of this Package. * * 8. The name of the Copyright Holder may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * The author may be reached via email at brazilofmux@gmail.com. * * * * TinyMUX 1.6 Credits: * * James Callahan (Darkenelf), who contributed many patches, and ideas * (@teleport/quiet, @readcache fixes, side effect functions, many bug fixes). * * Chris (Children of the Atom) for many ideas and many bug finds. * * Ralph Melton (Rhyanna@Castle D'Image) for bugs reports, patches, ideas, * and extensions. * * T. Alexander Popiel for bug reports, patches, ideas, and extensions, too. * * Al Brown (Kalkin@DarkZone) for many clever ideas * * Kalkin(DarkZone) and Harlock(StarWarsII) who extended the comsystem and * added tons of new commands. * * Kalkin, again, for the basis of the mail alias and guest code, and the * idea of restarting on a fatal signal. * * Alan Schwartz (Javelin/Paul) and Lydia Leong (Amberyl), whose extended * mailer from PennMUSH is the basis for MUX's @mail system. Also, Brandy * (CrystalMUSH) whose +mail system inspired many of the features. * * Ethaniel and Kayan Telva (BTech3056) for the basic comsystem and macro * code. * * Dreamline(Horizons) who helped update the help text. * * Airam(Generations) for ideas on the stack and @program code. * * Mike(StarWars), idea for not saving GOING objects, and mail expiration * code. * * Dean Gaudet, for his user and hostname slave process code. * * Andrew Molitor, for the radix compression library, and some wonderful * utilities. * * Robby Griffin, whose skill in uncovering obscure bugs has saved * everyone a lot of time and effort. * * Many others. * * * TinyMUSH 2.0 Credits: * Lawrence Foard: * Wrote the original TinyMUSH 1.0 code from which this later derived. * Jin (and MicroMUSH): * Made many, many changes to the code that improved it immensely. * Robert Hood (virus): * Modified the interface.c code to support alots of users. * Lachesis: * Introduced the idea of property lists to TinyMUCK * Many others: * Many features borrowed from other muds. * */ mux2.6/src/mudconf.h0000600000175000017500000006253111025753746014411 0ustar sdennissdennis// mudconf.h // // $Id: mudconf.h 3420 2008-03-26 02:49:27Z brazilofmux $ // #ifndef __CONF_H #define __CONF_H #include "alloc.h" #include "htab.h" #include "stringutil.h" #ifndef WIN32 #include #endif // !WIN32 #define WIDTHOF_DOING_STRING 45 #define SIZEOF_DOING_STRING (2*WIDTHOF_DOING_STRING) /* CONFDATA: runtime configurable parameters */ typedef struct tag_int_array { int n; int *pi; } IntArray; typedef struct { const char *CommandName; CHashTable *ht; char *pBaseFilename; bool bEval; } HELP_DESC; typedef struct confdata CONFDATA; struct confdata { bool allow_guest_from_registered_site; // Whether guests from registered sites are allowed. bool autozone; // New objects are automatically zoned. bool cache_names; /* Should object names be cached separately */ bool clone_copy_cost; /* Does @clone copy value? */ bool compress_db; // should we use compress. bool dark_sleepers; /* Are sleeping players 'dark'? */ bool destroy_going_now; // Does GOING act like DESTROY_OK? bool eval_comtitle; /* Should Comtitles Evaluate? */ bool ex_flags; /* true = show flags on examine */ bool exam_public; /* Does EXAM show public attrs by default? */ bool fascist_tport; /* Src of teleport must be owned/JUMP_OK */ bool fork_dump; // perform dump in a forked process. bool have_comsys; // Should the comsystem be active? bool have_mailer; // Should @mail be active? bool have_zones; // Should zones be active? bool idle_wiz_dark; /* Do idling wizards get set dark? */ bool indent_desc; // Newlines before and after descs? bool match_mine; /* Should you check yourself for $-commands? */ bool match_mine_pl; /* Should players check selves for $-cmds? */ bool name_spaces; // allow player names to have spaces. bool paranoid_alloc; /* Rigorous buffer integrity checks */ bool pemit_any; /* Can you @pemit to ANY remote object? */ bool pemit_players; /* Can you @pemit to faraway players? */ bool player_listen; /* Are AxHEAR triggered on players? */ bool pub_flags; /* true = flags() works on anything */ bool quiet_look; /* true = don't see attribs when looking */ bool quiet_whisper; /* Can others tell when you whisper? */ bool quotas; /* true = have building quotas */ bool read_rem_desc; /* Can the DESCs of nonlocal objs be read? */ bool read_rem_name; /* Can the NAMEs of nonlocal objs be read? */ bool reset_players; // Reset the maximum player stat. bool robot_speak; /* true = allow robots to speak */ bool run_startup; // If no, startup attributes aren't processed on load. bool safe_unowned; /* Are objects not owned by you safe? */ bool safe_wipe; // If yes, SAFE flag must be removed to @wipe. bool safer_passwords; /* enforce reasonably good password choices? */ bool see_own_dark; /* Do you see your own dark stuff? */ bool space_compress; /* Convert multiple spaces into one space */ bool sweep_dark; /* Can you sweep dark places? */ bool switch_df_all; /* Should @switch match all by default? */ bool terse_contents; /* Does TERSE look show exits */ bool terse_exits; /* Does TERSE look show obvious exits */ bool terse_look; /* Does manual look obey TERSE */ bool terse_movemsg; /* Show move msgs (SUCC/LEAVE/etc) if TERSE? */ bool trace_topdown; /* Is TRACE output top-down or bottom-up? */ bool use_hostname; /* true = use machine NAME rather than quad */ dbref default_home; // HOME when home is inaccessable. dbref global_error_obj; // Object that is used to generate error messages. dbref guest_char; // player num of prototype GUEST character. dbref guest_nuker; // Wiz who nukes the GUEST characters. dbref hook_obj; // Object with @hook data. dbref master_room; // Room containing default cmds/exits/etc. dbref start_home; // initial HOME for players. dbref start_room; // initial location and home for players. dbref toad_recipient; /* Default @toad recipient. */ int active_q_chunk; /* # cmds to run from queue when active */ int cache_pages; // Size of hash page cache (in pages). int check_interval; /* interval between db check/cleans in secs */ int check_offset; /* when to perform first check and clean */ int cmd_quota_incr; /* Bump #cmds allowed by this each timeslice */ int cmd_quota_max; /* Max commands at one time */ int conn_timeout; /* Allow this long to connect before booting */ int control_flags; /* Global runtime control flags */ int createmax; /* max cost of @create command */ int createmin; /* default (and minimum) cost of @create cmd */ int digcost; /* cost of @dig command */ int dump_interval; /* interval between ckp dumps in seconds */ int dump_offset; /* when to take first checkpoint dump */ int events_daily_hour; /* At what hour should @daily be executed? */ int exit_quota; /* quota needed to make an exit */ int func_invk_lim; /* Max funcs invoked by a command */ int func_nest_lim; /* Max nesting of functions */ int hook_cmd; // @hooks to be initialized. int idle_interval; /* when to check for idle users */ int idle_timeout; /* Boot off players idle this long in secs */ int init_size; // initial db size. int killguarantee; /* cost of kill cmd that guarantees success */ int killmax; /* max cost of kill command */ int killmin; /* default (and minimum) cost of kill cmd */ int linkcost; /* cost of @link command */ int lock_nest_lim; /* Max nesting of lock evals */ int log_info; /* Info that goes into log entries */ int log_options; /* What gets logged */ int machinecost; /* One in mc+1 cmds costs 1 penny (POW2-1) */ int mail_expiration; /* Number of days to wait to delete mail */ int mail_per_hour; // Maximum sent @mail per hour per object. int max_players; /* Max # of connected players */ int min_guests; // The # we should start nuking at. int nStackLimit; // Current stack limit. #ifdef REALITY_LVLS int no_levels; /* Number of reality levels */ struct rlevel_def { char name[9]; /* Rlevel name */ RLEVEL value; /* Rlevel bitmask */ char attr[33]; /* desc attribute */ } reality_level[32]; /* Reality levels */ RLEVEL def_room_rx; /* Default room RX level */ RLEVEL def_room_tx; /* Default room TX level */ RLEVEL def_player_rx; /* Default player RX level */ RLEVEL def_player_tx; /* Default player RX level */ RLEVEL def_exit_rx; /* Default exit RX level */ RLEVEL def_exit_tx; /* Default exit TX level */ RLEVEL def_thing_rx; /* Default thing RX level */ RLEVEL def_thing_tx; /* Default thing TX level */ #endif // REALITY_LVLS int ntfy_nest_lim; /* Max nesting of notifys */ int number_guests; // number of guest characters allowed. int opencost; /* cost of @open command */ int output_limit; /* Max # chars queued for output */ int pagecost; /* cost of @page command */ int parent_nest_lim; /* Max levels of parents */ int paycheck; /* players earn this much each day connected */ int payfind; /* chance to find a penny with wandering */ int paylimit; /* getting money gets hard over this much */ int paystart; /* new players start with this much money */ int player_quota; /* quota needed to make a robot player */ int pcreate_per_hour; // Maximum allowed players created per hour */ int queue_chunk; /* # cmds to run from queue when idle */ int queuemax; /* max commands a player may have in queue */ int retry_limit; /* close conn after this many bad logins */ int robotcost; /* cost of @robot command */ int room_quota; /* quota needed to make a room */ int sacadjust; /* sacrifice earns (obj_cost/sfactor) + sadj */ int sacfactor; /* ... */ int searchcost; /* cost of commands that search the whole DB */ int sig_action; // What to do with fatal signals. int stack_limit; /* How big can stacks get? */ int start_quota; /* Quota for new players */ int thing_quota; /* quota needed to make a thing */ int trace_limit; /* Max lines of trace output if top-down */ int vattr_flags; /* Attr flags for all user-defined attrs */ int vattr_per_hour; // Maximum allowed vattrs per hour per object. int waitcost; /* cost of @wait (refunded when finishes) */ int wild_invk_lim; // Max Regular Expression function calls. int zone_nest_lim; /* Max nesting of zones */ int restrict_home; // Special condition to restrict 'home' command int float_precision; // Maximum precision of float-to-string conversion. int lbuf_size; // LBUF_SIZE accessible to softcode. unsigned int max_cache_size; /* Max size of attribute cache */ unsigned int site_chars; // where to truncate site name. IntArray ports; // user ports. char guest_prefix[32]; /* Prefix for the guest char's name */ char guests_channel[32]; /* Name of guests channel */ char guests_channel_alias[32]; /* Name of guests channel alias */ char many_coins[32]; /* name of many coins (ie. "pennies") */ char mud_name[32]; /* Name of the mud */ char one_coin[32]; /* name of one coin (ie. "penny") */ char public_channel[32]; /* Name of public channel */ char public_channel_alias[32]; /* Name of public channel alias */ char dump_msg[256]; /* Message displayed when @dump-ing */ char fixed_home_msg[128]; /* Message displayed when going home and FIXED */ char fixed_tel_msg[128]; /* Message displayed when teleporting and FIXED */ char postdump_msg[256]; /* Message displayed after @dump-ing */ #ifdef FIRANMUX char immobile_msg[128]; /* Message displayed to immobile players */ #endif // FIRANMUX #ifdef FIRANMUX char sql_server[128]; char sql_user[128]; char sql_password[128]; char sql_database[128]; #endif // FIRANMUX char mail_server[128]; char mail_ehlo[128]; char mail_sendaddr[128]; char mail_sendname[128]; char mail_subject[128]; char downmotd_msg[GBUF_SIZE]; /* Settable 'logins disabled' message */ char fullmotd_msg[GBUF_SIZE]; /* Settable 'Too many players' message */ char motd_msg[GBUF_SIZE]; /* Wizard-settable login message */ char pueblo_msg[GBUF_SIZE]; /* Message displayed to Pueblo clients */ char wizmotd_msg[GBUF_SIZE]; /* Login message for wizards only */ char *compress; /* program to run to compress */ char *comsys_db; /* name of the comsys db */ char *config_file; /* name of config file, used by @restart */ char *conn_file; /* display on connect if no registration */ char *crashdb; /* write database here on crash */ char *crea_file; /* display this on login for new users */ char *creg_file; /* display on connect if registration */ char *down_file; /* display this file if no logins */ char *full_file; /* display when max users exceeded */ char *game_dir; /* use this game CHashFile DIR file if we need one */ char *game_pag; /* use this game CHashFile PAG file if we need one */ char *guest_file; /* display if guest connects */ char *indb; /* database file name */ char *log_dir; /* directory for logging from the cmd line */ char *mail_db; /* name of the @mail database */ char *motd_file; /* display this file on login */ char *outdb; /* checkpoint the database to here */ char *quit_file; /* display on quit */ char *regf_file; /* display on (failed) create if reg is on */ char *site_file; /* display if conn from bad site */ char *status_file; /* Where to write arg to @shutdown */ char *uncompress; /* program to run to uncompress */ char *wizmotd_file; /* display this file on login to wizards */ const char *pid_file; // file for communicating process id back to ./Startmux unsigned char markdata[8]; /* Masks for marking/unmarking */ CLinearTimeDelta rpt_cmdsecs; /* Reporting Threshhold for time taken by command */ CLinearTimeDelta max_cmdsecs; /* Upper Limit for real time taken by command */ CLinearTimeDelta cache_tick_period; // Minor cycle for cache maintenance. CLinearTimeDelta timeslice; // How often do we bump people's cmd quotas? FLAGSET exit_flags; /* Flags exits start with */ FLAGSET player_flags; /* Flags players start with */ FLAGSET robot_flags; /* Flags robots start with */ FLAGSET room_flags; /* Flags rooms start with */ FLAGSET thing_flags; /* Flags things start with */ FLAGSET stripped_flags; // Flags stripped by @chown, @chownall, and @clone. ArtRuleset* art_rules; /* Rulesets for defining exceptions. */ }; extern CONFDATA mudconf; typedef struct site_data SITE; struct site_data { struct site_data *next; /* Next site in chain */ struct in_addr address; /* Host or network address */ struct in_addr mask; /* Mask to apply before comparing */ int flag; /* Value to return on match */ }; typedef struct objlist_block OBLOCK; struct objlist_block { struct objlist_block *next; dbref data[(LBUF_SIZE - sizeof(OBLOCK *)) / sizeof(dbref)]; }; #define OBLOCK_SIZE ((LBUF_SIZE - sizeof(OBLOCK *)) / sizeof(dbref)) typedef struct objlist_stack OLSTK; struct objlist_stack { struct objlist_stack *next; /* Next object list in stack */ OBLOCK *head; /* Head of object list */ OBLOCK *tail; /* Tail of object list */ OBLOCK *cblock; /* Current block for scan */ unsigned int count; /* Number of objs in last obj list block */ unsigned int citm; /* Current item for scan */ }; typedef struct markbuf MARKBUF; struct markbuf { char chunk[5000]; }; typedef struct alist ALIST; struct alist { char *data; size_t len; struct alist *next; }; typedef struct badname_struc BADNAME; struct badname_struc { char *name; struct badname_struc *next; }; typedef struct forward_list FWDLIST; struct forward_list { int count; dbref *data; }; #define MAX_ITEXT 100 typedef struct statedata STATEDATA; struct statedata { bool bCanRestart; // are we ready to even attempt a restart. bool bReadingConfiguration; // are we reading the config file at startup? bool bStackLimitReached; // Was stack slammed? bool bStandAlone; // Are we running in dbconvert mode. bool panicking; // are we in the middle of dying horribly? bool shutdown_flag; /* Should interface be shut down? */ bool inpipe; // Are we collecting output for a pipe? #ifndef WIN32 bool restarting; // Are we restarting? volatile bool dumping; // Are we dumping? volatile pid_t dumper; // PID of dumping process (as returned by fork()). volatile pid_t dumped; // PID of dumping process (as given by SIGCHLD). bool write_protect; // Write-protect against modifications to the // database during dumps. #endif // !WIN32 dbref curr_enactor; /* Who initiated the current command */ dbref curr_executor; /* Who is running the current command */ dbref freelist; /* Head of object freelist */ dbref mod_al_id; /* Where did mod_alist come from? */ dbref poutobj; /* Object doing the piping */ int attr_next; /* Next attr to alloc when freelist is empty */ int db_size; /* Allocated size of db structure */ int db_top; /* Number of items in the db */ int epoch; /* Generation number for dumps */ int events_flag; /* Flags for check_events */ int func_invk_ctr; /* Functions invoked so far by this command */ int func_nest_lev; /* Current nesting of functions */ int generation; /* DB global generation number */ int in_loop; // Loop nesting level. int lock_nest_lev; /* Current nesting of lock evals */ int logging; /* Are we in the middle of logging? */ int mail_db_size; /* Like db_size */ int mail_db_top; /* Like db_top */ int mHelpDesc; // Number of entries allocated. int min_size; /* Minimum db size (from file header) */ int mstat_curr; /* Which sample is latest */ int nHelpDesc; // Number of entries used. int nObjEvalNest; // The nesting level of objeval() invocations. int nStackNest; // Current stack depth. int nHearNest; // Current aahear depth. int pipe_nest_lev; // Number of piped commands. int pcreates_this_hour; // Player creations possible this hour. int ntfy_nest_lev; // Current nesting of notifys. int train_nest_lev; // Current nesting of train. int record_players; // The maximum # of player logged on. int wild_invk_ctr; // Regular Expression function calls. int zone_nest_num; /* Global current zone nest position */ int mstat_idrss[2]; /* Summed private data size */ int mstat_isrss[2]; /* Summed private stack size */ int mstat_ixrss[2]; /* Summed shared size */ int mstat_secs[2]; /* Time of samples */ int inum[MAX_ITEXT]; // Number of iter(). Equivalent to #@. int *guest_free; /* Table to keep track of free guests */ size_t mod_alist_len; /* Length of mod_alist */ size_t mod_size; /* Length of modified buffer */ char short_ver[64]; /* Short version number (for INFO) */ char doing_hdr[SIZEOF_DOING_STRING]; /* Doing column header in the WHO display */ char version[128]; /* MUX version string */ const char *curr_cmd; // The current command. const char *debug_cmd; // The command we are executing (if any). char *mod_alist; /* Attribute list for modifying */ char *pout; /* The output of the pipe used in %| */ char *poutbufc; /* Buffer position for poutnew */ char *poutnew; /* The output being build by the current command */ char *itext[MAX_ITEXT]; // Text of iter(). Equivalent to ##. reg_ref *global_regs[MAX_GLOBAL_REGS]; /* Global registers */ ALIST iter_alist; /* Attribute list for iterations */ BADNAME *badname_head; /* List of disallowed names */ HELP_DESC *aHelpDesc; // Table of help files hashes. MARKBUF *markbits; /* temp storage for marking/unmarking */ OLSTK *olist; /* Stack of object lists for nested searches */ SITE *suspect_list; /* Sites that are suspect */ SITE *access_list; /* Access states for sites */ CLinearTimeAbsolute check_counter; /* Countdown to next db check */ CLinearTimeAbsolute cpu_count_from; /* When did we last reset CPU counters? */ CLinearTimeAbsolute dump_counter; /* Countdown to next db dump */ CLinearTimeAbsolute events_counter; /* Countdown to next events check */ CLinearTimeAbsolute idle_counter; /* Countdown to next idle check */ CLinearTimeAbsolute start_time; /* When was MUX started */ CLinearTimeAbsolute tThrottleExpired; // How much time is left in this hour of throttling. #if !defined(MEMORY_BASED) CHashTable acache_htab; // Attribute Cache #endif // MEMORY_BASED CHashTable attr_name_htab; /* Attribute names hashtable */ CHashTable channel_htab; /* Channels hashtable */ CHashTable command_htab; /* Commands hashtable */ CHashTable desc_htab; /* Socket descriptor hashtable */ CHashTable flags_htab; /* Flags hashtable */ CHashTable func_htab; /* Functions hashtable */ CHashTable fwdlist_htab; /* Room forwardlists */ CHashTable logout_cmd_htab; /* Logged-out commands hashtable (WHO, etc) */ CHashTable mail_htab; /* Mail players hashtable */ CHashTable parent_htab; /* Parent $-command exclusion */ CHashTable player_htab; /* Player name->number hashtable */ CHashTable powers_htab; /* Powers hashtable */ #ifdef PARSE_TREES CHashTable tree_htab; /* Parse trees for evaluation */ #endif // PARSE_TREES CHashTable ufunc_htab; /* Local functions hashtable */ CHashTable vattr_name_htab; /* User attribute names hashtable */ CBitField bfNoListens; // Cache knowledge that there are no ^-Commands. CBitField bfNoCommands; // Cache knowledge that there are no $-Commands. CBitField bfCommands; // Cache knowledge that there are $-Commands. CBitField bfListens; // Cache knowledge that there are ^-Commands. CBitField bfReport; // Used for LROOMS. CBitField bfTraverse; // Used for LROOMS. }; extern STATEDATA mudstate; /* Configuration parameter handler definition */ #define CF_HAND(proc) int proc(int *vp, char *str, void *pExtra, UINT32 nExtra, dbref player, char *cmd) /* Global flags */ // Game control flags in mudconf.control_flags. // #define CF_LOGIN 0x0001 /* Allow nonwiz logins to the mux */ #define CF_BUILD 0x0002 /* Allow building commands */ #define CF_INTERP 0x0004 /* Allow object triggering */ #define CF_CHECKPOINT 0x0008 /* Perform auto-checkpointing */ #define CF_DBCHECK 0x0010 /* Periodically check/clean the DB */ #define CF_IDLECHECK 0x0020 /* Periodically check for idle users */ #define CF_GUEST 0x0040 /* Allow guest logins to the mux */ /* empty 0x0080 */ #define CF_DEQUEUE 0x0100 /* Remove entries from the queue */ #ifdef MUSH3 #define CF_GODMONITOR 0x0200 // Display commands to the god. #endif // MUSH3 #define CF_EVENTCHECK 0x0400 // Allow events checking. // Host information codes // #define H_REGISTRATION 0x0001 /* Registration ALWAYS on */ #define H_FORBIDDEN 0x0002 /* Reject all connects */ #define H_SUSPECT 0x0004 /* Notify wizards of connects/disconnects */ #define H_GUEST 0x0008 // Don't permit guests from here #define H_NOSITEMON 0x0010 // Block SiteMon Information // Event flags, for noting when an event has taken place. // #define ET_DAILY 0x00000001 /* Daily taken place? */ /* Logging options */ #define LOG_ALLCOMMANDS 0x00000001 /* Log all commands */ #define LOG_ACCOUNTING 0x00000002 /* Write accounting info on logout */ #define LOG_BADCOMMANDS 0x00000004 /* Log bad commands */ #define LOG_BUGS 0x00000008 /* Log program bugs found */ #define LOG_DBSAVES 0x00000010 /* Log database dumps */ #define LOG_CONFIGMODS 0x00000020 /* Log changes to configuration */ #define LOG_PCREATES 0x00000040 /* Log character creations */ #define LOG_KILLS 0x00000080 /* Log KILLs */ #define LOG_LOGIN 0x00000100 /* Log logins and logouts */ #define LOG_NET 0x00000200 /* Log net connects and disconnects */ #define LOG_SECURITY 0x00000400 /* Log security-related events */ #define LOG_SHOUTS 0x00000800 /* Log shouts */ #define LOG_STARTUP 0x00001000 /* Log nonfatal errors in startup */ #define LOG_WIZARD 0x00002000 /* Log dangerous things */ #define LOG_ALLOCATE 0x00004000 /* Log alloc/free from buffer pools */ #define LOG_PROBLEMS 0x00008000 /* Log runtime problems */ #define LOG_SUSPECTCMDS 0x00020000 // Log SUSPECT player keyboard commands. #ifdef MUSH3 #define LOG_KBCOMMANDS 0x00010000 // Log keyboard commands. #endif // MUSH3 #define LOG_TIMEUSE 0x00040000 // Log CPU time usage. #define LOG_ALWAYS 0x80000000 /* Always log it */ #define LOGOPT_FLAGS 0x01 /* Report flags on object */ #define LOGOPT_LOC 0x02 /* Report loc of obj when requested */ #define LOGOPT_OWNER 0x04 /* Report owner of obj if not obj */ #define LOGOPT_TIMESTAMP 0x08 /* Timestamp log entries */ #endif // !__CONF_H mux2.6/src/help.h0000600000175000017500000000044411025753746013701 0ustar sdennissdennis// help.h // // $Id: help.h 8 2006-09-05 01:55:58Z brazilofmux $ // #define TOPIC_NAME_LEN 30 typedef struct { size_t pos; /* index into help file */ size_t len; /* length of help entry */ char topic[TOPIC_NAME_LEN + 1]; /* topic of help entry */ } help_indx; mux2.6/src/mguests.h0000600000175000017500000000165111025753746014441 0ustar sdennissdennis// mguests.h // // $Id: mguests.h 8 2006-09-05 01:55:58Z brazilofmux $ // #ifndef __MGUESTS_H #define __MGUESTS_H #include "copyright.h" #include "interface.h" // Zenty does OOP. // class CGuests { private: static char name[50]; dbref *Guests; int nMaxGuests; // Size of Guests[]. int nGuests; // Number of guests stored in Guests[]. void SizeGuests(int); int MakeGuestChar(void); // Make the guest character void DestroyGuestChar(dbref); // Destroy the guest character void WipeAttrs(dbref guest); // Wipe all the attrbutes void AddToGuestChannel(dbref player); public: CGuests(void); ~CGuests(void); bool CheckGuest(dbref); void ListAll(dbref); // @list guests void StartUp(); const char *Create(DESC *d); void CleanUp(void); }; extern CGuests Guest; #define GUEST_PASSWORD "Guest" #endif // !__MGUESTS_H mux2.6/src/install-sh0000600000175000017500000000000211025753746014567 0ustar sdennissdennis mux2.6/src/sha1.h0000600000175000017500000000045211025753746013604 0ustar sdennissdennis#ifndef SHA1_H #define SHA1_H typedef struct { UINT64 nTotal; UINT32 H[5]; UINT8 block[64]; size_t nblock; } SHA1_CONTEXT; void SHA1_Init(SHA1_CONTEXT *p); void SHA1_Compute(SHA1_CONTEXT *p, size_t n, const char *buf); void SHA1_Final(SHA1_CONTEXT *p); #endif // SHA1_H mux2.6/src/interface.h0000600000175000017500000002012311025753746014705 0ustar sdennissdennis// interface.h // // $Id: interface.h 456 2006-11-26 05:08:03Z brazilofmux $ // #include "copyright.h" #ifndef __INTERFACE__H #define __INTERFACE__H #include #ifndef WIN32 #include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif // HAVE_SYS_SELECT_H #endif // !WIN32 /* these symbols must be defined by the interface */ /* Disconnection reason codes */ #define R_MIN 0 #define R_UNKNOWN 0 /* Unknown/unexpected */ #define R_QUIT 1 /* User quit */ #define R_TIMEOUT 2 /* Inactivity timeout */ #define R_BOOT 3 /* Victim of @boot, @toad, or @destroy */ #define R_SOCKDIED 4 /* Other end of socked closed it */ #define R_GOING_DOWN 5 /* Game is going down */ #define R_BADLOGIN 6 /* Too many failed login attempts */ #define R_GAMEDOWN 7 /* Not admitting users now */ #define R_LOGOUT 8 /* Logged out w/o disconnecting */ #define R_GAMEFULL 9 /* Too many players logged in */ #define R_MAX 9 /* Logged out command table definitions */ #define CMD_QUIT 1 #define CMD_WHO 2 #define CMD_DOING 3 #define CMD_PREFIX 5 #define CMD_SUFFIX 6 #define CMD_LOGOUT 7 #define CMD_SESSION 8 #define CMD_PUEBLOCLIENT 9 #define CMD_INFO 10 #define CMD_MASK 0xff #define CMD_NOxFIX 0x100 extern NAMETAB logout_cmdtable[]; typedef struct cmd_block CBLK; typedef struct cmd_block_hdr { struct cmd_block *nxt; } CBLKHDR; typedef struct cmd_block { CBLKHDR hdr; char cmd[LBUF_SIZE - sizeof(CBLKHDR)]; } CBLK; typedef struct text_block TBLOCK; typedef struct text_block_hdr { struct text_block *nxt; char *start; char *end; size_t nchars; } TBLOCKHDR; typedef struct text_block { TBLOCKHDR hdr; char data[OUTPUT_BLOCK_SIZE - sizeof(TBLOCKHDR)]; } TBLOCK; typedef struct prog_data PROG; struct prog_data { dbref wait_enactor; reg_ref *wait_regs[MAX_GLOBAL_REGS]; }; // Input state // #define NVT_IS_NORMAL 0 #define NVT_IS_HAVE_IAC 1 #define NVT_IS_HAVE_IAC_WILL 2 #define NVT_IS_HAVE_IAC_WONT 3 #define NVT_IS_HAVE_IAC_DO 4 #define NVT_IS_HAVE_IAC_DONT 5 #define NVT_IS_HAVE_IAC_SB 6 #define NVT_IS_HAVE_IAC_SB_IAC 7 // Character Names // #define NVT_BS '\x08' #define NVT_DEL '\x7F' #define NVT_EOR '\xEF' #define NVT_NOP '\xF1' #define NVT_GA '\xF9' #define NVT_WILL '\xFB' #define NVT_WONT '\xFC' #define NVT_DO '\xFD' #define NVT_DONT '\xFE' #define NVT_IAC '\xFF' // Telnet Options // #define TELNET_SGA '\x03' #define TELNET_EOR '\x19' #define TELNET_NAWS '\x1F' // Telnet Option Negotiation States // #define OPTION_NO 0 #define OPTION_YES 1 #define OPTION_WANTNO_EMPTY 2 #define OPTION_WANTNO_OPPOSITE 3 #define OPTION_WANTYES_EMPTY 4 #define OPTION_WANTYES_OPPOSITE 5 typedef struct descriptor_data DESC; struct descriptor_data { CLinearTimeAbsolute connected_at; CLinearTimeAbsolute last_time; SOCKET descriptor; #ifdef WIN32 // these are for the Windows NT TCP/IO #define SIZEOF_OVERLAPPED_BUFFERS 512 char input_buffer[SIZEOF_OVERLAPPED_BUFFERS]; // buffer for reading char output_buffer[SIZEOF_OVERLAPPED_BUFFERS]; // buffer for writing OVERLAPPED InboundOverlapped; // for asynchronous reading OVERLAPPED OutboundOverlapped; // for asynchronous writing bool bWritePending; // true if in process of writing bool bConnectionDropped; // true if we cannot send to player bool bConnectionShutdown; // true if connection has been shutdown bool bCallProcessOutputLater; // Does the socket need priming for output. #endif // WIN32 int flags; int retries_left; int command_count; int timeout; int host_info; dbref player; char *output_prefix; char *output_suffix; size_t output_size; size_t output_tot; size_t output_lost; TBLOCK *output_head; TBLOCK *output_tail; size_t input_size; size_t input_tot; size_t input_lost; CBLK *input_head; CBLK *input_tail; CBLK *raw_input; char *raw_input_at; size_t nOption; unsigned char aOption[SBUF_SIZE]; int raw_input_state; int nvt_sga_him_state; int nvt_sga_us_state; int nvt_eor_him_state; int nvt_eor_us_state; int nvt_naws_him_state; int nvt_naws_us_state; int width; int height; int quota; PROG *program_data; struct descriptor_data *hashnext; struct descriptor_data *next; struct descriptor_data **prev; struct sockaddr_in address; /* added 3/6/90 SCG */ char addr[51]; char username[11]; char doing[SIZEOF_DOING_STRING]; }; int HimState(DESC *d, unsigned char chOption); int UsState(DESC *d, unsigned char chOption); void EnableHim(DESC *d, unsigned char chOption); void DisableHim(DESC *d, unsigned char chOption); void EnableUs(DESC *d, unsigned char chOption); void DisableUs(DESC *d, unsigned char chOption); /* flags in the flag field */ #define DS_CONNECTED 0x0001 // player is connected. #define DS_AUTODARK 0x0002 // Wizard was auto set dark. #define DS_PUEBLOCLIENT 0x0004 // Client is Pueblo-enhanced. extern DESC *descriptor_list; /* from the net interface */ extern void emergency_shutdown(void); extern void shutdownsock(DESC *, int); extern void SetupPorts(int *pnPorts, PortInfo aPorts[], IntArray *pia); #ifdef WIN32 extern void shovechars9x(int nPorts, PortInfo aPorts[]); extern void shovecharsNT(int nPorts, PortInfo aPorts[]); void process_output9x(void *, int); void process_outputNT(void *, int); extern FTASK *process_output; #else // WIN32 extern void shovechars(int nPorts, PortInfo aPorts[]); extern void process_output(void *, int); extern void dump_restart_db(void); #endif // WIN32 extern void BuildSignalNamesTable(void); extern void set_signals(void); // From netcommon.cpp // extern void make_ulist(dbref, char *, char **, bool); extern void make_port_ulist(dbref, char *, char **); extern int fetch_session(dbref target); extern int fetch_idle(dbref target); extern int fetch_connect(dbref target); extern int fetch_height(dbref target); extern int fetch_width(dbref target); extern const char *time_format_1(int Seconds, size_t maxWidth); extern const char *time_format_2(int Seconds); extern void update_quotas(CLinearTimeAbsolute& tLast, const CLinearTimeAbsolute& tCurrent); extern void raw_notify(dbref, const char *); extern void raw_notify_newline(dbref); extern void clearstrings(DESC *); extern void queue_write_LEN(DESC *, const char *, size_t n); extern void queue_write(DESC *, const char *); extern void queue_string(DESC *, const char *); extern void freeqs(DESC *); extern void welcome_user(DESC *); extern void save_command(DESC *, CBLK *); extern void announce_disconnect(dbref, DESC *, const char *); extern int boot_by_port(SOCKET port, bool bGod, const char *message); extern void find_oldest(dbref target, DESC *dOldest[2]); extern void check_idle(void); void Task_ProcessCommand(void *arg_voidptr, int arg_iInteger); extern int site_check(struct in_addr, SITE *); extern dbref find_connected_name(dbref, char *); extern void do_command(DESC *, char *); extern void desc_addhash(DESC *); // From predicates.cpp // #define alloc_desc(s) (DESC *)pool_alloc(POOL_DESC,s, __FILE__, __LINE__) #define free_desc(b) pool_free(POOL_DESC,(char *)(b), __FILE__, __LINE__) extern void handle_prog(DESC *d, char *message); // From player.cpp // extern void record_login(dbref, bool, char *, char *, char *, char *); extern dbref connect_player(char *, char *, char *, char *, char *); #define DESC_ITER_PLAYER(p,d) \ for (d=(DESC *)hashfindLEN(&(p), sizeof(p), &mudstate.desc_htab); d; d = d->hashnext) #define DESC_ITER_CONN(d) \ for (d=descriptor_list;(d);d=(d)->next) \ if ((d)->flags & DS_CONNECTED) #define DESC_ITER_ALL(d) \ for (d=descriptor_list;(d);d=(d)->next) #define DESC_SAFEITER_PLAYER(p,d,n) \ for (d=(DESC *)hashfindLEN(&(p), sizeof(p), &mudstate.desc_htab), \ n=((d!=NULL) ? d->hashnext : NULL); \ d; \ d=n,n=((n!=NULL) ? n->hashnext : NULL)) #define DESC_SAFEITER_ALL(d,n) \ for (d=descriptor_list,n=((d!=NULL) ? d->next : NULL); \ d; \ d=n,n=((n!=NULL) ? n->next : NULL)) #endif // !__INTERFACE__H mux2.6/src/slave.h0000600000175000017500000000020211025753746014053 0ustar sdennissdennis// slave.h // // $Id: slave.h 8 2006-09-05 01:55:58Z brazilofmux $ // enum { SLAVE_IDENTQ = 'i', SLAVE_IPTONAME = 'h' }; mux2.6/src/config.sub0000700000175000017500000007730011025753746014566 0ustar sdennissdennis#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, # Inc. timestamp='2006-07-02' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16c) basic_machine=cr16c-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: mux2.6/src/Makefile.in0000600000175000017500000001416111025753746014646 0ustar sdennissdennis# Makefile for TinyMUX 2.6 # # Search for the text 'CONFIGURATION SECTION' and make any changes needed # there. SHELL=/bin/sh srcdir = @srcdir@ VPATH = @srcdir@ BIN = ../game/bin CC = @CC@ CXX = @CXX@ #CXXCPP = @CXXCPP@ # This is broken in autoconf. Sigh. CXXCPP = $(CXX) -E LIBS = @LIBS@ @FIRANLIBS@ .SUFFIXES: .cpp # After we finish beta testing, we'll take away the debugging -g flag. # If you don't use GCC, don't use -g. Add -pg for profiling (gprof netmux # gmon.out) # #OPTIM = -O #OPTIM = -g -pg -O OPTIM = -g -O # By default, REALITY_LVLS is not enabled. If you wish to use REALITY_LVLS, # run configure with --enable-realitylvls. Please read the docs/REALITY. # # NOTE: To ensure a clean build, please 'make clean' first. # REALITY_LVLS = @REALITY_LVLS@ REALITY_SRC = @REALITY_SRC@ REALITY_OBJ = @REALITY_OBJ@ # By default, WOD_REALMS is not enabled. If you wish to use WOD_REALMS, # run configure with --enable-wodrealms. Please read the docs/REALMS. # # NOTE: To ensure a clean build, please 'make clean' first. # WOD_REALMS = @WOD_REALMS@ # Disk-based caching is the default. If you wish to use memory-based, run # configure with --enable-memorybased. Disk-based usually uses less memory, # but more disk space. Memory-based usually uses more memory, less # disk-space, and some gain in performance for a very narrow set of # operations. # # NOTE: To ensure a clean build, please 'make clean' first. # MEMORY_BASED = @MEMORY_BASED@ # Firan MUX. By default, this is off. This can be turned on by running # configure with --enable-firanmux. Firan MUX modifications are necessary # in order to run Firan's database. Typically, --enable-memorybased is also # necessary. # FIRANMUX = @FIRANMUX@ # Firan MUX Conversion. By default, this is off. This can be turned on by # running configure with --enable-firanmuxconvert. Firan MUX modifications # are necessary in order convert Firan's old database. This should only # be done once. Typically, --enable-memorybased and --enable-firanmux are # also necessary. # FIRANMUX_CONVERT = @FIRANMUX_CONVERT@ # Deprecated Features. By default, this is off. This can be turned on by # running configure with --enable-deprecated. Features which are infrequently # used become deprecated and are eventually removed from the source. # DEPRECATED = @DEPRECATED@ # Distribution source files D_SRC = _build.cpp alloc.cpp attrcache.cpp boolexp.cpp bsd.cpp command.cpp \ comsys.cpp conf.cpp cque.cpp create.cpp db.cpp db_rw.cpp eval.cpp \ file_c.cpp flags.cpp funceval.cpp functions.cpp funmath.cpp game.cpp \ help.cpp htab.cpp local.cpp log.cpp look.cpp mail.cpp match.cpp \ mguests.cpp move.cpp muxcli.cpp netcommon.cpp object.cpp \ predicates.cpp player.cpp player_c.cpp plusemail.cpp powers.cpp \ quota.cpp rob.cpp pcre.cpp set.cpp sha1.cpp speech.cpp \ stringutil.cpp strtod.cpp svdrand.cpp svdhash.cpp svdreport.cpp \ timer.cpp timeutil.cpp unparse.cpp vattr.cpp walkdb.cpp wild.cpp \ wiz.cpp D_OBJ = _build.o alloc.o attrcache.o boolexp.o bsd.o command.o comsys.o \ conf.o cque.o create.o db.o db_rw.o eval.o file_c.o flags.o \ funceval.o functions.o funmath.o game.o help.o htab.o local.o log.o \ look.o mail.o match.o mguests.o move.o muxcli.o netcommon.o object.o \ predicates.o player.o player_c.o plusemail.o powers.o quota.o rob.o \ pcre.o set.o sha1.o speech.o stringutil.o strtod.o \ svdrand.o svdhash.o svdreport.o timer.o timeutil.o unparse.o vattr.o \ walkdb.o wild.o wiz.o # Version number routine VER_SRC = version.cpp VER_OBJ = version.o VER_FLG = -DMUX_BUILD_DATE="\"`date`\"" \ -DMUX_BUILD_NUM="\"`sh ./buildnum.sh`\"" # ===================== CONFIGURATION SECTION ==================== # # Select the correct C compiler. Whatever you choose, it must be able # to grok ANSI C (function prototypes) # #-----CC or GCC (must be able to grok function prototypes) # DEFS = # #-----CC on a NeXT system, really weird derivative of GCC # #DEFS = -DNEXT -DNEED_STRDUP # #-----GCC if the libraries were built for a pcc-derived cc compiler # (most systems) # #DEFS = -fpcc-struct-return -Wall # #-----GCC with GCC-compatible libraries if you want verbose error messages # #DEFS = -Wall # #-----HP-UX C compiler # #DEFS = -w +Obb800 -Aa -D_INCLUDE_POSIX_SOURCE -D_INCLUDE_HPUX_SOURCE -D_INCLUDE_XOPEN_SOURCE # #-----MIPS C compiler (also DEC 3xxx, Prime EXL7xxx) # #DEFS = -signed # # Libraries. Use the second line if you want to use the resolver to get # hostnames and your libc doesn't use it already. If you use it, you'd # better have your nameserver working or things may hang for a while when # people try to login from distant sites. Use the third line if you're running # on a SysV-ish system and BSD support isn't built in to the standard libc. # MORELIBS = -lm #MORELIBS = -lm -lnsl -lsocket -L/usr/ucblib -lucb # Mips # ================== END OF CONFIGURATION SECTION ================= # Auxiliary source files: only used by offline utilities. # AUX_SRC = unsplit.cpp ALLCXXFLAGS = $(CXXFLAGS) $(OPTIM) $(DEFS) $(MEMORY_BASED) $(WOD_REALMS) $(REALITY_LVLS) $(QUERY_SLAVE) $(FIRANMUX) $(FIRANMUX_CONVERT) $(DEPRECATED) # Compiliation source files. # ALLSRC = $(D_SRC) $(REALITY_SRC) $(VER_SRC) $(AUX_SRC) SRC = $(D_SRC) $(REALITY_SRC) OBJ = $(D_OBJ) $(REALITY_OBJ) .cpp.o: $(CXX) $(ALLCXXFLAGS) -c $< all: netmux slave $(SQLSLAVE) links links: netmux slave $(SQLSLAVE) cd ../game/bin ; rm -f dbconvert ; ln -s ../../src/netmux dbconvert cd ../game/bin ; rm -f netmux ; ln -s ../../src/netmux netmux cd ../game/bin ; rm -f slave ; ln -s ../../src/slave slave slave: slave.o $(CXX) $(ALLCXXFLAGS) $(LIBS) -o slave slave.o unsplit: unsplit.o $(CXX) $(ALLCXXFLAGS) -o unsplit unsplit.o netmux: $(OBJ) $(VER_SRC) $(CXX) $(ALLCXXFLAGS) $(VER_FLG) -c $(VER_SRC) ( if [ -f netmux ]; then mv -f netmux netmux~ ; fi ) $(CXX) $(ALLCXXFLAGS) -o netmux $(OBJ) $(VER_OBJ) $(LIBS) $(MORELIBS) depend: $(ALLSRC) unsplit for i in $(D_SRC) $(AUX_SRC) slave.cpp ; do $(CXXCPP) $(ALLCXXFLAGS) -M $$i; done | sed -e 's:/usr[^ ]*[ ]*::g' | ./unsplit > .depend~ mv .depend~ .depend realclean: -rm -f *.o a.out core gmon.out mux.*log mux.*sum netmux netmux~ clean: -rm -f *.o a.out core gmon.out mux.*log mux.*sum slave netmux include .depend mux2.6/src/conf.cpp0000600000175000017500000024735011025753746014242 0ustar sdennissdennis/*! \file conf.cpp * Set up configuration information and static data. * * $Id: conf.cpp 3420 2008-03-26 02:49:27Z brazilofmux $ * * This parses the configuration files and controls configuration options used * to control the server and its behavior. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "interface.h" // --------------------------------------------------------------------------- // CONFPARM: Data used to find fields in CONFDATA. // typedef struct confparm { const char *pname; // parm name int (*interpreter)(int *vp, char *str, void *pExtra, UINT32 nExtra, dbref player, char *cmd); // routine to interp parameter int flags; // control flags int rperms; // read permission flags. int *loc; // where to store value void *pExtra; // extra pointer for interpreter UINT32 nExtra; // extra data for interpreter } CONF; // --------------------------------------------------------------------------- // External symbols. // CONFDATA mudconf; STATEDATA mudstate; // --------------------------------------------------------------------------- // cf_init: Initialize mudconf to default values. // void cf_init(void) { int i; mudconf.indb = StringClone("netmux.db"); mudconf.outdb = StringClone(""); mudconf.crashdb = StringClone(""); mudconf.game_dir = StringClone(""); mudconf.game_pag = StringClone(""); mudconf.mail_db = StringClone("mail.db"); mudconf.comsys_db = StringClone("comsys.db"); mudconf.compress_db = false; mudconf.compress = StringClone("gzip"); mudconf.uncompress = StringClone("gzip -d"); mudconf.status_file = StringClone("shutdown.status"); mudconf.max_cache_size = 1*1024*1024; mudconf.ports.n = 1; mudconf.ports.pi = (int *)MEMALLOC(sizeof(int)); if (mudconf.ports.pi) { mudconf.ports.pi[0] = 2860; } else { ISOUTOFMEMORY(mudconf.ports.pi); } mudconf.init_size = 1000; mudconf.guest_char = -1; mudconf.guest_nuker = GOD; mudconf.number_guests = 30; mudconf.min_guests = 1; mux_strncpy(mudconf.guest_prefix, "Guest", 31); mudconf.guest_file = StringClone("text/guest.txt"); mudconf.conn_file = StringClone("text/connect.txt"); mudconf.creg_file = StringClone("text/register.txt"); mudconf.regf_file = StringClone("text/create_reg.txt"); mudconf.motd_file = StringClone("text/motd.txt"); mudconf.wizmotd_file = StringClone("text/wizmotd.txt"); mudconf.quit_file = StringClone("text/quit.txt"); mudconf.down_file = StringClone("text/down.txt"); mudconf.full_file = StringClone("text/full.txt"); mudconf.site_file = StringClone("text/badsite.txt"); mudconf.crea_file = StringClone("text/newuser.txt"); mudconf.motd_msg[0] = '\0'; mudconf.wizmotd_msg[0] = '\0'; mudconf.downmotd_msg[0] = '\0'; mudconf.fullmotd_msg[0] = '\0'; mudconf.dump_msg[0] = '\0'; mudconf.postdump_msg[0] = '\0'; mudconf.fixed_home_msg[0] = '\0'; mudconf.fixed_tel_msg[0] = '\0'; mux_strncpy(mudconf.public_channel, "Public", 31); mux_strncpy(mudconf.public_channel_alias, "pub", 31); mux_strncpy(mudconf.guests_channel, "Guests", 31); mux_strncpy(mudconf.guests_channel_alias, "g", 31); mux_strncpy(mudconf.pueblo_msg, "", GBUF_SIZE-1); #if defined(FIRANMUX) mux_strncpy(mudconf.immobile_msg, "You have been set immobile.", sizeof(mudconf.immobile_msg)-1); mudconf.sql_server[0] = '\0'; mudconf.sql_user[0] = '\0'; mudconf.sql_password[0] = '\0'; mudconf.sql_database[0] = '\0'; mudconf.mail_server[0] = '\0'; mudconf.mail_ehlo[0] = '\0'; mudconf.mail_sendaddr[0]= '\0'; mudconf.mail_sendname[0]= '\0'; mudconf.mail_subject[0] = '\0'; #endif // FIRANMUX mudconf.art_rules = NULL; mudconf.indent_desc = false; mudconf.name_spaces = true; #ifndef WIN32 mudconf.fork_dump = true; mudstate.dumping = false; mudstate.dumper = 0; mudstate.dumped = 0; mudstate.write_protect = false; #endif mudconf.restrict_home = false; mudconf.have_comsys = true; mudconf.have_mailer = true; mudconf.have_zones = true; mudconf.paranoid_alloc = false; mudconf.sig_action = SA_DFLT; mudconf.max_players = -1; mudconf.dump_interval = 3600; mudconf.check_interval = 600; mudconf.events_daily_hour = 7; mudconf.dump_offset = 0; mudconf.check_offset = 300; mudconf.idle_timeout = 3600; mudconf.conn_timeout = 120; mudconf.idle_interval = 60; mudconf.retry_limit = 3; mudconf.output_limit = 16384; mudconf.paycheck = 0; mudconf.paystart = 0; mudconf.paylimit = 10000; #ifdef REALITY_LVLS mudconf.no_levels = 0; mudconf.def_room_rx = 1; mudconf.def_room_tx = ~(RLEVEL)0; mudconf.def_player_rx = 1; mudconf.def_player_tx = 1; mudconf.def_exit_rx = 1; mudconf.def_exit_tx = 1; mudconf.def_thing_rx = 1; mudconf.def_thing_tx = 1; #endif // REALITY_LVLS mudconf.start_quota = 20; mudconf.site_chars = 25; mudconf.payfind = 0; mudconf.digcost = 10; mudconf.linkcost = 1; mudconf.opencost = 1; mudconf.createmin = 10; mudconf.createmax = 505; mudconf.killmin = 10; mudconf.killmax = 100; mudconf.killguarantee = 100; mudconf.robotcost = 1000; mudconf.pagecost = 10; mudconf.searchcost = 100; mudconf.waitcost = 10; mudconf.machinecost = 64; mudconf.exit_quota = 1; mudconf.player_quota = 1; mudconf.room_quota = 1; mudconf.thing_quota = 1; mudconf.mail_expiration = 14; mudconf.queuemax = 100; mudconf.queue_chunk = 10; mudconf.active_q_chunk = 10; mudconf.sacfactor = 5; mudconf.sacadjust = -1; mudconf.trace_limit = 200; mudconf.float_precision = -1; mudconf.autozone = true; mudconf.use_hostname = true; mudconf.clone_copy_cost = false; mudconf.dark_sleepers = true; mudconf.ex_flags = true; mudconf.exam_public = true; mudconf.fascist_tport = false; mudconf.idle_wiz_dark = false; mudconf.match_mine = true; mudconf.match_mine_pl = true; mudconf.pemit_players = false; mudconf.pemit_any = false; mudconf.player_listen = false; mudconf.pub_flags = true; mudconf.quiet_look = true; mudconf.quiet_whisper = true; mudconf.quotas = false; mudconf.read_rem_desc = false; mudconf.read_rem_name = false; mudconf.reset_players = false; mudconf.robot_speak = true; mudconf.safe_unowned = false; mudconf.safer_passwords = false; mudconf.see_own_dark = true; mudconf.sweep_dark = false; mudconf.switch_df_all = true; mudconf.terse_contents = true; mudconf.terse_exits = true; mudconf.terse_look = true; mudconf.terse_movemsg = true; mudconf.trace_topdown = true; // -- ??? Running SC on a non-SC DB may cause problems. // mudconf.space_compress = true; mudconf.allow_guest_from_registered_site = true; mudconf.start_room = 0; mudconf.start_home = NOTHING; mudconf.default_home = NOTHING; mudconf.master_room = NOTHING; for (i = FLAG_WORD1; i <= FLAG_WORD3; i++) { mudconf.player_flags.word[i] = 0; mudconf.room_flags.word[i] = 0; mudconf.exit_flags.word[i] = 0; mudconf.thing_flags.word[i] = 0; mudconf.robot_flags.word[i] = 0; mudconf.stripped_flags.word[i] = 0; } mudconf.robot_flags.word[FLAG_WORD1] |= ROBOT; mudconf.stripped_flags.word[FLAG_WORD1] = IMMORTAL | INHERIT | ROYALTY | WIZARD; mudconf.stripped_flags.word[FLAG_WORD2] = BLIND | CONNECTED | GAGGED | HEAD_FLAG | SLAVE | STAFF | SUSPECT | UNINSPECTED; mudconf.vattr_flags = AF_ODARK; mux_strncpy(mudconf.mud_name, "MUX", 31); mux_strncpy(mudconf.one_coin, "penny", 31); mux_strncpy(mudconf.many_coins, "pennies", 31); mudconf.timeslice.SetSeconds(1); mudconf.cmd_quota_max = 100; mudconf.cmd_quota_incr = 1; mudconf.rpt_cmdsecs.SetSeconds(120); mudconf.max_cmdsecs.SetSeconds(60); mudconf.cache_tick_period.SetSeconds(30); mudconf.control_flags = 0xffffffff; // Everything for now... mudconf.log_options = LOG_ALWAYS | LOG_BUGS | LOG_SECURITY | LOG_NET | LOG_LOGIN | LOG_DBSAVES | LOG_CONFIGMODS | LOG_SHOUTS | LOG_STARTUP | LOG_WIZARD | LOG_SUSPECTCMDS | LOG_PROBLEMS | LOG_PCREATES | LOG_TIMEUSE; mudconf.log_info = LOGOPT_TIMESTAMP | LOGOPT_LOC; mudconf.markdata[0] = 0x01; mudconf.markdata[1] = 0x02; mudconf.markdata[2] = 0x04; mudconf.markdata[3] = 0x08; mudconf.markdata[4] = 0x10; mudconf.markdata[5] = 0x20; mudconf.markdata[6] = 0x40; mudconf.markdata[7] = 0x80; mudconf.func_nest_lim = 50; mudconf.func_invk_lim = 2500; mudconf.wild_invk_lim = 100000; mudconf.ntfy_nest_lim = 20; mudconf.lock_nest_lim = 20; mudconf.parent_nest_lim = 10; mudconf.zone_nest_lim = 20; mudconf.stack_limit = 50; mudconf.cache_names = true; mudconf.toad_recipient = -1; mudconf.eval_comtitle = true; mudconf.run_startup = true; mudconf.safe_wipe = false; mudconf.destroy_going_now = false; mudconf.nStackLimit = 10000; mudconf.hook_obj = NOTHING; mudconf.global_error_obj = NOTHING; mudconf.cache_pages = 40; mudconf.mail_per_hour = 50; mudconf.vattr_per_hour = 5000; mudconf.pcreate_per_hour = 100; mudconf.lbuf_size = LBUF_SIZE; mudstate.events_flag = 0; mudstate.bReadingConfiguration = false; mudstate.bCanRestart = false; mudstate.panicking = false; mudstate.logging = 0; mudstate.epoch = 0; mudstate.generation = 0; mudstate.curr_executor = NOTHING; mudstate.curr_enactor = NOTHING; mudstate.shutdown_flag = false; mudstate.attr_next = A_USER_START; mudstate.debug_cmd = "< init >"; mudstate.curr_cmd = "< none >"; mux_strncpy(mudstate.doing_hdr, "Doing", SIZEOF_DOING_STRING-1); mudstate.access_list = NULL; mudstate.suspect_list = NULL; mudstate.badname_head = NULL; mudstate.mstat_ixrss[0] = 0; mudstate.mstat_ixrss[1] = 0; mudstate.mstat_idrss[0] = 0; mudstate.mstat_idrss[1] = 0; mudstate.mstat_isrss[0] = 0; mudstate.mstat_isrss[1] = 0; mudstate.mstat_secs[0] = 0; mudstate.mstat_secs[1] = 0; mudstate.mstat_curr = 0; mudstate.iter_alist.data = NULL; mudstate.iter_alist.len = 0; mudstate.iter_alist.next = NULL; mudstate.mod_alist = NULL; mudstate.mod_alist_len = 0; mudstate.mod_size = 0; mudstate.mod_al_id = NOTHING; mudstate.olist = NULL; mudstate.min_size = 0; mudstate.db_top = 0; mudstate.db_size = 0; mudstate.mail_db_top = 0; mudstate.mail_db_size = 0; mudstate.freelist = NOTHING; mudstate.markbits = NULL; mudstate.func_nest_lev = 0; mudstate.func_invk_ctr = 0; mudstate.wild_invk_ctr = 0; mudstate.ntfy_nest_lev = 0; mudstate.train_nest_lev = 0; mudstate.lock_nest_lev = 0; mudstate.zone_nest_num = 0; mudstate.pipe_nest_lev = 0; mudstate.inpipe = false; mudstate.pout = NULL; mudstate.poutnew = NULL; mudstate.poutbufc = NULL; mudstate.poutobj = NOTHING; for (i = 0; i < MAX_GLOBAL_REGS; i++) { mudstate.global_regs[i] = NULL; } mudstate.nObjEvalNest = 0; mudstate.in_loop = 0; mudstate.bStackLimitReached = false; mudstate.nStackNest = 0; mudstate.nHearNest = 0; mudstate.aHelpDesc = NULL; mudstate.mHelpDesc = 0; mudstate.nHelpDesc = 0; } // --------------------------------------------------------------------------- // cf_log_notfound: Log a 'parameter not found' error. // void cf_log_notfound(dbref player, const char *cmd, const char *thingname, const char *thing) { if (mudstate.bReadingConfiguration) { STARTLOG(LOG_STARTUP, "CNF", "NFND"); Log.tinyprintf("%s: %s %s not found", cmd, thingname, thing); ENDLOG; } else { notify(player, tprintf("%s %s not found", thingname, thing)); } } // --------------------------------------------------------------------------- // cf_log_syntax: Log a syntax error. // void DCL_CDECL cf_log_syntax(dbref player, char *cmd, const char *fmt, ...) { va_list ap; va_start(ap, fmt); char *buf = alloc_lbuf("cf_log_syntax"); mux_vsnprintf(buf, LBUF_SIZE, fmt, ap); if (mudstate.bReadingConfiguration) { STARTLOG(LOG_STARTUP, "CNF", "SYNTX") log_text(cmd); log_text(": "); log_text(buf); ENDLOG; } else { notify(player, buf); } free_lbuf(buf); va_end(ap); } // --------------------------------------------------------------------------- // cf_status_from_succfail: Return command status from succ and fail info // static int cf_status_from_succfail(dbref player, char *cmd, int success, int failure) { char *buff; // If any successes, return SUCCESS(0) if no failures or // PARTIAL_SUCCESS(1) if any failures. // if (success > 0) return ((failure == 0) ? 0 : 1); // No successes. If no failures indicate nothing done. Always return // FAILURE(-1) // if (failure == 0) { if (mudstate.bReadingConfiguration) { STARTLOG(LOG_STARTUP, "CNF", "NDATA") buff = alloc_lbuf("cf_status_from_succfail.LOG"); mux_sprintf(buff, LBUF_SIZE, "%s: Nothing to set", cmd); log_text(buff); free_lbuf(buff); ENDLOG } else { notify(player, "Nothing to set"); } } return -1; } //--------------------------------------------------------------------------- // cf_rlevel // #ifdef REALITY_LVLS CF_HAND(cf_rlevel) { CONFDATA *mc = (CONFDATA *)vp; int i; if(mc->no_levels >= 32) return 1; for(i=0; *str && !mux_isspace[*str]; ++str) if(i < 8) mc->reality_level[mc->no_levels].name[i++] = *str; mc->reality_level[mc->no_levels].name[i] = '\0'; mc->reality_level[mc->no_levels].value = 1; strcpy(mc->reality_level[mc->no_levels].attr, "DESC"); for(; *str && mux_isspace[*str]; ++str); for(i=0; *str && mux_isdigit[*str]; ++str) i = i * 10 + (*str - '0'); if(i) mc->reality_level[mc->no_levels].value = (RLEVEL) i; for(; *str && mux_isspace[*str]; ++str); if(*str) strncpy(mc->reality_level[mc->no_levels].attr, str, 32); mc->no_levels++; return 0; } #endif // REALITY_LVLS // --------------------------------------------------------------------------- // cf_int_array: Setup array of integers. // static CF_HAND(cf_int_array) { UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(player); UNUSED_PARAMETER(cmd); int *aPorts = NULL; try { aPorts = new int[nExtra]; } catch (...) { ; // Nothing. } if (NULL == aPorts) { cf_log_syntax(player, cmd, "Out of memory."); return -1; } unsigned int nPorts = 0; char *p; MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t\n\r"); while ( (p = mux_strtok_parse(&tts)) != NULL && nPorts < nExtra) { int unused; if (is_integer(p, &unused)) { aPorts[nPorts++] = mux_atol(p); } } IntArray *pia = (IntArray *)vp; if (nPorts) { int *q = NULL; try { q = new int[nPorts]; } catch (...) { ; // Nothing. } if (NULL == q) { cf_log_syntax(player, cmd, "Out of memory."); return -1; } if (pia->pi) { delete [] pia->pi; pia->pi = NULL; } pia->pi = q; pia->n = nPorts; for (unsigned int i = 0; i < nPorts; i++) { pia->pi[i] = aPorts[i]; } } delete [] aPorts; return 0; } // --------------------------------------------------------------------------- // cf_int: Set integer parameter. // static CF_HAND(cf_int) { UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); UNUSED_PARAMETER(player); UNUSED_PARAMETER(cmd); // Copy the numeric value to the parameter. // *vp = mux_atol(str); return 0; } // --------------------------------------------------------------------------- // cf_dbref: Set dbref parameter....looking for an ignoring the leading '#'. // static CF_HAND(cf_dbref) { UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); UNUSED_PARAMETER(player); UNUSED_PARAMETER(cmd); char *p = str; while (mux_isspace(*p)) { p++; } if (*p == '#') { p++; } // Copy the numeric value to the parameter. // *vp = mux_atol(p); return 0; } // --------------------------------------------------------------------------- // cf_seconds: Set CLinearTimeDelta in units of seconds. // static CF_HAND(cf_seconds) { UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); UNUSED_PARAMETER(player); UNUSED_PARAMETER(cmd); CLinearTimeDelta *pltd = (CLinearTimeDelta *)vp; pltd->SetSecondsString(str); return 0; } // --------------------------------------------------------------------------- // cf_bool: Set boolean parameter. // static NAMETAB bool_names[] = { {"true", 1, 0, true}, {"false", 1, 0, false}, {"yes", 1, 0, true}, {"no", 1, 0, false}, {"1", 1, 0, true}, {"0", 1, 0, false}, {NULL, 0, 0, 0} }; static CF_HAND(cf_bool) { UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); int i; if (!search_nametab(GOD, bool_names, str, &i)) { cf_log_notfound(player, cmd, "Value", str); return -1; } bool *pb = (bool *)vp; *pb = isTRUE(i); return 0; } // --------------------------------------------------------------------------- // cf_option: Select one option from many choices. // static CF_HAND(cf_option) { UNUSED_PARAMETER(nExtra); int i; if (!search_nametab(GOD, (NAMETAB *)pExtra, str, &i)) { cf_log_notfound(player, cmd, "Value", str); return -1; } *vp = i; return 0; } // --------------------------------------------------------------------------- // cf_string: Set string parameter. // static CF_HAND(cf_string) { UNUSED_PARAMETER(pExtra); char *pc = (char *)vp; // The following should never happen because extra is always a non-zero // constant in the config table. // if (nExtra <= 0) { return 1; } // Copy the string to the buffer if it is not too big. // int retval = 0; size_t nStr = strlen(str); if (nStr >= nExtra) { nStr = nExtra - 1; if (mudstate.bReadingConfiguration) { STARTLOG(LOG_STARTUP, "CNF", "NFND"); Log.tinyprintf("%s: String truncated", cmd); ENDLOG; } else { notify(player, "String truncated"); } retval = 1; } memcpy(pc, str, nStr+1); pc[nStr] = '\0'; if (pc == mudconf.mud_name) { // We are changing the name of the MUD. Form a prefix from the // mudname and let the logger know. // char *buff = alloc_sbuf("cf_string.prefix"); char *p = buff; char *q = strip_ansi(mudconf.mud_name); size_t nLen = 0; while ( *q && nLen < SBUF_SIZE) { if (mux_isalnum(*q)) { *p++ = *q; nLen++; } q++; } *p = '\0'; Log.SetPrefix(buff); free_sbuf(buff); } return retval; } // --------------------------------------------------------------------------- // cf_string_dyn: Set string parameter using dynamically allocated memory. // static CF_HAND(cf_string_dyn) { UNUSED_PARAMETER(pExtra); char **ppc = (char **)vp; // Allocate memory for buffer and copy string to it. If nExtra is non-zero, // then there is a size limitation as well. // int retval = 0; size_t nStr = strlen(str); if (nExtra && nStr >= nExtra) { nStr = nExtra - 1; if (mudstate.bReadingConfiguration) { STARTLOG(LOG_STARTUP, "CNF", "NFND"); Log.tinyprintf("%s: String truncated", cmd); ENDLOG; } else { notify(player, "String truncated"); } retval = 1; } char *confbuff = StringCloneLen(str, nStr); // Free previous memory for buffer. // if (*ppc != NULL) { MEMFREE(*ppc); } *ppc = confbuff; return retval; } // --------------------------------------------------------------------------- // cf_alias: define a generic hash table alias. // static CF_HAND(cf_alias) { UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t=,"); char *alias = mux_strtok_parse(&tts); char *orig = mux_strtok_parse(&tts); if (orig) { mux_strlwr(orig); void *cp = hashfindLEN(orig, strlen(orig), (CHashTable *) vp); if (cp == NULL) { mux_strupr(orig); cp = hashfindLEN(orig, strlen(orig), (CHashTable *) vp); if (cp == NULL) { cf_log_notfound(player, cmd, "Entry", orig); return -1; } } if (!hashfindLEN(alias, strlen(alias), (CHashTable *) vp)) { hashaddLEN(alias, strlen(alias), cp, (CHashTable *) vp); } return 0; } return -1; } // --------------------------------------------------------------------------- // cf_flagalias: define a flag alias. // static CF_HAND(cf_flagalias) { UNUSED_PARAMETER(vp); UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t=,"); char *alias = mux_strtok_parse(&tts); char *orig = mux_strtok_parse(&tts); if ( NULL == alias || '\0' == alias[0] || NULL == orig || '\0' == orig[0]) { return -1; } bool success = false; int nName; bool bValid; void *cp; char *pName = MakeCanonicalFlagName(orig, &nName, &bValid); if (bValid) { cp = hashfindLEN(pName, nName, &mudstate.flags_htab); if (cp) { pName = MakeCanonicalFlagName(alias, &nName, &bValid); if (bValid) { if (!hashfindLEN(pName, nName, &mudstate.flags_htab)) { hashaddLEN(pName, nName, cp, &mudstate.flags_htab); success = true; } } } } if (!success) { cf_log_notfound(player, cmd, "Flag", orig); } return (success ? 0 : -1); } // --------------------------------------------------------------------------- // cf_poweralias: define a power alias. // static CF_HAND(cf_poweralias) { UNUSED_PARAMETER(vp); UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t=,"); char *alias = mux_strtok_parse(&tts); char *orig = mux_strtok_parse(&tts); if ( NULL == alias || '\0' == alias[0] || NULL == orig || '\0' == orig[0]) { return -1; } bool success = false; int nName; bool bValid; void *cp; char *pName = MakeCanonicalFlagName(orig, &nName, &bValid); if (bValid) { cp = hashfindLEN(pName, nName, &mudstate.powers_htab); if (cp) { pName = MakeCanonicalFlagName(alias, &nName, &bValid); if (bValid) { hashaddLEN(pName, nName, cp, &mudstate.powers_htab); success = true; } } } if (!success) { cf_log_notfound(player, cmd, "Power", orig); } return (success ? 0 : -1); } #if 0 // --------------------------------------------------------------------------- // cf_or_in_bits: OR in bits from namelist to a word. // static CF_HAND(cf_or_in_bits) { UNUSED_PARAMETER(nExtra); int f, success, failure; // Walk through the tokens. // success = failure = 0; MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t"); char *sp = mux_strtok_parse(&tts); while (sp != NULL) { // Set the appropriate bit. // if (search_nametab(GOD, (NAMETAB *)pExtra, sp, &f)) { *vp |= f; success++; } else { cf_log_notfound(player, cmd, "Entry", sp); failure++; } // Get the next token. // sp = mux_strtok_parse(&tts); } return cf_status_from_succfail(player, cmd, success, failure); } #endif // --------------------------------------------------------------------------- // cf_modify_bits: set or clear bits in a flag word from a namelist. // CF_HAND(cf_modify_bits) { UNUSED_PARAMETER(nExtra); int f, success, failure; bool negate; // Walk through the tokens. // success = failure = 0; MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t"); char *sp = mux_strtok_parse(&tts); while (sp != NULL) { // Check for negation. // negate = false; if (*sp == '!') { negate = true; sp++; } // Set or clear the appropriate bit. // if (search_nametab(GOD, (NAMETAB *)pExtra, sp, &f)) { if (negate) *vp &= ~f; else *vp |= f; success++; } else { cf_log_notfound(player, cmd, "Entry", sp); failure++; } // Get the next token. // sp = mux_strtok_parse(&tts); } return cf_status_from_succfail(player, cmd, success, failure); } #if 0 // --------------------------------------------------------------------------- // cf_set_bits: Clear flag word and then set specified bits from namelist. // static CF_HAND(cf_set_bits) { UNUSED_PARAMETER(nExtra); int f, success, failure; // Walk through the tokens // success = failure = 0; *vp = 0; MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t"); char *sp = mux_strtok_parse(&tts); while (sp != NULL) { // Set the appropriate bit. // if (search_nametab(GOD, (NAMETAB *)pExtra, sp, &f)) { *vp |= f; success++; } else { cf_log_notfound(player, cmd, "Entry", sp); failure++; } // Get the next token. // sp = mux_strtok_parse(&tts); } return cf_status_from_succfail(player, cmd, success, failure); } #endif // --------------------------------------------------------------------------- // cf_set_flags: Clear flag word and then set from a flags htab. // static CF_HAND(cf_set_flags) { UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); int success, failure; // Walk through the tokens. // success = failure = 0; MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t"); char *sp = mux_strtok_parse(&tts); FLAGSET *fset = (FLAGSET *) vp; while (sp != NULL) { // Canonical Flag Name. // int nName; bool bValid; char *pName = MakeCanonicalFlagName(sp, &nName, &bValid); FLAGNAMEENT *fp = NULL; if (bValid) { fp = (FLAGNAMEENT *)hashfindLEN(pName, nName, &mudstate.flags_htab); } if (fp != NULL) { // Set the appropriate bit. // if (success == 0) { for (int i = FLAG_WORD1; i <= FLAG_WORD3; i++) { (*fset).word[i] = 0; } } FLAGBITENT *fbe = fp->fbe; if (fp->bPositive) { (*fset).word[fbe->flagflag] |= fbe->flagvalue; } else { (*fset).word[fbe->flagflag] &= ~(fbe->flagvalue); } success++; } else { cf_log_notfound(player, cmd, "Entry", sp); failure++; } // Get the next token // sp = mux_strtok_parse(&tts); } if ((success == 0) && (failure == 0)) { for (int i = FLAG_WORD1; i <= FLAG_WORD3; i++) { (*fset).word[i] = 0; } return 0; } if (success > 0) { return ((failure == 0) ? 0 : 1); } return -1; } // --------------------------------------------------------------------------- // cf_badname: Disallow use of player name/alias. // static CF_HAND(cf_badname) { UNUSED_PARAMETER(vp); UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(player); UNUSED_PARAMETER(cmd); if (nExtra) { badname_remove(str); } else { badname_add(str); } return 0; } typedef struct { int nShift; UINT32 maxValue; size_t maxOctLen; size_t maxDecLen; size_t maxHexLen; } DECODEIPV4; static bool DecodeN(int nType, size_t len, const char *p, in_addr_t *pu32) { static DECODEIPV4 DecodeIPv4Table[4] = { { 8, 255UL, 3, 3, 2 }, { 16, 65535UL, 6, 5, 4 }, { 24, 16777215UL, 8, 8, 6 }, { 32, 4294967295UL, 11, 10, 8 } }; *pu32 = (*pu32 << DecodeIPv4Table[nType].nShift) & 0xFFFFFFFFUL; if (len == 0) { return false; } in_addr_t ul = 0; in_addr_t ul2; if ( len >= 3 && p[0] == '0' && mux_tolower(p[1]) == 'x') { // Hexadecimal Path // // Skip the leading zeros. // p += 2; len -= 2; while (*p == '0' && len) { p++; len--; } if (len > DecodeIPv4Table[nType].maxHexLen) { return false; } while (len) { unsigned char ch = mux_tolower(*p); ul2 = ul; ul = (ul << 4) & 0xFFFFFFFFUL; if (ul < ul2) { // Overflow // return false; } if ('0' <= ch && ch <= '9') { ul |= ch - '0'; } else if ('a' <= ch && ch <= 'f') { ul |= ch - 'a'; } else { return false; } p++; len--; } } else if (len >= 1 && p[0] == '0') { // Octal Path // // Skip the leading zeros. // p++; len--; while (*p == '0' && len) { p++; len--; } if (len > DecodeIPv4Table[nType].maxOctLen) { return false; } while (len) { unsigned char ch = *p; ul2 = ul; ul = (ul << 3) & 0xFFFFFFFFUL; if (ul < ul2) { // Overflow // return false; } if ('0' <= ch && ch <= '7') { ul |= ch - '0'; } else { return false; } p++; len--; } } else { // Decimal Path // if (len > DecodeIPv4Table[nType].maxDecLen) { return false; } while (len) { unsigned char ch = *p; ul2 = ul; ul = (ul * 10) & 0xFFFFFFFFUL; if (ul < ul2) { // Overflow // return false; } ul2 = ul; if ('0' <= ch && ch <= '9') { ul += ch - '0'; } else { return false; } if (ul < ul2) { // Overflow // return false; } p++; len--; } } if (ul > DecodeIPv4Table[nType].maxValue) { return false; } *pu32 |= ul; return true; } // --------------------------------------------------------------------------- // MakeCanonicalIPv4: inet_addr() does not do reasonable checking for sane // syntax on all platforms. On certain operating systems, if passed less than // four octets, it will cause a segmentation violation. Furthermore, there is // confusion between return values for valid input "255.255.255.255" and // return values for invalid input (INADDR_NONE as -1). To overcome these // problems, it appears necessary to re-implement inet_addr() with a different // interface. // // n8.n8.n8.n8 Class A format. 0 <= n8 <= 255. // // Supported Berkeley IP formats: // // n8.n8.n16 Class B 128.net.host format. 0 <= n16 <= 65535. // n8.n24 Class A net.host format. 0 <= n24 <= 16777215. // n32 Single 32-bit number. 0 <= n32 <= 4294967295. // // Each element may be expressed in decimal, octal or hexadecimal. '0' is the // octal prefix. '0x' or '0X' is the hexadecimal prefix. Otherwise the number // is taken as decimal. // // 08 Octal // 0x8 Hexadecimal // 0X8 Hexadecimal // 8 Decimal // static bool MakeCanonicalIPv4(const char *str, in_addr_t *pnIP) { *pnIP = 0; if (!str) { return false; } // Skip leading spaces. // const char *q = str; while (*q == ' ') { q++; } const char *p = strchr(q, '.'); int n = 0; while (p) { // Decode // n++; if (n > 3) { return false; } if (!DecodeN(0, p-q, q, pnIP)) { return false; } q = p + 1; p = strchr(q, '.'); } // Decode last element. // size_t len = strlen(q); if (!DecodeN(3-n, len, q, pnIP)) { return false; } *pnIP = htonl(*pnIP); return true; } // Given a host-ordered mask, this function will determine whether it is a // valid one. Valid masks consist of a N-bit sequence of '1' bits followed by // a (32-N)-bit sequence of '0' bits, where N is 0 to 32. // static bool isValidSubnetMask(in_addr_t ulMask) { in_addr_t ulTest = 0xFFFFFFFFUL; for (int i = 0; i <= 32; i++) { if (ulMask == ulTest) { return true; } ulTest = (ulTest << 1) & 0xFFFFFFFFUL; } return false; } // --------------------------------------------------------------------------- // cf_site: Update site information static CF_HAND(cf_site) { UNUSED_PARAMETER(pExtra); SITE **ppv = (SITE **)vp; struct in_addr addr_num, mask_num; in_addr_t ulMask, ulNetBits; char *addr_txt; char *mask_txt = strchr(str, '/'); if (!mask_txt) { // Standard IP range and netmask notation. // MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t=,"); addr_txt = mux_strtok_parse(&tts); mask_txt = NULL; if (addr_txt) { mask_txt = mux_strtok_parse(&tts); } if (!addr_txt || !*addr_txt || !mask_txt || !*mask_txt) { cf_log_syntax(player, cmd, "Missing host address or mask.", ""); return -1; } if ( !MakeCanonicalIPv4(mask_txt, &ulNetBits) || !isValidSubnetMask(ulMask = ntohl(ulNetBits))) { cf_log_syntax(player, cmd, "Malformed mask address: %s", mask_txt); return -1; } mask_num.s_addr = ulNetBits; } else { // RFC 1517, 1518, 1519, 1520: CIDR IP prefix notation // addr_txt = str; *mask_txt++ = '\0'; if (!is_integer(mask_txt, NULL)) { cf_log_syntax(player, cmd, "Mask field (%s) in CIDR IP prefix is not numeric.", mask_txt); return -1; } int mask_bits = mux_atol(mask_txt); if ( mask_bits < 0 || 32 < mask_bits) { cf_log_syntax(player, cmd, "Mask bits (%d) in CIDR IP prefix out of range.", mask_bits); return -1; } else { // << [0,31] works. << 32 is problematic on some systems. // ulMask = 0; if (mask_bits > 0) { ulMask = (0xFFFFFFFFUL << (32 - mask_bits)) & 0xFFFFFFFFUL; } mask_num.s_addr = htonl(ulMask); } } if (!MakeCanonicalIPv4(addr_txt, &ulNetBits)) { cf_log_syntax(player, cmd, "Malformed host address: %s", addr_txt); return -1; } addr_num.s_addr = ulNetBits; in_addr_t ulAddr = ntohl(addr_num.s_addr); if (ulAddr & ~ulMask) { // The given subnet address contains 'one' bits which are outside // the given subnet mask. If we don't clear these bits, they will // interfere with the subnet tests in site_check. The subnet spec // would be defunct and useless. // cf_log_syntax(player, cmd, "Non-zero host address bits outside the subnet mask (fixed): %s %s", addr_txt, mask_txt); ulAddr &= ulMask; addr_num.s_addr = htonl(ulAddr); } SITE *head = *ppv; // Parse the access entry and allocate space for it. // SITE *site = NULL; try { site = new SITE; } catch (...) { ; // Nothing. } if (NULL == site) { cf_log_syntax(player, cmd, "Out of memory."); return -1; } // Initialize the site entry. // site->address.s_addr = addr_num.s_addr; site->mask.s_addr = mask_num.s_addr; site->flag = nExtra; site->next = NULL; // Link in the entry. Link it at the start if not initializing, at the // end if initializing. This is so that entries in the config file are // processed as you would think they would be, while entries made while // running are processed first. // if (mudstate.bReadingConfiguration) { if (head == NULL) { *ppv = site; } else { SITE *last; for (last = head; last->next; last = last->next) { // Nothing } last->next = site; } } else { site->next = head; *ppv = site; } return 0; } // --------------------------------------------------------------------------- // cf_helpfile, cf_raw_helpfile: Add help files and their corresponding // command. // static int add_helpfile(dbref player, char *cmd, char *str, bool bRaw) { // Parse the two arguments. // MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t\n\r"); char *pCmdName = mux_strtok_parse(&tts); char *pBase = mux_strtok_parse(&tts); if (pBase == NULL) { cf_log_syntax(player, cmd, "Missing path for helpfile %s", pCmdName); return -1; } if ( pCmdName[0] == '_' && pCmdName[1] == '_') { cf_log_syntax(player, cmd, "Helpfile %s would conflict with the use of @addcommand.", pCmdName); return -1; } if (SBUF_SIZE <= strlen(pBase)) { cf_log_syntax(player, cmd, "Helpfile '%s' filename too long", pBase); return -1; } // Allocate an empty place in the table of help file hashes. // if (mudstate.aHelpDesc == NULL) { mudstate.mHelpDesc = 4; mudstate.nHelpDesc = 0; try { mudstate.aHelpDesc = new HELP_DESC[mudstate.mHelpDesc]; } catch (...) { ; // Nothing. } if (NULL == mudstate.aHelpDesc) { cf_log_syntax(player, cmd, "Out of memory."); return -1; } } else if (mudstate.mHelpDesc <= mudstate.nHelpDesc) { int newsize = mudstate.mHelpDesc + 4; HELP_DESC *q = NULL; try { q = new HELP_DESC[newsize]; } catch (...) { ; // Nothing. } if (NULL == mudstate.aHelpDesc) { cf_log_syntax(player, cmd, "Out of memory."); return -1; } memset(q, 0, sizeof(HELP_DESC)*newsize); memcpy(q, mudstate.aHelpDesc, sizeof(HELP_DESC)*mudstate.mHelpDesc); delete [] mudstate.aHelpDesc; mudstate.aHelpDesc = q; mudstate.mHelpDesc = newsize; } // Build HELP_DESC // HELP_DESC *pDesc = mudstate.aHelpDesc + mudstate.nHelpDesc; pDesc->CommandName = StringClone(pCmdName); pDesc->ht = NULL; pDesc->pBaseFilename = StringClone(pBase); pDesc->bEval = !bRaw; // Build up Command Entry. // CMDENT_ONE_ARG *cmdp = NULL; try { cmdp = new CMDENT_ONE_ARG; } catch (...) { ; // Nothing. } if (NULL != cmdp) { cmdp->callseq = CS_ONE_ARG; cmdp->cmdname = StringClone(pCmdName); cmdp->extra = mudstate.nHelpDesc; cmdp->handler = do_help; cmdp->hookmask = 0; cmdp->perms = CA_PUBLIC; cmdp->switches = NULL; // TODO: If a command is deleted with one or both of the two // hashdeleteLEN() calls below, what guarantee do we have that parts // of the command weren't dynamically allocated. This might leak // memory. // const char *p = cmdp->cmdname; hashdeleteLEN(p, strlen(p), &mudstate.command_htab); hashaddLEN(p, strlen(p), cmdp, &mudstate.command_htab); p = tprintf("__%s", cmdp->cmdname); hashdeleteLEN(p, strlen(p), &mudstate.command_htab); hashaddLEN(p, strlen(p), cmdp, &mudstate.command_htab); } else { ISOUTOFMEMORY(cmdp); } mudstate.nHelpDesc++; return 0; } static CF_HAND(cf_helpfile) { UNUSED_PARAMETER(vp); UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); return add_helpfile(player, cmd, str, false); } static CF_HAND(cf_raw_helpfile) { UNUSED_PARAMETER(vp); UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); return add_helpfile(player, cmd, str, true); } // @hook: run softcode before or after running a hardcode command, or softcode access. // Original idea from TinyMUSH 3, code from RhostMUSH. // Used with express permission of RhostMUSH developers. // Bludgeoned into MUX by Jake Nelson 7/2002. // static NAMETAB hook_names[] = { {"after", 3, 0, HOOK_AFTER}, {"before", 3, 0, HOOK_BEFORE}, {"fail", 3, 0, HOOK_AFAIL}, {"ignore", 3, 0, HOOK_IGNORE}, {"igswitch", 3, 0, HOOK_IGSWITCH}, {"permit", 3, 0, HOOK_PERMIT}, {NULL, 0, 0, 0} }; static CF_HAND(cf_hook) { UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); UNUSED_PARAMETER(player); UNUSED_PARAMETER(cmd); char *hookcmd, *hookptr, playbuff[201]; int hookflg; CMDENT *cmdp; int retval = -1; memset(playbuff, '\0', sizeof(playbuff)); mux_strncpy(playbuff, str, 200); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, playbuff); mux_strtok_ctl(&tts, " \t"); hookcmd = mux_strtok_parse(&tts); if (hookcmd != NULL) { cmdp = (CMDENT *)hashfindLEN(hookcmd, strlen(hookcmd), &mudstate.command_htab); } else { return retval; } if (!cmdp) { return retval; } *vp = cmdp->hookmask; mux_strncpy(playbuff, str, 200); hookptr = mux_strtok_parse(&tts); while (hookptr != NULL) { if ( hookptr[0] == '!' && hookptr[1] != '\0') { if (search_nametab(GOD, hook_names, hookptr+1, &hookflg)) { retval = 0; *vp = *vp & ~hookflg; } } else { if (search_nametab(GOD, hook_names, hookptr, &hookflg)) { retval = 0; *vp = *vp | hookflg; } } hookptr = mux_strtok_parse(&tts); } cmdp->hookmask = *vp; return retval; } // --------------------------------------------------------------------------- // cf_include: Read another config file. Only valid during startup. // static CF_HAND(cf_include) { UNUSED_PARAMETER(vp); UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); if (!mudstate.bReadingConfiguration) { return -1; } FILE *fp; if (!mux_fopen(&fp, str, "rb")) { cf_log_notfound(player, cmd, "Config file", str); return -1; } DebugTotalFiles++; char *buf = alloc_lbuf("cf_include"); if (NULL == fgets(buf, LBUF_SIZE, fp)) { return 0; } while (!feof(fp)) { char *zp = buf; // Remove comments. Anything after the '#' is a comment except if it // matches: whitespace + '#' + digit. // while (*zp != '\0') { if ( *zp == '#' && ( zp <= buf || !mux_isspace(zp[-1]) || !mux_isdigit(zp[1]))) { // Found a comment. // *zp = '\0'; } else { zp++; } } // Trim trailing spaces. // while ( buf < zp && mux_isspace(zp[-1])) { *(--zp) = '\0'; } // Process line. // char *cp = buf; // Trim leading spaces. // while (mux_isspace(*cp)) { cp++; } // Skip over command. // char *ap; for (ap = cp; *ap && !mux_isspace(*ap); ap++) { ; // Nothing. } // Terminate command. // if (*ap) { *ap++ = '\0'; } // Skip spaces between command and argument. // while (mux_isspace(*ap)) { ap++; } if (*cp) { cf_set(cp, ap, player); } if (NULL == fgets(buf, LBUF_SIZE, fp)) { break; } } free_lbuf(buf); if (fclose(fp) == 0) { DebugTotalFiles--; } return 0; } // --------------------------------------------------------------------------- // conftable: Table for parsing the configuration file. static CONF conftable[] = { {"access", cf_access, CA_GOD, CA_DISABLED, NULL, access_nametab, 0}, {"alias", cf_cmd_alias, CA_GOD, CA_DISABLED, (int *)&mudstate.command_htab, 0, 0}, {"allow_guest_from_registered_site", cf_bool, CA_GOD, CA_WIZARD, (int *)&mudconf.allow_guest_from_registered_site, NULL, 1}, {"article_rule", cf_art_rule, CA_GOD, CA_DISABLED, (int *)&mudconf.art_rules, NULL, 0}, {"attr_access", cf_attr_access, CA_GOD, CA_DISABLED, NULL, attraccess_nametab, 0}, {"attr_alias", cf_alias, CA_GOD, CA_DISABLED, (int *)&mudstate.attr_name_htab, 0, 0}, {"attr_cmd_access", cf_acmd_access, CA_GOD, CA_DISABLED, NULL, access_nametab, 0}, {"autozone", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.autozone, NULL, 0}, {"bad_name", cf_badname, CA_GOD, CA_DISABLED, NULL, NULL, 0}, {"badsite_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.site_file, NULL, SIZEOF_PATHNAME}, {"cache_names", cf_bool, CA_STATIC, CA_GOD, (int *)&mudconf.cache_names, NULL, 0}, {"cache_pages", cf_int, CA_STATIC, CA_WIZARD, &mudconf.cache_pages, NULL, 0}, {"cache_tick_period", cf_seconds, CA_GOD, CA_WIZARD, (int *)&mudconf.cache_tick_period, NULL, 0}, {"check_interval", cf_int, CA_GOD, CA_WIZARD, &mudconf.check_interval, NULL, 0}, {"check_offset", cf_int, CA_GOD, CA_WIZARD, &mudconf.check_offset, NULL, 0}, {"clone_copies_cost", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.clone_copy_cost, NULL, 0}, {"command_quota_increment", cf_int, CA_GOD, CA_WIZARD, &mudconf.cmd_quota_incr, NULL, 0}, {"command_quota_max", cf_int, CA_GOD, CA_WIZARD, &mudconf.cmd_quota_max, NULL, 0}, {"compress_program", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.compress, NULL, SIZEOF_PATHNAME}, {"compression", cf_bool, CA_GOD, CA_GOD, (int *)&mudconf.compress_db, NULL, 0}, {"comsys_database", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.comsys_db, NULL, SIZEOF_PATHNAME}, {"config_access", cf_cf_access, CA_GOD, CA_DISABLED, NULL, access_nametab, 0}, {"conn_timeout", cf_int, CA_GOD, CA_WIZARD, &mudconf.conn_timeout, NULL, 0}, {"connect_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.conn_file, NULL, SIZEOF_PATHNAME}, {"connect_reg_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.creg_file, NULL, SIZEOF_PATHNAME}, {"lag_limit", cf_seconds, CA_GOD, CA_WIZARD, (int *)&mudconf.max_cmdsecs, NULL, 0}, {"crash_database", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.crashdb, NULL, SIZEOF_PATHNAME}, {"create_max_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.createmax, NULL, 0}, {"create_min_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.createmin, NULL, 0}, {"dark_sleepers", cf_bool, CA_GOD, CA_WIZARD, (int *)&mudconf.dark_sleepers, NULL, 0}, {"default_home", cf_dbref, CA_GOD, CA_PUBLIC, &mudconf.default_home, NULL, 0}, {"destroy_going_now", cf_bool, CA_GOD, CA_WIZARD, (int *)&mudconf.destroy_going_now, NULL, 0}, {"dig_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.digcost, NULL, 0}, {"down_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.down_file, NULL, SIZEOF_PATHNAME}, {"down_motd_message", cf_string, CA_GOD, CA_WIZARD, (int *)mudconf.downmotd_msg, NULL, GBUF_SIZE}, {"dump_interval", cf_int, CA_GOD, CA_WIZARD, &mudconf.dump_interval, NULL, 0}, {"dump_message", cf_string, CA_GOD, CA_WIZARD, (int *)mudconf.dump_msg, NULL, 256}, {"dump_offset", cf_int, CA_GOD, CA_WIZARD, &mudconf.dump_offset, NULL, 0}, {"earn_limit", cf_int, CA_GOD, CA_PUBLIC, &mudconf.paylimit, NULL, 0}, {"eval_comtitle", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.eval_comtitle, NULL, 0}, {"events_daily_hour", cf_int, CA_GOD, CA_PUBLIC, &mudconf.events_daily_hour, NULL, 0}, {"examine_flags", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.ex_flags, NULL, 0}, {"examine_public_attrs", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.exam_public, NULL, 0}, {"exit_flags", cf_set_flags, CA_GOD, CA_DISABLED, (int *)&mudconf.exit_flags, NULL, 0}, {"exit_quota", cf_int, CA_GOD, CA_PUBLIC, &mudconf.exit_quota, NULL, 0}, {"fascist_teleport", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.fascist_tport, NULL, 0}, {"find_money_chance", cf_int, CA_GOD, CA_WIZARD, &mudconf.payfind, NULL, 0}, {"fixed_home_message", cf_string, CA_STATIC, CA_PUBLIC, (int *)mudconf.fixed_home_msg, NULL, 128}, {"fixed_tel_message", cf_string, CA_STATIC, CA_PUBLIC, (int *)mudconf.fixed_tel_msg, NULL, 128}, {"flag_access", cf_flag_access, CA_GOD, CA_DISABLED, NULL, NULL, 0}, {"flag_alias", cf_flagalias, CA_GOD, CA_DISABLED, NULL, NULL, 0}, {"flag_name", cf_flag_name, CA_GOD, CA_DISABLED, NULL, NULL, 0}, {"float_precision", cf_int, CA_STATIC, CA_PUBLIC, &mudconf.float_precision, NULL, 0}, {"forbid_site", cf_site, CA_GOD, CA_DISABLED, (int *)&mudstate.access_list, NULL, H_FORBIDDEN}, #ifndef WIN32 {"fork_dump", cf_bool, CA_GOD, CA_WIZARD, (int *)&mudconf.fork_dump, NULL, 0}, #endif {"full_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.full_file, NULL, SIZEOF_PATHNAME}, {"full_motd_message", cf_string, CA_GOD, CA_WIZARD, (int *)mudconf.fullmotd_msg, NULL, GBUF_SIZE}, {"function_access", cf_func_access, CA_GOD, CA_DISABLED, NULL, access_nametab, 0}, {"function_alias", cf_alias, CA_GOD, CA_DISABLED, (int *)&mudstate.func_htab, NULL, 0}, {"function_invocation_limit", cf_int, CA_GOD, CA_PUBLIC, &mudconf.func_invk_lim, NULL, 0}, {"function_recursion_limit", cf_int, CA_GOD, CA_PUBLIC, &mudconf.func_nest_lim, NULL, 0}, {"game_dir_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.game_dir, NULL, SIZEOF_PATHNAME}, {"game_pag_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.game_pag, NULL, SIZEOF_PATHNAME}, {"global_error_obj", cf_dbref, CA_GOD, CA_GOD, &mudconf.global_error_obj, NULL, 0}, {"good_name", cf_badname, CA_GOD, CA_DISABLED, NULL, NULL, 1}, {"guest_char_num", cf_dbref, CA_STATIC, CA_WIZARD, &mudconf.guest_char, NULL, 0}, {"guest_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.guest_file, NULL, SIZEOF_PATHNAME}, {"guest_nuker", cf_dbref, CA_GOD, CA_WIZARD, &mudconf.guest_nuker, NULL, 0}, {"guest_prefix", cf_string, CA_STATIC, CA_PUBLIC, (int *)mudconf.guest_prefix, NULL, 32}, {"guest_site", cf_site, CA_GOD, CA_DISABLED, (int *)&mudstate.access_list, NULL, H_GUEST}, {"guests_channel", cf_string, CA_STATIC, CA_PUBLIC, (int *)mudconf.guests_channel, NULL, 32}, {"guests_channel_alias", cf_string, CA_STATIC, CA_PUBLIC, (int *)mudconf.guests_channel_alias, NULL, 32}, {"have_comsys", cf_bool, CA_STATIC, CA_PUBLIC, (int *)&mudconf.have_comsys, NULL, 0}, {"have_mailer", cf_bool, CA_STATIC, CA_PUBLIC, (int *)&mudconf.have_mailer, NULL, 0}, {"have_zones", cf_bool, CA_STATIC, CA_PUBLIC, (int *)&mudconf.have_zones, NULL, 0}, {"helpfile", cf_helpfile, CA_STATIC, CA_DISABLED, NULL, NULL, 0}, {"hook_cmd", cf_hook, CA_GOD, CA_GOD, &mudconf.hook_cmd, NULL, 0}, {"hook_obj", cf_dbref, CA_GOD, CA_GOD, &mudconf.hook_obj, NULL, 0}, {"hostnames", cf_bool, CA_GOD, CA_WIZARD, (int *)&mudconf.use_hostname, NULL, 0}, {"idle_interval", cf_int, CA_GOD, CA_WIZARD, &mudconf.idle_interval, NULL, 0}, {"idle_timeout", cf_int, CA_GOD, CA_PUBLIC, &mudconf.idle_timeout, NULL, 0}, {"idle_wiz_dark", cf_bool, CA_GOD, CA_WIZARD, (int *)&mudconf.idle_wiz_dark, NULL, 0}, {"include", cf_include, CA_STATIC, CA_DISABLED, NULL, NULL, 0}, {"indent_desc", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.indent_desc, NULL, 0}, {"initial_size", cf_int, CA_STATIC, CA_WIZARD, &mudconf.init_size, NULL, 0}, {"input_database", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.indb, NULL, SIZEOF_PATHNAME}, {"kill_guarantee_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.killguarantee, NULL, 0}, {"kill_max_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.killmax, NULL, 0}, {"kill_min_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.killmin, NULL, 0}, {"lag_maximum", cf_seconds, CA_GOD, CA_WIZARD, (int *)&mudconf.rpt_cmdsecs, NULL, 0}, {"lbuf_size", cf_int, CA_DISABLED, CA_PUBLIC, (int *)&mudconf.lbuf_size, NULL, 0}, {"link_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.linkcost, NULL, 0}, {"list_access", cf_ntab_access, CA_GOD, CA_DISABLED, (int *)list_names, access_nametab, 0}, {"lock_recursion_limit", cf_int, CA_WIZARD, CA_PUBLIC, &mudconf.lock_nest_lim, NULL, 0}, {"log", cf_modify_bits, CA_GOD, CA_DISABLED, &mudconf.log_options, logoptions_nametab, 0}, {"log_options", cf_modify_bits, CA_GOD, CA_DISABLED, &mudconf.log_info, logdata_nametab, 0}, {"logout_cmd_access", cf_ntab_access, CA_GOD, CA_DISABLED, (int *)logout_cmdtable, access_nametab, 0}, {"logout_cmd_alias", cf_alias, CA_GOD, CA_DISABLED, (int *)&mudstate.logout_cmd_htab,NULL, 0}, {"look_obey_terse", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.terse_look, NULL, 0}, {"machine_command_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.machinecost, NULL, 0}, {"mail_database", cf_string_dyn, CA_GOD, CA_GOD, (int *)&mudconf.mail_db, NULL, SIZEOF_PATHNAME}, {"mail_expiration", cf_int, CA_GOD, CA_PUBLIC, &mudconf.mail_expiration, NULL, 0}, {"mail_per_hour", cf_int, CA_GOD, CA_PUBLIC, &mudconf.mail_per_hour, NULL, 0}, {"master_room", cf_dbref, CA_GOD, CA_WIZARD, &mudconf.master_room, NULL, 0}, {"match_own_commands", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.match_mine, NULL, 0}, {"max_cache_size", cf_int, CA_GOD, CA_GOD, (int *)&mudconf.max_cache_size, NULL, 0}, {"max_players", cf_int, CA_GOD, CA_WIZARD, &mudconf.max_players, NULL, 0}, {"min_guests", cf_int, CA_STATIC, CA_GOD, (int *)&mudconf.min_guests, NULL, 0}, {"money_name_plural", cf_string, CA_GOD, CA_PUBLIC, (int *)mudconf.many_coins, NULL, 32}, {"money_name_singular", cf_string, CA_GOD, CA_PUBLIC, (int *)mudconf.one_coin, NULL, 32}, {"motd_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.motd_file, NULL, SIZEOF_PATHNAME}, {"motd_message", cf_string, CA_GOD, CA_WIZARD, (int *)mudconf.motd_msg, NULL, GBUF_SIZE}, {"mud_name", cf_string, CA_GOD, CA_PUBLIC, (int *)mudconf.mud_name, NULL, 32}, {"newuser_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.crea_file, NULL, SIZEOF_PATHNAME}, {"nositemon_site", cf_site, CA_GOD, CA_DISABLED, (int *)&mudstate.access_list, NULL, H_NOSITEMON}, {"notify_recursion_limit", cf_int, CA_GOD, CA_PUBLIC, &mudconf.ntfy_nest_lim, NULL, 0}, {"number_guests", cf_int, CA_STATIC, CA_WIZARD, &mudconf.number_guests, NULL, 0}, {"open_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.opencost, NULL, 0}, {"output_database", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.outdb, NULL, SIZEOF_PATHNAME}, {"output_limit", cf_int, CA_GOD, CA_WIZARD, (int *)&mudconf.output_limit, NULL, 0}, {"page_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.pagecost, NULL, 0}, {"paranoid_allocate", cf_bool, CA_GOD, CA_WIZARD, (int *)&mudconf.paranoid_alloc, NULL, 0}, {"parent_recursion_limit", cf_int, CA_GOD, CA_PUBLIC, &mudconf.parent_nest_lim, NULL, 0}, {"paycheck", cf_int, CA_GOD, CA_PUBLIC, &mudconf.paycheck, NULL, 0}, {"pemit_any_object", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.pemit_any, NULL, 0}, {"pemit_far_players", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.pemit_players, NULL, 0}, {"permit_site", cf_site, CA_GOD, CA_DISABLED, (int *)&mudstate.access_list, NULL, 0}, {"player_flags", cf_set_flags, CA_GOD, CA_DISABLED, (int *)&mudconf.player_flags, NULL, 0}, {"player_listen", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.player_listen, NULL, 0}, {"player_match_own_commands", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.match_mine_pl, NULL, 0}, {"player_name_spaces", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.name_spaces, NULL, 0}, {"player_queue_limit", cf_int, CA_GOD, CA_PUBLIC, &mudconf.queuemax, NULL, 0}, {"player_quota", cf_int, CA_GOD, CA_PUBLIC, &mudconf.player_quota, NULL, 0}, {"player_starting_home", cf_dbref, CA_GOD, CA_PUBLIC, &mudconf.start_home, NULL, 0}, {"player_starting_room", cf_dbref, CA_GOD, CA_PUBLIC, &mudconf.start_room, NULL, 0}, {"port", cf_int_array, CA_STATIC, CA_PUBLIC, (int *)&mudconf.ports, NULL, MAX_LISTEN_PORTS}, {"postdump_message", cf_string, CA_GOD, CA_WIZARD, (int *)mudconf.postdump_msg, NULL, 256}, {"power_alias", cf_poweralias, CA_GOD, CA_DISABLED, NULL, NULL, 0}, {"pcreate_per_hour", cf_int, CA_STATIC, CA_PUBLIC, (int *)&mudconf.pcreate_per_hour,NULL, 0}, {"public_channel", cf_string, CA_STATIC, CA_PUBLIC, (int *)mudconf.public_channel, NULL, 32}, {"public_channel_alias", cf_string, CA_STATIC, CA_PUBLIC, (int *)mudconf.public_channel_alias, NULL, 32}, {"public_flags", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.pub_flags, NULL, 0}, {"pueblo_message", cf_string, CA_GOD, CA_WIZARD, (int *)mudconf.pueblo_msg, NULL, GBUF_SIZE}, {"queue_active_chunk", cf_int, CA_GOD, CA_PUBLIC, &mudconf.active_q_chunk, NULL, 0}, {"queue_idle_chunk", cf_int, CA_GOD, CA_PUBLIC, &mudconf.queue_chunk, NULL, 0}, {"quiet_look", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.quiet_look, NULL, 0}, {"quiet_whisper", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.quiet_whisper, NULL, 0}, {"quit_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.quit_file, NULL, SIZEOF_PATHNAME}, {"quotas", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.quotas, NULL, 0}, {"raw_helpfile", cf_raw_helpfile,CA_STATIC, CA_DISABLED, NULL, NULL, 0}, {"read_remote_desc", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.read_rem_desc, NULL, 0}, {"read_remote_name", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.read_rem_name, NULL, 0}, {"register_create_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.regf_file, NULL, SIZEOF_PATHNAME}, {"register_site", cf_site, CA_GOD, CA_DISABLED, (int *)&mudstate.access_list, NULL, H_REGISTRATION}, {"reset_players", cf_bool, CA_GOD, CA_DISABLED, (int *)&mudconf.reset_players, NULL, 0}, {"restrict_home", cf_bool, CA_GOD, CA_DISABLED, (int *)&mudconf.restrict_home, NULL, 0}, {"retry_limit", cf_int, CA_GOD, CA_WIZARD, &mudconf.retry_limit, NULL, 0}, {"robot_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.robotcost, NULL, 0}, {"robot_flags", cf_set_flags, CA_GOD, CA_DISABLED, (int *)&mudconf.robot_flags, NULL, 0}, {"robot_speech", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.robot_speak, NULL, 0}, {"room_flags", cf_set_flags, CA_GOD, CA_DISABLED, (int *)&mudconf.room_flags, NULL, 0}, {"room_quota", cf_int, CA_GOD, CA_PUBLIC, &mudconf.room_quota, NULL, 0}, {"run_startup", cf_bool, CA_STATIC, CA_WIZARD, (int *)&mudconf.run_startup, NULL, 0}, {"sacrifice_adjust", cf_int, CA_GOD, CA_PUBLIC, &mudconf.sacadjust, NULL, 0}, {"sacrifice_factor", cf_int, CA_GOD, CA_PUBLIC, &mudconf.sacfactor, NULL, 0}, {"safe_wipe", cf_bool, CA_GOD, CA_WIZARD, (int *)&mudconf.safe_wipe, NULL, 0}, {"safer_passwords", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.safer_passwords, NULL, 0}, {"search_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.searchcost, NULL, 0}, {"see_owned_dark", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.see_own_dark, NULL, 0}, {"signal_action", cf_option, CA_STATIC, CA_GOD, &mudconf.sig_action, sigactions_nametab, 0}, {"site_chars", cf_int, CA_GOD, CA_WIZARD, (int *)&mudconf.site_chars, NULL, 0}, {"space_compress", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.space_compress, NULL, 0}, {"stack_limit", cf_int, CA_GOD, CA_PUBLIC, &mudconf.stack_limit, NULL, 0}, {"starting_money", cf_int, CA_GOD, CA_PUBLIC, &mudconf.paystart, NULL, 0}, {"starting_quota", cf_int, CA_GOD, CA_PUBLIC, &mudconf.start_quota, NULL, 0}, {"status_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.status_file, NULL, SIZEOF_PATHNAME}, {"stripped_flags", cf_set_flags, CA_GOD, CA_DISABLED, (int *)&mudconf.stripped_flags, NULL, 0}, {"suspect_site", cf_site, CA_GOD, CA_DISABLED, (int *)&mudstate.suspect_list, NULL, H_SUSPECT}, {"sweep_dark", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.sweep_dark, NULL, 0}, {"switch_default_all", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.switch_df_all, NULL, 0}, {"terse_shows_contents", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.terse_contents, NULL, 0}, {"terse_shows_exits", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.terse_exits, NULL, 0}, {"terse_shows_move_messages", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.terse_movemsg, NULL, 0}, {"thing_flags", cf_set_flags, CA_GOD, CA_DISABLED, (int *)&mudconf.thing_flags, NULL, 0}, {"thing_quota", cf_int, CA_GOD, CA_PUBLIC, &mudconf.thing_quota, NULL, 0}, {"timeslice", cf_seconds, CA_GOD, CA_PUBLIC, (int *)&mudconf.timeslice, NULL, 0}, {"toad_recipient", cf_dbref, CA_GOD, CA_WIZARD, &mudconf.toad_recipient, NULL, 0}, {"trace_output_limit", cf_int, CA_GOD, CA_PUBLIC, &mudconf.trace_limit, NULL, 0}, {"trace_topdown", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.trace_topdown, NULL, 0}, {"trust_site", cf_site, CA_GOD, CA_DISABLED, (int *)&mudstate.suspect_list, NULL, 0}, {"uncompress_program", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.uncompress, NULL, SIZEOF_PATHNAME}, {"unowned_safe", cf_bool, CA_GOD, CA_PUBLIC, (int *)&mudconf.safe_unowned, NULL, 0}, {"user_attr_access", cf_modify_bits, CA_GOD, CA_DISABLED, &mudconf.vattr_flags, attraccess_nametab, 0}, {"user_attr_per_hour", cf_int, CA_GOD, CA_PUBLIC, &mudconf.vattr_per_hour, NULL, 0}, {"wait_cost", cf_int, CA_GOD, CA_PUBLIC, &mudconf.waitcost, NULL, 0}, {"wizard_motd_file", cf_string_dyn, CA_STATIC, CA_GOD, (int *)&mudconf.wizmotd_file, NULL, SIZEOF_PATHNAME}, {"wizard_motd_message", cf_string, CA_GOD, CA_WIZARD, (int *)mudconf.wizmotd_msg, NULL, GBUF_SIZE}, {"zone_recursion_limit", cf_int, CA_GOD, CA_PUBLIC, &mudconf.zone_nest_lim, NULL, 0}, #ifdef REALITY_LVLS {"reality_level", cf_rlevel, CA_STATIC, CA_GOD, (int *)&mudconf, NULL, 0}, {"def_room_rx", cf_int, CA_WIZARD, CA_PUBLIC, (int *)&mudconf.def_room_rx, NULL, 0}, {"def_room_tx", cf_int, CA_WIZARD, CA_PUBLIC, (int *)&mudconf.def_room_tx, NULL, 0}, {"def_player_rx", cf_int, CA_WIZARD, CA_PUBLIC, (int *)&mudconf.def_player_rx, NULL, 0}, {"def_player_tx", cf_int, CA_WIZARD, CA_PUBLIC, (int *)&mudconf.def_player_tx, NULL, 0}, {"def_exit_rx", cf_int, CA_WIZARD, CA_PUBLIC, (int *)&mudconf.def_exit_rx, NULL, 0}, {"def_exit_tx", cf_int, CA_WIZARD, CA_PUBLIC, (int *)&mudconf.def_exit_tx, NULL, 0}, {"def_thing_rx", cf_int, CA_WIZARD, CA_PUBLIC, (int *)&mudconf.def_thing_rx, NULL, 0}, {"def_thing_tx", cf_int, CA_WIZARD, CA_PUBLIC, (int *)&mudconf.def_thing_tx, NULL, 0}, #endif // REALITY_LVLS #ifdef FIRANMUX {"immobile_message", cf_string, CA_WIZARD, CA_PUBLIC, (int *)mudconf.immobile_msg, NULL, 128}, {"sql_server", cf_string, CA_STATIC, CA_DISABLED, (int *)mudconf.sql_server, NULL, 128}, {"sql_user", cf_string, CA_STATIC, CA_DISABLED, (int *)mudconf.sql_user, NULL, 128}, {"sql_password", cf_string, CA_STATIC, CA_DISABLED, (int *)mudconf.sql_password, NULL, 128}, {"sql_database", cf_string, CA_STATIC, CA_DISABLED, (int *)mudconf.sql_database, NULL, 128}, #endif // FIRANMUX {"mail_server", cf_string, CA_STATIC, CA_DISABLED, (int *)mudconf.mail_server, NULL, 128}, {"mail_ehlo", cf_string, CA_STATIC, CA_DISABLED, (int *)mudconf.mail_ehlo, NULL, 128}, {"mail_sendaddr", cf_string, CA_STATIC, CA_DISABLED, (int *)mudconf.mail_sendaddr, NULL, 128}, {"mail_sendname", cf_string, CA_STATIC, CA_DISABLED, (int *)mudconf.mail_sendname, NULL, 128}, {"mail_subject", cf_string, CA_STATIC, CA_DISABLED, (int *)mudconf.mail_subject, NULL, 128}, { NULL, NULL, 0, 0, NULL, NULL, 0} }; // --------------------------------------------------------------------------- // cf_cf_access: Set access on config directives // CF_HAND(cf_cf_access) { UNUSED_PARAMETER(vp); CONF *tp; char *ap; for (ap = str; *ap && !mux_isspace(*ap); ap++) { ; // Nothing } if (*ap) { *ap++ = '\0'; } for (tp = conftable; tp->pname; tp++) { if (!strcmp(tp->pname, str)) { // Cannot modify parameters set CA_STATIC. // if ( tp->flags & CA_STATIC && !mudstate.bReadingConfiguration) { notify(player, NOPERM_MESSAGE); STARTLOG(LOG_CONFIGMODS, "CFG", "PERM"); log_name(player); log_text(" tried to change access to static param: "); log_text(tp->pname); ENDLOG; return -1; } return cf_modify_bits(&tp->flags, ap, pExtra, nExtra, player, cmd); } } cf_log_notfound(player, cmd, "Config directive", str); return -1; } // --------------------------------------------------------------------------- // cf_set: Set config parameter. // int cf_set(char *cp, char *ap, dbref player) { CONF *tp; char *buff = 0; // Search the config parameter table for the command. If we find // it, call the handler to parse the argument. // for (tp = conftable; tp->pname; tp++) { if (!strcmp(tp->pname, cp)) { int i = -1; if ( (tp->flags & CA_DISABLED) == 0 && ( mudstate.bReadingConfiguration || check_access(player, tp->flags))) { if (!mudstate.bReadingConfiguration) { buff = alloc_lbuf("cf_set"); mux_strncpy(buff, ap, LBUF_SIZE-1); } i = tp->interpreter(tp->loc, ap, tp->pExtra, tp->nExtra, player, cp); if (!mudstate.bReadingConfiguration) { STARTLOG(LOG_CONFIGMODS, "CFG", "UPDAT"); log_name(player); log_text(" entered config directive: "); log_text(cp); log_text(" with args '"); log_text(buff); log_text("'. Status: "); switch (i) { case 0: log_text("Success."); break; case 1: log_text("Partial success."); break; case -1: log_text("Failure."); break; default: log_text("Strange."); } ENDLOG; free_lbuf(buff); } } else if (!mudstate.bReadingConfiguration) { notify(player, NOPERM_MESSAGE); } return i; } } // Config directive not found. Complain about it. // cf_log_notfound(player, "Set", "Config directive", cp); return -1; } // Validate important dbrefs. // void ValidateConfigurationDbrefs(void) { static struct { dbref *ploc; dbref dflt; } Table[] = { { &mudconf.default_home, NOTHING }, { &mudconf.global_error_obj, NOTHING }, { &mudconf.guest_char, NOTHING }, { &mudconf.guest_nuker, GOD }, { &mudconf.hook_obj, NOTHING }, { &mudconf.master_room, NOTHING }, { &mudconf.start_home, NOTHING }, { &mudconf.start_room, 0 }, { &mudconf.toad_recipient, GOD }, { NULL, NOTHING } }; for (int i = 0; NULL != Table[i].ploc; i++) { if (*Table[i].ploc != Table[i].dflt) { if (!Good_obj(*Table[i].ploc)) { *Table[i].ploc = Table[i].dflt; } } } } // --------------------------------------------------------------------------- // do_admin: Command handler to set config params at runtime // void do_admin ( dbref executor, dbref caller, dbref enactor, int extra, int nargs, char *kw, char *value ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(extra); UNUSED_PARAMETER(nargs); int i = cf_set(kw, value, executor); if ((i >= 0) && !Quiet(executor)) { notify(executor, "Set."); } ValidateConfigurationDbrefs(); } // --------------------------------------------------------------------------- // cf_read: Read in config parameters from named file // static struct { char **pFilename; const char *pSuffix; } DefaultSuffixes[] = { { &mudconf.outdb, ".out" }, { &mudconf.crashdb, ".CRASH" }, { &mudconf.game_dir, ".dir" }, { &mudconf.game_pag, ".pag" }, { 0, 0 } }; int cf_read(void) { int retval; mudstate.bReadingConfiguration = true; retval = cf_include(NULL, mudconf.config_file, (void *)0, 0, 0, (char *)"init"); mudstate.bReadingConfiguration = false; // Fill in missing DB file names. // size_t nInDB = strlen(mudconf.indb); for (int i = 0; DefaultSuffixes[i].pFilename; i++) { char **p = DefaultSuffixes[i].pFilename; if (**p == '\0') { // The filename is an empty string so we should construct // a default filename. // const char *pSuffix = DefaultSuffixes[i].pSuffix; size_t nSuffix = strlen(pSuffix); char *buff = (char *)MEMALLOC(nInDB + nSuffix + 1); ISOUTOFMEMORY(buff); memcpy(buff, mudconf.indb, nInDB); memcpy(buff + nInDB, pSuffix, nSuffix+1); MEMFREE(*p); *p = buff; } } return retval; } // --------------------------------------------------------------------------- // list_cf_access: List access to config directives. // void list_cf_access(dbref player) { CONF *tp; char *buff; buff = alloc_mbuf("list_cf_access"); for (tp = conftable; tp->pname; tp++) { if (God(player) || check_access(player, tp->flags)) { mux_sprintf(buff, MBUF_SIZE, "%s:", tp->pname); listset_nametab(player, access_nametab, tp->flags, buff, true); } } free_mbuf(buff); } // --------------------------------------------------------------------------- // cf_display: Given a config parameter by name, return its value in some // sane fashion. // void cf_display(dbref player, char *param_name, char *buff, char **bufc) { CONF *tp; for (tp = conftable; tp->pname; tp++) { if (!mux_stricmp(tp->pname, param_name)) { if (check_access(player, tp->rperms)) { if (tp->interpreter == cf_int) { safe_ltoa(*(tp->loc), buff, bufc); return; } else if (tp->interpreter == cf_dbref) { safe_chr('#', buff, bufc); safe_ltoa(*(tp->loc), buff, bufc); return; } else if (tp->interpreter == cf_bool) { bool *pb = (bool *)tp->loc; safe_bool(*pb, buff, bufc); return; } else if (tp->interpreter == cf_string) { safe_str((char *)tp->loc, buff, bufc); return; } else if (tp->interpreter == cf_string_dyn) { safe_str(*(char **)tp->loc, buff, bufc); return; } else if (tp->interpreter == cf_int_array) { IntArray *pia = (IntArray *)(tp->loc); ITL itl; ItemToList_Init(&itl, buff, bufc); for (int i = 0; i < pia->n; i++) { if (!ItemToList_AddInteger(&itl, pia->pi[i])) { break; } } ItemToList_Final(&itl); return; } else if (tp->interpreter == cf_seconds) { CLinearTimeDelta *pltd = (CLinearTimeDelta *)(tp->loc); safe_str(pltd->ReturnSecondsString(7), buff, bufc); return; } } safe_noperm(buff, bufc); return; } } safe_nomatch(buff, bufc); } // --------------------------------------------------------------------------- // cf_list: List all config options the player can read. // void cf_list(dbref player, char *buff, char **bufc) { CONF *tp; ITL itl; ItemToList_Init(&itl, buff, bufc); for (tp = conftable; tp->pname; tp++) { if (check_access(player, tp->rperms)) { if (!ItemToList_AddString(&itl, tp->pname)) { break; } } } ItemToList_Final(&itl); return; } mux2.6/src/bsd.cpp0000600000175000017500000040514711025753746014065 0ustar sdennissdennis/*! \file bsd.cpp * Low-level TCP socket-related code. * * $Id: bsd.cpp 2734 2007-10-28 23:02:55Z brazilofmux $ * * Contains most of the TCP socket-related code. Some socket-related code also * exists in netcommon.cpp, but most of it is here. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #ifndef WIN32 #include #include #include #include #endif // !WIN32 #include #include "attrs.h" #include "command.h" #include "file_c.h" #include "slave.h" #ifdef SOLARIS extern const int _sys_nsig; #define NSIG _sys_nsig #endif // SOLARIS PortInfo aMainGamePorts[MAX_LISTEN_PORTS]; int nMainGamePorts = 0; unsigned int ndescriptors = 0; DESC *descriptor_list = NULL; static void TelnetSetup(DESC *d); static void SiteMonSend(SOCKET, const char *, DESC *, const char *); static DESC *initializesock(SOCKET, struct sockaddr_in *); static DESC *new_connection(PortInfo *Port, int *piError); static bool process_input(DESC *); static int make_nonblocking(SOCKET s); #ifdef WIN32 static bool bDescriptorListInit = false; int game_pid; #else // WIN32 int maxd = 0; pid_t slave_pid = 0; int slave_socket = INVALID_SOCKET; pid_t game_pid; #ifdef QUERY_SLAVE pid_t sqlslave_pid = 0; int sqlslave_socket = INVALID_SOCKET; #endif // QUERY_SLAVE #endif // WIN32 #ifdef WIN32 // First version of Windows NT TCP/IP routines written by Nick Gammon // , and were throughly reviewed, re-written and debugged // by Stephen Dennis . // HANDLE hGameProcess = INVALID_HANDLE_VALUE; FCANCELIO *fpCancelIo = NULL; FGETPROCESSTIMES *fpGetProcessTimes = NULL; HANDLE CompletionPort; // IOs are queued up on this port bool bUseCompletionPorts = true; static OVERLAPPED lpo_aborted; // special to indicate a player has finished TCP IOs static OVERLAPPED lpo_aborted_final; // Finally free the descriptor. static OVERLAPPED lpo_shutdown; // special to indicate a player should do a shutdown static OVERLAPPED lpo_welcome; // special to indicate a player has -just- connected. static OVERLAPPED lpo_wakeup; // special to indicate that the loop should wakeup and return. CRITICAL_SECTION csDescriptorList; // for thread synchronization static DWORD WINAPI MUDListenThread(LPVOID pVoid); static void ProcessWindowsTCP(DWORD dwTimeout); // handle NT-style IOs typedef struct { int port_in; struct sockaddr_in sa_in; } SLAVE_REQUEST; static HANDLE hSlaveRequestStackSemaphore; #define SLAVE_REQUEST_STACK_SIZE 50 static SLAVE_REQUEST SlaveRequests[SLAVE_REQUEST_STACK_SIZE]; static int iSlaveRequest = 0; #define MAX_STRING 514 typedef struct { char host[MAX_STRING]; char token[MAX_STRING]; char ident[MAX_STRING]; } SLAVE_RESULT; static HANDLE hSlaveResultStackSemaphore; #define SLAVE_RESULT_STACK_SIZE 50 static SLAVE_RESULT SlaveResults[SLAVE_RESULT_STACK_SIZE]; static volatile int iSlaveResult = 0; #define NUM_SLAVE_THREADS 5 typedef struct tagSlaveThreadsInfo { unsigned iDoing; DWORD iError; DWORD hThreadId; } SLAVETHREADINFO; static SLAVETHREADINFO SlaveThreadInfo[NUM_SLAVE_THREADS]; static HANDLE hSlaveThreadsSemaphore; static DWORD WINAPI SlaveProc(LPVOID lpParameter) { SLAVE_REQUEST req; unsigned long addr; struct hostent *hp; DWORD iSlave = (DWORD)lpParameter; if (NUM_SLAVE_THREADS <= iSlave) return 1; SlaveThreadInfo[iSlave].iDoing = __LINE__; for (;;) { // Go to sleep until there's something useful to do. // SlaveThreadInfo[iSlave].iDoing = __LINE__; DWORD dwReason = WaitForSingleObject(hSlaveThreadsSemaphore, 30000UL*NUM_SLAVE_THREADS); switch (dwReason) { case WAIT_TIMEOUT: case WAIT_OBJECT_0: // Either the main game thread rang, or 60 seconds has past, // and it's probably a good idea to check the stack anyway. // break; default: // Either the main game thread has terminated, in which case // we want to, too, or the function itself has failed, in which // case: calling it again won't do much good. // SlaveThreadInfo[iSlave].iError = __LINE__; return 1; } SlaveThreadInfo[iSlave].iDoing = __LINE__; for (;;) { // Go take the request off the stack, but not if it takes more // than 5 seconds to do it. Go back to sleep if we time out. The // request can wait: either another thread will pick it up, or // we'll wakeup in 60 seconds anyway. // SlaveThreadInfo[iSlave].iDoing = __LINE__; if (WAIT_OBJECT_0 != WaitForSingleObject(hSlaveRequestStackSemaphore, 5000)) { SlaveThreadInfo[iSlave].iError = __LINE__; break; } SlaveThreadInfo[iSlave].iDoing = __LINE__; // We have control of the stack. // if (iSlaveRequest <= 0) { // The stack is empty. Release control and go back to sleep. // SlaveThreadInfo[iSlave].iDoing = __LINE__; ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL); SlaveThreadInfo[iSlave].iDoing = __LINE__; break; } // Remove the request from the stack. // iSlaveRequest--; req = SlaveRequests[iSlaveRequest]; SlaveThreadInfo[iSlave].iDoing = __LINE__; ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL); SlaveThreadInfo[iSlave].iDoing = __LINE__; // Ok, we have complete control of this address, now, so let's // do the host/ident thing. // // Take note of what time it is. // #define IDENT_PROTOCOL_TIMEOUT 5*60 // 5 minutes expressed in seconds. CLinearTimeAbsolute ltaTimeoutOrigin; ltaTimeoutOrigin.GetUTC(); CLinearTimeDelta ltdTimeout; ltdTimeout.SetSeconds(IDENT_PROTOCOL_TIMEOUT); CLinearTimeAbsolute ltaTimeoutForward(ltaTimeoutOrigin, ltdTimeout); ltdTimeout.SetSeconds(-IDENT_PROTOCOL_TIMEOUT); CLinearTimeAbsolute ltaTimeoutBackward(ltaTimeoutOrigin, ltdTimeout); addr = req.sa_in.sin_addr.S_un.S_addr; hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); if ( hp && strlen(hp->h_name) < MAX_STRING) { SlaveThreadInfo[iSlave].iDoing = __LINE__; char host[MAX_STRING]; char token[MAX_STRING]; char szIdent[MAX_STRING]; struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); SOCKET s; // We have a host name. // mux_strncpy(host, inet_ntoa(req.sa_in.sin_addr), MAX_STRING-1); mux_strncpy(token, hp->h_name, MAX_STRING-1); // Setup ident port. // sin.sin_family = hp->h_addrtype; memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); sin.sin_port = htons(113); szIdent[0] = 0; s = socket(hp->h_addrtype, SOCK_STREAM, 0); SlaveThreadInfo[iSlave].iDoing = __LINE__; if (s != INVALID_SOCKET) { SlaveThreadInfo[iSlave].iDoing = __LINE__; DebugTotalSockets++; if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR) { SlaveThreadInfo[iSlave].iDoing = __LINE__; shutdown(s, SD_BOTH); SlaveThreadInfo[iSlave].iDoing = __LINE__; if (closesocket(s) == 0) { DebugTotalSockets--; } s = INVALID_SOCKET; } else { int TurnOn = 1; setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&TurnOn, sizeof(TurnOn)); SlaveThreadInfo[iSlave].iDoing = __LINE__; char szPortPair[128]; mux_sprintf(szPortPair, sizeof(szPortPair), "%d, %d\r\n", ntohs(req.sa_in.sin_port), req.port_in); SlaveThreadInfo[iSlave].iDoing = __LINE__; size_t nPortPair = strlen(szPortPair); CLinearTimeAbsolute ltaCurrent; ltaCurrent.GetUTC(); if ( ltaTimeoutBackward < ltaCurrent && ltaCurrent < ltaTimeoutForward && send(s, szPortPair, static_cast(nPortPair), 0) != SOCKET_ERROR) { SlaveThreadInfo[iSlave].iDoing = __LINE__; int nIdent = 0; int cc; char szIdentBuffer[MAX_STRING]; szIdentBuffer[0] = 0; bool bAllDone = false; ltaCurrent.GetUTC(); while ( !bAllDone && nIdent < sizeof(szIdent)-1 && ltaTimeoutBackward < ltaCurrent && ltaCurrent < ltaTimeoutForward && (cc = recv(s, szIdentBuffer, sizeof(szIdentBuffer)-1, 0)) != SOCKET_ERROR && cc != 0) { SlaveThreadInfo[iSlave].iDoing = __LINE__; int nIdentBuffer = cc; szIdentBuffer[nIdentBuffer] = 0; char *p = szIdentBuffer; for (; nIdent < sizeof(szIdent)-1;) { if ( *p == '\0' || *p == '\r' || *p == '\n') { bAllDone = true; break; } if (mux_isprint(*p)) { szIdent[nIdent++] = *p; } p++; } szIdent[nIdent] = '\0'; ltaCurrent.GetUTC(); } } SlaveThreadInfo[iSlave].iDoing = __LINE__; shutdown(s, SD_BOTH); SlaveThreadInfo[iSlave].iDoing = __LINE__; if (closesocket(s) == 0) { DebugTotalSockets--; } s = INVALID_SOCKET; } } SlaveThreadInfo[iSlave].iDoing = __LINE__; if (WAIT_OBJECT_0 == WaitForSingleObject(hSlaveResultStackSemaphore, INFINITE)) { SlaveThreadInfo[iSlave].iDoing = __LINE__; if (iSlaveResult < SLAVE_RESULT_STACK_SIZE) { SlaveThreadInfo[iSlave].iDoing = __LINE__; mux_strncpy(SlaveResults[iSlaveResult].host, host, MAX_STRING-1); mux_strncpy(SlaveResults[iSlaveResult].token, token, MAX_STRING-1); mux_strncpy(SlaveResults[iSlaveResult].ident, szIdent, MAX_STRING-1); iSlaveResult++; } else { // The result stack is full, so we just toss // the info and act like it never happened. // SlaveThreadInfo[iSlave].iError = __LINE__; } SlaveThreadInfo[iSlave].iDoing = __LINE__; ReleaseSemaphore(hSlaveResultStackSemaphore, 1, NULL); SlaveThreadInfo[iSlave].iDoing = __LINE__; } else { // The main game thread terminated or the function itself failed, // There isn't much left to do except terminate ourselves. // SlaveThreadInfo[iSlave].iError = __LINE__; return 1; } } } } //SlaveThreadInfo[iSlave].iDoing = __LINE__; //return 1; } static bool bSlaveBooted = false; void boot_slave(dbref executor, dbref caller, dbref enactor, int) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); int iSlave; if (bSlaveBooted) return; hSlaveThreadsSemaphore = CreateSemaphore(NULL, 0, NUM_SLAVE_THREADS, NULL); hSlaveRequestStackSemaphore = CreateSemaphore(NULL, 1, 1, NULL); hSlaveResultStackSemaphore = CreateSemaphore(NULL, 1, 1, NULL); DebugTotalSemaphores += 3; for (iSlave = 0; iSlave < NUM_SLAVE_THREADS; iSlave++) { SlaveThreadInfo[iSlave].iDoing = 0; SlaveThreadInfo[iSlave].iError = 0; CreateThread(NULL, 0, SlaveProc, (LPVOID)iSlave, 0, &SlaveThreadInfo[iSlave].hThreadId); DebugTotalThreads++; } bSlaveBooted = true; } static int get_slave_result(void) { char host[MAX_STRING]; char token[MAX_STRING]; char ident[MAX_STRING]; char os[MAX_STRING]; char userid[MAX_STRING]; DESC *d; int local_port, remote_port; // Go take the result off the stack, but not if it takes more // than 5 seconds to do it. Skip it if we time out. // if (WAIT_OBJECT_0 != WaitForSingleObject(hSlaveResultStackSemaphore, 5000)) { return 1; } // We have control of the stack. Go back to sleep if the stack is empty. // if (iSlaveResult <= 0) { ReleaseSemaphore(hSlaveResultStackSemaphore, 1, NULL); return 1; } iSlaveResult--; mux_strncpy(host, SlaveResults[iSlaveResult].host, MAX_STRING-1); mux_strncpy(token, SlaveResults[iSlaveResult].token, MAX_STRING-1); mux_strncpy(ident, SlaveResults[iSlaveResult].ident, MAX_STRING-1); ReleaseSemaphore(hSlaveResultStackSemaphore, 1, NULL); // At this point, we have a host name on our own stack. // if (!mudconf.use_hostname) { return 1; } for (d = descriptor_list; d; d = d->next) { if (strcmp(d->addr, host)) { continue; } mux_strncpy(d->addr, token, 50); if (d->player != 0) { if (d->username[0]) { atr_add_raw(d->player, A_LASTSITE, tprintf("%s@%s", d->username, d->addr)); } else { atr_add_raw(d->player, A_LASTSITE, d->addr); } atr_add_raw(d->player, A_LASTIP, inet_ntoa((d->address).sin_addr)); } } if (sscanf(ident, "%d , %d : %s : %s : %s", &remote_port, &local_port, token, os, userid) != 5) { return 1; } for (d = descriptor_list; d; d = d->next) { if (ntohs((d->address).sin_port) != remote_port) { continue; } mux_strncpy(d->username, userid, 10); if (d->player != 0) { atr_add_raw(d->player, A_LASTSITE, tprintf("%s@%s", d->username, d->addr)); } } return 1; } #else // WIN32 void CleanUpSlaveSocket(void) { if (!IS_INVALID_SOCKET(slave_socket)) { shutdown(slave_socket, SD_BOTH); if (SOCKET_CLOSE(slave_socket) == 0) { DebugTotalSockets--; } slave_socket = INVALID_SOCKET; } } void CleanUpSlaveProcess(void) { if (slave_pid > 0) { kill(slave_pid, SIGKILL); waitpid(slave_pid, NULL, 0); } slave_pid = 0; } #ifdef QUERY_SLAVE void CleanUpSQLSlaveSocket(void) { if (!IS_INVALID_SOCKET(sqlslave_socket)) { shutdown(sqlslave_socket, SD_BOTH); if (SOCKET_CLOSE(sqlslave_socket) == 0) { DebugTotalSockets--; } sqlslave_socket = INVALID_SOCKET; } } void CleanUpSQLSlaveProcess(void) { if (sqlslave_pid > 0) { kill(sqlslave_pid, SIGKILL); waitpid(sqlslave_pid, NULL, 0); } sqlslave_pid = 0; } /*! \brief Lauch query slave process. * * This spawns the query slave process and creates a socket-oriented, * bi-directional communiocation path between that process and this * process. Any existing slave process is killed. * * \param executor dbref of Executor. * \param caller dbref of Caller. * \param enactor dbref of Enactor. * \return None. */ void boot_sqlslave(dbref executor, dbref caller, dbref enactor, int) { const char *pFailedFunc = NULL; int sv[2]; int i; int maxfds; #ifdef HAVE_GETDTABLESIZE maxfds = getdtablesize(); #else // HAVE_GETDTABLESIZE maxfds = sysconf(_SC_OPEN_MAX); #endif // HAVE_GETDTABLESIZE CleanUpSQLSlaveSocket(); CleanUpSQLSlaveProcess(); if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) { pFailedFunc = "socketpair() error: "; goto failure; } // Set to nonblocking. // if (make_nonblocking(sv[0]) < 0) { pFailedFunc = "make_nonblocking() error: "; mux_close(sv[0]); mux_close(sv[1]); goto failure; } sqlslave_pid = fork(); switch (sqlslave_pid) { case -1: pFailedFunc = "fork() error: "; mux_close(sv[0]); mux_close(sv[1]); goto failure; case 0: // If we don't clear this alarm, the child will eventually receive a // SIG_PROF. // MuxAlarm.Clear(); // Child. The following calls to dup2() assume only the minimal // dup2() functionality. That is, the destination descriptor is // always available for it, and sv[1] is never that descriptor. // It is likely that the standard defined behavior of dup2() // would handle the job by itself more directly, but a little // extra code is low-cost insurance. // mux_close(sv[0]); if (sv[1] != 0) { mux_close(0); if (dup2(sv[1], 0) == -1) { _exit(1); } } if (sv[1] != 1) { mux_close(1); if (dup2(sv[1], 1) == -1) { _exit(1); } } for (i = 3; i < maxfds; i++) { mux_close(i); } execlp("bin/sqlslave", "sqlslave", NULL); _exit(1); } mux_close(sv[1]); sqlslave_socket = sv[0]; DebugTotalSockets++; if (make_nonblocking(sqlslave_socket) < 0) { pFailedFunc = "make_nonblocking() error: "; CleanUpSQLSlaveSocket(); goto failure; } if ( !IS_INVALID_SOCKET(sqlslave_socket) && maxd <= sqlslave_socket) { maxd = sqlslave_socket + 1; } STARTLOG(LOG_ALWAYS, "NET", "QUERY"); log_text("SQL slave started on fd "); log_number(sqlslave_socket); ENDLOG; mux_write(sqlslave_socket, "PING", 4); return; failure: CleanUpSQLSlaveProcess(); STARTLOG(LOG_ALWAYS, "NET", "SQL"); log_text(pFailedFunc); log_number(errno); ENDLOG; } #endif // QUERY_SLAVE /*! \brief Lauch reverse-DNS slave process. * * This spawns the reverse-DNS slave process and creates a socket-oriented, * bi-directional communiocation path between that process and this * process. Any existing slave process is killed. * * \param executor dbref of Executor. * \param caller dbref of Caller. * \param enactor dbref of Enactor. * \return None. */ void boot_slave(dbref executor, dbref caller, dbref enactor, int) { const char *pFailedFunc = 0; int sv[2]; int i; int maxfds; #ifdef HAVE_GETDTABLESIZE maxfds = getdtablesize(); #else // HAVE_GETDTABLESIZE maxfds = sysconf(_SC_OPEN_MAX); #endif // HAVE_GETDTABLESIZE CleanUpSlaveSocket(); CleanUpSlaveProcess(); if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) { pFailedFunc = "socketpair() error: "; goto failure; } // Set to nonblocking. // if (make_nonblocking(sv[0]) < 0) { pFailedFunc = "make_nonblocking() error: "; mux_close(sv[0]); mux_close(sv[1]); goto failure; } slave_pid = fork(); switch (slave_pid) { case -1: pFailedFunc = "fork() error: "; mux_close(sv[0]); mux_close(sv[1]); goto failure; case 0: // If we don't clear this alarm, the child will eventually receive a // SIG_PROF. // MuxAlarm.Clear(); // Child. The following calls to dup2() assume only the minimal // dup2() functionality. That is, the destination descriptor is // always available for it, and sv[1] is never that descriptor. // It is likely that the standard defined behavior of dup2() // would handle the job by itself more directly, but a little // extra code is low-cost insurance. // mux_close(sv[0]); if (sv[1] != 0) { mux_close(0); if (dup2(sv[1], 0) == -1) { _exit(1); } } if (sv[1] != 1) { mux_close(1); if (dup2(sv[1], 1) == -1) { _exit(1); } } for (i = 3; i < maxfds; i++) { mux_close(i); } execlp("bin/slave", "slave", NULL); _exit(1); } close(sv[1]); slave_socket = sv[0]; DebugTotalSockets++; if (make_nonblocking(slave_socket) < 0) { pFailedFunc = "make_nonblocking() error: "; CleanUpSlaveSocket(); goto failure; } if ( !IS_INVALID_SOCKET(slave_socket) && maxd <= slave_socket) { maxd = slave_socket + 1; } STARTLOG(LOG_ALWAYS, "NET", "SLAVE"); log_text("DNS lookup slave started on fd "); log_number(slave_socket); ENDLOG; return; failure: CleanUpSlaveProcess(); STARTLOG(LOG_ALWAYS, "NET", "SLAVE"); log_text(pFailedFunc); log_number(errno); ENDLOG; } #ifdef QUERY_SLAVE /*! \brief Get results from the SQL query slave. * * Any communication from the SQL query slave is logged. * * \return -1 for failure and 0 for success. */ static int get_sqlslave_result(void) { char buf[LBUF_SIZE]; int len = mux_read(sqlslave_socket, buf, sizeof(buf)-1); if (len < 0) { int iSocketError = SOCKET_LAST_ERROR; if ( iSocketError == SOCKET_EAGAIN || iSocketError == SOCKET_EWOULDBLOCK) { return -1; } CleanUpSQLSlaveSocket(); CleanUpSQLSlaveProcess(); STARTLOG(LOG_ALWAYS, "NET", "QUERY"); log_text("read() of query slave failed. Query Slave stopped."); ENDLOG; return -1; } else if (len == 0) { return -1; } buf[len] = '\0'; STARTLOG(LOG_ALWAYS, "NET", "QUERY"); log_text(buf); ENDLOG; return 0; } #endif // QUERY_SLAVE // Get a result from the slave // static int get_slave_result(void) { int local_port, remote_port; DESC *d; char *buf = alloc_lbuf("slave_buf"); int len = mux_read(slave_socket, buf, LBUF_SIZE-1); if (len < 0) { int iSocketError = SOCKET_LAST_ERROR; if ( iSocketError == SOCKET_EAGAIN || iSocketError == SOCKET_EWOULDBLOCK) { free_lbuf(buf); return -1; } CleanUpSlaveSocket(); CleanUpSlaveProcess(); free_lbuf(buf); STARTLOG(LOG_ALWAYS, "NET", "SLAVE"); log_text("read() of slave result failed. Slave stopped."); ENDLOG; return -1; } else if (len == 0) { free_lbuf(buf); return -1; } buf[len] = '\0'; char *token = alloc_lbuf("slave_token"); char *os = alloc_lbuf("slave_os"); char *userid = alloc_lbuf("slave_userid"); char *host = alloc_lbuf("slave_host"); char *p; if (sscanf(buf, "%s %s", host, token) != 2) { goto Done; } p = strchr(buf, '\n'); if (!p) { goto Done; } *p = '\0'; if (mudconf.use_hostname) { for (d = descriptor_list; d; d = d->next) { if (strcmp(d->addr, host) != 0) { continue; } strncpy(d->addr, token, 50); d->addr[50] = '\0'; if (d->player != 0) { if (d->username[0]) { atr_add_raw(d->player, A_LASTSITE, tprintf("%s@%s", d->username, d->addr)); } else { atr_add_raw(d->player, A_LASTSITE, d->addr); } atr_add_raw(d->player, A_LASTIP, inet_ntoa((d->address).sin_addr)); } } } if (sscanf(p + 1, "%s %d , %d : %s : %s : %s", host, &remote_port, &local_port, token, os, userid) != 6) { goto Done; } for (d = descriptor_list; d; d = d->next) { if (ntohs((d->address).sin_port) != remote_port) continue; strncpy(d->username, userid, 10); d->username[10] = '\0'; if (d->player != 0) { atr_add_raw(d->player, A_LASTSITE, tprintf("%s@%s", d->username, d->addr)); } } Done: free_lbuf(buf); free_lbuf(token); free_lbuf(os); free_lbuf(userid); free_lbuf(host); return 0; } #endif // WIN32 static void make_socket(PortInfo *Port) { SOCKET s; struct sockaddr_in server; int opt = 1; Port->socket = INVALID_SOCKET; #ifdef WIN32 // If we are running Windows NT we must create a completion port, // and start up a listening thread for new connections // if (bUseCompletionPorts) { int nRet; // create initial IO completion port, so threads have something to wait on // CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (!CompletionPort) { Log.tinyprintf("Error %ld on CreateIoCompletionPort" ENDLINE, GetLastError()); return; } // Initialize the critical section // if (!bDescriptorListInit) { InitializeCriticalSection(&csDescriptorList); bDescriptorListInit = true; } // Create a TCP/IP stream socket // s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (IS_INVALID_SOCKET(s)) { log_perror("NET", "FAIL", NULL, "creating master socket"); return; } DebugTotalSockets++; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) { log_perror("NET", "FAIL", NULL, "setsockopt"); } // Fill in the the address structure // server.sin_port = htons((unsigned short)(Port->port)); server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; // bind our name to the socket // nRet = bind(s, (LPSOCKADDR) &server, sizeof server); if (IS_SOCKET_ERROR(nRet)) { Log.tinyprintf("Error %ld on bind" ENDLINE, SOCKET_LAST_ERROR); if (SOCKET_CLOSE(s) == 0) { DebugTotalSockets--; } s = INVALID_SOCKET; return; } // Set the socket to listen // nRet = listen(s, SOMAXCONN); if (nRet) { Log.tinyprintf("Error %ld on listen" ENDLINE, SOCKET_LAST_ERROR); if (SOCKET_CLOSE(s) == 0) { DebugTotalSockets--; } s = INVALID_SOCKET; return; } // Create the MUD listening thread // HANDLE hThread = CreateThread(NULL, 0, MUDListenThread, (LPVOID)Port, 0, NULL); if (NULL == hThread) { log_perror("NET", "FAIL", "CreateThread", "setsockopt"); if (SOCKET_CLOSE(s) == 0) { DebugTotalSockets--; } s = INVALID_SOCKET; return; } Port->socket = s; Log.tinyprintf("Listening (NT-style) on port %d" ENDLINE, Port->port); return; } #endif // WIN32 s = socket(AF_INET, SOCK_STREAM, 0); if (IS_INVALID_SOCKET(s)) { log_perror("NET", "FAIL", NULL, "creating master socket"); return; } DebugTotalSockets++; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) { log_perror("NET", "FAIL", NULL, "setsockopt"); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons((unsigned short)(Port->port)); int cc = bind(s, (struct sockaddr *)&server, sizeof(server)); if (IS_SOCKET_ERROR(cc)) { log_perror("NET", "FAIL", NULL, "bind"); if (SOCKET_CLOSE(s) == 0) { DebugTotalSockets--; } s = INVALID_SOCKET; return; } listen(s, SOMAXCONN); Port->socket = s; Log.tinyprintf("Listening on port %d" ENDLINE, Port->port); } #ifndef WIN32 bool ValidSocket(SOCKET s) { struct stat fstatbuf; if (fstat(s, &fstatbuf) < 0) { return false; } return true; } #endif // WIN32 void SetupPorts(int *pnPorts, PortInfo aPorts[], IntArray *pia) { // Any existing open port which does not appear in the requested set // should be closed. // int i, j, k; bool bFound; for (i = 0; i < *pnPorts; i++) { bFound = false; for (j = 0; j < pia->n; j++) { if (aPorts[i].port == pia->pi[j]) { bFound = true; break; } } if (!bFound) { if (SOCKET_CLOSE(aPorts[i].socket) == 0) { DebugTotalSockets--; (*pnPorts)--; k = *pnPorts; if (i != k) { aPorts[i] = aPorts[k]; } aPorts[k].port = 0; aPorts[k].socket = INVALID_SOCKET; } } } // Any requested port which does not appear in the existing open set // of ports should be opened. // for (j = 0; j < pia->n; j++) { bFound = false; for (i = 0; i < *pnPorts; i++) { if (aPorts[i].port == pia->pi[j]) { bFound = true; break; } } if (!bFound) { k = *pnPorts; aPorts[k].port = pia->pi[j]; make_socket(aPorts+k); if ( !IS_INVALID_SOCKET(aPorts[k].socket) #ifndef WIN32 && ValidSocket(aPorts[k].socket) #endif // WIN32 ) { #ifndef WIN32 if (maxd <= aPorts[k].socket) { maxd = aPorts[k].socket + 1; } #endif // WIN32 (*pnPorts)++; } } } // If we were asked to listen on at least one port, but we aren't // listening to at least one port, we should bring the game down. // if ( 0 < pia->n && 0 == *pnPorts) { #ifdef WIN32 WSACleanup(); #endif // WIN32 exit(1); } } #ifdef WIN32 // Private version of FD_ISSET: // // The following routine is only used on Win9x. Ordinarily, FD_ISSET // maps to a __WSAFDIsSet call, however, the Intel compiler encounters // an internal error at link time when some of the higher-order // optimizations are requested (-Qipo). Including this function is a // workaround. // DCL_INLINE bool FD_ISSET_priv(SOCKET fd, fd_set *set) { unsigned int i; for (i = 0; i < set->fd_count; i++) { if (set->fd_array[i] == fd) { return true; } } return false; } DCL_INLINE void FD_ZERO_priv(fd_set *set) { set->fd_count = 0; } DCL_INLINE void FD_SET_priv(SOCKET fd, fd_set *set) { if (set->fd_count < FD_SETSIZE) { set->fd_array[set->fd_count++] = fd; } } void shovechars9x(int nPorts, PortInfo aPorts[]) { fd_set input_set, output_set; int found; DESC *d, *dnext, *newd; #define CheckInput(x) FD_ISSET_priv(x, &input_set) #define CheckOutput(x) FD_ISSET_priv(x, &output_set) mudstate.debug_cmd = "< shovechars >"; CLinearTimeAbsolute ltaLastSlice; ltaLastSlice.GetUTC(); while (mudstate.shutdown_flag == 0) { CLinearTimeAbsolute ltaCurrent; ltaCurrent.GetUTC(); update_quotas(ltaLastSlice, ltaCurrent); // Before processing a possible QUIT command, be sure to give the slave // a chance to report it's findings. // if (iSlaveResult) get_slave_result(); // Check the scheduler. Run a little ahead into the future so that // we tend to sleep longer. // scheduler.RunTasks(ltaCurrent); CLinearTimeAbsolute ltaWakeUp; if (!scheduler.WhenNext(<aWakeUp)) { CLinearTimeDelta ltd = time_30m; ltaWakeUp = ltaCurrent + ltd; } else if (ltaWakeUp < ltaCurrent) { ltaWakeUp = ltaCurrent; } if (mudstate.shutdown_flag) { break; } FD_ZERO_priv(&input_set); FD_ZERO_priv(&output_set); // Listen for new connections. // int i; for (i = 0; i < nPorts; i++) { FD_SET_priv(aPorts[i].socket, &input_set); } // Mark sockets that we want to test for change in status. // DESC_ITER_ALL(d) { if (!d->input_head) { FD_SET_priv(d->descriptor, &input_set); } if (d->output_head) { FD_SET_priv(d->descriptor, &output_set); } } // Wait for something to happen // struct timeval timeout; CLinearTimeDelta ltdTimeout = ltaWakeUp - ltaCurrent; ltdTimeout.ReturnTimeValueStruct(&timeout); found = select(0, &input_set, &output_set, (fd_set *) NULL, &timeout); switch (found) { case SOCKET_ERROR: { STARTLOG(LOG_NET, "NET", "CONN"); log_text("shovechars: Socket error."); ENDLOG; } case 0: continue; } // Check for new connection requests. // for (i = 0; i < nPorts; i++) { if (CheckInput(aPorts[i].socket)) { int iSocketError; newd = new_connection(aPorts+i, &iSocketError); if (!newd) { if ( iSocketError && iSocketError != SOCKET_EINTR) { log_perror("NET", "FAIL", NULL, "new_connection"); } } } } // Check for activity on user sockets // DESC_SAFEITER_ALL(d, dnext) { // Process input from sockets with pending input // if (CheckInput(d->descriptor)) { // Undo autodark // if (d->flags & DS_AUTODARK) { // Clear the DS_AUTODARK on every related session. // DESC *d1; DESC_ITER_PLAYER(d->player, d1) { d1->flags &= ~DS_AUTODARK; } db[d->player].fs.word[FLAG_WORD1] &= ~DARK; } // Process received data // if (!process_input(d)) { shutdownsock(d, R_SOCKDIED); continue; } } // Process output for sockets with pending output // if (CheckOutput(d->descriptor)) { process_output9x(d, true); } } } } static LRESULT WINAPI mux_WindowProc ( HWND hWin, UINT msg, WPARAM wParam, LPARAM lParam ) { switch (msg) { case WM_CLOSE: mudstate.shutdown_flag = true; PostQueuedCompletionStatus(CompletionPort, 0, 0, &lpo_wakeup); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWin, msg, wParam, lParam); } const char szApp[] = "MUX2"; static DWORD WINAPI ListenForCloseProc(LPVOID lpParameter) { UNUSED_PARAMETER(lpParameter); WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = mux_WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = 0; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = szApp; RegisterClass(&wc); HWND hWnd = CreateWindow(szApp, szApp, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, 0, NULL); ShowWindow(hWnd, SW_HIDE); UpdateWindow(hWnd); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { DispatchMessage(&msg); } mudstate.shutdown_flag = true; PostQueuedCompletionStatus(CompletionPort, 0, 0, &lpo_wakeup); return 1; } void shovecharsNT(int nPorts, PortInfo aPorts[]) { UNUSED_PARAMETER(nPorts); UNUSED_PARAMETER(aPorts); mudstate.debug_cmd = "< shovechars >"; CreateThread(NULL, 0, ListenForCloseProc, NULL, 0, NULL); CLinearTimeAbsolute ltaLastSlice; ltaLastSlice.GetUTC(); for (;;) { CLinearTimeAbsolute ltaCurrent; ltaCurrent.GetUTC(); update_quotas(ltaLastSlice, ltaCurrent); // Before processing a possible QUIT command, be sure to give the slave // a chance to report it's findings. // if (iSlaveResult) get_slave_result(); // Check the scheduler. Run a little ahead into the future so that // we tend to sleep longer. // scheduler.RunTasks(ltaCurrent); CLinearTimeAbsolute ltaWakeUp; if (!scheduler.WhenNext(<aWakeUp)) { CLinearTimeDelta ltd = time_30m; ltaWakeUp = ltaCurrent + ltd; } else if (ltaWakeUp < ltaCurrent) { ltaWakeUp = ltaCurrent; } // The following gets Asyncronous writes to the sockets going // if they are not already going. Doing it this way is better // than: // // 1) starting an asyncronous write after a single addition // to the socket's output queue, // // 2) scheduling a task to do it (because we would need to // either maintain the task's uniqueness in the // scheduler's queue, or endure many redudant calls to // process_output for the same descriptor. // DESC *d, *dnext; DESC_SAFEITER_ALL(d, dnext) { if (d->bCallProcessOutputLater) { d->bCallProcessOutputLater = false; process_outputNT(d, false); } } if (mudstate.shutdown_flag) break; CLinearTimeDelta ltdTimeOut = ltaWakeUp - ltaCurrent; unsigned int iTimeout = ltdTimeOut.ReturnMilliseconds(); ProcessWindowsTCP(iTimeout); } } #else // WIN32 void shovechars(int nPorts, PortInfo aPorts[]) { fd_set input_set, output_set; int found; DESC *d, *dnext, *newd; unsigned int avail_descriptors; int maxfds; int i; #define CheckInput(x) FD_ISSET(x, &input_set) #define CheckOutput(x) FD_ISSET(x, &output_set) mudstate.debug_cmd = "< shovechars >"; CLinearTimeAbsolute ltaLastSlice; ltaLastSlice.GetUTC(); #ifdef HAVE_GETDTABLESIZE maxfds = getdtablesize(); #else // HAVE_GETDTABLESIZE maxfds = sysconf(_SC_OPEN_MAX); #endif // HAVE_GETDTABLESIZE avail_descriptors = maxfds - 7; while (mudstate.shutdown_flag == 0) { CLinearTimeAbsolute ltaCurrent; ltaCurrent.GetUTC(); update_quotas(ltaLastSlice, ltaCurrent); // Check the scheduler. // scheduler.RunTasks(ltaCurrent); CLinearTimeAbsolute ltaWakeUp; if (scheduler.WhenNext(<aWakeUp)) { if (ltaWakeUp < ltaCurrent) { ltaWakeUp = ltaCurrent; } } else { CLinearTimeDelta ltd = time_30m; ltaWakeUp = ltaCurrent + ltd; } if (mudstate.shutdown_flag) { break; } FD_ZERO(&input_set); FD_ZERO(&output_set); // Listen for new connections if there are free descriptors. // if (ndescriptors < avail_descriptors) { for (i = 0; i < nPorts; i++) { FD_SET(aPorts[i].socket, &input_set); } } // Listen for replies from the slave socket. // if (!IS_INVALID_SOCKET(slave_socket)) { FD_SET(slave_socket, &input_set); } #ifdef QUERY_SLAVE // Listen for replies from the sqlslave socket. // if (!IS_INVALID_SOCKET(sqlslave_socket)) { FD_SET(sqlslave_socket, &input_set); } #endif // QUERY_SLAVE // Mark sockets that we want to test for change in status. // DESC_ITER_ALL(d) { if (!d->input_head) { FD_SET(d->descriptor, &input_set); } if (d->output_head) { FD_SET(d->descriptor, &output_set); } } // Wait for something to happen. // struct timeval timeout; CLinearTimeDelta ltdTimeout = ltaWakeUp - ltaCurrent; ltdTimeout.ReturnTimeValueStruct(&timeout); found = select(maxd, &input_set, &output_set, (fd_set *) NULL, &timeout); if (IS_SOCKET_ERROR(found)) { int iSocketError = SOCKET_LAST_ERROR; if (iSocketError == SOCKET_EBADF) { // This one is bad, as it results in a spiral of // doom, unless we can figure out what the bad file // descriptor is and get rid of it. // log_perror("NET", "FAIL", "checking for activity", "select"); // Search for a bad socket amoungst the players. // DESC_ITER_ALL(d) { if (!ValidSocket(d->descriptor)) { STARTLOG(LOG_PROBLEMS, "ERR", "EBADF"); log_text("Bad descriptor "); log_number(d->descriptor); ENDLOG; shutdownsock(d, R_SOCKDIED); } } if ( !IS_INVALID_SOCKET(slave_socket) && !ValidSocket(slave_socket)) { // Try to restart the slave, since it presumably // died. // STARTLOG(LOG_PROBLEMS, "ERR", "EBADF"); log_text("Bad slave descriptor "); log_number(slave_socket); ENDLOG; boot_slave(GOD, GOD, GOD, 0); } #ifdef QUERY_SLAVE if ( !IS_INVALID_SOCKET(sqlslave_socket) && !ValidSocket(sqlslave_socket)) { CleanUpSQLSlaveSocket(); } #endif // QUERY_SLAVE for (i = 0; i < nPorts; i++) { if (!ValidSocket(aPorts[i].socket)) { // That's it. Game over. // STARTLOG(LOG_PROBLEMS, "ERR", "EBADF"); log_text("Bad game port descriptor "); log_number(aPorts[i].socket); ENDLOG; return; } } } else if (iSocketError != SOCKET_EINTR) { log_perror("NET", "FAIL", "checking for activity", "select"); } continue; } // Get usernames and hostnames. // if ( !IS_INVALID_SOCKET(slave_socket) && CheckInput(slave_socket)) { while (get_slave_result() == 0) { ; // Nothing. } } #ifdef QUERY_SLAVE // Get result sets from sqlslave. // if ( !IS_INVALID_SOCKET(sqlslave_socket) && CheckInput(sqlslave_socket)) { while (get_sqlslave_result() == 0) { ; // Nothing. } } #endif // QUERY_SLAVE // Check for new connection requests. // for (i = 0; i < nPorts; i++) { if (CheckInput(aPorts[i].socket)) { int iSocketError; newd = new_connection(aPorts+i, &iSocketError); if (!newd) { if ( iSocketError && iSocketError != SOCKET_EINTR) { log_perror("NET", "FAIL", NULL, "new_connection"); } } else if ( !IS_INVALID_SOCKET(newd->descriptor) && maxd <= newd->descriptor) { maxd = newd->descriptor + 1; } } } // Check for activity on user sockets. // DESC_SAFEITER_ALL(d, dnext) { // Process input from sockets with pending input. // if (CheckInput(d->descriptor)) { // Undo autodark // if (d->flags & DS_AUTODARK) { // Clear the DS_AUTODARK on every related session. // DESC *d1; DESC_ITER_PLAYER(d->player, d1) { d1->flags &= ~DS_AUTODARK; } db[d->player].fs.word[FLAG_WORD1] &= ~DARK; } // Process received data. // if (!process_input(d)) { shutdownsock(d, R_SOCKDIED); continue; } } // Process output for sockets with pending output. // if (CheckOutput(d->descriptor)) { process_output(d, true); } } } } #endif // WIN32 DESC *new_connection(PortInfo *Port, int *piSocketError) { DESC *d; struct sockaddr_in addr; #ifdef SOCKLEN_T_DCL socklen_t addr_len; #else // SOCKLEN_T_DCL int addr_len; #endif // SOCKLEN_T_DCL #ifndef WIN32 int len; #endif // !WIN32 const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = "< new_connection >"; addr_len = sizeof(struct sockaddr); SOCKET newsock = accept(Port->socket, (struct sockaddr *)&addr, &addr_len); if (IS_INVALID_SOCKET(newsock)) { *piSocketError = SOCKET_LAST_ERROR; mudstate.debug_cmd = cmdsave; return 0; } char *pBuffM2 = alloc_mbuf("new_connection.address"); mux_strncpy(pBuffM2, inet_ntoa(addr.sin_addr), MBUF_SIZE-1); unsigned short usPort = ntohs(addr.sin_port); DebugTotalSockets++; if (site_check(addr.sin_addr, mudstate.access_list) == H_FORBIDDEN) { STARTLOG(LOG_NET | LOG_SECURITY, "NET", "SITE"); char *pBuffM1 = alloc_mbuf("new_connection.LOG.badsite"); mux_sprintf(pBuffM1, MBUF_SIZE, "[%u/%s] Connection refused. (Remote port %d)", newsock, pBuffM2, usPort); log_text(pBuffM1); free_mbuf(pBuffM1); ENDLOG; // Report site monitor information. // SiteMonSend(newsock, pBuffM2, NULL, "Connection refused"); fcache_rawdump(newsock, FC_CONN_SITE); shutdown(newsock, SD_BOTH); if (SOCKET_CLOSE(newsock) == 0) { DebugTotalSockets--; } newsock = INVALID_SOCKET; errno = 0; d = NULL; } else { #ifdef WIN32 // Make slave request // // Go take control of the stack, but don't bother if it takes // longer than 5 seconds to do it. // if ( bSlaveBooted && WAIT_OBJECT_0 == WaitForSingleObject(hSlaveRequestStackSemaphore, 5000)) { // We have control of the stack. Skip the request if the stack is full. // if (iSlaveRequest < SLAVE_REQUEST_STACK_SIZE) { // There is room on the stack, so make the request. // SlaveRequests[iSlaveRequest].sa_in = addr; SlaveRequests[iSlaveRequest].port_in = Port->port; iSlaveRequest++; ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL); // Wake up a single slave thread. Event automatically resets itself. // ReleaseSemaphore(hSlaveThreadsSemaphore, 1, NULL); } else { // No room on the stack, so skip it. // ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL); } } #else // WIN32 // Make slave request // if ( !IS_INVALID_SOCKET(slave_socket) && mudconf.use_hostname) { char *pBuffL1 = alloc_lbuf("new_connection.write"); mux_sprintf(pBuffL1, LBUF_SIZE, "%s\n%s,%d,%d\n", pBuffM2, pBuffM2, usPort, Port->port); len = strlen(pBuffL1); if (mux_write(slave_socket, pBuffL1, len) < 0) { CleanUpSlaveSocket(); CleanUpSlaveProcess(); STARTLOG(LOG_ALWAYS, "NET", "SLAVE"); log_text("write() of slave request failed. Slave stopped."); ENDLOG; } free_lbuf(pBuffL1); } #endif // WIN32 STARTLOG(LOG_NET, "NET", "CONN"); char *pBuffM3 = alloc_mbuf("new_connection.LOG.open"); mux_sprintf(pBuffM3, MBUF_SIZE, "[%u/%s] Connection opened (remote port %d)", newsock, pBuffM2, usPort); log_text(pBuffM3); free_mbuf(pBuffM3); ENDLOG; d = initializesock(newsock, &addr); TelnetSetup(d); // Initalize everything before sending the sitemon info, so that we // can pass the descriptor, d. // SiteMonSend(newsock, pBuffM2, d, "Connection"); welcome_user(d); } free_mbuf(pBuffM2); *piSocketError = SOCKET_LAST_ERROR; mudstate.debug_cmd = cmdsave; return d; } // Disconnect reasons that get written to the logfile // static const char *disc_reasons[] = { "Unspecified", "Quit", "Inactivity Timeout", "Booted", "Remote Close or Net Failure", "Game Shutdown", "Login Retry Limit", "Logins Disabled", "Logout (Connection Not Dropped)", "Too Many Connected Players" }; // Disconnect reasons that get fed to A_ADISCONNECT via announce_disconnect // static const char *disc_messages[] = { "Unknown", "Quit", "Timeout", "Boot", "Netfailure", "Shutdown", "BadLogin", "NoLogins", "Logout", "GameFull" }; void shutdownsock(DESC *d, int reason) { char *buff, *buff2; int i, num; DESC *dtemp; if ( (reason == R_LOGOUT) && (site_check((d->address).sin_addr, mudstate.access_list) == H_FORBIDDEN)) { reason = R_QUIT; } if ( reason < R_MIN || R_MAX < reason) { reason = R_UNKNOWN; } CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); if (d->flags & DS_CONNECTED) { // Reason: attribute (disconnect reason) // atr_add_raw(d->player, A_REASON, disc_messages[reason]); // Update the A_CONNINFO attribute. // long anFields[4]; fetch_ConnectionInfoFields(d->player, anFields); // One of the active sessions is going away. It doesn't matter which // one. // anFields[CIF_NUMCONNECTS]++; // What are the two longest sessions? // DESC *dOldest[2]; find_oldest(d->player, dOldest); CLinearTimeDelta ltdFull; ltdFull = ltaNow - dOldest[0]->connected_at; long tFull = ltdFull.ReturnSeconds(); if (dOldest[0] == d) { // We are dropping the oldest connection. // CLinearTimeDelta ltdPart; if (dOldest[1]) { // There is another (more recently made) connection. // ltdPart = dOldest[1]->connected_at - dOldest[0]->connected_at; } else { // There is only one connection. // ltdPart = ltdFull; } long tPart = ltdPart.ReturnSeconds(); anFields[CIF_TOTALTIME] += tPart; if (anFields[CIF_LONGESTCONNECT] < tFull) { anFields[CIF_LONGESTCONNECT] = tFull; } } anFields[CIF_LASTCONNECT] = tFull; put_ConnectionInfoFields(d->player, anFields, ltaNow); // If we are doing a LOGOUT, keep the connection open so that the // player can connect to a different character. Otherwise, we // do the normal disconnect stuff. // if (reason == R_LOGOUT) { STARTLOG(LOG_NET | LOG_LOGIN, "NET", "LOGO") buff = alloc_mbuf("shutdownsock.LOG.logout"); mux_sprintf(buff, MBUF_SIZE, "[%u/%s] Logout by ", d->descriptor, d->addr); log_text(buff); log_name(d->player); mux_sprintf(buff, MBUF_SIZE, " ", disc_reasons[reason]); log_text(buff); free_mbuf(buff); ENDLOG; } else { fcache_dump(d, FC_QUIT); STARTLOG(LOG_NET | LOG_LOGIN, "NET", "DISC") buff = alloc_mbuf("shutdownsock.LOG.disconn"); mux_sprintf(buff, MBUF_SIZE, "[%u/%s] Logout by ", d->descriptor, d->addr); log_text(buff); log_name(d->player); mux_sprintf(buff, MBUF_SIZE, " ", disc_reasons[reason]); log_text(buff); free_mbuf(buff); ENDLOG; SiteMonSend(d->descriptor, d->addr, d, "Disconnection"); } // If requested, write an accounting record of the form: // Plyr# Flags Cmds ConnTime Loc Money [Site] Name // STARTLOG(LOG_ACCOUNTING, "DIS", "ACCT"); CLinearTimeDelta ltd = ltaNow - d->connected_at; int Seconds = ltd.ReturnSeconds(); buff = alloc_lbuf("shutdownsock.LOG.accnt"); buff2 = decode_flags(GOD, &(db[d->player].fs)); dbref locPlayer = Location(d->player); int penPlayer = Pennies(d->player); const char *PlayerName = Name(d->player); mux_sprintf(buff, LBUF_SIZE, "%d %s %d %d %d %d [%s] <%s> %s", d->player, buff2, d->command_count, Seconds, locPlayer, penPlayer, d->addr, disc_reasons[reason], PlayerName); log_text(buff); free_lbuf(buff); free_sbuf(buff2); ENDLOG; announce_disconnect(d->player, d, disc_messages[reason]); } else { if (reason == R_LOGOUT) { reason = R_QUIT; } STARTLOG(LOG_SECURITY | LOG_NET, "NET", "DISC"); buff = alloc_mbuf("shutdownsock.LOG.neverconn"); mux_sprintf(buff, MBUF_SIZE, "[%u/%s] Connection closed, never connected. ", d->descriptor, d->addr, disc_reasons[reason]); log_text(buff); free_mbuf(buff); ENDLOG; SiteMonSend(d->descriptor, d->addr, d, "N/C Connection Closed"); } process_output(d, false); clearstrings(d); d->flags &= ~DS_CONNECTED; // Is this desc still in interactive mode? // if (d->program_data != NULL) { num = 0; DESC_ITER_PLAYER(d->player, dtemp) { num++; } if (0 == num) { for (i = 0; i < MAX_GLOBAL_REGS; i++) { if (d->program_data->wait_regs[i]) { RegRelease(d->program_data->wait_regs[i]); d->program_data->wait_regs[i] = NULL; } } MEMFREE(d->program_data); atr_clr(d->player, A_PROGCMD); } d->program_data = NULL; } if (reason == R_LOGOUT) { d->connected_at.GetUTC(); d->retries_left = mudconf.retry_limit; d->command_count = 0; d->timeout = mudconf.idle_timeout; d->player = 0; d->doing[0] = '\0'; d->quota = mudconf.cmd_quota_max; d->last_time = d->connected_at; int AccessFlag = site_check((d->address).sin_addr, mudstate.access_list); int SuspectFlag = site_check((d->address).sin_addr, mudstate.suspect_list); d->host_info = AccessFlag | SuspectFlag; d->input_tot = d->input_size; d->output_tot = 0; welcome_user(d); } else { // Cancel any scheduled processing on this descriptor. // scheduler.CancelTask(Task_ProcessCommand, d, 0); #ifdef WIN32 if (bUseCompletionPorts) { // Don't close down the socket twice. // if (!d->bConnectionShutdown) { // Make sure we don't try to initiate or process any // outstanding IOs // d->bConnectionShutdown = true; // Protect removing the descriptor from our linked list from // any interference from the listening thread. // EnterCriticalSection(&csDescriptorList); *d->prev = d->next; if (d->next) { d->next->prev = d->prev; } LeaveCriticalSection(&csDescriptorList); // This descriptor may hang around awhile, clear out the links. // d->next = 0; d->prev = 0; // Close the connection in 5 seconds. // scheduler.DeferTask(ltaNow + time_5s, PRIORITY_SYSTEM, Task_DeferredClose, d, 0); } return; } #endif shutdown(d->descriptor, SD_BOTH); if (SOCKET_CLOSE(d->descriptor) == 0) { DebugTotalSockets--; } d->descriptor = INVALID_SOCKET; *d->prev = d->next; if (d->next) { d->next->prev = d->prev; } // This descriptor may hang around awhile, clear out the links. // d->next = 0; d->prev = 0; // If we don't have queued IOs, then we can free these, now. // freeqs(d); free_desc(d); ndescriptors--; } } #ifdef WIN32 static void shutdownsock_brief(DESC *d) { // don't close down the socket twice // if (d->bConnectionShutdown) { return; } // make sure we don't try to initiate or process any outstanding IOs // d->bConnectionShutdown = true; d->bConnectionDropped = true; // cancel any pending reads or writes on this socket // if (!fpCancelIo((HANDLE) d->descriptor)) { Log.tinyprintf("Error %ld on CancelIo" ENDLINE, GetLastError()); } shutdown(d->descriptor, SD_BOTH); if (closesocket(d->descriptor) == 0) { DebugTotalSockets--; } d->descriptor = INVALID_SOCKET; // protect removing the descriptor from our linked list from // any interference from the listening thread // EnterCriticalSection(&csDescriptorList); *d->prev = d->next; if (d->next) { d->next->prev = d->prev; } d->next = 0; d->prev = 0; // safe to allow the listening thread to continue now LeaveCriticalSection(&csDescriptorList); // post a notification that it is safe to free the descriptor // we can't free the descriptor here (below) as there may be some // queued completed IOs that will crash when they refer to a descriptor // (d) that has been freed. // if (!PostQueuedCompletionStatus(CompletionPort, 0, (MUX_ULONG_PTR) d, &lpo_aborted)) { Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in shutdownsock" ENDLINE, GetLastError()); } } #endif // WIN32 int make_nonblocking(SOCKET s) { #ifdef WIN32 unsigned long on = 1; if (IS_SOCKET_ERROR(ioctlsocket(s, FIONBIO, &on))) { log_perror("NET", "FAIL", "make_nonblocking", "ioctlsocket"); return -1; } #else // WIN32 #if defined(O_NONBLOCK) if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) { log_perror("NET", "FAIL", "make_nonblocking", "fcntl"); return -1; } #elif defined(FNDELAY) if (fcntl(s, F_SETFL, FNDELAY) < 0) { log_perror("NET", "FAIL", "make_nonblocking", "fcntl"); return -1; } #elif defined(O_NDELAY) if (fcntl(s, F_SETFL, O_NDELAY) < 0) { log_perror("NET", "FAIL", "make_nonblocking", "fcntl"); return -1; } #elif defined(FIONBIO) unsigned long on = 1; if (ioctl(s, FIONBIO, &on) < 0) { log_perror("NET", "FAIL", "make_nonblocking", "ioctl"); return -1; } #endif // O_NONBLOCK, FNDELAY, O_NDELAY, FIONBIO #endif // WIN32 return 0; } static void make_nolinger(SOCKET s) { #if defined(HAVE_LINGER) struct linger ling; ling.l_onoff = 0; ling.l_linger = 0; if (IS_SOCKET_ERROR(setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling)))) { log_perror("NET", "FAIL", "linger", "setsockopt"); } #endif // HAVE_LINGER } static void config_socket(SOCKET s) { make_nonblocking(s); make_nolinger(s); } // This function must be thread safe WinNT // DESC *initializesock(SOCKET s, struct sockaddr_in *a) { DESC *d; #ifdef WIN32 // protect adding the descriptor from the linked list from // any interference from socket shutdowns // if (bUseCompletionPorts) { EnterCriticalSection(&csDescriptorList); } #endif // WIN32 d = alloc_desc("init_sock"); #ifdef WIN32 if (bUseCompletionPorts) { LeaveCriticalSection(&csDescriptorList); } #endif // WIN32 d->descriptor = s; d->flags = 0; d->connected_at.GetUTC(); d->last_time = d->connected_at; d->retries_left = mudconf.retry_limit; d->command_count = 0; d->timeout = mudconf.idle_timeout; int AccessFlag = site_check((*a).sin_addr, mudstate.access_list); int SuspectFlag = site_check((*a).sin_addr, mudstate.suspect_list); d->host_info = AccessFlag | SuspectFlag; // Be sure #0 isn't wizard. Shouldn't be. // d->player = 0; d->addr[0] = '\0'; d->doing[0] = '\0'; d->username[0] = '\0'; config_socket(s); d->output_prefix = NULL; d->output_suffix = NULL; d->output_size = 0; d->output_tot = 0; d->output_lost = 0; d->output_head = NULL; d->output_tail = NULL; d->input_head = NULL; d->input_tail = NULL; d->input_size = 0; d->input_tot = 0; d->input_lost = 0; d->raw_input = NULL; d->raw_input_at = NULL; d->nOption = 0; d->raw_input_state = NVT_IS_NORMAL; d->nvt_sga_him_state = OPTION_NO; d->nvt_sga_us_state = OPTION_NO; d->nvt_eor_him_state = OPTION_NO; d->nvt_eor_us_state = OPTION_NO; d->nvt_naws_him_state = OPTION_NO; d->nvt_naws_us_state = OPTION_NO; d->height = 24; d->width = 78; d->quota = mudconf.cmd_quota_max; d->program_data = NULL; d->address = *a; mux_strncpy(d->addr, inet_ntoa(a->sin_addr), 50); #ifdef WIN32 // protect adding the descriptor from the linked list from // any interference from socket shutdowns // if (bUseCompletionPorts) { EnterCriticalSection (&csDescriptorList); } #endif // WIN32 ndescriptors++; if (descriptor_list) { descriptor_list->prev = &d->next; } d->hashnext = NULL; d->next = descriptor_list; d->prev = &descriptor_list; descriptor_list = d; #ifdef WIN32 // ok to continue now // if (bUseCompletionPorts) { LeaveCriticalSection (&csDescriptorList); d->OutboundOverlapped.hEvent = NULL; d->InboundOverlapped.hEvent = NULL; d->InboundOverlapped.Offset = 0; d->InboundOverlapped.OffsetHigh = 0; d->bWritePending = false; // no write pending yet d->bConnectionShutdown = false; // not shutdown yet d->bConnectionDropped = false; // not dropped yet d->bCallProcessOutputLater = false; } #endif // WIN32 return d; } #ifdef WIN32 FTASK *process_output = 0; void process_output9x(void *dvoid, int bHandleShutdown) { DESC *d = (DESC *)dvoid; int cnt; const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = "< process_output >"; TBLOCK *tb = d->output_head; while (tb != NULL) { while (tb->hdr.nchars > 0) { cnt = SOCKET_WRITE(d->descriptor, tb->hdr.start, tb->hdr.nchars, 0); if (IS_SOCKET_ERROR(cnt)) { int iSocketError = SOCKET_LAST_ERROR; if ( iSocketError != SOCKET_EWOULDBLOCK #ifdef SOCKET_EAGAIN && iSocketError != SOCKET_EAGAIN #endif // SOCKET_EAGAIN && bHandleShutdown) { shutdownsock(d, R_SOCKDIED); } mudstate.debug_cmd = cmdsave; return; } d->output_size -= cnt; tb->hdr.nchars -= cnt; tb->hdr.start += cnt; } TBLOCK *save = tb; tb = tb->hdr.nxt; MEMFREE(save); save = NULL; d->output_head = tb; if (tb == NULL) { d->output_tail = NULL; } } mudstate.debug_cmd = cmdsave; } static int AsyncSend(DESC *d, char *buf, size_t len) { DWORD nBytes; // Move data from one buffer to another. // if (len <= SIZEOF_OVERLAPPED_BUFFERS) { // We can consume this buffer. // nBytes = static_cast(len); } else { // Use the entire bufer and leave the remaining data in the queue. // nBytes = SIZEOF_OVERLAPPED_BUFFERS; } memcpy(d->output_buffer, buf, nBytes); d->OutboundOverlapped.Offset = 0; d->OutboundOverlapped.OffsetHigh = 0; BOOL bResult = WriteFile((HANDLE) d->descriptor, d->output_buffer, nBytes, NULL, &d->OutboundOverlapped); d->bWritePending = false; if (!bResult) { DWORD dwLastError = GetLastError(); if (dwLastError == ERROR_IO_PENDING) { d->bWritePending = true; } else { if (!(d->bConnectionDropped)) { // Do no more writes and post a notification that the descriptor should be shutdown. // d->bConnectionDropped = true; Log.tinyprintf("AsyncSend(%d) failed with error %ld. Requesting port shutdown." ENDLINE, d->descriptor, dwLastError); if (!PostQueuedCompletionStatus(CompletionPort, 0, (MUX_ULONG_PTR) d, &lpo_shutdown)) { Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in AsyncSend" ENDLINE, GetLastError()); } } return 0; } } return nBytes; } void process_outputNT(void *dvoid, int bHandleShutdown) { UNUSED_PARAMETER(bHandleShutdown); DESC *d = (DESC *)dvoid; // Don't write if connection dropped or a write is pending. // if (d->bConnectionDropped || d->bWritePending) { return; } const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = "< process_output >"; TBLOCK *tb = d->output_head; TBLOCK *save; int cnt; if (tb != NULL) { while (tb->hdr.nchars == 0) { save = tb; tb = tb->hdr.nxt; MEMFREE(save); save = NULL; d->output_head = tb; if (tb == NULL) { d->output_tail = NULL; break; } } if (tb != NULL) { if (tb->hdr.nchars > 0) { cnt = AsyncSend(d, tb->hdr.start, tb->hdr.nchars); if (cnt <= 0) { mudstate.debug_cmd = cmdsave; return; } d->output_size -= cnt; tb->hdr.nchars -= cnt; tb->hdr.start += cnt; } if (tb->hdr.nchars <= 0) { save = tb; tb = tb->hdr.nxt; MEMFREE(save); save = NULL; d->output_head = tb; if (tb == NULL) { d->output_tail = NULL; } } } } mudstate.debug_cmd = cmdsave; } #else // WIN32 void process_output(void *dvoid, int bHandleShutdown) { DESC *d = (DESC *)dvoid; const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = "< process_output >"; TBLOCK *tb = d->output_head; while (tb != NULL) { while (tb->hdr.nchars > 0) { int cnt = SOCKET_WRITE(d->descriptor, tb->hdr.start, tb->hdr.nchars, 0); if (IS_SOCKET_ERROR(cnt)) { int iSocketError = SOCKET_LAST_ERROR; mudstate.debug_cmd = cmdsave; if ( iSocketError != SOCKET_EWOULDBLOCK #ifdef SOCKET_EAGAIN && iSocketError != SOCKET_EAGAIN #endif // SOCKET_EAGAIN && bHandleShutdown) { shutdownsock(d, R_SOCKDIED); } return; } d->output_size -= cnt; tb->hdr.nchars -= cnt; tb->hdr.start += cnt; } TBLOCK *save = tb; tb = tb->hdr.nxt; MEMFREE(save); save = NULL; d->output_head = tb; if (tb == NULL) { d->output_tail = NULL; } } mudstate.debug_cmd = cmdsave; } #endif // WIN32 /*! \brief Table to quickly classify characters recieved from the wire with * their Telnet meaning. * * The use of this table reduces the size of the state table. * * Class 0 - Any byte. Class 5 - BRK (0xF3) Class 10 - WONT (0xFC) * Class 1 - BS (0x08) Class 5 - IP (0xF4) Class 11 - DO (0xFD) * Class 2 - LF (0x0A) Class 5 - AO (0xF5) Class 12 - DONT (0xFE) * Class 3 - CR (0x0D) Class 6 - AYT (0xF6) Class 13 - IAC (0xFF) * Class 1 - DEL (0x7F) Class 7 - EC (0xF7) * Class 5 - EOR (0xEF) Class 5 - EL (0xF8) * Class 4 - SE (0xF0) Class 5 - GA (0xF9) * Class 5 - NOP (0xF1) Class 8 - SB (0xFA) * Class 5 - DM (0xF2) Class 9 - WILL (0xFB) */ static const unsigned char nvt_input_xlat_table[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 3, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, // E 4, 5, 5, 5, 5, 5, 6, 7, 5, 5, 8, 9, 10, 11, 12, 13 // F }; /*! \brief Table to map current telnet parsing state state and input to * specific actions and state changes. * * Action 0 - Nothing. * Action 1 - Accept CHR(X) (and transition to Normal state). * Action 2 - Erase Character. * Action 3 - Accept Line. * Action 4 - Transition to the Normal state. * Action 5 - Transition to Have_IAC state. * Action 6 - Transition to the Have_IAC_WILL state. * Action 7 - Transition to the Have_IAC_DONT state. * Action 8 - Transition to the Have_IAC_DO state. * Action 9 - Transition to the Have_IAC_WONT state. * Action 10 - Transition to the Have_IAC_SB state. * Action 11 - Transition to the Have_IAC_SB_IAC state. * Action 12 - Respond to IAC AYT and return to the Normal state. * Action 13 - Respond to IAC WILL X * Action 14 - Respond to IAC DONT X * Action 15 - Respond to IAC DO X * Action 16 - Respond to IAC WONT X * Action 17 - Accept CHR(X) for Sub-Option (and transition to Have_IAC_SB state). * Action 18 - Accept Completed Sub-option and transition to Normal state. */ static const int nvt_input_action_table[8][14] = { // Any BS LF CR SE NOP AYT EC SB WILL DONT DO WONT IAC { 1, 2, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5 }, // Normal { 4, 4, 4, 4, 4, 4, 12, 2, 10, 6, 7, 8, 9, 1 }, // Have_IAC { 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 4 }, // Have_IAC_WILL { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 4 }, // Have_IAC_DONT { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4 }, // Have_IAC_DO { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 4 }, // Have_IAC_WONT { 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 11 }, // Have_IAC_SB { 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 17 }, // Have_IAC_SB_IAC }; /*! \brief Return the other side's negotiation state. * * The negotiation of each optional feature of telnet can be in one of six * states (defined in interface.h): OPTION_NO, OPTION_YES, * OPTION_WANTNO_EMPTY, OPTION_WANTNO_OPPOSITE, OPTION_WANTYES_EMPTY, and * OPTION_WANTYES_OPPOSITE. * * An option is only enabled when it is in the OPTION_YES state. * * \param d Player connection context. * \param chOption Telnet Option * \return One of six states. */ int HimState(DESC *d, unsigned char chOption) { if (TELNET_NAWS == chOption) { return d->nvt_naws_him_state; } else if (TELNET_EOR == chOption) { return d->nvt_eor_him_state; } else if (TELNET_SGA == chOption) { return d->nvt_sga_him_state; } return OPTION_NO; } /*! \brief Return our side's negotiation state. * * The negotiation of each optional feature of telnet can be in one of six * states (defined in interface.h): OPTION_NO, OPTION_YES, * OPTION_WANTNO_EMPTY, OPTION_WANTNO_OPPOSITE, OPTION_WANTYES_EMPTY, and * OPTION_WANTYES_OPPOSITE. * * An option is only enabled when it is in the OPTION_YES state. * * \param d Player connection context. * \param chOption Telnet Option * \return One of six states. */ int UsState(DESC *d, unsigned char chOption) { if (TELNET_NAWS == chOption) { return d->nvt_naws_us_state; } else if (TELNET_EOR == chOption) { return d->nvt_eor_us_state; } else if (TELNET_SGA == chOption) { return d->nvt_sga_us_state; } return OPTION_NO; } /*! \brief Change the other side's negotiation state. * * \param d Player connection context. * \param chOption Telnet Option * \param iHimState One of the six option negotiation states. * \return None. */ static void SetHimState(DESC *d, unsigned char chOption, int iHimState) { if (TELNET_NAWS == chOption) { d->nvt_naws_him_state = iHimState; } else if (TELNET_EOR == chOption) { d->nvt_eor_him_state = iHimState; } else if (TELNET_SGA == chOption) { d->nvt_sga_him_state = iHimState; } } /*! \brief Change our side's negotiation state. * * \param d Player connection context. * \param chOption Telnet Option. * \param iUsState One of the six option negotiation states. * \return None. */ static void SetUsState(DESC *d, unsigned char chOption, int iUsState) { if (TELNET_NAWS == chOption) { d->nvt_naws_us_state = iUsState; } else if (TELNET_EOR == chOption) { d->nvt_eor_us_state = iUsState; if (OPTION_YES == iUsState) { EnableUs(d, TELNET_SGA); } else if (OPTION_NO == iUsState) { DisableUs(d, TELNET_SGA); } } else if (TELNET_SGA == chOption) { d->nvt_sga_us_state = iUsState; } } /*! \brief Transmit a Telnet WILL sequence for the given option. * * \param d Player connection context. * \param chOption Telnet Option. * \return None. */ static void SendWill(DESC *d, unsigned char chOption) { char aWill[3] = { NVT_IAC, NVT_WILL, 0 }; aWill[2] = chOption; queue_write_LEN(d, aWill, sizeof(aWill)); } /*! \brief Transmit a Telnet DONT sequence for the given option. * * \param d Player connection context. * \param chOption Telnet Option. * \return None. */ static void SendDont(DESC *d, unsigned char chOption) { char aDont[3] = { NVT_IAC, NVT_DONT, 0 }; aDont[2] = chOption; queue_write_LEN(d, aDont, sizeof(aDont)); } /*! \brief Transmit a Telnet DO sequence for the given option. * * \param d Player connection context. * \param chOption Telnet Option. * \return None. */ static void SendDo(DESC *d, unsigned char chOption) { char aDo[3] = { NVT_IAC, NVT_DO, 0 }; aDo[2] = chOption; queue_write_LEN(d, aDo, sizeof(aDo)); } /*! \brief Transmit a Telnet WONT sequence for the given option. * * \param d Player connection context. * \param chOption Telnet Option. * \return None. */ static void SendWont(DESC *d, unsigned char chOption) { char aWont[3] = { NVT_IAC, NVT_WONT, 0 }; aWont[2] = chOption; queue_write_LEN(d, aWont, sizeof(aWont)); } /*! \brief Determine whether we want a particular option on his side of the * link to be enabled. * * \param d Player connection context. * \param chOption Telnet Option. * \return Yes if we want it enabled. */ static bool DesiredHimOption(DESC *d, unsigned char chOption) { UNUSED_PARAMETER(d); if ( TELNET_NAWS == chOption || TELNET_EOR == chOption || TELNET_SGA == chOption) { return true; } return false; } /*! \brief Determine whether we want a particular option on our side of the * link to be enabled. * * It doesn't make sense for NAWS to be enabled on the server side, and we * only negotiate SGA on our side if we have already successfully negotiated * the EOR option. * * \param d Player connection context. * \param chOption Telnet Option. * \return Yes if we want it enabled. */ static bool DesiredUsOption(DESC *d, unsigned char chOption) { if ( TELNET_EOR == chOption || ( TELNET_SGA == chOption && OPTION_YES == UsState(d, TELNET_EOR))) { return true; } return false; } /*! \brief Start the process of negotiating the enablement of an option on * his side. * * Whether we actually send anything across the wire to enable this depends * on the negotiation state. The option could potentially already be enabled. * * \param d Player connection context. * \param chOption Telnet Option. * \return None. */ void EnableHim(DESC *d, unsigned char chOption) { switch (HimState(d, chOption)) { case OPTION_NO: SetHimState(d, chOption, OPTION_WANTYES_EMPTY); SendDo(d, chOption); break; case OPTION_WANTNO_EMPTY: SetHimState(d, chOption, OPTION_WANTNO_OPPOSITE); break; case OPTION_WANTYES_OPPOSITE: SetHimState(d, chOption, OPTION_WANTYES_EMPTY); break; } } /*! \brief Start the process of negotiating the disablement of an option on * his side. * * Whether we actually send anything across the wire to disable this depends * on the negotiation state. The option could potentially already be disabled. * * \param d Player connection context. * \param chOption Telnet Option. * \return None. */ void DisableHim(DESC *d, unsigned char chOption) { switch (HimState(d, chOption)) { case OPTION_YES: SetHimState(d, chOption, OPTION_WANTNO_EMPTY); SendDont(d, chOption); break; case OPTION_WANTNO_OPPOSITE: SetHimState(d, chOption, OPTION_WANTNO_EMPTY); break; case OPTION_WANTYES_EMPTY: SetHimState(d, chOption, OPTION_WANTYES_OPPOSITE); break; } } /*! \brief Start the process of negotiating the enablement of an option on * our side. * * Whether we actually send anything across the wire to enable this depends * on the negotiation state. The option could potentially already be enabled. * * \param d Player connection context. * \param chOption Telnet Option. * \return None. */ void EnableUs(DESC *d, unsigned char chOption) { switch (HimState(d, chOption)) { case OPTION_NO: SetUsState(d, chOption, OPTION_WANTYES_EMPTY); SendWill(d, chOption); break; case OPTION_WANTNO_EMPTY: SetUsState(d, chOption, OPTION_WANTNO_OPPOSITE); break; case OPTION_WANTYES_OPPOSITE: SetUsState(d, chOption, OPTION_WANTYES_EMPTY); break; } } /*! \brief Start the process of negotiating the disablement of an option on * our side. * * Whether we actually send anything across the wire to disable this depends * on the negotiation state. The option could potentially already be disabled. * * \param d Player connection context. * \param chOption Telnet Option. * \return None. */ void DisableUs(DESC *d, unsigned char chOption) { switch (HimState(d, chOption)) { case OPTION_YES: SetUsState(d, chOption, OPTION_WANTNO_EMPTY); SendWont(d, chOption); break; case OPTION_WANTNO_OPPOSITE: SetUsState(d, chOption, OPTION_WANTNO_EMPTY); break; case OPTION_WANTYES_EMPTY: SetUsState(d, chOption, OPTION_WANTYES_OPPOSITE); break; } } /*! \brief Begin initial telnet negotiations on a socket. * * The two sides of the connection may not agree on the following set of * options, and keep in mind that the successful negotiation of a particular * option may cause the negotiation of another option. * * Without this function, we are only react to client requests. * * \param d Player connection on which the input arrived. * \return None. */ void TelnetSetup(DESC *d) { // Attempt negotation of EOR so we can use that, and if that succeeds, // code elsewhere will attempt the negotation of SGA for our side as well. // EnableUs(d, TELNET_EOR); EnableHim(d, TELNET_EOR); EnableHim(d, TELNET_SGA); EnableHim(d, TELNET_NAWS); } /*! \brief Parse raw data from network connection into command lines and * Telnet indications. * * Once input has been received from a particular socket, it is given to this * function for initial parsing. While most clients do line editing on their * side, a raw telnet client is still capable of sending backspace (BS) and * Delete (DEL) to the server, so we perform basic editing on our side. * * TinyMUX only allows printable characters through, imposes a maximum line * length, and breaks lines at CRLF. * * \param d Player connection on which the input arrived. * \param pBytes Point to received bytes. * \param nBytes Number of received bytes in above buffer. * \return None. */ static void process_input_helper(DESC *d, char *pBytes, int nBytes) { if (!d->raw_input) { d->raw_input = (CBLK *) alloc_lbuf("process_input.raw"); d->raw_input_at = d->raw_input->cmd; } int nInputBytes = 0; int nLostBytes = 0; char *p = d->raw_input_at; char *pend = d->raw_input->cmd + (LBUF_SIZE - sizeof(CBLKHDR) - 1); unsigned char *q = d->aOption + d->nOption; unsigned char *qend = d->aOption + SBUF_SIZE - 1; int n = nBytes; while (n--) { unsigned char ch = (unsigned char)*pBytes; int iAction = nvt_input_action_table[d->raw_input_state][nvt_input_xlat_table[ch]]; switch (iAction) { case 1: // Action 1 - Accept CHR(X). // if (mux_isprint(ch)) { if (p < pend) { *p++ = ch; nInputBytes++; } else { nLostBytes++; } } d->raw_input_state = NVT_IS_NORMAL; break; case 0: // Action 0 - Nothing. // break; case 2: // Action 2 - Erase Character. // if (NVT_DEL == ch) { queue_string(d, "\b \b"); } else { queue_string(d, " \b"); } if (p > d->raw_input->cmd) { // The character we took back. // nInputBytes -= 1; p--; } d->raw_input_state = NVT_IS_NORMAL; break; case 3: // Action 3 - Accept Line. // *p = '\0'; if (d->raw_input->cmd < p) { save_command(d, d->raw_input); d->raw_input = (CBLK *) alloc_lbuf("process_input.raw"); p = d->raw_input_at = d->raw_input->cmd; pend = d->raw_input->cmd + (LBUF_SIZE - sizeof(CBLKHDR) - 1); } break; case 4: // Action 4 - Transition to the Normal state. // d->raw_input_state = NVT_IS_NORMAL; break; case 5: // Action 5 - Transition to Have_IAC state. // d->raw_input_state = NVT_IS_HAVE_IAC; break; case 6: // Action 6 - Transition to the Have_IAC_WILL state. // d->raw_input_state = NVT_IS_HAVE_IAC_WILL; break; case 7: // Action 7 - Transition to the Have_IAC_DONT state. // d->raw_input_state = NVT_IS_HAVE_IAC_DONT; break; case 8: // Action 8 - Transition to the Have_IAC_DO state. // d->raw_input_state = NVT_IS_HAVE_IAC_DO; break; case 9: // Action 9 - Transition to the Have_IAC_WONT state. // d->raw_input_state = NVT_IS_HAVE_IAC_WONT; break; case 10: // Action 10 - Transition to the Have_IAC_SB state. // q = d->aOption; d->raw_input_state = NVT_IS_HAVE_IAC_SB; break; case 11: // Action 11 - Transition to the Have_IAC_SB_IAC state. // d->raw_input_state = NVT_IS_HAVE_IAC_SB_IAC; break; case 12: // Action 12 - Respond to IAC AYT and return to the Normal state. // queue_string(d, "\r\n[Yes]\r\n"); d->raw_input_state = NVT_IS_NORMAL; break; case 13: // Action 13 - Respond to IAC WILL X // switch (HimState(d, ch)) { case OPTION_NO: if (DesiredHimOption(d, ch)) { SetHimState(d, ch, OPTION_YES); SendDo(d, ch); } else { SendDont(d, ch); } break; case OPTION_WANTNO_EMPTY: SetHimState(d, ch, OPTION_NO); break; case OPTION_WANTYES_OPPOSITE: SetHimState(d, ch, OPTION_WANTNO_EMPTY); SendDont(d, ch); break; default: SetHimState(d, ch, OPTION_YES); break; } d->raw_input_state = NVT_IS_NORMAL; break; case 14: // Action 14 - Respond to IAC DONT X // switch (UsState(d, ch)) { case OPTION_YES: SetUsState(d, ch, OPTION_NO); SendWont(d, ch); break; case OPTION_WANTNO_OPPOSITE: SetUsState(d, ch, OPTION_WANTYES_EMPTY); SendWill(d, ch); break; default: SetUsState(d, ch, OPTION_NO); break; } d->raw_input_state = NVT_IS_NORMAL; break; case 15: // Action 15 - Respond to IAC DO X // switch (UsState(d, ch)) { case OPTION_NO: if (DesiredUsOption(d, ch)) { SetUsState(d, ch, OPTION_YES); SendWill(d, ch); } else { SendWont(d, ch); } break; case OPTION_WANTNO_EMPTY: SetUsState(d, ch, OPTION_NO); break; case OPTION_WANTYES_OPPOSITE: SetUsState(d, ch, OPTION_WANTNO_EMPTY); SendWont(d, ch); break; default: SetUsState(d, ch, OPTION_YES); break; } d->raw_input_state = NVT_IS_NORMAL; break; case 16: // Action 16 - Respond to IAC WONT X // // Ignore. // switch (HimState(d, ch)) { case OPTION_NO: break; case OPTION_YES: SetHimState(d, ch, OPTION_NO); SendDont(d, ch); break; case OPTION_WANTNO_OPPOSITE: SetHimState(d, ch, OPTION_WANTYES_EMPTY); SendDo(d, ch); break; default: SetHimState(d, ch, OPTION_NO); break; } d->raw_input_state = NVT_IS_NORMAL; break; case 17: // Action 17 - Accept CHR(X) for Sub-Option (and transition to Have_IAC_SB state). // d->raw_input_state = NVT_IS_HAVE_IAC_SB; if ( d->aOption <= q && q < qend) { *q++ = ch; } break; case 18: // Action 18 - Accept Completed Sub-option and transition to Normal state. // if ( d->aOption < q && q < qend) { size_t m = q - d->aOption; switch (d->aOption[0]) { case TELNET_NAWS: if (m == 5) { d->width = (d->aOption[1] << 8 ) | d->aOption[2]; d->height = (d->aOption[3] << 8 ) | d->aOption[4]; } break; } } q = d->aOption; d->raw_input_state = NVT_IS_NORMAL; break; } pBytes++; } if ( d->raw_input->cmd < p && p <= pend) { d->raw_input_at = p; } else { free_lbuf(d->raw_input); d->raw_input = NULL; d->raw_input_at = NULL; } if ( d->aOption <= q && q < qend) { d->nOption = q - d->aOption; } else { d->nOption = 0; } d->input_tot += nBytes; d->input_size += nInputBytes; d->input_lost += nLostBytes; } bool process_input(DESC *d) { const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = "< process_input >"; char buf[LBUF_SIZE]; int got = SOCKET_READ(d->descriptor, buf, sizeof(buf), 0); if (IS_SOCKET_ERROR(got) || got == 0) { int iSocketError = SOCKET_LAST_ERROR; mudstate.debug_cmd = cmdsave; if ( IS_SOCKET_ERROR(got) && ( iSocketError == SOCKET_EWOULDBLOCK #ifdef SOCKET_EAGAIN || iSocketError == SOCKET_EAGAIN #endif // SOCKET_EAGAIN || iSocketError == SOCKET_EINTR)) { return true; } return false; } process_input_helper(d, buf, got); mudstate.debug_cmd = cmdsave; return true; } void close_sockets(bool emergency, const char *message) { DESC *d, *dnext; DESC_SAFEITER_ALL(d, dnext) { if (emergency) { SOCKET_WRITE(d->descriptor, message, strlen(message), 0); if (IS_SOCKET_ERROR(shutdown(d->descriptor, SD_BOTH))) { log_perror("NET", "FAIL", NULL, "shutdown"); } if (SOCKET_CLOSE(d->descriptor) == 0) { DebugTotalSockets--; } } else { queue_string(d, message); queue_write_LEN(d, "\r\n", 2); shutdownsock(d, R_GOING_DOWN); } } for (int i = 0; i < nMainGamePorts; i++) { if (SOCKET_CLOSE(aMainGamePorts[i].socket) == 0) { DebugTotalSockets--; } aMainGamePorts[i].socket = INVALID_SOCKET; } } void emergency_shutdown(void) { close_sockets(true, "Going down - Bye"); } // --------------------------------------------------------------------------- // Signal handling routines. // #ifdef _SGI_SOURCE #define CAST_SIGNAL_FUNC (SIG_PF) #else // _SGI_SOURCE #define CAST_SIGNAL_FUNC #endif // _SGI_SOURCE // The purpose of the following code is support the case where sys_siglist is // is not part of the environment. This is the case for some Unix platforms // and also for Win32. // typedef struct { int iSignal; const char *szSignal; } SIGNALTYPE, *PSIGNALTYPE; const SIGNALTYPE aSigTypes[] = { #ifdef SIGHUP // Hangup detected on controlling terminal or death of controlling process. // { SIGHUP, "SIGHUP"}, #endif // SIGHUP #ifdef SIGINT // Interrupt from keyboard. // { SIGINT, "SIGINT"}, #endif // SIGINT #ifdef SIGQUIT // Quit from keyboard. // { SIGQUIT, "SIGQUIT"}, #endif // SIGQUIT #ifdef SIGILL // Illegal Instruction. // { SIGILL, "SIGILL"}, #endif // SIGILL #ifdef SIGTRAP // Trace/breakpoint trap. // { SIGTRAP, "SIGTRAP"}, #endif // SIGTRAP #if defined(SIGABRT) // Abort signal from abort(3). // { SIGABRT, "SIGABRT"}, #elif defined(SIGIOT) #define SIGABRT SIGIOT // Abort signal from abort(3). // { SIGIOT, "SIGIOT"}, #endif // SIGABRT #ifdef SIGEMT { SIGEMT, "SIGEMT"}, #endif // SIGEMT #ifdef SIGFPE // Floating-point exception. // { SIGFPE, "SIGFPE"}, #endif // SIGFPE #ifdef SIGKILL // Kill signal. Not catchable. // { SIGKILL, "SIGKILL"}, #endif // SIGKILL #ifdef SIGSEGV // Invalid memory reference. // { SIGSEGV, "SIGSEGV"}, #endif // SIGSEGV #ifdef SIGPIPE // Broken pipe: write to pipe with no readers. // { SIGPIPE, "SIGPIPE"}, #endif // SIGPIPE #ifdef SIGALRM // Timer signal from alarm(2). // { SIGALRM, "SIGALRM"}, #endif // SIGALRM #ifdef SIGTERM // Termination signal. // { SIGTERM, "SIGTERM"}, #endif // SIGTERM #ifdef SIGBREAK // Ctrl-Break. // { SIGBREAK, "SIGBREAK"}, #endif // SIGBREAK #ifdef SIGUSR1 // User-defined signal 1. // { SIGUSR1, "SIGUSR1"}, #endif // SIGUSR1 #ifdef SIGUSR2 // User-defined signal 2. // { SIGUSR2, "SIGUSR2"}, #endif // SIGUSR2 #if defined(SIGCHLD) // Child stopped or terminated. // { SIGCHLD, "SIGCHLD"}, #elif defined(SIGCLD) #define SIGCHLD SIGCLD // Child stopped or terminated. // { SIGCLD, "SIGCLD"}, #endif // SIGCHLD #ifdef SIGCONT // Continue if stopped. // { SIGCONT, "SIGCONT"}, #endif // SIGCONT #ifdef SIGSTOP // Stop process. Not catchable. // { SIGSTOP, "SIGSTOP"}, #endif // SIGSTOP #ifdef SIGTSTP // Stop typed at tty // { SIGTSTP, "SIGTSTP"}, #endif // SIGTSTP #ifdef SIGTTIN // tty input for background process. // { SIGTTIN, "SIGTTIN"}, #endif // SIGTTIN #ifdef SIGTTOU // tty output for background process. // { SIGTTOU, "SIGTTOU"}, #endif // SIGTTOU #ifdef SIGBUS // Bus error (bad memory access). // { SIGBUS, "SIGBUS"}, #endif // SIGBUS #ifdef SIGPROF // Profiling timer expired. // { SIGPROF, "SIGPROF"}, #endif // SIGPROF #ifdef SIGSYS // Bad argument to routine (SVID). // { SIGSYS, "SIGSYS"}, #endif // SIGSYS #ifdef SIGURG // Urgent condition on socket (4.2 BSD). // { SIGURG, "SIGURG"}, #endif // SIGURG #ifdef SIGVTALRM // Virtual alarm clock (4.2 BSD). // { SIGVTALRM, "SIGVTALRM"}, #endif // SIGVTALRM #ifdef SIGXCPU // CPU time limit exceeded (4.2 BSD). // { SIGXCPU, "SIGXCPU"}, #endif // SIGXCPU #ifdef SIGXFSZ // File size limit exceeded (4.2 BSD). // { SIGXFSZ, "SIGXFSZ"}, #endif // SIGXFSZ #ifdef SIGSTKFLT // Stack fault on coprocessor. // { SIGSTKFLT, "SIGSTKFLT"}, #endif // SIGSTKFLT #if defined(SIGIO) // I/O now possible (4.2 BSD). File lock lost. // { SIGIO, "SIGIO"}, #elif defined(SIGPOLL) #define SIGIO SIGPOLL // Pollable event (Sys V). // { SIGPOLL, "SIGPOLL"}, #endif // SIGIO #ifdef SIGLOST { SIGLOST, "SIGLOST"}, #endif // SIGLOST #if defined(SIGPWR) // Power failure (System V). // { SIGPWR, "SIGPWR"}, #elif defined(SIGINFO) #define SIGPWR SIGINFO // Power failure (System V). // { SIGINFO, "SIGINFO"}, #endif // SIGPWR #ifdef SIGWINCH // Window resize signal (4.3 BSD, Sun). // { SIGWINCH, "SIGWINCH"}, #endif // SIGWINCH { 0, "SIGZERO" }, { -1, NULL } }; typedef struct { const char *pShortName; const char *pLongName; } MUX_SIGNAMES; static MUX_SIGNAMES signames[NSIG]; #if defined(HAVE_SYS_SIGNAME) #define SysSigNames sys_signame #elif defined(SYS_SIGLIST_DECLARED) #define SysSigNames sys_siglist #endif // HAVE_SYS_SIGNAME void BuildSignalNamesTable(void) { int i; for (i = 0; i < NSIG; i++) { signames[i].pShortName = NULL; signames[i].pLongName = NULL; } const SIGNALTYPE *pst = aSigTypes; while (pst->szSignal) { int sig = pst->iSignal; if ( 0 <= sig && sig < NSIG) { MUX_SIGNAMES *tsn = &signames[sig]; if (tsn->pShortName == NULL) { tsn->pShortName = pst->szSignal; #ifndef WIN32 if (sig == SIGUSR1) { tsn->pLongName = "Restart server"; } else if (sig == SIGUSR2) { tsn->pLongName = "Drop flatfile"; } #endif // WIN32 #ifdef SysSigNames if ( tsn->pLongName == NULL && SysSigNames[sig] && strcmp(tsn->pShortName, SysSigNames[sig]) != 0) { tsn->pLongName = SysSigNames[sig]; } #endif // SysSigNames } } pst++; } for (i = 0; i < NSIG; i++) { MUX_SIGNAMES *tsn = &signames[i]; if (tsn->pShortName == NULL) { #ifdef SysSigNames if (SysSigNames[i]) { tsn->pLongName = SysSigNames[i]; } #endif // SysSigNames // This is the only non-const memory case. // tsn->pShortName = StringClone(tprintf("SIG%03d", i)); } } } static void unset_signals(void) { const SIGNALTYPE *pst = aSigTypes; while (pst->szSignal) { int sig = pst->iSignal; signal(sig, SIG_DFL); } } static void check_panicking(int sig) { // If we are panicking, turn off signal catching and resignal. // if (mudstate.panicking) { unset_signals(); #ifdef WIN32 UNUSED_PARAMETER(sig); abort(); #else // WIN32 kill(game_pid, sig); #endif // WIN32 } mudstate.panicking = true; } static char *SignalDesc(int iSignal) { static char buff[LBUF_SIZE]; char *bufc = buff; safe_str(signames[iSignal].pShortName, buff, &bufc); if (signames[iSignal].pLongName) { safe_str(" (", buff, &bufc); safe_str(signames[iSignal].pLongName, buff, &bufc); safe_chr(')', buff, &bufc); } *bufc = '\0'; return buff; } static void log_signal(int iSignal) { STARTLOG(LOG_PROBLEMS, "SIG", "CATCH"); log_text("Caught signal "); log_text(SignalDesc(iSignal)); ENDLOG; } #ifndef WIN32 static void log_signal_ignore(int iSignal) { STARTLOG(LOG_PROBLEMS, "SIG", "CATCH"); log_text("Caught signal and ignored signal "); log_text(SignalDesc(iSignal)); log_text(" because server just came up."); ENDLOG; } void LogStatBuf(int stat_buf, const char *Name) { STARTLOG(LOG_ALWAYS, "NET", Name); if (WIFEXITED(stat_buf)) { Log.tinyprintf("process exited unexpectedly with exit status %d.", WEXITSTATUS(stat_buf)); } else if (WIFSIGNALED(stat_buf)) { Log.tinyprintf("process was terminated with signal %s.", SignalDesc(WTERMSIG(stat_buf))); } else { log_text("process ended unexpectedly."); } ENDLOG; } #endif static RETSIGTYPE DCL_CDECL sighandler(int sig) { #ifndef WIN32 int stat_buf; pid_t child; #endif // !WIN32 switch (sig) { #ifndef WIN32 case SIGUSR1: if (mudstate.bCanRestart) { log_signal(sig); do_restart(GOD, GOD, GOD, 0); } else { log_signal_ignore(sig); } break; case SIGUSR2: // Drop a flatfile. // log_signal(sig); raw_broadcast(0, "Caught signal %s requesting a flatfile @dump. Please wait.", SignalDesc(sig)); dump_database_internal(DUMP_I_SIGNAL); break; case SIGCHLD: // Change in child status. // #ifndef SIGNAL_SIGCHLD_BRAINDAMAGE signal(SIGCHLD, CAST_SIGNAL_FUNC sighandler); #endif // !SIGNAL_SIGCHLD_BRAINDAMAGE while ((child = waitpid(0, &stat_buf, WNOHANG)) > 0) { if ( WIFEXITED(stat_buf) || WIFSIGNALED(stat_buf)) { if (child == slave_pid) { // The reverse-DNS slave process ended unexpectedly. // CleanUpSlaveSocket(); slave_pid = 0; LogStatBuf(stat_buf, "SLAVE"); continue; } #ifdef QUERY_SLAVE else if (child == sqlslave_pid) { // The SQL slave process ended unexpectedly. // CleanUpSQLSlaveSocket(); sqlslave_pid = 0; LogStatBuf(stat_buf, "QUERY"); continue; } #endif // QUERY_SLAVE else if ( mudconf.fork_dump && mudstate.dumping) { mudstate.dumped = child; if (mudstate.dumper == mudstate.dumped) { // The dumping process finished. // mudstate.dumper = 0; mudstate.dumped = 0; } else { // The dumping process finished before we could // obtain its process id from fork(). // } mudstate.dumping = false; local_dump_complete_signal(); continue; } } log_signal(sig); LogStatBuf(stat_buf, "UKNWN"); STARTLOG(LOG_PROBLEMS, "SIG", "DEBUG"); #ifdef QUERY_SLAVE Log.tinyprintf("mudstate.dumper=%d, child=%d, slave_pid=%d, sqlslave_pid=%d" ENDLINE, mudstate.dumper, child, slave_pid, sqlslave_pid); #else Log.tinyprintf("mudstate.dumper=%d, child=%d, slave_pid=%d" ENDLINE, mudstate.dumper, child, slave_pid); #endif // QUERY_SLAVE ENDLOG; } break; case SIGHUP: // Perform a database dump. // log_signal(sig); extern void dispatch_DatabaseDump(void *pUnused, int iUnused); scheduler.CancelTask(dispatch_DatabaseDump, 0, 0); mudstate.dump_counter.GetUTC(); scheduler.DeferTask(mudstate.dump_counter, PRIORITY_SYSTEM, dispatch_DatabaseDump, 0, 0); break; #ifdef HAVE_SETITIMER case SIGPROF: // Softcode is running longer than is reasonable. Apply the brakes. // log_signal(sig); MuxAlarm.Signal(); break; #endif #endif // !WIN32 case SIGINT: // Log + ignore // log_signal(sig); break; #ifndef WIN32 case SIGQUIT: #endif // !WIN32 case SIGTERM: #ifdef SIGXCPU case SIGXCPU: #endif // SIGXCPU // Time for a normal and short-winded shutdown. // check_panicking(sig); log_signal(sig); raw_broadcast(0, "GAME: Caught signal %s, exiting.", SignalDesc(sig)); mudstate.shutdown_flag = true; break; case SIGILL: case SIGFPE: case SIGSEGV: #ifndef WIN32 case SIGTRAP: #ifdef SIGXFSZ case SIGXFSZ: #endif // SIGXFSZ #ifdef SIGEMT case SIGEMT: #endif // SIGEMT #ifdef SIGBUS case SIGBUS: #endif // SIGBUS #ifdef SIGSYS case SIGSYS: #endif // SIGSYS #endif // !WIN32 // Panic save + restart. // Log.Flush(); check_panicking(sig); log_signal(sig); report(); local_presync_database_sigsegv(); #ifndef MEMORY_BASED al_store(); #endif pcache_sync(); SYNC; if ( mudconf.sig_action != SA_EXIT && mudstate.bCanRestart) { raw_broadcast ( 0, "GAME: Fatal signal %s caught, restarting.", SignalDesc(sig) ); // There is no older DB. It's a fiction. Our only choice is // between unamed attributes and named ones. We go with what we // got. // dump_database_internal(DUMP_I_RESTART); SYNC; CLOSE; #ifdef WIN32 unset_signals(); signal(sig, SIG_DFL); WSACleanup(); exit(12345678); #else // WIN32 CleanUpSlaveSocket(); CleanUpSlaveProcess(); // Try our best to dump a core first // if (!fork()) { // We are the broken parent. Die. // unset_signals(); exit(1); } // We are the reproduced child with a slightly better chance. // dump_restart_db(); #ifdef GAME_DOOFERMUX execl("bin/netmux", mudconf.mud_name, "-c", mudconf.config_file, "-p", mudconf.pid_file, "-e", mudconf.log_dir, NULL); #else // GAME_DOOFERMUX execl("bin/netmux", "netmux", "-c", mudconf.config_file, "-p", mudconf.pid_file, "-e", mudconf.log_dir, NULL); #endif // GAME_DOOFERMUX break; #endif // WIN32 } else { #ifdef WIN32 WSACleanup(); #endif // WIN32 unset_signals(); signal(sig, SIG_DFL); exit(1); } break; case SIGABRT: // Coredump. // check_panicking(sig); log_signal(sig); report(); #ifdef WIN32 WSACleanup(); #endif // WIN32 unset_signals(); signal(sig, SIG_DFL); exit(1); } signal(sig, CAST_SIGNAL_FUNC sighandler); mudstate.panicking = 0; } NAMETAB sigactions_nametab[] = { {"exit", 3, 0, SA_EXIT}, {"default", 1, 0, SA_DFLT}, { NULL, 0, 0, 0} }; void set_signals(void) { #ifndef WIN32 sigset_t sigs; // We have to reset our signal mask, because of the possibility // that we triggered a restart on a SIGUSR1. If we did so, then // the signal became blocked, and stays blocked, since control // never returns to the caller; i.e., further attempts to send // a SIGUSR1 would fail. // #undef sigfillset #undef sigprocmask sigfillset(&sigs); sigprocmask(SIG_UNBLOCK, &sigs, NULL); #endif // !WIN32 signal(SIGINT, CAST_SIGNAL_FUNC sighandler); signal(SIGTERM, CAST_SIGNAL_FUNC sighandler); signal(SIGILL, CAST_SIGNAL_FUNC sighandler); signal(SIGSEGV, CAST_SIGNAL_FUNC sighandler); signal(SIGABRT, CAST_SIGNAL_FUNC sighandler); signal(SIGFPE, SIG_IGN); #ifndef WIN32 signal(SIGCHLD, CAST_SIGNAL_FUNC sighandler); signal(SIGHUP, CAST_SIGNAL_FUNC sighandler); signal(SIGQUIT, CAST_SIGNAL_FUNC sighandler); signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, CAST_SIGNAL_FUNC sighandler); signal(SIGUSR2, CAST_SIGNAL_FUNC sighandler); signal(SIGTRAP, CAST_SIGNAL_FUNC sighandler); signal(SIGILL, CAST_SIGNAL_FUNC sighandler); #ifdef HAVE_SETITIMER signal(SIGPROF, CAST_SIGNAL_FUNC sighandler); #endif #ifdef SIGXCPU signal(SIGXCPU, CAST_SIGNAL_FUNC sighandler); #endif // SIGXCPU #ifdef SIGFSZ signal(SIGXFSZ, CAST_SIGNAL_FUNC sighandler); #endif // SIGFSZ #ifdef SIGEMT signal(SIGEMT, CAST_SIGNAL_FUNC sighandler); #endif // SIGEMT #ifdef SIGBUS signal(SIGBUS, CAST_SIGNAL_FUNC sighandler); #endif // SIGBUS #ifdef SIGSYS signal(SIGSYS, CAST_SIGNAL_FUNC sighandler); #endif // SIGSYS #endif // !WIN32 } void list_system_resources(dbref player) { char buffer[80]; int nTotal = 0; notify(player, "System Resources"); mux_sprintf(buffer, sizeof(buffer), "Total Open Files: %ld", DebugTotalFiles); notify(player, buffer); nTotal += DebugTotalFiles; mux_sprintf(buffer, sizeof(buffer), "Total Sockets: %ld", DebugTotalSockets); notify(player, buffer); nTotal += DebugTotalSockets; #ifdef WIN32 mux_sprintf(buffer, sizeof(buffer), "Total Threads: %ld", DebugTotalThreads); notify(player, buffer); nTotal += DebugTotalThreads; mux_sprintf(buffer, sizeof(buffer), "Total Semaphores: %ld", DebugTotalSemaphores); notify(player, buffer); nTotal += DebugTotalSemaphores; #endif // WIN32 mux_sprintf(buffer, sizeof(buffer), "Total Handles (sum of above): %d", nTotal); notify(player, buffer); #ifdef WIN32 for (int i = 0; i < NUM_SLAVE_THREADS; i++) { mux_sprintf(buffer, sizeof(buffer), "Thread %d at line %u", i+1, SlaveThreadInfo[i].iDoing); notify(player, buffer); } #endif // WIN32 } #ifdef WIN32 // --------------------------------------------------------------------------- // Thread to listen on MUD port - for Windows NT // --------------------------------------------------------------------------- // static DWORD WINAPI MUDListenThread(LPVOID pVoid) { PortInfo *Port = (PortInfo *)pVoid; SOCKADDR_IN SockAddr; int nLen; BOOL b; struct descriptor_data * d; Log.tinyprintf("Starting NT-style listening on port %d" ENDLINE, Port->port); // // Loop forever accepting connections // for (;;) { // // Block on accept() // nLen = sizeof(SOCKADDR_IN); SOCKET socketClient = accept(Port->socket, (LPSOCKADDR) &SockAddr, &nLen); if (socketClient == INVALID_SOCKET) { // parent thread closes the listening socket // when it wants this thread to stop. // break; } DebugTotalSockets++; if (site_check(SockAddr.sin_addr, mudstate.access_list) == H_FORBIDDEN) { STARTLOG(LOG_NET | LOG_SECURITY, "NET", "SITE"); unsigned short us = ntohs(SockAddr.sin_port); Log.tinyprintf("[%d/%s] Connection refused. (Remote port %d)", socketClient, inet_ntoa(SockAddr.sin_addr), us); ENDLOG; // The following are commented out for thread-safety, but // ordinarily, they would occur at this time. // //SiteMonSend(socketClient, inet_ntoa(SockAddr.sin_addr), NULL, // "Connection refused"); //fcache_rawdump(socketClient, FC_CONN_SITE); shutdown(socketClient, SD_BOTH); if (closesocket(socketClient) == 0) { DebugTotalSockets--; } continue; } // Make slave request // // Go take control of the stack, but don't bother if it takes // longer than 5 seconds to do it. // if (bSlaveBooted && (WAIT_OBJECT_0 == WaitForSingleObject(hSlaveRequestStackSemaphore, 5000))) { // We have control of the stack. Skip the request if the stack is full. // if (iSlaveRequest < SLAVE_REQUEST_STACK_SIZE) { // There is room on the stack, so make the request. // SlaveRequests[iSlaveRequest].sa_in = SockAddr; SlaveRequests[iSlaveRequest].port_in = mudconf.ports.pi[0]; iSlaveRequest++; ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL); // Wake up a single slave thread. Event automatically resets itself. // ReleaseSemaphore(hSlaveThreadsSemaphore, 1, NULL); } else { // No room on the stack, so skip it. // ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL); } } d = initializesock(socketClient, &SockAddr); // Add this socket to the IO completion port. // CompletionPort = CreateIoCompletionPort((HANDLE)socketClient, CompletionPort, (MUX_ULONG_PTR) d, 1); if (!CompletionPort) { Log.tinyprintf("Error %ld on CreateIoCompletionPort for socket %ld" ENDLINE, GetLastError(), socketClient); shutdownsock_brief(d); continue; } TelnetSetup(d); if (!PostQueuedCompletionStatus(CompletionPort, 0, (MUX_ULONG_PTR) d, &lpo_welcome)) { Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (read)" ENDLINE, GetLastError()); shutdownsock_brief(d); continue; } // Do the first read // b = ReadFile((HANDLE) socketClient, d->input_buffer, sizeof(d->input_buffer), NULL, &d->InboundOverlapped); if (!b && GetLastError() != ERROR_IO_PENDING) { // Post a notification that the descriptor should be shutdown, and do no more IO. // d->bConnectionDropped = true; Log.tinyprintf("ProcessWindowsTCP(%d) cannot queue read request with error %ld. Requesting port shutdown." ENDLINE, d->descriptor, GetLastError()); if (!PostQueuedCompletionStatus(CompletionPort, 0, (MUX_ULONG_PTR) d, &lpo_shutdown)) { Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (initial read)" ENDLINE, GetLastError()); } } } Log.tinyprintf("End of NT-style listening on port %d" ENDLINE, Port->port); return 1; } void Task_FreeDescriptor(void *arg_voidptr, int arg_Integer) { UNUSED_PARAMETER(arg_Integer); DESC *d = (DESC *)arg_voidptr; if (d) { EnterCriticalSection(&csDescriptorList); ndescriptors--; freeqs(d); free_desc(d); LeaveCriticalSection(&csDescriptorList); } } void Task_DeferredClose(void *arg_voidptr, int arg_Integer) { UNUSED_PARAMETER(arg_Integer); DESC *d = (DESC *)arg_voidptr; if (d) { d->bConnectionDropped = true; // Cancel any pending reads or writes on this socket // if (!fpCancelIo((HANDLE) d->descriptor)) { Log.tinyprintf("Error %ld on CancelIo" ENDLINE, GetLastError()); } shutdown(d->descriptor, SD_BOTH); if (SOCKET_CLOSE(d->descriptor) == 0) { DebugTotalSockets--; } d->descriptor = INVALID_SOCKET; // Post a notification that it is safe to free the descriptor // we can't free the descriptor here (below) as there may be some // queued completed IOs that will crash when they refer to a descriptor // (d) that has been freed. // if (!PostQueuedCompletionStatus(CompletionPort, 0, (MUX_ULONG_PTR) d, &lpo_aborted)) { Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in shutdownsock" ENDLINE, GetLastError()); } } } /* This is called from within shovechars when it needs to see if any IOs have completed for the Windows NT version. The 4 sorts of IO completions are: 1. Outstanding read completing (there should always be an outstanding read) 2. Outstanding write completing 3. A special "shutdown" message to tell us to shutdown the socket 4. A special "aborted" message to tell us the socket has shut down, and we can now free the descriptor. The latter 2 are posted by the application by PostQueuedCompletionStatus when it is necessary to signal these "events". The reason for posting the special messages is to shut down sockets in an orderly way. */ void ProcessWindowsTCP(DWORD dwTimeout) { LPOVERLAPPED lpo; DWORD nbytes; DESC *d; for ( ; ; dwTimeout = 0) { // pull out the next completed IO // BOOL b = GetQueuedCompletionStatus(CompletionPort, &nbytes, (MUX_PULONG_PTR) &d, &lpo, dwTimeout); if (!b) { DWORD dwLastError = GetLastError(); // Ignore timeouts and cancelled IOs // switch (dwLastError) { case WAIT_TIMEOUT: //Log.WriteString("Timeout." ENDLINE); return; case ERROR_OPERATION_ABORTED: //Log.WriteString("Operation Aborted." ENDLINE); continue; default: if (!(d->bConnectionDropped)) { // bad IO - shut down this client // d->bConnectionDropped = true; // Post a notification that the descriptor should be shutdown // Log.tinyprintf("ProcessWindowsTCP(%d) failed IO with error %ld. Requesting port shutdown." ENDLINE, d->descriptor, dwLastError); if (!PostQueuedCompletionStatus(CompletionPort, 0, (MUX_ULONG_PTR) d, &lpo_shutdown)) { Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (write)" ENDLINE, GetLastError()); } } } } else if (lpo == &d->OutboundOverlapped && !d->bConnectionDropped) { //Log.tinyprintf("Write(%d bytes)." ENDLINE, nbytes); // Write completed // TBLOCK *tp; DWORD nBytes; bool bNothingToWrite; do { bNothingToWrite = true; tp = d->output_head; if (tp == NULL) { d->bWritePending = false; break; } bNothingToWrite = true; // Move data from one buffer to another. // if (tp->hdr.nchars <= SIZEOF_OVERLAPPED_BUFFERS) { // We can consume this buffer. // nBytes = static_cast(tp->hdr.nchars); memcpy(d->output_buffer, tp->hdr.start, nBytes); TBLOCK *save = tp; tp = tp->hdr.nxt; MEMFREE(save); save = NULL; d->output_head = tp; if (tp == NULL) { //Log.tinyprintf("Write...%d bytes taken from a queue of %d bytes...Empty Queue, now." ENDLINE, nBytes, d->output_size); d->output_tail = NULL; } else { //Log.tinyprintf("Write...%d bytes taken from a queue of %d bytes...more buffers in Queue" ENDLINE, nBytes, d->output_size); } } else { // Use the entire bufer and leave the remaining data in the queue. // nBytes = SIZEOF_OVERLAPPED_BUFFERS; memcpy(d->output_buffer, tp->hdr.start, nBytes); tp->hdr.nchars -= nBytes; tp->hdr.start += nBytes; //Log.tinyprintf("Write...%d bytes taken from a queue of %d bytes...buffer still has bytes" ENDLINE, nBytes, d->output_size); } d->output_size -= nBytes; d->OutboundOverlapped.Offset = 0; d->OutboundOverlapped.OffsetHigh = 0; // We do allow more than one complete write request in the IO // completion port queue. The reason is that if WriteFile // returns true, we -can- re-used the output_buffer -and- // redundant queue entries just cause us to try to write more // often. There is no possibility of corruption. // // It then becomes a trade off between the costs. I find that // keeping the TCP/IP full of data is more important. // DWORD nWritten; b = WriteFile((HANDLE) d->descriptor, d->output_buffer, nBytes, &nWritten, &d->OutboundOverlapped); } while (b); if (bNothingToWrite) { if (d->bConnectionShutdown) { scheduler.CancelTask(Task_DeferredClose, d, 0); scheduler.DeferImmediateTask(PRIORITY_SYSTEM, Task_DeferredClose, d, 0); } continue; } d->bWritePending = true; DWORD dwLastError = GetLastError(); if (dwLastError != ERROR_IO_PENDING) { // Post a notification that the descriptor should be shutdown // d->bWritePending = false; d->bConnectionDropped = true; Log.tinyprintf("ProcessWindowsTCP(%d) cannot queue write request with error %ld. Requesting port shutdown." ENDLINE, d->descriptor, dwLastError); if (!PostQueuedCompletionStatus(CompletionPort, 0, (MUX_ULONG_PTR) d, &lpo_shutdown)) { Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (write)" ENDLINE, GetLastError()); } } } else if (lpo == &d->InboundOverlapped && !d->bConnectionDropped) { //Log.tinyprintf("Read(%d bytes)." ENDLINE, nbytes); // The read operation completed // if (nbytes == 0) { // A zero-length IO completion means that the connection was dropped by the client. // // Post a notification that the descriptor should be shutdown // d->bConnectionDropped = true; Log.tinyprintf("ProcessWindowsTCP(%d) zero-length read. Requesting port shutdown." ENDLINE, d->descriptor); if (!PostQueuedCompletionStatus(CompletionPort, 0, (MUX_ULONG_PTR) d, &lpo_shutdown)) { Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (read)" ENDLINE, GetLastError()); } continue; } d->last_time.GetUTC(); // Undo autodark // if (d->flags & DS_AUTODARK) { // Clear the DS_AUTODARK on every related session. // DESC *d1; DESC_ITER_PLAYER(d->player, d1) { d1->flags &= ~DS_AUTODARK; } db[d->player].fs.word[FLAG_WORD1] &= ~DARK; } // process the player's input // process_input_helper(d, d->input_buffer, nbytes); // now fire off another read // b = ReadFile((HANDLE) d->descriptor, d->input_buffer, sizeof(d->input_buffer), &nbytes, &d->InboundOverlapped); // if ReadFile returns true, then the read completed successfully already, but it was also added to the IO // completion port queue, so in order to avoid having two requests in the queue for the same buffer // (corruption problems), we act as if the IO is still pending. // if (!b) { // ERROR_IO_PENDING is a normal way of saying, 'not done yet'. All other errors are serious errors. // DWORD dwLastError = GetLastError(); if (dwLastError != ERROR_IO_PENDING) { // Post a notification that the descriptor should be shutdown, and do no more IO. // d->bConnectionDropped = true; Log.tinyprintf("ProcessWindowsTCP(%d) cannot queue read request with error %ld. Requesting port shutdown." ENDLINE, d->descriptor, dwLastError); if (!PostQueuedCompletionStatus(CompletionPort, 0, (MUX_ULONG_PTR) d, &lpo_shutdown)) { Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (read)" ENDLINE, GetLastError()); } } } } else if (lpo == &lpo_welcome) { char *buff = alloc_mbuf("ProcessWindowsTCP.Premature"); mux_strncpy(buff, inet_ntoa(d->address.sin_addr), MBUF_SIZE-1); // If the socket is invalid, the we were unable to queue a read // request, and the port was shutdown while this packet was in // the completion port queue. // bool bInvalidSocket = IS_INVALID_SOCKET(d->descriptor); // Log connection. // STARTLOG(LOG_NET | LOG_LOGIN, "NET", "CONN"); const char *lDesc = mux_i64toa_t(d->descriptor); Log.tinyprintf("[%s/%s] Connection opened (remote port %d)", bInvalidSocket ? "UNKNOWN" : lDesc, buff, ntohs(d->address.sin_port)); ENDLOG; SiteMonSend(d->descriptor, buff, d, "Connection"); if (bInvalidSocket) { // Log premature disconnection. // STARTLOG(LOG_NET | LOG_LOGIN, "NET", "DISC"); Log.tinyprintf("[UNKNOWN/%s] Connection closed prematurely (remote port %d)", buff, ntohs(d->address.sin_port)); ENDLOG; SiteMonSend(d->descriptor, buff, d, "Connection closed prematurely"); } else { // Welcome the user. // welcome_user(d); } free_mbuf(buff); } else if (lpo == &lpo_shutdown) { //Log.WriteString("Shutdown." ENDLINE); // Shut this descriptor down. // shutdownsock(d, R_SOCKDIED); // shut him down } else if (lpo == &lpo_aborted) { // Instead of freeing the descriptor immediately, we are going to put it back at the // end of the queue. CancelIo will still generate aborted packets. We don't want the descriptor // be be re-used and have a new connection be stepped on by a dead one. // if (!PostQueuedCompletionStatus(CompletionPort, 0, (MUX_ULONG_PTR) d, &lpo_aborted_final)) { Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (aborted)" ENDLINE, GetLastError()); } } else if (lpo == &lpo_aborted_final) { // Now that we are fairly certain that all IO packets refering to this descriptor have been processed // and no further packets remain in the IO queue, schedule a task to free the descriptor. This allows // any tasks which might potentially refer to this descriptor to be handled before we free the // descriptor. // scheduler.DeferImmediateTask(PRIORITY_SYSTEM, Task_FreeDescriptor, d, 0); } else if (lpo == &lpo_wakeup) { // Just waking up is good enough. // } } } #endif // WIN32 void SiteMonSend(SOCKET port, const char *address, DESC *d, const char *msg) { // Don't do sitemon for blocked sites. // if ( d != NULL && (d->host_info & H_NOSITEMON)) { return; } // Build the msg. // char *sendMsg; bool bSuspect = (d != NULL) && (d->host_info & H_SUSPECT); if (IS_INVALID_SOCKET(port)) { sendMsg = tprintf("SITEMON: [UNKNOWN] %s from %s.%s", msg, address, bSuspect ? " (SUSPECT)": ""); } else { sendMsg = tprintf("SITEMON: [%d] %s from %s.%s", port, msg, address, bSuspect ? " (SUSPECT)": ""); } DESC *nd; DESC_ITER_CONN(nd) { if (SiteMon(nd->player)) { queue_string(nd, sendMsg); queue_write_LEN(nd, "\r\n", 2); process_output(nd, false); } } } mux2.6/src/command.cpp0000600000175000017500000047423711025753746014741 0ustar sdennissdennis/*! \file command.cpp * Command parser and support routines. * * $Id: command.cpp 2734 2007-10-28 23:02:55Z brazilofmux $ * * The functions here crack command lists into commands, decode switches, and * match commands to built-in and softcoded commands. This is one of the * three parsers in the server. The other two parsers are for functions * (see eval.cpp) and locks (boolexp.cpp). */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "ansi.h" #include "attrs.h" #include "command.h" #include "comsys.h" #include "functions.h" #include "mguests.h" #include "powers.h" #include "vattr.h" #include "help.h" #include "pcre.h" // Switch tables for the various commands. // static NAMETAB attrib_sw[] = { {"access", 1, CA_GOD, ATTRIB_ACCESS}, {"delete", 1, CA_GOD, ATTRIB_DELETE}, {"rename", 1, CA_GOD, ATTRIB_RENAME}, { NULL, 0, 0, 0} }; static NAMETAB boot_sw[] = { {"port", 1, CA_WIZARD, BOOT_PORT|SW_MULTIPLE}, {"quiet", 1, CA_WIZARD, BOOT_QUIET|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB cboot_sw[] = { {"quiet", 1, CA_PUBLIC, CBOOT_QUIET}, { NULL, 0, 0, 0} }; static NAMETAB comtitle_sw[] = { {"off", 2, CA_PUBLIC, COMTITLE_OFF}, {"on", 2, CA_PUBLIC, COMTITLE_ON}, { NULL, 0, 0, 0} }; static NAMETAB cemit_sw[] = { {"noheader", 1, CA_PUBLIC, CEMIT_NOHEADER}, { NULL, 0, 0, 0} }; static NAMETAB chown_sw[] = { {"nostrip", 1, CA_PUBLIC, CHOWN_NOSTRIP}, { NULL, 0, 0, 0} }; static NAMETAB clone_sw[] = { {"cost", 1, CA_PUBLIC, CLONE_SET_COST}, {"inherit", 3, CA_PUBLIC, CLONE_INHERIT|SW_MULTIPLE}, {"inventory", 3, CA_PUBLIC, CLONE_INVENTORY}, {"location", 1, CA_PUBLIC, CLONE_LOCATION}, {"nostrip", 2, CA_WIZARD, CLONE_NOSTRIP|SW_MULTIPLE}, {"parent", 2, CA_PUBLIC, CLONE_FROM_PARENT|SW_MULTIPLE}, {"preserve", 2, CA_WIZARD, CLONE_PRESERVE|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB clist_sw[] = { {"full", 0, CA_PUBLIC, CLIST_FULL}, {"headers", 0, CA_PUBLIC, CLIST_HEADERS}, { NULL, 0, 0, 0} }; static NAMETAB cset_sw[] = { {"anon", 1, CA_PUBLIC, CSET_SPOOF}, {"header", 1, CA_PUBLIC, CSET_HEADER}, {"list", 2, CA_PUBLIC, CSET_LIST}, {"log" , 3, CA_PUBLIC, CSET_LOG}, {"loud", 3, CA_PUBLIC, CSET_LOUD}, {"mute", 1, CA_PUBLIC, CSET_QUIET}, {"nospoof", 1, CA_PUBLIC, CSET_NOSPOOF}, {"object", 1, CA_PUBLIC, CSET_OBJECT}, {"private", 2, CA_PUBLIC, CSET_PRIVATE}, {"public", 2, CA_PUBLIC, CSET_PUBLIC}, {"quiet", 1, CA_PUBLIC, CSET_QUIET}, {"spoof", 1, CA_PUBLIC, CSET_SPOOF}, { NULL, 0, 0, 0} }; static NAMETAB dbck_sw[] = { {"full", 1, CA_WIZARD, DBCK_FULL}, { NULL, 0, 0, 0} }; static NAMETAB decomp_sw[] = { {"dbref", 1, CA_PUBLIC, DECOMP_DBREF}, { NULL, 0, 0, 0} }; static NAMETAB destroy_sw[] = { {"instant", 4, CA_PUBLIC, DEST_INSTANT|SW_MULTIPLE}, {"override", 8, CA_PUBLIC, DEST_OVERRIDE|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB dig_sw[] = { {"teleport", 1, CA_PUBLIC, DIG_TELEPORT}, { NULL, 0, 0, 0} }; static NAMETAB doing_sw[] = { {"header", 1, CA_PUBLIC, DOING_HEADER}, {"message", 1, CA_PUBLIC, DOING_MESSAGE}, {"poll", 1, CA_PUBLIC, DOING_POLL}, {"quiet", 1, CA_PUBLIC, DOING_QUIET|SW_MULTIPLE}, {"unique", 1, CA_PUBLIC, DOING_UNIQUE}, { NULL, 0, 0, 0} }; static NAMETAB dolist_sw[] = { {"delimit", 1, CA_PUBLIC, DOLIST_DELIMIT}, {"notify", 1, CA_PUBLIC, DOLIST_NOTIFY|SW_MULTIPLE}, {"space", 1, CA_PUBLIC, DOLIST_SPACE}, { NULL, 0, 0, 0} }; #ifdef QUERY_SLAVE static NAMETAB query_sw[] = { {"sql", 1, CA_PUBLIC, QUERY_SQL}, { NULL, 0, 0, 0} }; #endif // QUERY_SLAVE static NAMETAB drop_sw[] = { {"quiet", 1, CA_PUBLIC, DROP_QUIET}, { NULL, 0, 0, 0} }; static NAMETAB dump_sw[] = { {"flatfile", 1, CA_WIZARD, DUMP_FLATFILE|SW_MULTIPLE}, {"structure", 1, CA_WIZARD, DUMP_STRUCT|SW_MULTIPLE}, {"text", 1, CA_WIZARD, DUMP_TEXT|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB emit_sw[] = { {"here", 2, CA_PUBLIC, SAY_HERE|SW_MULTIPLE}, {"html", 2, CA_PUBLIC, SAY_HTML|SW_MULTIPLE}, {"room", 1, CA_PUBLIC, SAY_ROOM|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB enter_sw[] = { {"quiet", 1, CA_PUBLIC, MOVE_QUIET}, { NULL, 0, 0, 0} }; static NAMETAB examine_sw[] = { {"brief", 1, CA_PUBLIC, EXAM_BRIEF}, {"debug", 1, CA_WIZARD, EXAM_DEBUG}, {"full", 1, CA_PUBLIC, EXAM_LONG}, {"parent", 1, CA_PUBLIC, EXAM_PARENT}, { NULL, 0, 0, 0} }; static NAMETAB femit_sw[] = { {"here", 1, CA_PUBLIC, PEMIT_HERE|SW_MULTIPLE}, {"room", 1, CA_PUBLIC, PEMIT_ROOM|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB fixdb_sw[] = { {"contents", 1, CA_GOD, FIXDB_CON}, {"exits", 1, CA_GOD, FIXDB_EXITS}, {"location", 1, CA_GOD, FIXDB_LOC}, {"next", 1, CA_GOD, FIXDB_NEXT}, {"owner", 1, CA_GOD, FIXDB_OWNER}, {"pennies", 1, CA_GOD, FIXDB_PENNIES}, {"rename", 1, CA_GOD, FIXDB_NAME}, { NULL, 0, 0, 0} }; static NAMETAB flag_sw[] = { {"remove", 1, CA_GOD, FLAG_REMOVE}, { NULL, 0, 0, 0} }; static NAMETAB fpose_sw[] = { {"default", 1, CA_PUBLIC, 0}, {"nospace", 1, CA_PUBLIC, SAY_NOSPACE}, { NULL, 0, 0, 0} }; static NAMETAB function_sw[] = { {"list", 1, CA_WIZARD, FN_LIST}, {"preserve", 3, CA_WIZARD, FN_PRES|SW_MULTIPLE}, {"privileged", 3, CA_WIZARD, FN_PRIV|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB get_sw[] = { {"quiet", 1, CA_PUBLIC, GET_QUIET}, { NULL, 0, 0, 0} }; static NAMETAB give_sw[] = { {"quiet", 1, CA_WIZARD, GIVE_QUIET}, { NULL, 0, 0, 0} }; static NAMETAB goto_sw[] = { {"quiet", 1, CA_PUBLIC, MOVE_QUIET}, { NULL, 0, 0, 0} }; static NAMETAB halt_sw[] = { {"all", 1, CA_PUBLIC, HALT_ALL}, { NULL, 0, 0, 0} }; static NAMETAB hook_sw[] = { {"after", 3, CA_GOD, HOOK_AFTER}, {"before", 3, CA_GOD, HOOK_BEFORE}, {"clear", 3, CA_GOD, HOOK_CLEAR|SW_MULTIPLE}, {"fail", 1, CA_GOD, HOOK_AFAIL}, {"ignore", 3, CA_GOD, HOOK_IGNORE}, {"igswitch", 3, CA_GOD, HOOK_IGSWITCH}, {"list", 3, CA_GOD, HOOK_LIST}, {"permit", 3, CA_GOD, HOOK_PERMIT}, {NULL, 0, 0, 0} }; static NAMETAB icmd_sw[] = { {"check", 2, CA_GOD, ICMD_CHECK}, {"clear", 2, CA_GOD, ICMD_CLEAR}, {"croom", 2, CA_GOD, ICMD_CROOM}, {"disable", 1, CA_GOD, ICMD_DISABLE}, {"droom", 2, CA_GOD, ICMD_DROOM}, {"ignore", 1, CA_GOD, ICMD_IGNORE}, {"iroom", 2, CA_GOD, ICMD_IROOM}, {"lroom", 2, CA_GOD, ICMD_LROOM}, {"lallroom", 2, CA_GOD, ICMD_LALLROOM}, {"off", 2, CA_GOD, ICMD_OFF}, {"on", 2, CA_GOD, ICMD_ON}, {NULL, 0, 0, 0} }; static NAMETAB leave_sw[] = { {"quiet", 1, CA_PUBLIC, MOVE_QUIET}, { NULL, 0, 0, 0} }; static NAMETAB listmotd_sw[] = { {"brief", 1, CA_WIZARD, MOTD_BRIEF}, { NULL, 0, 0, 0} }; NAMETAB lock_sw[] = { {"defaultlock", 1, CA_PUBLIC, A_LOCK}, {"droplock", 1, CA_PUBLIC, A_LDROP}, {"enterlock", 1, CA_PUBLIC, A_LENTER}, {"getfromlock", 1, CA_PUBLIC, A_LGET}, {"givelock", 1, CA_PUBLIC, A_LGIVE}, {"leavelock", 2, CA_PUBLIC, A_LLEAVE}, {"linklock", 2, CA_PUBLIC, A_LLINK}, {"maillock", 1, CA_PUBLIC, A_LMAIL}, {"openlock", 1, CA_PUBLIC, A_LOPEN}, {"pagelock", 3, CA_PUBLIC, A_LPAGE}, {"parentlock", 3, CA_PUBLIC, A_LPARENT}, {"receivelock", 1, CA_PUBLIC, A_LRECEIVE}, {"speechlock", 1, CA_PUBLIC, A_LSPEECH}, {"teloutlock", 2, CA_PUBLIC, A_LTELOUT}, {"tportlock", 2, CA_PUBLIC, A_LTPORT}, {"uselock", 1, CA_PUBLIC, A_LUSE}, {"userlock", 4, CA_PUBLIC, A_LUSER}, { NULL, 0, 0, 0} }; static NAMETAB look_sw[] = { {"outside", 1, CA_PUBLIC, LOOK_OUTSIDE}, { NULL, 0, 0, 0} }; static NAMETAB mail_sw[] = { {"abort", 2, CA_PUBLIC, MAIL_ABORT}, {"alias", 4, CA_PUBLIC, MAIL_ALIAS}, {"alist", 4, CA_PUBLIC, MAIL_ALIST}, {"bcc", 1, CA_PUBLIC, MAIL_BCC}, {"cc", 2, CA_PUBLIC, MAIL_CC}, {"clear", 2, CA_PUBLIC, MAIL_CLEAR}, {"debug", 2, CA_PUBLIC, MAIL_DEBUG}, {"dstats", 2, CA_PUBLIC, MAIL_DSTATS}, {"edit", 1, CA_PUBLIC, MAIL_EDIT}, {"file", 2, CA_PUBLIC, MAIL_FILE}, {"folder", 3, CA_PUBLIC, MAIL_FOLDER}, {"forward", 3, CA_PUBLIC, MAIL_FORWARD}, {"fstats", 2, CA_PUBLIC, MAIL_FSTATS}, {"fwd", 2, CA_PUBLIC, MAIL_FORWARD}, {"list", 1, CA_PUBLIC, MAIL_LIST}, {"nuke", 1, CA_PUBLIC, MAIL_NUKE}, {"proof", 2, CA_PUBLIC, MAIL_PROOF}, {"purge", 2, CA_PUBLIC, MAIL_PURGE}, {"quick", 3, CA_PUBLIC, MAIL_QUICK}, {"quote", 3, CA_PUBLIC, MAIL_QUOTE|SW_MULTIPLE}, {"read", 3, CA_PUBLIC, MAIL_READ}, {"reply", 3, CA_PUBLIC, MAIL_REPLY}, {"replyall", 6, CA_PUBLIC, MAIL_REPLYALL}, {"retract", 3, CA_PUBLIC, MAIL_RETRACT}, {"review", 3, CA_PUBLIC, MAIL_REVIEW}, {"safe", 2, CA_PUBLIC, MAIL_SAFE}, {"send", 2, CA_PUBLIC, MAIL_SEND}, {"stats", 2, CA_PUBLIC, MAIL_STATS}, {"tag", 1, CA_PUBLIC, MAIL_TAG}, {"unclear", 3, CA_PUBLIC, MAIL_UNCLEAR}, {"untag", 3, CA_PUBLIC, MAIL_UNTAG}, {"urgent", 2, CA_PUBLIC, MAIL_URGENT}, { NULL, 0, 0, 0} }; static NAMETAB malias_sw[] = { {"add", 1, CA_PUBLIC, MALIAS_ADD}, {"chown", 1, CA_PUBLIC, MALIAS_CHOWN}, {"desc", 1, CA_PUBLIC, MALIAS_DESC}, {"delete", 1, CA_PUBLIC, MALIAS_DELETE}, {"list", 1, CA_PUBLIC, MALIAS_LIST}, {"remove", 1, CA_PUBLIC, MALIAS_REMOVE}, {"rename", 1, CA_PUBLIC, MALIAS_RENAME}, {"status", 1, CA_PUBLIC, MALIAS_STATUS}, { NULL, 0, 0, 0} }; static NAMETAB mark_sw[] = { {"clear", 1, CA_PUBLIC, MARK_CLEAR}, {"set", 1, CA_PUBLIC, MARK_SET}, { NULL, 0, 0, 0} }; static NAMETAB markall_sw[] = { {"clear", 1, CA_PUBLIC, MARK_CLEAR}, {"set", 1, CA_PUBLIC, MARK_SET}, { NULL, 0, 0, 0} }; static NAMETAB motd_sw[] = { {"brief", 1, CA_WIZARD, MOTD_BRIEF|SW_MULTIPLE}, {"connect", 1, CA_WIZARD, MOTD_ALL}, {"down", 1, CA_WIZARD, MOTD_DOWN}, {"full", 1, CA_WIZARD, MOTD_FULL}, {"list", 1, CA_PUBLIC, MOTD_LIST}, {"wizard", 1, CA_WIZARD, MOTD_WIZ}, { NULL, 0, 0, 0} }; static NAMETAB notify_sw[] = { {"all", 1, CA_PUBLIC, NFY_NFYALL}, {"first", 1, CA_PUBLIC, NFY_NFY}, {"quiet", 1, CA_PUBLIC, NFY_QUIET}, { NULL, 0, 0, 0} }; static NAMETAB open_sw[] = { {"inventory", 1, CA_PUBLIC, OPEN_INVENTORY}, {"location", 1, CA_PUBLIC, OPEN_LOCATION}, { NULL, 0, 0, 0} }; static NAMETAB page_sw[] = { {"noeval", 1, CA_PUBLIC, SW_NOEVAL|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB pemit_sw[] = { {"contents", 1, CA_PUBLIC, PEMIT_CONTENTS|SW_MULTIPLE}, {"html", 1, CA_PUBLIC, PEMIT_HTML|SW_MULTIPLE}, {"list", 1, CA_PUBLIC, PEMIT_LIST|SW_MULTIPLE}, {"noeval", 1, CA_PUBLIC, SW_NOEVAL|SW_MULTIPLE}, {"object", 1, CA_PUBLIC, 0}, {"silent", 1, CA_PUBLIC, 0}, { NULL, 0, 0, 0} }; static NAMETAB pose_sw[] = { {"default", 1, CA_PUBLIC, 0}, {"noeval", 3, CA_PUBLIC, SW_NOEVAL|SW_MULTIPLE}, {"nospace", 3, CA_PUBLIC, SAY_NOSPACE}, { NULL, 0, 0, 0} }; static NAMETAB ps_sw[] = { {"all", 1, CA_PUBLIC, PS_ALL|SW_MULTIPLE}, {"brief", 1, CA_PUBLIC, PS_BRIEF}, {"long", 1, CA_PUBLIC, PS_LONG}, {"summary", 1, CA_PUBLIC, PS_SUMM}, { NULL, 0, 0, 0} }; static NAMETAB quota_sw[] = { {"all", 1, CA_GOD, QUOTA_ALL|SW_MULTIPLE}, {"fix", 1, CA_WIZARD, QUOTA_FIX}, {"remaining", 1, CA_WIZARD, QUOTA_REM|SW_MULTIPLE}, {"set", 1, CA_WIZARD, QUOTA_SET}, {"total", 1, CA_WIZARD, QUOTA_TOT|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB say_sw[] = { {"noeval", 1, CA_PUBLIC, SAY_NOEVAL|SW_NOEVAL|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB set_sw[] = { {"quiet", 1, CA_PUBLIC, SET_QUIET}, { NULL, 0, 0, 0} }; static NAMETAB stats_sw[] = { {"all", 1, CA_PUBLIC, STAT_ALL}, {"me", 1, CA_PUBLIC, STAT_ME}, {"player", 1, CA_PUBLIC, STAT_PLAYER}, { NULL, 0, 0, 0} }; static NAMETAB sweep_sw[] = { {"commands", 3, CA_PUBLIC, SWEEP_COMMANDS|SW_MULTIPLE}, {"connected", 3, CA_PUBLIC, SWEEP_CONNECT|SW_MULTIPLE}, {"exits", 1, CA_PUBLIC, SWEEP_EXITS|SW_MULTIPLE}, {"here", 1, CA_PUBLIC, SWEEP_HERE|SW_MULTIPLE}, {"inventory", 1, CA_PUBLIC, SWEEP_ME|SW_MULTIPLE}, {"listeners", 1, CA_PUBLIC, SWEEP_LISTEN|SW_MULTIPLE}, {"players", 1, CA_PUBLIC, SWEEP_PLAYER|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB switch_sw[] = { {"all", 1, CA_PUBLIC, SWITCH_ANY}, {"default", 1, CA_PUBLIC, SWITCH_DEFAULT}, {"first", 1, CA_PUBLIC, SWITCH_ONE}, {"notify", 1, CA_PUBLIC, SWITCH_NOTIFY|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB teleport_sw[] = { {"list", 1, CA_PUBLIC, TELEPORT_LIST|SW_MULTIPLE}, {"loud", 1, CA_PUBLIC, TELEPORT_DEFAULT}, {"quiet", 1, CA_PUBLIC, TELEPORT_QUIET}, { NULL, 0, 0, 0} }; static NAMETAB timecheck_sw[] = { {"log", 1, CA_WIZARD, TIMECHK_LOG | SW_MULTIPLE}, {"reset", 1, CA_WIZARD, TIMECHK_RESET | SW_MULTIPLE}, {"screen", 1, CA_WIZARD, TIMECHK_SCREEN | SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB toad_sw[] = { {"no_chown", 1, CA_WIZARD, TOAD_NO_CHOWN|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB trig_sw[] = { {"quiet", 1, CA_PUBLIC, TRIG_QUIET}, {"notify", 1, CA_PUBLIC, TRIG_NOTIFY|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB wait_sw[] = { {"until", 1, CA_PUBLIC, WAIT_UNTIL}, { NULL, 0, 0, 0} }; static NAMETAB verb_sw[] = { {"no_name", 3, CA_PUBLIC, VERB_NONAME}, { NULL, 0, 0, 0} }; static NAMETAB wall_sw[] = { {"admin", 1, CA_ADMIN, SHOUT_ADMINSHOUT}, {"emit", 1, CA_ANNOUNCE, SHOUT_WALLEMIT}, {"no_prefix", 1, CA_ANNOUNCE, SAY_NOTAG|SW_MULTIPLE}, {"pose", 1, CA_ANNOUNCE, SHOUT_WALLPOSE}, {"wizard", 1, CA_ANNOUNCE, SHOUT_WIZSHOUT|SW_MULTIPLE}, { NULL, 0, 0, 0} }; static NAMETAB warp_sw[] = { {"check", 1, CA_WIZARD, TWARP_CLEAN|SW_MULTIPLE}, {"dump", 1, CA_WIZARD, TWARP_DUMP|SW_MULTIPLE}, {"events", 1, CA_WIZARD, TWARP_EVENTS|SW_MULTIPLE}, {"idle", 1, CA_WIZARD, TWARP_IDLE|SW_MULTIPLE}, {"queue", 1, CA_WIZARD, TWARP_QUEUE|SW_MULTIPLE}, { NULL, 0, 0, 0} }; /* --------------------------------------------------------------------------- * Command table: Definitions for builtin commands, used to build the command * hash table. * * Format: Name Switches Permissions Needed * Key (if any) Calling Seq Handler */ static CMDENT_NO_ARG command_table_no_arg[] = { {"@@", NULL, CA_PUBLIC, 0, CS_NO_ARGS, 0, do_comment}, {"@backup", NULL, CA_WIZARD, 0, CS_NO_ARGS, 0, do_backup}, {"@dbck", dbck_sw, CA_WIZARD, 0, CS_NO_ARGS, 0, do_dbck}, {"@dbclean", NULL, CA_GOD, 0, CS_NO_ARGS, 0, do_dbclean}, {"@dump", dump_sw, CA_WIZARD, 0, CS_NO_ARGS, 0, do_dump}, {"@mark_all", markall_sw, CA_WIZARD, MARK_SET, CS_NO_ARGS, 0, do_markall}, {"@readcache", NULL, CA_WIZARD, 0, CS_NO_ARGS, 0, do_readcache}, {"@restart", NULL, CA_NO_GUEST|CA_NO_SLAVE, 0, CS_NO_ARGS, 0, do_restart}, #ifndef WIN32 {"@startslave", NULL, CA_WIZARD, 0, CS_NO_ARGS, 0, boot_slave}, #endif // !WIN32 {"@timecheck", timecheck_sw, CA_WIZARD, 0, CS_NO_ARGS, 0, do_timecheck}, {"clearcom", NULL, CA_NO_SLAVE, 0, CS_NO_ARGS, 0, do_clearcom}, {"info", NULL, CA_PUBLIC, CMD_INFO, CS_NO_ARGS, 0, logged_out0}, {"inventory", NULL, CA_PUBLIC, 0, CS_NO_ARGS, 0, do_inventory}, {"leave", leave_sw, CA_LOCATION, 0, CS_NO_ARGS, 0, do_leave}, {"logout", NULL, CA_PUBLIC, CMD_LOGOUT, CS_NO_ARGS, 0, logged_out0}, {"quit", NULL, CA_PUBLIC, CMD_QUIT, CS_NO_ARGS, 0, logged_out0}, {"report", NULL, CA_PUBLIC, 0, CS_NO_ARGS, 0, do_report}, {"score", NULL, CA_PUBLIC, 0, CS_NO_ARGS, 0, do_score}, {"version", NULL, CA_PUBLIC, 0, CS_NO_ARGS, 0, do_version}, {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_ONE_ARG command_table_one_arg[] = { {"@boot", boot_sw, CA_NO_GUEST|CA_NO_SLAVE, 0, CS_ONE_ARG|CS_INTERP, 0, do_boot}, {"@break", NULL, CA_PUBLIC, 0, CS_ONE_ARG, 0, do_break}, {"@ccreate", NULL, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_ONE_ARG, 0, do_createchannel}, {"@cdestroy", NULL, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_ONE_ARG, 0, do_destroychannel}, {"@clist", clist_sw, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_chanlist}, {"@cut", NULL, CA_WIZARD|CA_LOCATION, 0, CS_ONE_ARG|CS_INTERP, 0, do_cut}, {"@cwho", NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_channelwho}, {"@destroy", destroy_sw, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, DEST_ONE, CS_ONE_ARG|CS_INTERP, 0, do_destroy}, {"@disable", NULL, CA_WIZARD, GLOB_DISABLE, CS_ONE_ARG, 0, do_global}, {"@doing", doing_sw, CA_PUBLIC, 0, CS_ONE_ARG, 0, do_doing}, {"@emit", emit_sw, CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE, SAY_EMIT, CS_ONE_ARG|CS_INTERP, 0, do_say}, {"@enable", NULL, CA_WIZARD, GLOB_ENABLE, CS_ONE_ARG, 0, do_global}, {"@entrances", NULL, CA_NO_GUEST, 0, CS_ONE_ARG|CS_INTERP, 0, do_entrances}, {"@find", NULL, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_find}, {"@halt", halt_sw, CA_NO_SLAVE, 0, CS_ONE_ARG|CS_INTERP, 0, do_halt}, {"@hook", hook_sw, CA_GOD, 0, CS_ONE_ARG|CS_INTERP, 0, do_hook}, {"@kick", NULL, CA_WIZARD, QUEUE_KICK, CS_ONE_ARG|CS_INTERP, 0, do_queue}, {"@last", NULL, CA_NO_GUEST, 0, CS_ONE_ARG|CS_INTERP, 0, do_last}, {"@list", NULL, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_list}, {"@list_file", NULL, CA_WIZARD, 0, CS_ONE_ARG|CS_INTERP, 0, do_list_file}, {"@listcommands", NULL, CA_GOD, 0, CS_ONE_ARG, 0, do_listcommands}, {"@listmotd", listmotd_sw,CA_PUBLIC, MOTD_LIST, CS_ONE_ARG, 0, do_motd}, {"@mark", mark_sw, CA_WIZARD, SRCH_MARK, CS_ONE_ARG|CS_NOINTERP, 0, do_search}, {"@motd", motd_sw, CA_WIZARD, 0, CS_ONE_ARG, 0, do_motd}, {"@nemit", emit_sw, CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE, SAY_EMIT, CS_ONE_ARG|CS_UNPARSE|CS_NOSQUISH, 0, do_say}, {"@poor", NULL, CA_GOD, 0, CS_ONE_ARG|CS_INTERP, 0, do_poor}, {"@ps", ps_sw, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_ps}, {"@quitprogram", NULL, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_quitprog}, {"@search", NULL, CA_PUBLIC, SRCH_SEARCH, CS_ONE_ARG|CS_NOINTERP, 0, do_search}, {"@shutdown", NULL, CA_NO_GUEST|CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_shutdown}, {"@stats", stats_sw, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_stats}, {"@sweep", sweep_sw, CA_PUBLIC, 0, CS_ONE_ARG, 0, do_sweep}, {"@timewarp", warp_sw, CA_WIZARD, 0, CS_ONE_ARG|CS_INTERP, 0, do_timewarp}, {"@unlink", NULL, CA_NO_SLAVE|CA_GBL_BUILD, 0, CS_ONE_ARG|CS_INTERP, 0, do_unlink}, {"@unlock", lock_sw, CA_NO_SLAVE, 0, CS_ONE_ARG|CS_INTERP, 0, do_unlock}, {"@wall", wall_sw, CA_ANNOUNCE, SHOUT_SHOUT, CS_ONE_ARG|CS_INTERP, 0, do_shout}, {"@wipe", NULL, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0, CS_ONE_ARG|CS_INTERP, 0, do_wipe}, {"allcom", NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_allcom}, {"comlist", NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_comlist}, {"delcom", NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_delcom}, {"doing", NULL, CA_PUBLIC, CMD_DOING, CS_ONE_ARG, 0, logged_out1}, {"drop", drop_sw, CA_NO_SLAVE|CA_CONTENTS|CA_LOCATION|CA_NO_GUEST, 0, CS_ONE_ARG|CS_INTERP, 0, do_drop}, {"enter", enter_sw, CA_LOCATION, 0, CS_ONE_ARG|CS_INTERP, 0, do_enter}, {"examine", examine_sw, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_examine}, {"get", get_sw, CA_LOCATION|CA_NO_GUEST, 0, CS_ONE_ARG|CS_INTERP, 0, do_get}, #if defined(FIRANMUX) {"goto", goto_sw, CA_LOCATION|CA_NO_IMMOBILE, 0, CS_ONE_ARG|CS_INTERP, 0, do_move}, #else {"goto", goto_sw, CA_LOCATION, 0, CS_ONE_ARG|CS_INTERP, 0, do_move}, #endif // FIRANMUX {"look", look_sw, CA_LOCATION, LOOK_LOOK, CS_ONE_ARG|CS_INTERP, 0, do_look}, {"outputprefix", NULL, CA_PUBLIC, CMD_PREFIX, CS_ONE_ARG, 0, logged_out1}, {"outputsuffix", NULL, CA_PUBLIC, CMD_SUFFIX, CS_ONE_ARG, 0, logged_out1}, {"pose", pose_sw, CA_LOCATION|CA_NO_SLAVE, SAY_POSE, CS_ONE_ARG|CS_INTERP, 0, do_say}, {"puebloclient", NULL, CA_PUBLIC, CMD_PUEBLOCLIENT, CS_ONE_ARG, 0, logged_out1}, {"say", say_sw, CA_LOCATION|CA_NO_SLAVE, SAY_SAY, CS_ONE_ARG|CS_INTERP, 0, do_say}, {"session", NULL, CA_PUBLIC, CMD_SESSION, CS_ONE_ARG, 0, logged_out1}, {"think", NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_think}, {"train", NULL, CA_PUBLIC, 0, CS_ONE_ARG, 0, do_train}, {"use", NULL, CA_NO_SLAVE|CA_GBL_INTERP, 0, CS_ONE_ARG|CS_INTERP, 0, do_use}, {"who", NULL, CA_PUBLIC, CMD_WHO, CS_ONE_ARG, 0, logged_out1}, {"\\", NULL, CA_NO_GUEST|CA_LOCATION|CF_DARK|CA_NO_SLAVE, SAY_PREFIX, CS_ONE_ARG|CS_INTERP, 0, do_say}, {":", NULL, CA_LOCATION|CF_DARK|CA_NO_SLAVE, SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, 0, do_say}, {";", NULL, CA_LOCATION|CF_DARK|CA_NO_SLAVE, SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, 0, do_say}, {"\"", NULL, CA_LOCATION|CF_DARK|CA_NO_SLAVE, SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, 0, do_say}, {"-", NULL, CA_NO_GUEST|CA_NO_SLAVE|CF_DARK, 0, CS_ONE_ARG|CS_LEADIN, 0, do_postpend}, {"~", NULL, CA_NO_GUEST|CA_NO_SLAVE|CF_DARK, 0, CS_ONE_ARG|CS_LEADIN, 0, do_prepend}, {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_ONE_ARG_CMDARG command_table_one_arg_cmdarg[] = { {"@apply_marked", NULL, CA_WIZARD|CA_GBL_INTERP, 0, CS_ONE_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_apply_marked}, {"#", NULL, CA_NO_SLAVE|CA_GBL_INTERP|CF_DARK, 0, CS_ONE_ARG|CS_INTERP|CS_CMDARG, 0, do_force_prefixed}, {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG command_table_two_arg[] = { {"@addcommand", NULL, CA_GOD, 0, CS_TWO_ARG, 0, do_addcommand}, {"@admin", NULL, CA_WIZARD, 0, CS_TWO_ARG|CS_INTERP, 0, do_admin}, {"@alias", NULL, CA_NO_GUEST|CA_NO_SLAVE, 0, CS_TWO_ARG, 0, do_alias}, {"@attribute", attrib_sw, CA_GOD, 0, CS_TWO_ARG|CS_INTERP, 0, do_attribute}, {"@cboot", cboot_sw, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_chboot}, {"@ccharge", NULL, CA_NO_SLAVE|CA_NO_GUEST, 1, CS_TWO_ARG, 0, do_editchannel}, {"@cchown", NULL, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_editchannel}, {"@cemit", cemit_sw, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_cemit}, {"@chown", chown_sw, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, CHOWN_ONE, CS_TWO_ARG|CS_INTERP, 0, do_chown}, {"@chownall", chown_sw, CA_WIZARD|CA_GBL_BUILD, CHOWN_ALL, CS_TWO_ARG|CS_INTERP, 0, do_chownall}, {"@chzone", NULL, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0, CS_TWO_ARG|CS_INTERP, 0, do_chzone}, {"@clone", clone_sw, CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_clone}, {"@coflags", NULL, CA_NO_SLAVE, 4, CS_TWO_ARG, 0, do_editchannel}, {"@cpflags", NULL, CA_NO_SLAVE, 3, CS_TWO_ARG, 0, do_editchannel}, {"@create", NULL, CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_create}, {"@cset", cset_sw, CA_NO_SLAVE, 0, CS_TWO_ARG|CS_INTERP, 0, do_chopen}, {"@decompile", decomp_sw, CA_PUBLIC, 0, CS_TWO_ARG|CS_INTERP, 0, do_decomp}, {"@delcommand", NULL, CA_GOD, 0, CS_TWO_ARG, 0, do_delcommand}, {"@drain", NULL, CA_GBL_INTERP|CA_NO_SLAVE|CA_NO_GUEST, NFY_DRAIN, CS_TWO_ARG, 0, do_notify}, {"@femit", femit_sw, CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE, PEMIT_FEMIT, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {"@fixdb", fixdb_sw, CA_GOD, 0, CS_TWO_ARG|CS_INTERP, 0, do_fixdb}, {"@flag", flag_sw, CA_GOD, 0, CS_TWO_ARG, 0, do_flag}, {"@forwardlist", NULL, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_forwardlist}, {"@fpose", fpose_sw, CA_LOCATION|CA_NO_SLAVE, PEMIT_FPOSE, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {"@fsay", NULL, CA_LOCATION|CA_NO_SLAVE, PEMIT_FSAY, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {"@function", function_sw,CA_GOD, 0, CS_TWO_ARG|CS_INTERP, 0, do_function}, {"@link", NULL, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_link}, {"@lock", lock_sw, CA_NO_SLAVE, 0, CS_TWO_ARG|CS_INTERP, 0, do_lock}, {"@log", NULL, CA_WIZARD, 0, CS_TWO_ARG, 0, do_log}, {"@mail", mail_sw, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_mail}, {"@malias", malias_sw, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_malias}, {"@moniker", NULL, CA_NO_GUEST|CA_NO_SLAVE, 0, CS_TWO_ARG|CS_INTERP, 0, do_moniker}, {"@name", NULL, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_name}, {"@newpassword", NULL, CA_WIZARD, 0, CS_TWO_ARG, 0, do_newpassword}, {"@notify", notify_sw, CA_GBL_INTERP|CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_notify}, {"@npemit", pemit_sw, CA_NO_GUEST|CA_NO_SLAVE, PEMIT_PEMIT, CS_TWO_ARG|CS_UNPARSE|CS_NOSQUISH, 0, do_pemit}, {"@oemit", NULL, CA_NO_GUEST|CA_NO_SLAVE, PEMIT_OEMIT, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {"@parent", NULL, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_parent}, {"@password", NULL, CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_password}, {"@pcreate", NULL, CA_WIZARD|CA_GBL_BUILD, PCRE_PLAYER, CS_TWO_ARG, 0, do_pcreate}, {"@pemit", pemit_sw, CA_NO_GUEST|CA_NO_SLAVE, PEMIT_PEMIT, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {"@power", NULL, CA_PUBLIC, 0, CS_TWO_ARG, 0, do_power}, {"@program", NULL, CA_PUBLIC, 0, CS_TWO_ARG|CS_INTERP, 0, do_prog}, {"@quota", quota_sw, CA_PUBLIC, 0, CS_TWO_ARG|CS_INTERP, 0, do_quota}, {"@robot", NULL, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST|CA_PLAYER, PCRE_ROBOT, CS_TWO_ARG, 0, do_pcreate}, #ifdef REALITY_LVLS {"@rxlevel", NULL, CA_WIZARD, 0, CS_TWO_ARG|CS_INTERP, 0, do_rxlevel}, #endif {"@set", set_sw, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_set}, {"@teleport", teleport_sw,CA_NO_GUEST, TELEPORT_DEFAULT, CS_TWO_ARG|CS_INTERP, 0, do_teleport}, #ifdef REALITY_LVLS {"@txlevel", NULL, CA_WIZARD, 0, CS_TWO_ARG|CS_INTERP, 0, do_txlevel}, #endif {"@toad", toad_sw, CA_WIZARD, 0, CS_TWO_ARG|CS_INTERP, 0, do_toad}, {"@email", NULL, CA_WIZARD, 0, CS_TWO_ARG, 0, do_plusemail}, {"addcom", NULL, CA_NO_SLAVE, 0, CS_TWO_ARG, 0, do_addcom}, {"comtitle", comtitle_sw,CA_NO_SLAVE, 0, CS_TWO_ARG, 0, do_comtitle}, {"give", give_sw, CA_LOCATION|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_give}, {"kill", NULL, CA_NO_GUEST|CA_NO_SLAVE, KILL_KILL, CS_TWO_ARG|CS_INTERP, 0, do_kill}, {"page", page_sw, CA_NO_SLAVE, 0, CS_TWO_ARG|CS_INTERP, 0, do_page}, {"slay", NULL, CA_WIZARD, KILL_SLAY, CS_TWO_ARG|CS_INTERP, 0, do_kill}, {"whisper", NULL, CA_LOCATION|CA_NO_SLAVE, PEMIT_WHISPER, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {"&", NULL, CA_NO_GUEST|CA_NO_SLAVE|CF_DARK, 0, CS_TWO_ARG|CS_LEADIN, 0, do_setvattr}, {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG_ARGV command_table_two_arg_argv[] = { {"@cpattr", NULL, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0, CS_TWO_ARG|CS_ARGV, 0, do_cpattr}, {"@dig", dig_sw, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0, CS_TWO_ARG|CS_ARGV|CS_INTERP, 0, do_dig}, {"@edit", NULL, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG|CS_ARGV|CS_STRIP_AROUND, 0, do_edit}, {"@icmd", icmd_sw, CA_GOD, 0, CS_TWO_ARG|CS_ARGV|CS_INTERP, 0, do_icmd}, {"@mvattr", NULL, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0, CS_TWO_ARG|CS_ARGV, 0, do_mvattr}, {"@open", open_sw, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST, 0, CS_TWO_ARG|CS_ARGV|CS_INTERP, 0, do_open}, {"@trigger", trig_sw, CA_GBL_INTERP, 0, CS_TWO_ARG|CS_ARGV, 0, do_trigger}, {"@verb", verb_sw, CA_GBL_INTERP|CA_NO_SLAVE, 0, CS_TWO_ARG|CS_ARGV|CS_INTERP|CS_STRIP_AROUND, 0, do_verb}, {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG_CMDARG command_table_two_arg_cmdarg[] = { {"@dolist", dolist_sw, CA_GBL_INTERP, 0, CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_dolist}, {"@force", NULL, CA_NO_SLAVE|CA_GBL_INTERP|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP|CS_CMDARG, 0, do_force}, #ifdef QUERY_SLAVE {"@query", query_sw, CA_WIZARD, 0, CS_TWO_ARG|CS_INTERP|CS_CMDARG, 0, do_query}, #endif {"@wait", wait_sw, CA_GBL_INTERP, 0, CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_wait}, {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG_ARGV_CMDARG command_table_two_arg_argv_cmdarg[] = { {"@if", NULL, CA_GBL_INTERP, 0, CS_TWO_ARG|CS_ARGV|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_if}, {"@switch", switch_sw, CA_GBL_INTERP, 0, CS_TWO_ARG|CS_ARGV|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_switch}, {NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT *prefix_cmds[256]; static CMDENT *goto_cmdp; void commands_no_arg_add(CMDENT_NO_ARG cmdent[]) { CMDENT_NO_ARG *cp0a; for (cp0a = cmdent; cp0a->cmdname; cp0a++) { if (!hashfindLEN(cp0a->cmdname, strlen(cp0a->cmdname), &mudstate.command_htab)) { hashaddLEN(cp0a->cmdname, strlen(cp0a->cmdname), cp0a, &mudstate.command_htab); } } } void commands_one_arg_add(CMDENT_ONE_ARG cmdent[]) { CMDENT_ONE_ARG *cp1a; for (cp1a = cmdent; cp1a->cmdname; cp1a++) { if (!hashfindLEN(cp1a->cmdname, strlen(cp1a->cmdname), &mudstate.command_htab)) { hashaddLEN(cp1a->cmdname, strlen(cp1a->cmdname), cp1a, &mudstate.command_htab); } } } void commands_one_arg_cmdarg_add(CMDENT_ONE_ARG_CMDARG cmdent[]) { CMDENT_ONE_ARG_CMDARG *cp1ac; for (cp1ac = cmdent; cp1ac->cmdname; cp1ac++) { if (!hashfindLEN(cp1ac->cmdname, strlen(cp1ac->cmdname), &mudstate.command_htab)) { hashaddLEN(cp1ac->cmdname, strlen(cp1ac->cmdname), cp1ac, &mudstate.command_htab); } } } void commands_two_arg_add(CMDENT_TWO_ARG cmdent[]) { CMDENT_TWO_ARG *cp2a; for (cp2a = cmdent; cp2a->cmdname; cp2a++) { if (!hashfindLEN(cp2a->cmdname, strlen(cp2a->cmdname), &mudstate.command_htab)) { hashaddLEN(cp2a->cmdname, strlen(cp2a->cmdname), cp2a, &mudstate.command_htab); } } } void commands_two_arg_argv_add(CMDENT_TWO_ARG_ARGV cmdent[]) { CMDENT_TWO_ARG_ARGV *cp2aa; for (cp2aa = cmdent; cp2aa->cmdname; cp2aa++) { if (!hashfindLEN(cp2aa->cmdname, strlen(cp2aa->cmdname), &mudstate.command_htab)) { hashaddLEN(cp2aa->cmdname, strlen(cp2aa->cmdname), cp2aa, &mudstate.command_htab); } } } void commands_two_arg_cmdarg_add(CMDENT_TWO_ARG_CMDARG cmdent[]) { CMDENT_TWO_ARG_CMDARG *cp2ac; for (cp2ac = cmdent; cp2ac->cmdname; cp2ac++) { if (!hashfindLEN(cp2ac->cmdname, strlen(cp2ac->cmdname), &mudstate.command_htab)) { hashaddLEN(cp2ac->cmdname, strlen(cp2ac->cmdname), cp2ac, &mudstate.command_htab); } } } void commands_two_arg_argv_cmdarg_add(CMDENT_TWO_ARG_ARGV_CMDARG cmdent[]) { CMDENT_TWO_ARG_ARGV_CMDARG *cp2aac; for (cp2aac = cmdent; cp2aac->cmdname; cp2aac++) { if (!hashfindLEN(cp2aac->cmdname, strlen(cp2aac->cmdname), &mudstate.command_htab)) { hashaddLEN(cp2aac->cmdname, strlen(cp2aac->cmdname), cp2aac, &mudstate.command_htab); } } } void init_cmdtab(void) { ATTR *ap; // Load attribute-setting commands. // for (ap = AttrTable; ap->name; ap++) { if (ap->flags & AF_NOCMD) { continue; } size_t nBuffer; bool bValid; char *cbuff = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid); if (!bValid) { continue; } CMDENT_TWO_ARG *cp2a = NULL; try { cp2a = new CMDENT_TWO_ARG; } catch (...) { ; // Nothing. } if (NULL != cp2a) { cp2a->cmdname = StringClone(cbuff); cp2a->perms = CA_NO_GUEST | CA_NO_SLAVE; cp2a->switches = NULL; if (ap->flags & (AF_WIZARD | AF_MDARK)) { cp2a->perms |= CA_WIZARD; } cp2a->extra = ap->number; cp2a->callseq = CS_TWO_ARG; cp2a->hookmask = 0; cp2a->handler = do_setattr; hashaddLEN(cp2a->cmdname, nBuffer, cp2a, &mudstate.command_htab); } else { ISOUTOFMEMORY(cp2a); } } // Load the builtin commands // commands_no_arg_add(command_table_no_arg); commands_one_arg_add(command_table_one_arg); commands_one_arg_cmdarg_add(command_table_one_arg_cmdarg); commands_two_arg_add(command_table_two_arg); commands_two_arg_argv_add(command_table_two_arg_argv); commands_two_arg_cmdarg_add(command_table_two_arg_cmdarg); commands_two_arg_argv_cmdarg_add(command_table_two_arg_argv_cmdarg); set_prefix_cmds(); goto_cmdp = (CMDENT *) hashfindLEN((char *)"goto", strlen("goto"), &mudstate.command_htab); } /*! \brief Fills in the table of single-character prefix commands. * * Command entries for known prefix commands (" : ; \ # & - ~) * are copied from the regular command table. Entries for all other starting * characters are set to \c NULL. * * \return None. */ void set_prefix_cmds() { for (int i = 0; i < 256; i++) { prefix_cmds[i] = NULL; } #define SET_PREFIX_CMD(s) prefix_cmds[(unsigned char)(s)[0]] = \ (CMDENT *) hashfindLEN((char *)(s), 1, &mudstate.command_htab) SET_PREFIX_CMD("\""); SET_PREFIX_CMD(":"); SET_PREFIX_CMD(";"); SET_PREFIX_CMD("\\"); SET_PREFIX_CMD("#"); SET_PREFIX_CMD("&"); SET_PREFIX_CMD("-"); SET_PREFIX_CMD("~"); #undef SET_PREFIX_CMD } // --------------------------------------------------------------------------- // check_access: Check if player has access to function. // bool check_access(dbref player, int mask) { if (mask & (CA_DISABLED|CA_STATIC)) { return false; } if ( God(player) || mudstate.bReadingConfiguration) { return true; } if (mask & CA_MUSTBE_MASK) { // Since CA_GOD by itself is a frequent case, for the sake of // performance, we test CA_GOD specifically. If CA_GOD were ever // combined with anything, it would be passed through to the general // case. // if ((mask & CA_MUSTBE_MASK) == CA_GOD) { return false; } // Since God(player) is always false here, CA_GOD is still handled by // the following code even though it doesn't appear in any of the // cases explicitly. CA_WIZARD by itself is also a common case, but // since we have have a bit (mask & CA_MUSTBE_MASK), and since that // bit is not a lone CA_GOD bit (handled above), and since CA_WIZARD // it tested first below, it doesn't make sense to test CA_WIZARD // as a special case. // if (!( ((mask & CA_WIZARD) && Wizard(player)) || ((mask & CA_ADMIN) && WizRoy(player)) || ((mask & CA_BUILDER) && Builder(player)) || ((mask & CA_STAFF) && Staff(player)) || ((mask & CA_HEAD) && Head(player)) || ((mask & CA_ANNOUNCE) && Announce(player)) || ((mask & CA_IMMORTAL) && Immortal(player)) || ((mask & CA_UNINS) && Uninspected(player)) || ((mask & CA_ROBOT) && Robot(player)))) { return false; } } // Check for forbidden flags. // if ( (mask & CA_CANTBE_MASK) && !Wizard(player)) { if ( ((mask & CA_NO_HAVEN) && Player_haven(player)) || ((mask & CA_NO_ROBOT) && Robot(player)) || ((mask & CA_NO_SLAVE) && Slave(player)) || ((mask & CA_NO_SUSPECT) && Suspect(player)) || ((mask & CA_NO_GUEST) && Guest(player)) #if defined(FIRANMUX) // || ((mask & CA_NO_IMMOBILE) && Immobile(player)) || ((mask & CA_NO_RESTRICTED) && Restricted(player)) #endif // FIRANMUX || ((mask & CA_NO_UNINS) && Uninspected(player))) { return false; } } return true; } /***************************************************************************** * Process the various hook calls. * Idea taken from TinyMUSH3, code from RhostMUSH, ported by Jake Nelson. * Hooks processed: before, after, ignore, permit, fail *****************************************************************************/ static bool process_hook(dbref executor, dbref thing, char *s_uselock, ATTR *hk_attr, bool save_flg) { UNUSED_PARAMETER(s_uselock); bool retval = true; if (hk_attr) { dbref aowner; int aflags; int anum = hk_attr->number; char *atext = atr_get(thing, anum, &aowner, &aflags); if (atext[0] && !(aflags & AF_NOPROG)) { reg_ref **preserve = NULL; if (save_flg) { preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); } char *buff, *bufc; bufc = buff = alloc_lbuf("process_hook"); char *str = atext; mux_exec(buff, &bufc, thing, executor, executor, AttrTrace(aflags, EV_FCHECK|EV_EVAL), &str, NULL, 0); *bufc = '\0'; if (save_flg) { restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); } retval = xlate(buff); free_lbuf(buff); } free_lbuf(atext); } return retval; } static char *hook_name(char *pCommand, int key) { const char *keylet; switch (key) { case HOOK_AFAIL: keylet = "AF"; break; case HOOK_AFTER: keylet = "A"; break; case HOOK_BEFORE: keylet = "B"; break; case HOOK_IGNORE: keylet = "I"; break; case HOOK_PERMIT: keylet = "P"; break; default: return NULL; } const char *cmdName = pCommand; if ( pCommand[0] && !pCommand[1]) { switch (pCommand[0]) { case '"' : cmdName = "say"; break; case ':' : case ';' : cmdName = "pose"; break; case '\\': cmdName = "@emit"; break; case '#' : cmdName = "@force"; break; case '&' : cmdName = "@set"; break; case '-' : cmdName = "@mail"; break; case '~' : cmdName = "@mail"; break; } } char *s_uselock = alloc_sbuf("command_hook.hookname"); mux_sprintf(s_uselock, SBUF_SIZE, "%s_%s", keylet, cmdName); return s_uselock; } /* --------------------------------------------------------------------------- * process_cmdent: Perform indicated command with passed args. */ static void process_cmdent(CMDENT *cmdp, char *switchp, dbref executor, dbref caller, dbref enactor, int eval, bool interactive, char *arg, char *unp_command, char *cargs[], int ncargs) { // Perform object type checks. // if (Invalid_Objtype(executor)) { notify(executor, "Command incompatible with executor type."); return; } // Check if we have permission to execute the command. // if (!check_access(executor, cmdp->perms)) { notify(executor, NOPERM_MESSAGE); return; } // Check global flags // if ( !Builder(executor) && Protect(CA_GBL_BUILD) && !(mudconf.control_flags & CF_BUILD)) { notify(executor, "Sorry, building is not allowed now."); return; } if (Protect(CA_GBL_INTERP) && !(mudconf.control_flags & CF_INTERP)) { notify(executor, "Sorry, queueing and triggering are not allowed now."); return; } char *buf1, *buf2, tchar, *bp, *str, *buff, *j, *new0, *s_uselock; char *args[MAX_ARG]; int nargs, i, interp, key, xkey, aflags; dbref aowner; char *aargs[NUM_ENV_VARS]; ADDENT *add; ATTR *hk_ap2; key = cmdp->extra & ~SW_MULTIPLE; if (key & SW_GOT_UNIQUE) { i = 1; key = key & ~SW_GOT_UNIQUE; } else { i = 0; } // Check command switches. Note that there may be more than one, // and that we OR all of them together along with the extra value // from the command table to produce the key value in the handler // call. // if (switchp && cmdp->switches) { do { buf1 = strchr(switchp, '/'); if (buf1) { *buf1++ = '\0'; } if (!search_nametab(executor, cmdp->switches, switchp, &xkey)) { if (xkey == -1) { notify(executor, tprintf("Unrecognized switch '%s' for command '%s'.", switchp, cmdp->cmdname)); return; } else if (xkey == -2) { notify(executor, NOPERM_MESSAGE); return; } } else if (!(xkey & SW_MULTIPLE)) { if (i == 1) { notify(executor, "Illegal combination of switches."); return; } i = 1; } else { xkey &= ~SW_MULTIPLE; } key |= xkey; switchp = buf1; } while (buf1); } else if (switchp && !(cmdp->callseq & CS_ADDED)) { notify(executor, tprintf("Command %s does not take switches.", cmdp->cmdname)); return; } // 'Before' hooks. // @hook idea from TinyMUSH 3, code from RhostMUSH. Ported by Jake Nelson. // if ( (cmdp->hookmask & HOOK_BEFORE) && Good_obj(mudconf.hook_obj) && !Going(mudconf.hook_obj)) { s_uselock = hook_name(cmdp->cmdname, HOOK_BEFORE); hk_ap2 = atr_str(s_uselock); process_hook(executor, mudconf.hook_obj, s_uselock, hk_ap2, false); free_sbuf(s_uselock); } // We are allowed to run the command. Now, call the handler using // the appropriate calling sequence and arguments. // //if ((cmdp->callseq & CS_INTERP) && (key & SW_NOEVAL)) if (key & SW_NOEVAL) { // The user specified /noeval on a @pemit or a @npemit, // just do EV_STRIP_CURLY and remove the SW_NOEVAL from the // 'key'. // interp = 0; key &= ~SW_NOEVAL; } else if ( (cmdp->callseq & CS_INTERP) || !( interactive || (cmdp->callseq & CS_NOINTERP))) { // If the command is interpreted, or we're interactive (and // the command isn't specified CS_NOINTERP), eval the args. // interp = EV_EVAL | EV_STRIP_CURLY; } else if (cmdp->callseq & CS_STRIP) { interp = EV_STRIP_CURLY; } else if (cmdp->callseq & CS_STRIP_AROUND) { interp = EV_STRIP_AROUND; } else { interp = 0; } int nargs2; switch (cmdp->callseq & CS_NARG_MASK) { case CS_NO_ARGS: // (no args) (*(((CMDENT_NO_ARG *)cmdp)->handler))(executor, caller, enactor, key); break; case CS_ONE_ARG: // // If an unparsed command, just give it to the handler // #if 0 // This never happens. // if (cmdp->callseq & CS_UNPARSE) { (*(((CMDENT_ONE_ARG *)cmdp)->handler))(executor, unp_command); break; } #endif // Interpret if necessary, but not twice for CS_ADDED. // if ((interp & EV_EVAL) && !(cmdp->callseq & CS_ADDED)) { buf1 = bp = alloc_lbuf("process_cmdent"); str = arg; mux_exec(buf1, &bp, executor, caller, enactor, eval|interp|EV_FCHECK|EV_TOP, &str, cargs, ncargs); *bp = '\0'; } else { buf1 = parse_to(&arg, '\0', interp | EV_TOP); } // Call the correct handler. // if (cmdp->callseq & CS_CMDARG) { (*(((CMDENT_ONE_ARG_CMDARG *)cmdp)->handler))(executor, caller, enactor, eval, key, buf1, cargs, ncargs); } else if (cmdp->callseq & CS_ADDED) { for (add = cmdp->addent; add != NULL; add = add->next) { buff = atr_get(add->thing, add->atr, &aowner, &aflags); // Attribute should contain at least two characters and first // character is '$'. // if ( AMATCH_CMD != buff[0] || '\0' == buff[1]) { free_lbuf(buff); break; } // Skip the '$' character and the next to allow "$::cmd". // size_t iBuff; for (iBuff = 2; '\0' != buff[iBuff] && ':' != buff[iBuff]; iBuff++) { ; // Nothing. } if ('\0' == buff[iBuff]) { free_lbuf(buff); break; } buff[iBuff++] = '\0'; if (!(cmdp->callseq & CS_LEADIN)) { for (j = unp_command; *j && (*j != ' '); j++) ; } else { for (j = unp_command; *j; j++) ; } new0 = alloc_lbuf("process_cmdent.soft"); bp = new0; if (!*j) { // No args. // if (!(cmdp->callseq & CS_LEADIN)) { safe_str(cmdp->cmdname, new0, &bp); } else { safe_str(unp_command, new0, &bp); } if (switchp) { safe_chr('/', new0, &bp); safe_str(switchp, new0, &bp); } *bp = '\0'; } else { j++; safe_str(cmdp->cmdname, new0, &bp); if (switchp) { safe_chr('/', new0, &bp); safe_str(switchp, new0, &bp); } safe_chr(' ', new0, &bp); safe_str(j, new0, &bp); *bp = '\0'; } if ( ( (aflags & AF_REGEXP) && regexp_match(buff + 1, new0, ((aflags & AF_CASE) ? 0 : PCRE_CASELESS), aargs, NUM_ENV_VARS)) || ( (aflags & AF_REGEXP) == 0 && wild(buff + 1, new0, aargs, NUM_ENV_VARS))) { CLinearTimeAbsolute lta; wait_que(add->thing, caller, executor, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buff + iBuff, NUM_ENV_VARS, aargs, mudstate.global_regs); for (i = 0; i < NUM_ENV_VARS; i++) { if (aargs[i]) { free_lbuf(aargs[i]); } } } free_lbuf(new0); free_lbuf(buff); } } else { (*(((CMDENT_ONE_ARG *)cmdp)->handler))(executor, caller, enactor, eval, key, buf1); } // Free the buffer if one was allocated. // if ((interp & EV_EVAL) && !(cmdp->callseq & CS_ADDED)) { free_lbuf(buf1); } break; case CS_TWO_ARG: // = // Interpret ARG1 // buf2 = parse_to(&arg, '=', EV_STRIP_TS); nargs2 = 0; if (buf2) { if (arg) { nargs2 = 2; } else { nargs2 = 1; } } // Handle when no '=' was specified. // if (!arg || (arg && !*arg)) { arg = &tchar; *arg = '\0'; } buf1 = bp = alloc_lbuf("process_cmdent.2"); str = buf2; mux_exec(buf1, &bp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL|EV_TOP, &str, cargs, ncargs); *bp = '\0'; if (cmdp->callseq & CS_ARGV) { // Arg2 is ARGV style. Go get the args. // parse_arglist(executor, caller, enactor, arg, '\0', eval|interp|EV_STRIP_LS|EV_STRIP_TS, args, MAX_ARG, cargs, ncargs, &nargs); // Call the correct command handler. // if (cmdp->callseq & CS_CMDARG) { (*(((CMDENT_TWO_ARG_ARGV_CMDARG *)cmdp)->handler))(executor, caller, enactor, eval, key, buf1, args, nargs, cargs, ncargs); } else { (*(((CMDENT_TWO_ARG_ARGV *)cmdp)->handler))(executor, caller, enactor, eval, key, buf1, args, nargs); } // Free the argument buffers. // for (i = 0; i < nargs; i++) { free_lbuf(args[i]); } } else { // Arg2 is normal style. Interpret if needed. // if (interp & EV_EVAL) { buf2 = bp = alloc_lbuf("process_cmdent.3"); str = arg; mux_exec(buf2, &bp, executor, caller, enactor, eval|interp|EV_FCHECK|EV_TOP, &str, cargs, ncargs); *bp = '\0'; } else if (cmdp->callseq & CS_UNPARSE) { buf2 = parse_to(&arg, '\0', eval|interp|EV_TOP|EV_NO_COMPRESS); } else { buf2 = parse_to(&arg, '\0', eval|interp|EV_STRIP_LS|EV_STRIP_TS|EV_TOP); } // Call the correct command handler. // if (cmdp->callseq & CS_CMDARG) { (*(((CMDENT_TWO_ARG_CMDARG *)cmdp)->handler))(executor, caller, enactor, eval, key, buf1, buf2, cargs, ncargs); } else { (*(((CMDENT_TWO_ARG *)cmdp)->handler))(executor, caller, enactor, key, nargs2, buf1, buf2); } // Free the buffer, if needed. // if (interp & EV_EVAL) { free_lbuf(buf2); } } // Free the buffer obtained by evaluating Arg1. // free_lbuf(buf1); break; } // 'After' hooks. // @hook idea from TinyMUSH 3, code from RhostMUSH. Ported by Jake Nelson. // if ( (cmdp->hookmask & HOOK_AFTER) && Good_obj(mudconf.hook_obj) && !Going(mudconf.hook_obj)) { s_uselock = hook_name(cmdp->cmdname, HOOK_AFTER); hk_ap2 = atr_str(s_uselock); (void)process_hook(executor, mudconf.hook_obj, s_uselock, hk_ap2, false); free_sbuf(s_uselock); } return; } static int cmdtest(dbref player, const char *cmd) { char *buff1, *pt1, *pt2; dbref aowner; int aflags, rval; rval = 0; buff1 = atr_get(player, A_CMDCHECK, &aowner, &aflags); pt1 = buff1; while (pt1 && *pt1) { pt2 = strchr(pt1, ':'); if (!pt2 || (pt2 == pt1)) break; if (!strncmp(pt2+1, cmd, strlen(cmd))) { if (*(pt2-1) == '1') rval = 1; else rval = 2; break; } pt1 = strchr(pt2+1,' '); if (pt1 && *pt1) { while (mux_isspace(*pt1)) { pt1++; } } } free_lbuf(buff1); return rval; } static int zonecmdtest(dbref player, const char *cmd) { if (!Good_obj(player) || God(player)) { return 0; } dbref loc = Location(player); int i_ret = 0; if (Good_obj(loc)) { i_ret = cmdtest(loc, cmd); if (i_ret == 0) { dbref zone = Zone(loc); if ( Good_obj(zone) && ( isRoom(zone) || isThing(zone))) { i_ret = cmdtest(zone, cmd); } } } return i_ret; } static int higcheck(dbref executor, dbref caller, dbref enactor, CMDENT *cmdp, const char *pCommand) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(pCommand); if ( Good_obj(mudconf.hook_obj) && !Going(mudconf.hook_obj)) { char *s_uselock; ATTR *checkattr; bool bResult; if (cmdp->hookmask & HOOK_IGNORE) { s_uselock = hook_name(cmdp->cmdname, HOOK_IGNORE); checkattr = atr_str(s_uselock); bResult = process_hook(executor, mudconf.hook_obj, s_uselock, checkattr, true); free_sbuf(s_uselock); if (!bResult) { return 2; } } if (cmdp->hookmask & HOOK_PERMIT) { s_uselock = hook_name(cmdp->cmdname, HOOK_PERMIT); checkattr = atr_str(s_uselock); bResult = process_hook(executor, mudconf.hook_obj, s_uselock, checkattr, true); free_sbuf(s_uselock); if (!bResult) { return 1; } } } return 0; } static void hook_fail(dbref executor, CMDENT *cmdp, const char *pCommand) { UNUSED_PARAMETER(pCommand); if ( Good_obj(mudconf.hook_obj) && !Going(mudconf.hook_obj)) { char *s_uselock = hook_name(cmdp->cmdname, HOOK_AFAIL); ATTR *hk_ap2 = atr_str(s_uselock); process_hook(executor, mudconf.hook_obj, s_uselock, hk_ap2, false); free_sbuf(s_uselock); } } // --------------------------------------------------------------------------- // process_command: Execute a command. // char *process_command ( dbref executor, dbref caller, dbref enactor, int eval, bool interactive, char *arg_command, char *args[], int nargs ) { static char preserve_cmd[LBUF_SIZE]; char *pOriginalCommand = arg_command; static char SpaceCompressCommand[LBUF_SIZE]; static char LowerCaseCommand[LBUF_SIZE]; char *pCommand; char *p, *q, *arg, *pSlash, *bp, *str, check2[2]; const char *cmdsave; int aflags, i; dbref exit, aowner; CMDENT *cmdp; // Robustify player. // cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< process_command >"; mudstate.nStackNest = 0; mudstate.bStackLimitReached = false; *(check2 + 1) = '\0'; mux_assert(pOriginalCommand); if (!Good_obj(executor)) { // We are using SpaceCompressCommand temporarily. // STARTLOG(LOG_BUGS, "CMD", "PLYR"); mux_sprintf(SpaceCompressCommand, sizeof(SpaceCompressCommand), "Bad player in process_command: %d", executor); log_text(SpaceCompressCommand); ENDLOG; mudstate.debug_cmd = cmdsave; return pOriginalCommand; } // Make sure player isn't going or halted. // if ( Going(executor) || ( Halted(executor) && !( isPlayer(executor) && interactive))) { notify(Owner(executor), tprintf("Attempt to execute command by halted object #%d", executor)); mudstate.debug_cmd = cmdsave; return pOriginalCommand; } if ( Suspect(executor) && (mudconf.log_options & LOG_SUSPECTCMDS)) { STARTLOG(LOG_SUSPECTCMDS, "CMD", "SUSP"); log_name_and_loc(executor); log_text(" entered: "); log_text(pOriginalCommand); ENDLOG; } else { STARTLOG(LOG_ALLCOMMANDS, "CMD", "ALL"); log_name_and_loc(executor); log_text(" entered: "); log_text(pOriginalCommand); ENDLOG; } // Reset recursion limits. // mudstate.func_nest_lev = 0; mudstate.func_invk_ctr = 0; mudstate.ntfy_nest_lev = 0; mudstate.lock_nest_lev = 0; if (Verbose(executor)) { notify(Owner(executor), tprintf("%s] %s", Name(executor), pOriginalCommand)); } // Eat leading whitespace, and space-compress if configured. // while (mux_isspace(*pOriginalCommand)) { pOriginalCommand++; } mux_strncpy(preserve_cmd, pOriginalCommand, LBUF_SIZE-1); mudstate.debug_cmd = pOriginalCommand; mudstate.curr_cmd = preserve_cmd; if (mudconf.space_compress) { // Compress out the spaces and use that as the command // pCommand = SpaceCompressCommand; p = pOriginalCommand; q = SpaceCompressCommand; while ( *p && q < SpaceCompressCommand + LBUF_SIZE) { while ( *p && !mux_isspace(*p) && q < SpaceCompressCommand + LBUF_SIZE) { *q++ = *p++; } while (mux_isspace(*p)) { p++; } if ( *p && q < SpaceCompressCommand + LBUF_SIZE) { *q++ = ' '; } } *q = '\0'; } else { // Don't compress the spaces. Use the original command // (without leading spaces) as the command to use. // pCommand = pOriginalCommand; } // Now comes the fun stuff. First check for single-letter leadins. // We check these before checking HOME because they are among the // most frequently executed commands, and they can never be the // HOME command. // i = pCommand[0] & 0xff; int cval = 0; int hval = 0; if (i && (prefix_cmds[i] != NULL)) { // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore // *check2 = (char)i; if (CmdCheck(executor)) { cval = cmdtest(executor, check2); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), check2); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, check2); } if (prefix_cmds[i]->hookmask & (HOOK_IGNORE|HOOK_PERMIT)) { hval = higcheck(executor, caller, enactor, prefix_cmds[i], pCommand); } else { hval = 0; } if ( cval != 2 && hval != 2) { if ( cval == 1 || hval == 1) { if (prefix_cmds[i]->hookmask & HOOK_AFAIL) { hook_fail(executor, prefix_cmds[i], pCommand); } else { notify(executor, NOPERM_MESSAGE); } mudstate.debug_cmd = cmdsave; return preserve_cmd; } process_cmdent(prefix_cmds[i], NULL, executor, caller, enactor, eval, interactive, pCommand, pCommand, args, nargs); if (mudstate.bStackLimitReached) { STARTLOG(LOG_ALWAYS, "CMD", "SPAM"); log_name_and_loc(executor); log_text(" entered: "); log_text(pOriginalCommand); ENDLOG; } mudstate.bStackLimitReached = false; mudstate.debug_cmd = cmdsave; return preserve_cmd; } } if ( mudconf.have_comsys && !Slave(executor) && !do_comsystem(executor, pCommand)) { mudstate.debug_cmd = cmdsave; return preserve_cmd; } // Check for the HOME command. // if ( Has_location(executor) && string_compare(pCommand, "home") == 0) { // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore. // if (CmdCheck(executor)) { cval = cmdtest(executor, "home"); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), "home"); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, "home"); } if (cval != 2) { if (!check_access(executor, mudconf.restrict_home)) { notify(executor, NOPERM_MESSAGE); mudstate.debug_cmd = cmdsave; return preserve_cmd; } if (cval == 1) { notify(executor, NOPERM_MESSAGE); mudstate.debug_cmd = cmdsave; return preserve_cmd; } if ( ( Fixed(executor) || Fixed(Owner(executor))) && !WizRoy(executor)) { notify(executor, mudconf.fixed_home_msg); mudstate.debug_cmd = cmdsave; return preserve_cmd; } do_move(executor, caller, enactor, eval, 0, (char *)"home"); mudstate.debug_cmd = cmdsave; return preserve_cmd; } } // Only check for exits if we may use the goto command. // if (check_access(executor, goto_cmdp->perms)) { // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore // Master room exits are not affected. // if (CmdCheck(executor)) { cval = cmdtest(executor, "goto"); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), "goto"); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, "goto"); } if (goto_cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT)) { hval = higcheck(executor, caller, enactor, goto_cmdp, "goto"); } else { hval = 0; } if ( cval != 2 && hval != 2) { // Check for an exit name. // init_match_check_keys(executor, pCommand, TYPE_EXIT); match_exit_with_parents(); exit = last_match_result(); if (exit != NOTHING) { if (cval || hval) { if (goto_cmdp->hookmask & HOOK_AFAIL) { hook_fail(executor, goto_cmdp, "goto"); } else { notify(executor, NOPERM_MESSAGE); } mudstate.debug_cmd = cmdsave; return preserve_cmd; } move_exit(executor, exit, false, "You can't go that way.", 0); mudstate.debug_cmd = cmdsave; return preserve_cmd; } // Check for an exit in the master room. // init_match_check_keys(executor, pCommand, TYPE_EXIT); match_master_exit(); exit = last_match_result(); if (exit != NOTHING) { move_exit(executor, exit, true, NULL, 0); mudstate.debug_cmd = cmdsave; return preserve_cmd; } } } // Set up a lowercase command and an arg pointer for the hashed // command check. Since some types of argument processing destroy // the arguments, make a copy so that we keep the original command // line intact. Store the edible copy in LowerCaseCommand after // the lower-cased command. // // Make lowercase command // char *LowerCaseCommandEnd = LowerCaseCommand + (LBUF_SIZE - 1); for (p = pCommand, q = LowerCaseCommand; *p && !mux_isspace(*p) && q < LowerCaseCommandEnd; p++, q++) { *q = mux_tolower(*p); } *q = '\0'; size_t nLowerCaseCommand = q - LowerCaseCommand; // Skip spaces before arg // while (mux_isspace(*p)) { p++; } // Remember where arg starts // arg = p; // Strip off any command switches and save them. // pSlash = strchr(LowerCaseCommand, '/'); if (pSlash) { nLowerCaseCommand = pSlash - LowerCaseCommand; *pSlash++ = '\0'; } // Check for a builtin command (or an alias of a builtin command) // cmdp = (CMDENT *)hashfindLEN(LowerCaseCommand, nLowerCaseCommand, &mudstate.command_htab); /* If command is checked to ignore NONMATCHING switches, fall through */ if (cmdp) { // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore // if (CmdCheck(executor)) { cval = cmdtest(executor, cmdp->cmdname); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), cmdp->cmdname); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, cmdp->cmdname); } if (cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT)) { hval = higcheck(executor, caller, enactor, cmdp, LowerCaseCommand); } else { hval = 0; } // If the command contains a switch, but the command doesn't support // any switches or the command contains one that isn't supported, // HOOK_IGSWITCH will allow us to treat the entire command as if it // weren't a built-in command. // int flagvalue; if ( (cmdp->hookmask & HOOK_IGSWITCH) && pSlash) { if (cmdp->switches) { search_nametab(executor, cmdp->switches, pSlash, &flagvalue); if (flagvalue & SW_MULTIPLE) { MUX_STRTOK_STATE ttswitch; // All the switches given a command shouldn't exceed 200 chars together char switch_buff[200]; char *switch_ptr; mux_strncpy(switch_buff, pSlash, sizeof(switch_buff)-1); mux_strtok_src(&ttswitch, switch_buff); mux_strtok_ctl(&ttswitch, "/"); switch_ptr = mux_strtok_parse(&ttswitch); while ( switch_ptr && *switch_ptr) { search_nametab(executor, cmdp->switches, switch_ptr, &flagvalue); if (flagvalue == -1) { break; } switch_ptr = mux_strtok_parse(&ttswitch); } } if (flagvalue == -1) { cval = 2; } } else { // Switch exists but no switches allowed for command. // cval = 2; } } if ( cval != 2 && hval != 2) { if ( cval == 1 || hval == 1) { if (cmdp->hookmask & HOOK_AFAIL) { hook_fail(executor, cmdp, LowerCaseCommand); } else { notify(executor, NOPERM_MESSAGE); } mudstate.debug_cmd = cmdsave; return preserve_cmd; } if ( mudconf.space_compress && (cmdp->callseq & CS_NOSQUISH)) { // We handle this specially -- there is no space compression // involved, so we must go back to the original command. // We skip over the command and a single space to position // arg at the arguments. // arg = pCommand = pOriginalCommand; while (*arg && !mux_isspace(*arg)) { arg++; } if (*arg) { // We stopped on the space, advance to next. // arg++; } } process_cmdent(cmdp, pSlash, executor, caller, enactor, eval, interactive, arg, pCommand, args, nargs); if (mudstate.bStackLimitReached) { STARTLOG(LOG_ALWAYS, "CMD", "SPAM"); log_name_and_loc(executor); log_text(" entered: "); log_text(pOriginalCommand); ENDLOG; } mudstate.bStackLimitReached = false; mudstate.debug_cmd = cmdsave; return preserve_cmd; } } // Check for enter and leave aliases, user-defined commands on the // player, other objects where the player is, on objects in the // player's inventory, and on the room that holds the player. We // evaluate the command line here to allow chains of $-commands // to work. // bp = LowerCaseCommand; str = pCommand; mux_exec(LowerCaseCommand, &bp, executor, caller, enactor, eval|EV_EVAL|EV_FCHECK|EV_STRIP_CURLY|EV_TOP, &str, args, nargs); *bp = '\0'; bool succ = false; // Idea for enter/leave aliases from R'nice@TinyTIM // if (Has_location(executor) && Good_obj(Location(executor))) { // Check for a leave alias. // p = atr_pget(Location(executor), A_LALIAS, &aowner, &aflags); if (*p) { if (matches_exit_from_list(LowerCaseCommand, p)) { free_lbuf(p); // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore // if (CmdCheck(executor)) { cval = cmdtest(executor, "leave"); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), "leave"); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, "leave"); } cmdp = (CMDENT *)hashfindLEN((char *)"leave", strlen("leave"), &mudstate.command_htab); if (cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT)) { hval = higcheck(executor, caller, enactor, cmdp, "leave"); } else { hval = 0; } if ( cval != 2 && hval != 2) { if ( cval == 1 || hval == 1) { if (cmdp->hookmask & HOOK_AFAIL) { hook_fail(executor, cmdp, "leave"); } else { notify(executor, NOPERM_MESSAGE); } mudstate.debug_cmd = cmdsave; return preserve_cmd; } do_leave(executor, caller, executor, 0); mudstate.debug_cmd = cmdsave; return preserve_cmd; } } } free_lbuf(p); DOLIST(exit, Contents(Location(executor))) { p = atr_pget(exit, A_EALIAS, &aowner, &aflags); if (*p) { if (matches_exit_from_list(LowerCaseCommand, p)) { free_lbuf(p); // Check for enter aliases. // // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore // if (CmdCheck(executor)) { cval = cmdtest(executor, "enter"); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), "enter"); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, "enter"); } cmdp = (CMDENT *)hashfindLEN((char *)"enter", strlen("enter"), &mudstate.command_htab); if (cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT)) { hval = higcheck(executor, caller, enactor, cmdp, "enter"); } else { hval = 0; } if ( cval != 2 && hval != 2) { if ( cval == 1 || hval == 1) { if (cmdp->hookmask & HOOK_AFAIL) { hook_fail(executor, cmdp, "enter"); } else { notify(executor, NOPERM_MESSAGE); } mudstate.debug_cmd = cmdsave; return preserve_cmd; } do_enter_internal(executor, exit, false); mudstate.debug_cmd = cmdsave; return preserve_cmd; } else if (cval == 1) { notify_quiet(executor, NOPERM_MESSAGE); mudstate.debug_cmd = cmdsave; return preserve_cmd; } } } free_lbuf(p); } } // Check for $-command matches on me. // if (mudconf.match_mine && !No_Command(executor)) { if ( ( !isPlayer(executor) || mudconf.match_mine_pl) && atr_match(executor, executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true)) { succ = true; } } // Check for $-command matches on nearby things and on my room. // if (Has_location(executor)) { succ |= list_check(Contents(Location(executor)), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); if (!No_Command(Location(executor))) { succ |= atr_match(Location(executor), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); } } // Check for $-command matches in my inventory. // if (Has_contents(executor)) { succ |= list_check(Contents(executor), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); } if ( !succ && mudconf.have_zones) { // now do check on zones. // dbref zone = Zone(executor); dbref loc = Location(executor); dbref zone_loc = NOTHING; if ( Good_obj(loc) && Good_obj(zone_loc = Zone(loc))) { if (isRoom(zone_loc)) { // zone of player's location is a parent room. // if (loc != zone) { // check parent room exits. // init_match_check_keys(executor, pCommand, TYPE_EXIT); match_zone_exit(); exit = last_match_result(); if (exit != NOTHING) { move_exit(executor, exit, true, NULL, 0); mudstate.debug_cmd = cmdsave; return preserve_cmd; } succ |= list_check(Contents(zone_loc), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); // end of parent room checks. // } } else { // try matching commands on area zone object. // if (!No_Command(zone_loc)) { succ |= atr_match(zone_loc, executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); } } } // End of matching on zone of player's location. // // if nothing matched with parent room/zone object, try matching // zone commands on the player's personal zone. // if ( !succ && Good_obj(zone) && !No_Command(zone) && zone_loc != zone) { succ |= atr_match(zone, executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); } } // If we didn't find anything, try in the master room. // if (!succ) { if ( Good_obj(mudconf.master_room) && Has_contents(mudconf.master_room)) { succ |= list_check(Contents(mudconf.master_room), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, false); if (!No_Command(mudconf.master_room)) { succ |= atr_match(mudconf.master_room, executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, false); } } } // If we still didn't find anything, tell how to get help. // if (!succ) { if ( Good_obj(mudconf.global_error_obj) && !Going(mudconf.global_error_obj)) { char *errtext = atr_get(mudconf.global_error_obj, A_VA, &aowner, &aflags); char *errbuff = alloc_lbuf("process_command.error_msg"); char *errbufc = errbuff; str = errtext; mux_exec(errbuff, &errbufc, mudconf.global_error_obj, caller, enactor, AttrTrace(aflags, EV_EVAL|EV_FCHECK|EV_STRIP_CURLY|EV_TOP), &str, &pCommand, 1); *errbufc = '\0'; notify(executor, errbuff); free_lbuf(errtext); free_lbuf(errbuff); } else { // We use LowerCaseCommand for another purpose. // notify(executor, "Huh? (Type \"help\" for help.)"); STARTLOG(LOG_BADCOMMANDS, "CMD", "BAD"); log_name_and_loc(executor); log_text(" entered: "); log_text(pCommand); ENDLOG; } } mudstate.debug_cmd = cmdsave; return preserve_cmd; } // --------------------------------------------------------------------------- // list_cmdtable: List internal commands. // static void list_cmdtable(dbref player) { char *buf = alloc_lbuf("list_cmdtable"); char *bp = buf; ITL itl; ItemToList_Init(&itl, buf, &bp); ItemToList_AddString(&itl, (char *)"Commands:"); { CMDENT_NO_ARG *cmdp; for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_ONE_ARG *cmdp; for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_ONE_ARG_CMDARG *cmdp; for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_TWO_ARG *cmdp; for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_TWO_ARG_ARGV *cmdp; for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_TWO_ARG_CMDARG *cmdp; for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_TWO_ARG_ARGV_CMDARG *cmdp; for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } ItemToList_Final(&itl); *bp = '\0'; // Players get the list of logged-out cmds too // if (isPlayer(player)) { display_nametab(player, logout_cmdtable, buf, true); } else { notify(player, buf); } free_lbuf(buf); } // --------------------------------------------------------------------------- // list_attrtable: List available attributes. // static void list_attrtable(dbref player) { ATTR *ap; char *buf = alloc_lbuf("list_attrtable"); char *bp = buf; ITL itl; ItemToList_Init(&itl, buf, &bp); ItemToList_AddString(&itl, (char *)"Attributes:"); for (ap = AttrTable; ap->name; ap++) { if (See_attr(player, player, ap)) { ItemToList_AddString(&itl, (char *)ap->name); } } ItemToList_Final(&itl); *bp = '\0'; raw_notify(player, buf); free_lbuf(buf); } // --------------------------------------------------------------------------- // list_cmdaccess: List access commands. // NAMETAB access_nametab[] = { {"builder", 6, CA_WIZARD, CA_BUILDER}, #if !defined(FIRANMUX) {"dark", 4, CA_GOD, CF_DARK}, #endif // FIRANMUX {"disabled", 4, CA_GOD, CA_DISABLED}, {"global_build", 8, CA_PUBLIC, CA_GBL_BUILD}, {"global_interp", 8, CA_PUBLIC, CA_GBL_INTERP}, {"god", 2, CA_GOD, CA_GOD}, {"head", 2, CA_WIZARD, CA_HEAD}, {"immortal", 3, CA_WIZARD, CA_IMMORTAL}, {"need_location", 6, CA_PUBLIC, CA_LOCATION}, {"need_contents", 6, CA_PUBLIC, CA_CONTENTS}, {"need_player", 6, CA_PUBLIC, CA_PLAYER}, {"no_haven", 4, CA_PUBLIC, CA_NO_HAVEN}, #if defined(FIRANMUX) {"no_immobile", 5, CA_WIZARD, CA_NO_IMMOBILE}, {"no_restricted", 6, CA_WIZARD, CA_NO_RESTRICTED}, #endif // FIRANMUX {"no_robot", 4, CA_WIZARD, CA_NO_ROBOT}, {"no_slave", 5, CA_PUBLIC, CA_NO_SLAVE}, {"no_suspect", 5, CA_WIZARD, CA_NO_SUSPECT}, {"no_guest", 5, CA_WIZARD, CA_NO_GUEST}, {"no_uninspected", 5, CA_WIZARD, CA_NO_UNINS}, {"robot", 2, CA_WIZARD, CA_ROBOT}, {"staff", 4, CA_WIZARD, CA_STAFF}, {"static", 4, CA_GOD, CA_STATIC}, {"uninspected", 5, CA_WIZARD, CA_UNINS}, {"wizard", 3, CA_WIZARD, CA_WIZARD}, {NULL, 0, 0, 0} }; static void list_cmdaccess(dbref player) { ATTR *ap; char *buff = alloc_sbuf("list_cmdaccess"); { CMDENT_NO_ARG *cmdp; for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_ONE_ARG *cmdp; for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_ONE_ARG_CMDARG *cmdp; for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_TWO_ARG *cmdp; for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_TWO_ARG_ARGV *cmdp; for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_TWO_ARG_CMDARG *cmdp; for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_TWO_ARG_ARGV_CMDARG *cmdp; for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } free_sbuf(buff); for (ap = AttrTable; ap->name; ap++) { if (ap->flags & AF_NOCMD) { continue; } size_t nBuffer; bool bValid; buff = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid); if (!bValid) { continue; } CMDENT *cmdp = (CMDENT *)hashfindLEN(buff, nBuffer, &mudstate.command_htab); if (cmdp == NULL) { continue; } if (!check_access(player, cmdp->perms)) { continue; } if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } // --------------------------------------------------------------------------- // list_cmdswitches: List switches for commands. // static void list_cmdswitches(dbref player) { char *buff = alloc_sbuf("list_cmdswitches"); { CMDENT_NO_ARG *cmdp; for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_ONE_ARG *cmdp; for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_ONE_ARG_CMDARG *cmdp; for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_TWO_ARG *cmdp; for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_TWO_ARG_ARGV *cmdp; for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_TWO_ARG_CMDARG *cmdp; for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_TWO_ARG_ARGV_CMDARG *cmdp; for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } free_sbuf(buff); } // --------------------------------------------------------------------------- // list_attraccess: List access to attributes. // NAMETAB attraccess_nametab[] = { {"const", 1, CA_PUBLIC, AF_CONST}, {"dark", 2, CA_WIZARD, AF_DARK}, {"deleted", 2, CA_WIZARD, AF_DELETED}, {"god", 1, CA_PUBLIC, AF_GOD}, {"hidden", 1, CA_WIZARD, AF_MDARK}, {"ignore", 2, CA_WIZARD, AF_NOCMD}, {"internal", 2, CA_WIZARD, AF_INTERNAL}, {"is_lock", 4, CA_PUBLIC, AF_IS_LOCK}, {"locked", 1, CA_PUBLIC, AF_LOCK}, {"no_command", 4, CA_PUBLIC, AF_NOPROG}, {"no_inherit", 4, CA_PUBLIC, AF_PRIVATE}, {"private", 1, CA_PUBLIC, AF_ODARK}, {"regexp", 1, CA_PUBLIC, AF_REGEXP}, {"visual", 1, CA_PUBLIC, AF_VISUAL}, {"wizard", 1, CA_PUBLIC, AF_WIZARD}, { NULL, 0, 0, 0} }; NAMETAB indiv_attraccess_nametab[] = { {"case", 1, CA_PUBLIC, AF_CASE}, {"hidden", 1, CA_WIZARD, AF_MDARK}, {"html", 2, CA_PUBLIC, AF_HTML}, {"no_command", 4, CA_PUBLIC, AF_NOPROG}, {"no_inherit", 4, CA_PUBLIC, AF_PRIVATE}, {"no_name", 4, CA_PUBLIC, AF_NONAME}, {"no_parse", 4, CA_PUBLIC, AF_NOPARSE}, {"regexp", 1, CA_PUBLIC, AF_REGEXP}, {"trace", 1, CA_PUBLIC, AF_TRACE}, {"visual", 1, CA_PUBLIC, AF_VISUAL}, {"wizard", 1, CA_WIZARD, AF_WIZARD}, { NULL, 0, 0, 0} }; static void list_attraccess(dbref player) { ATTR *ap; char *buff = alloc_sbuf("list_attraccess"); for (ap = AttrTable; ap->name; ap++) { if (bCanReadAttr(player, player, ap, false)) { mux_sprintf(buff, SBUF_SIZE, "%s:", ap->name); listset_nametab(player, attraccess_nametab, ap->flags, buff, true); } } free_sbuf(buff); } // --------------------------------------------------------------------------- // cf_access: Change command or switch permissions. // CF_HAND(cf_access) { UNUSED_PARAMETER(vp); CMDENT *cmdp; char *ap; bool set_switch; for (ap = str; *ap && !mux_isspace(*ap) && (*ap != '/'); ap++) ; if (*ap == '/') { set_switch = true; *ap++ = '\0'; } else { set_switch = false; if (*ap) { *ap++ = '\0'; } while (mux_isspace(*ap)) { ap++; } } cmdp = (CMDENT *)hashfindLEN(str, strlen(str), &mudstate.command_htab); if (cmdp != NULL) { if (set_switch) { return cf_ntab_access((int *)cmdp->switches, ap, pExtra, nExtra, player, cmd); } else { return cf_modify_bits(&(cmdp->perms), ap, pExtra, nExtra, player, cmd); } } else { if (!mux_stricmp(str, "home")) { return cf_modify_bits(&(mudconf.restrict_home), ap, pExtra, nExtra, player, cmd); } cf_log_notfound(player, cmd, "Command", str); return -1; } } // --------------------------------------------------------------------------- // cf_acmd_access: Change command permissions for all attr-setting cmds. // CF_HAND(cf_acmd_access) { UNUSED_PARAMETER(vp); ATTR *ap; for (ap = AttrTable; ap->name; ap++) { size_t nBuffer; bool bValid; char *buff = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid); if (!bValid) { continue; } CMDENT *cmdp = (CMDENT *)hashfindLEN(buff, nBuffer, &mudstate.command_htab); if (cmdp != NULL) { int save = cmdp->perms; int failure = cf_modify_bits(&(cmdp->perms), str, pExtra, nExtra, player, cmd); if (failure != 0) { cmdp->perms = save; return -1; } } } return 0; } // --------------------------------------------------------------------------- // cf_attr_access: Change access on an attribute. // CF_HAND(cf_attr_access) { UNUSED_PARAMETER(vp); ATTR *ap; char *sp; for (sp = str; *sp && !mux_isspace(*sp); sp++) { ; // Nothing } if (*sp) { *sp++ = '\0'; } while (mux_isspace(*sp)) { sp++; } ap = atr_str(str); if (ap) { return cf_modify_bits(&(ap->flags), sp, pExtra, nExtra, player, cmd); } else { cf_log_notfound(player, cmd, "Attribute", str); return -1; } } // --------------------------------------------------------------------------- // cf_cmd_alias: Add a command alias. // CF_HAND(cf_cmd_alias) { UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); char *ap; CMDENT *cmdp, *cmd2; NAMETAB *nt; MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, " \t=,"); char *alias = mux_strtok_parse(&tts); char *orig = mux_strtok_parse(&tts); if (!orig) { // We only got one argument to @alias. Bad. // return -1; } for (ap = orig; *ap && (*ap != '/'); ap++) ; if (*ap == '/') { // Switch form of command aliasing: create an alias for // a command + a switch // *ap++ = '\0'; // Look up the command // cmdp = (CMDENT *) hashfindLEN(orig, strlen(orig), (CHashTable *) vp); if (cmdp == NULL || cmdp->switches == NULL) { cf_log_notfound(player, cmd, "Command", orig); return -1; } // Look up the switch // nt = find_nametab_ent(player, (NAMETAB *) cmdp->switches, ap); if (!nt) { cf_log_notfound(player, cmd, "Switch", ap); return -1; } if (!hashfindLEN(alias, strlen(alias), (CHashTable *)vp)) { // Create the new command table entry. // cmd2 = (CMDENT *)MEMALLOC(sizeof(CMDENT)); ISOUTOFMEMORY(cmd2); cmd2->cmdname = StringClone(alias); cmd2->switches = cmdp->switches; cmd2->perms = cmdp->perms | nt->perm; cmd2->extra = (cmdp->extra | nt->flag) & ~SW_MULTIPLE; if (!(nt->flag & SW_MULTIPLE)) { cmd2->extra |= SW_GOT_UNIQUE; } cmd2->callseq = cmdp->callseq; cmd2->handler = cmdp->handler; hashaddLEN(cmd2->cmdname, strlen(cmd2->cmdname), cmd2, (CHashTable *) vp); } } else { // A normal (non-switch) alias // void *hp = hashfindLEN(orig, strlen(orig), (CHashTable *) vp); if (hp == NULL) { cf_log_notfound(player, cmd, "Entry", orig); return -1; } hashaddLEN(alias, strlen(alias), hp, (CHashTable *) vp); } return 0; } // --------------------------------------------------------------------------- // list_df_flags: List default flags at create time. // static void list_df_flags(dbref player) { FLAGSET fs; fs = mudconf.player_flags; fs.word[FLAG_WORD1] |= TYPE_PLAYER; char *playerb = decode_flags(player, &fs); fs = mudconf.room_flags; fs.word[FLAG_WORD1] |= TYPE_ROOM; char *roomb = decode_flags(player, &fs); fs = mudconf.exit_flags; fs.word[FLAG_WORD1] |= TYPE_EXIT; char *exitb = decode_flags(player, &fs); fs = mudconf.thing_flags; fs.word[FLAG_WORD1] |= TYPE_THING; char *thingb = decode_flags(player, &fs); fs = mudconf.robot_flags; fs.word[FLAG_WORD1] |= TYPE_PLAYER; char *robotb = decode_flags(player, &fs); char *buff = alloc_lbuf("list_df_flags"); mux_sprintf(buff, LBUF_SIZE, "Default flags: Players...%s Rooms...%s Exits...%s Things...%s Robots...%s", playerb, roomb, exitb, thingb, robotb); free_sbuf(playerb); free_sbuf(roomb); free_sbuf(exitb); free_sbuf(thingb); free_sbuf(robotb); raw_notify(player, buff); free_lbuf(buff); } // --------------------------------------------------------------------------- // list_costs: List the costs of things. // #define coin_name(s) (((s)==1) ? mudconf.one_coin : mudconf.many_coins) static void list_costs(dbref player) { char *buff = alloc_mbuf("list_costs"); if (mudconf.quotas) { mux_sprintf(buff, MBUF_SIZE, " and %d quota", mudconf.room_quota); } notify(player, tprintf("Digging a room costs %d %s%s.", mudconf.digcost, coin_name(mudconf.digcost), buff)); if (mudconf.quotas) { mux_sprintf(buff, MBUF_SIZE, " and %d quota", mudconf.exit_quota); } notify(player, tprintf("Opening a new exit costs %d %s%s.", mudconf.opencost, coin_name(mudconf.opencost), buff)); notify(player, tprintf("Linking an exit, home, or dropto costs %d %s.", mudconf.linkcost, coin_name(mudconf.linkcost))); if (mudconf.quotas) { mux_sprintf(buff, MBUF_SIZE, " and %d quota", mudconf.thing_quota); } if (mudconf.createmin == mudconf.createmax) { raw_notify(player, tprintf("Creating a new thing costs %d %s%s.", mudconf.createmin, coin_name(mudconf.createmin), buff)); } else { raw_notify(player, tprintf("Creating a new thing costs between %d and %d %s%s.", mudconf.createmin, mudconf.createmax, mudconf.many_coins, buff)); } if (mudconf.quotas) { mux_sprintf(buff, MBUF_SIZE, " and %d quota", mudconf.player_quota); } notify(player, tprintf("Creating a robot costs %d %s%s.", mudconf.robotcost, coin_name(mudconf.robotcost), buff)); if (mudconf.killmin == mudconf.killmax) { int chance = 100; if (0 < mudconf.killguarantee) { chance = (mudconf.killmin * 100) / mudconf.killguarantee; } raw_notify(player, tprintf("Killing costs %d %s, with a %d%% chance of success.", mudconf.killmin, coin_name(mudconf.digcost), chance)); } else { int cost_surething; raw_notify(player, tprintf("Killing costs between %d and %d %s.", mudconf.killmin, mudconf.killmax, mudconf.many_coins)); if (0 < mudconf.killguarantee) { cost_surething = mudconf.killguarantee; } else { cost_surething = mudconf.killmin; } raw_notify(player, tprintf("You must spend %d %s to guarantee success.", cost_surething, coin_name(cost_surething))); } raw_notify(player, tprintf("Computationally expensive commands and functions (ie: @entrances, @find, @search, @stats (with an argument or switch), search(), and stats()) cost %d %s.", mudconf.searchcost, coin_name(mudconf.searchcost))); if (mudconf.machinecost > 0) raw_notify(player, tprintf("Each command run from the queue costs 1/%d %s.", mudconf.machinecost, mudconf.one_coin)); if (mudconf.waitcost > 0) { raw_notify(player, tprintf("A %d %s deposit is charged for putting a command on the queue.", mudconf.waitcost, mudconf.one_coin)); raw_notify(player, "The deposit is refunded when the command is run or canceled."); } if (mudconf.sacfactor == 0) { mux_ltoa(mudconf.sacadjust, buff); } else if (mudconf.sacfactor == 1) { if (mudconf.sacadjust < 0) mux_sprintf(buff, MBUF_SIZE, " - %d", -mudconf.sacadjust); else if (mudconf.sacadjust > 0) mux_sprintf(buff, MBUF_SIZE, " + %d", mudconf.sacadjust); else mux_sprintf(buff, MBUF_SIZE, ""); } else { if (mudconf.sacadjust < 0) mux_sprintf(buff, MBUF_SIZE, "( / %d) - %d", mudconf.sacfactor, -mudconf.sacadjust); else if (mudconf.sacadjust > 0) mux_sprintf(buff, MBUF_SIZE, "( / %d) + %d", mudconf.sacfactor, mudconf.sacadjust); else mux_sprintf(buff, MBUF_SIZE, " / %d", mudconf.sacfactor); } raw_notify(player, tprintf("The value of an object is %s.", buff)); if (mudconf.clone_copy_cost) raw_notify(player, "The default value of cloned objects is the value of the original object."); else raw_notify(player, tprintf("The default value of cloned objects is %d %s.", mudconf.createmin, coin_name(mudconf.createmin))); free_mbuf(buff); } // --------------------------------------------------------------------------- // list_options: List more game options from mudconf. // static const char *switchd[] = {"/first", "/all"}; static const char *examd[] = {"/brief", "/full"}; static const char *ed[] = {"Disabled", "Enabled"}; static void list_options(dbref player) { char *buff; CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); if (mudconf.quotas) raw_notify(player, "Building quotas are enforced."); if (mudconf.name_spaces) raw_notify(player, "Player names may contain spaces."); else raw_notify(player, "Player names may not contain spaces."); if (!mudconf.robot_speak) raw_notify(player, "Robots are not allowed to speak in public areas."); if (mudconf.player_listen) raw_notify(player, "The @Listen/@Ahear attribute set works on player objects."); if (mudconf.ex_flags) raw_notify(player, "The 'examine' command lists the flag names for the object's flags."); if (!mudconf.quiet_look) raw_notify(player, "The 'look' command shows visible attributes in addition to the description."); if (mudconf.see_own_dark) raw_notify(player, "The 'look' command lists DARK objects owned by you."); if (!mudconf.dark_sleepers) raw_notify(player, "The 'look' command shows disconnected players."); if (mudconf.terse_look) raw_notify(player, "The 'look' command obeys the TERSE flag."); if (mudconf.trace_topdown) { raw_notify(player, "Trace output is presented top-down (whole expression first, then sub-exprs)."); raw_notify(player, tprintf("Only %d lines of trace output are displayed.", mudconf.trace_limit)); } else { raw_notify(player, "Trace output is presented bottom-up (subexpressions first)."); } if (!mudconf.quiet_whisper) raw_notify(player, "The 'whisper' command lets others in the room with you know you whispered."); if (mudconf.pemit_players) raw_notify(player, "The '@pemit' command may be used to emit to faraway players."); if (!mudconf.terse_contents) raw_notify(player, "The TERSE flag suppresses listing the contents of a location."); if (!mudconf.terse_exits) raw_notify(player, "The TERSE flag suppresses listing obvious exits in a location."); if (!mudconf.terse_movemsg) raw_notify(player, "The TERSE flag suppresses enter/leave/succ/drop messages generated by moving."); if (mudconf.pub_flags) raw_notify(player, "The 'flags()' function will return the flags of any object."); if (mudconf.read_rem_desc) raw_notify(player, "The 'get()' function will return the description of faraway objects,"); if (mudconf.read_rem_name) raw_notify(player, "The 'name()' function will return the name of faraway objects."); raw_notify(player, tprintf("The default switch for the '@switch' command is %s.", switchd[mudconf.switch_df_all])); raw_notify(player, tprintf("The default switch for the 'examine' command is %s.", examd[mudconf.exam_public])); if (mudconf.sweep_dark) raw_notify(player, "Players may @sweep dark locations."); if (mudconf.fascist_tport) raw_notify(player, "You may only @teleport out of locations that are JUMP_OK or that you control."); raw_notify(player, tprintf("Players may have at most %d commands in the queue at one time.", mudconf.queuemax)); if (mudconf.match_mine) { if (mudconf.match_mine_pl) raw_notify(player, "All objects search themselves for $-commands."); else raw_notify(player, "Objects other than players search themselves for $-commands."); } if (!Wizard(player)) return; buff = alloc_mbuf("list_options"); raw_notify(player, tprintf("%d commands are run from the queue when there is no net activity.", mudconf.queue_chunk)); raw_notify(player, tprintf("%d commands are run from the queue when there is net activity.", mudconf.active_q_chunk)); if (mudconf.idle_wiz_dark) raw_notify(player, "Wizards idle for longer than the default timeout are automatically set DARK."); if (mudconf.safe_unowned) raw_notify(player, "Objects not owned by you are automatically considered SAFE."); if (mudconf.paranoid_alloc) raw_notify(player, "The buffer pools are checked for consistency on each allocate or free."); if (mudconf.cache_names) raw_notify(player, "A separate name cache is used."); #ifndef WIN32 if (mudconf.fork_dump) { raw_notify(player, "Database dumps are performed by a fork()ed process."); } #endif if (mudconf.max_players >= 0) raw_notify(player, tprintf("There may be at most %d players logged in at once.", mudconf.max_players)); if (mudconf.quotas) mux_sprintf(buff, MBUF_SIZE, " and %d quota", mudconf.start_quota); else *buff = '\0'; raw_notify(player, tprintf("New players are given %d %s to start with.", mudconf.paystart, mudconf.many_coins)); raw_notify(player, tprintf("Players are given %d %s each day they connect.", mudconf.paycheck, mudconf.many_coins)); raw_notify(player, tprintf("Earning money is difficult if you have more than %d %s.", mudconf.paylimit, mudconf.many_coins)); if (mudconf.payfind > 0) raw_notify(player, tprintf("Players have a 1 in %d chance of finding a %s each time they move.", mudconf.payfind, mudconf.one_coin)); raw_notify(player, tprintf("The head of the object freelist is #%d.", mudstate.freelist)); mux_sprintf(buff, MBUF_SIZE, "Intervals: Dump...%d Clean...%d Idlecheck...%d", mudconf.dump_interval, mudconf.check_interval, mudconf.idle_interval); raw_notify(player, buff); CLinearTimeDelta ltdDump = mudstate.dump_counter - ltaNow; CLinearTimeDelta ltdCheck = mudstate.check_counter - ltaNow; CLinearTimeDelta ltdIdle = mudstate.idle_counter - ltaNow; long lDump = ltdDump.ReturnSeconds(); long lCheck = ltdCheck.ReturnSeconds(); long lIdle = ltdIdle.ReturnSeconds(); mux_sprintf(buff, MBUF_SIZE, "Timers: Dump...%ld Clean...%ld Idlecheck...%ld", lDump, lCheck, lIdle); raw_notify(player, buff); mux_sprintf(buff, MBUF_SIZE, "Timeouts: Idle...%d Connect...%d Tries...%d", mudconf.idle_timeout, mudconf.conn_timeout, mudconf.retry_limit); raw_notify(player, buff); mux_sprintf(buff, MBUF_SIZE, "Scheduling: Timeslice...%s Max_Quota...%d Increment...%d", mudconf.timeslice.ReturnSecondsString(3),mudconf.cmd_quota_max, mudconf.cmd_quota_incr); raw_notify(player, buff); mux_sprintf(buff, MBUF_SIZE, "Spaces...%s Savefiles...%s", ed[mudconf.space_compress], ed[mudconf.compress_db]); raw_notify(player, buff); mux_sprintf(buff, MBUF_SIZE, "New characters: Room...#%d Home...#%d DefaultHome...#%d Quota...%d", mudconf.start_room, mudconf.start_home, mudconf.default_home, mudconf.start_quota); raw_notify(player, buff); mux_sprintf(buff, MBUF_SIZE, "Misc: GuestChar...#%d IdleQueueChunk...%d ActiveQueueChunk...%d Master_room...#%d", mudconf.guest_char, mudconf.queue_chunk, mudconf.active_q_chunk, mudconf.master_room); raw_notify(player, buff); free_mbuf(buff); } // --------------------------------------------------------------------------- // list_vattrs: List user-defined attributes // static void list_vattrs(dbref player, char *s_mask) { bool wild_mtch = s_mask && s_mask[0] != '\0'; char *buff = alloc_lbuf("list_vattrs"); // If wild_match, then only list attributes that match wildcard(s) // char *p = tprintf("--- User-Defined Attributes %s---", wild_mtch ? "(wildmatched) " : ""); raw_notify(player, p); ATTR *va; int na; int wna = 0; for (va = vattr_first(), na = 0; va; va = vattr_next(va), na++) { if (!(va->flags & AF_DELETED)) { // We need to be extremely careful that s_mask is !null and valid // if (wild_mtch) { mudstate.wild_invk_ctr = 0; if (!quick_wild(s_mask, va->name)) { continue; } wna++; } mux_sprintf(buff, LBUF_SIZE, "%s(%d):", va->name, va->number); listset_nametab(player, attraccess_nametab, va->flags, buff, true); } } if (wild_mtch) { p = tprintf("%d attributes matched, %d attributes total, next=%d", wna, na, mudstate.attr_next); } else { p = tprintf("%d attributes, next=%d", na, mudstate.attr_next); } raw_notify(player, p); free_lbuf(buff); } size_t LeftJustifyString(char *field, size_t nWidth, const char *value) { size_t n = strlen(value); if (n > nWidth) { n = nWidth; } memcpy(field, value, n); memset(field+n, ' ', nWidth-n); return nWidth; } size_t RightJustifyNumber(char *field, size_t nWidth, INT64 value, char chFill) { char buffer[22]; size_t nReturn = 0; if (nWidth < sizeof(buffer)) { size_t n = mux_i64toa(value, buffer); if (n < sizeof(buffer)) { nReturn = n; if (n < nWidth) { memset(field, chFill, nWidth-n); field += nWidth-n; nReturn = nWidth; } memcpy(field, buffer, n); } } return nReturn; } // list_hashstats: List information from hash tables // static void list_hashstat(dbref player, const char *tab_name, CHashTable *htab) { unsigned int hashsize; int entries, max_scan; INT64 deletes, scans, hits, checks; htab->GetStats(&hashsize, &entries, &deletes, &scans, &hits, &checks, &max_scan); char buff[MBUF_SIZE]; char *p = buff; p += LeftJustifyString(p, 13, tab_name); *p++ = ' '; p += RightJustifyNumber(p, 4, hashsize, ' '); *p++ = ' '; p += RightJustifyNumber(p, 6, entries, ' '); *p++ = ' '; p += RightJustifyNumber(p, 7, deletes, ' '); *p++ = ' '; p += RightJustifyNumber(p, 13, scans, ' '); *p++ = ' '; p += RightJustifyNumber(p, 13, hits, ' '); *p++ = ' '; p += RightJustifyNumber(p, 13, checks, ' '); *p++ = ' '; p += RightJustifyNumber(p, 4, max_scan, ' '); *p = '\0'; raw_notify(player, buff); } static void list_hashstats(dbref player) { raw_notify(player, "Hash Stats Size Num Del Lookups Hits Probes Long"); list_hashstat(player, "Commands", &mudstate.command_htab); list_hashstat(player, "Logout Cmds", &mudstate.logout_cmd_htab); list_hashstat(player, "Functions", &mudstate.func_htab); list_hashstat(player, "Flags", &mudstate.flags_htab); list_hashstat(player, "Powers", &mudstate.powers_htab); list_hashstat(player, "Attr Names", &mudstate.attr_name_htab); list_hashstat(player, "Vattr Names", &mudstate.vattr_name_htab); list_hashstat(player, "Player Names", &mudstate.player_htab); list_hashstat(player, "Net Descr.", &mudstate.desc_htab); list_hashstat(player, "Fwd. lists", &mudstate.fwdlist_htab); list_hashstat(player, "Excl. $-cmds", &mudstate.parent_htab); list_hashstat(player, "Mail Messages", &mudstate.mail_htab); list_hashstat(player, "Channel Names", &mudstate.channel_htab); #if !defined(MEMORY_BASED) list_hashstat(player, "Attr. Cache", &mudstate.acache_htab); #endif // MEMORY_BASED for (int i = 0; i < mudstate.nHelpDesc; i++) { list_hashstat(player, mudstate.aHelpDesc[i].pBaseFilename, mudstate.aHelpDesc[i].ht); } } // --------------------------------------------------------------------------- // list_db_stats: Get useful info from the DB layer about hash stats, etc. // static void list_db_stats(dbref player) { #ifdef MEMORY_BASED raw_notify(player, "Database is memory based."); #else // MEMORY_BASED CLinearTimeAbsolute lsaNow; lsaNow.GetUTC(); CLinearTimeDelta ltd = lsaNow - cs_ltime; raw_notify(player, tprintf("DB Cache Stats Writes Reads (over %d seconds)", ltd.ReturnSeconds())); raw_notify(player, tprintf("Calls %12d%12d", cs_writes, cs_reads)); raw_notify(player, tprintf("\nDeletes %12d", cs_dels)); raw_notify(player, tprintf("Syncs %12d", cs_syncs)); raw_notify(player, tprintf("I/O %12d%12d", cs_dbwrites, cs_dbreads)); raw_notify(player, tprintf("Cache Hits %12d%12d", cs_whits, cs_rhits)); #endif // MEMORY_BASED } // --------------------------------------------------------------------------- // list_process: List local resource usage stats of the mux process. // Adapted from code by Claudius@PythonMUCK, // posted to the net by Howard/Dark_Lord. // static void list_process(dbref player) { #ifdef HAVE_GETRUSAGE struct rusage usage; int ixrss, idrss, isrss, curr, last, dur; getrusage(RUSAGE_SELF, &usage); // Calculate memory use from the aggregate totals. // curr = mudstate.mstat_curr; last = 1 - curr; dur = mudstate.mstat_secs[curr] - mudstate.mstat_secs[last]; if (dur > 0) { ixrss = (mudstate.mstat_ixrss[curr] - mudstate.mstat_ixrss[last]) / dur; idrss = (mudstate.mstat_idrss[curr] - mudstate.mstat_idrss[last]) / dur; isrss = (mudstate.mstat_isrss[curr] - mudstate.mstat_isrss[last]) / dur; } else { ixrss = 0; idrss = 0; isrss = 0; } #endif // HAVE_GETRUSAGE #ifdef WIN32 #ifdef HAVE_GETRUSAGE int maxfds = FD_SETSIZE; #endif // HAVE_GETRUSAGE #else // WIN32 #ifdef HAVE_GETDTABLESIZE int maxfds = getdtablesize(); #else // HAVE_GETDTABLESIZE int maxfds = sysconf(_SC_OPEN_MAX); #endif // HAVE_GETDTABLESIZE int psize = getpagesize(); #endif // WIN32 // Go display everything // #ifdef WIN32 raw_notify(player, tprintf("Process ID: %10d", game_pid)); #else // WIN32 raw_notify(player, tprintf("Process ID: %10d %10d bytes per page", game_pid, psize)); #endif // WIN32 #ifdef HAVE_GETRUSAGE raw_notify(player, tprintf("Time used: %10d user %10d sys", usage.ru_utime.tv_sec, usage.ru_stime.tv_sec)); raw_notify(player, tprintf("Resident mem:%10d shared %10d private%10d stack", ixrss, idrss, isrss)); raw_notify(player, tprintf("Integral mem:%10d shared %10d private%10d stack", usage.ru_ixrss, usage.ru_idrss, usage.ru_isrss)); raw_notify(player, tprintf("Max res mem: %10d pages %10d bytes", usage.ru_maxrss, (usage.ru_maxrss * psize))); raw_notify(player, tprintf("Page faults: %10d hard %10d soft %10d swapouts", usage.ru_majflt, usage.ru_minflt, usage.ru_nswap)); raw_notify(player, tprintf("Disk I/O: %10d reads %10d writes", usage.ru_inblock, usage.ru_oublock)); raw_notify(player, tprintf("Network I/O: %10d in %10d out", usage.ru_msgrcv, usage.ru_msgsnd)); raw_notify(player, tprintf("Context swi: %10d vol %10d forced %10d sigs", usage.ru_nvcsw, usage.ru_nivcsw, usage.ru_nsignals)); raw_notify(player, tprintf("Descs avail: %10d", maxfds)); #endif // HAVE_GETRUSAGE } //---------------------------------------------------------------------------- // list_rlevels // #ifdef REALITY_LVLS static void list_rlevels(dbref player) { int i; raw_notify(player, "Reality levels:"); for(i = 0; i < mudconf.no_levels; ++i) raw_notify(player, tprintf(" Level: %-20.20s Value: 0x%08x Desc: %s", mudconf.reality_level[i].name, mudconf.reality_level[i].value, mudconf.reality_level[i].attr)); raw_notify(player, "--Completed."); } #endif // REALITY_LVLS // --------------------------------------------------------------------------- // do_list: List information stored in internal structures. // #define LIST_ATTRIBUTES 1 #define LIST_COMMANDS 2 #define LIST_COSTS 3 #define LIST_FLAGS 4 #define LIST_FUNCTIONS 5 #define LIST_GLOBALS 6 #define LIST_ALLOCATOR 7 #define LIST_LOGGING 8 #define LIST_DF_FLAGS 9 #define LIST_PERMS 10 #define LIST_ATTRPERMS 11 #define LIST_OPTIONS 12 #define LIST_HASHSTATS 13 #define LIST_BUFTRACE 14 #define LIST_CONF_PERMS 15 #define LIST_SITEINFO 16 #define LIST_POWERS 17 #define LIST_SWITCHES 18 #define LIST_VATTRS 19 #define LIST_DB_STATS 20 #define LIST_PROCESS 21 #define LIST_BADNAMES 22 #define LIST_RESOURCES 23 #define LIST_GUESTS 24 #ifdef REALITY_LVLS #define LIST_RLEVELS 25 #endif NAMETAB list_names[] = { {"allocations", 2, CA_WIZARD, LIST_ALLOCATOR}, {"attr_permissions", 5, CA_WIZARD, LIST_ATTRPERMS}, {"attributes", 2, CA_PUBLIC, LIST_ATTRIBUTES}, {"bad_names", 2, CA_WIZARD, LIST_BADNAMES}, {"buffers", 2, CA_WIZARD, LIST_BUFTRACE}, {"commands", 3, CA_PUBLIC, LIST_COMMANDS}, {"config_permissions", 3, CA_GOD, LIST_CONF_PERMS}, {"costs", 3, CA_PUBLIC, LIST_COSTS}, {"db_stats", 2, CA_WIZARD, LIST_DB_STATS}, {"default_flags", 1, CA_PUBLIC, LIST_DF_FLAGS}, {"flags", 2, CA_PUBLIC, LIST_FLAGS}, {"functions", 2, CA_PUBLIC, LIST_FUNCTIONS}, {"globals", 2, CA_WIZARD, LIST_GLOBALS}, {"hashstats", 1, CA_WIZARD, LIST_HASHSTATS}, {"logging", 1, CA_GOD, LIST_LOGGING}, {"options", 1, CA_PUBLIC, LIST_OPTIONS}, {"permissions", 2, CA_WIZARD, LIST_PERMS}, {"powers", 2, CA_WIZARD, LIST_POWERS}, {"process", 2, CA_WIZARD, LIST_PROCESS}, {"resources", 1, CA_WIZARD, LIST_RESOURCES}, {"site_information", 2, CA_WIZARD, LIST_SITEINFO}, {"switches", 2, CA_PUBLIC, LIST_SWITCHES}, {"user_attributes", 1, CA_WIZARD, LIST_VATTRS}, {"guests", 2, CA_WIZARD, LIST_GUESTS}, #ifdef REALITY_LVLS {"rlevels", 3, CA_PUBLIC, LIST_RLEVELS}, #endif { NULL, 0, 0, 0} }; void do_list(dbref executor, dbref caller, dbref enactor, int eval, int extra, char *arg) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(extra); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, arg); mux_strtok_ctl(&tts, " \t=,"); char *s_option = mux_strtok_parse(&tts); int flagvalue; if (!search_nametab(executor, list_names, arg, &flagvalue)) { if (flagvalue == -1) { display_nametab(executor, list_names, "Unknown option. Use one of:", true); } else { notify(executor, NOPERM_MESSAGE); } return; } switch (flagvalue) { case LIST_ALLOCATOR: list_bufstats(executor); break; case LIST_BUFTRACE: list_buftrace(executor); break; case LIST_ATTRIBUTES: list_attrtable(executor); break; case LIST_COMMANDS: list_cmdtable(executor); break; case LIST_SWITCHES: list_cmdswitches(executor); break; case LIST_COSTS: list_costs(executor); break; case LIST_OPTIONS: list_options(executor); break; case LIST_HASHSTATS: list_hashstats(executor); break; case LIST_SITEINFO: list_siteinfo(executor); break; case LIST_FLAGS: display_flagtab(executor); break; case LIST_FUNCTIONS: list_functable(executor); break; case LIST_GLOBALS: interp_nametab(executor, enable_names, mudconf.control_flags, "Global parameters:", "enabled", "disabled"); break; case LIST_DF_FLAGS: list_df_flags(executor); break; case LIST_PERMS: list_cmdaccess(executor); break; case LIST_CONF_PERMS: list_cf_access(executor); break; case LIST_POWERS: display_powertab(executor); break; case LIST_ATTRPERMS: list_attraccess(executor); break; case LIST_VATTRS: s_option = mux_strtok_parse(&tts); list_vattrs(executor, s_option); break; case LIST_LOGGING: interp_nametab(executor, logoptions_nametab, mudconf.log_options, "Events Logged:", "enabled", "disabled"); interp_nametab(executor, logdata_nametab, mudconf.log_info, "Information Logged:", "yes", "no"); break; case LIST_DB_STATS: list_db_stats(executor); break; case LIST_PROCESS: list_process(executor); break; case LIST_BADNAMES: badname_list(executor, "Disallowed names:"); break; case LIST_RESOURCES: list_system_resources(executor); break; case LIST_GUESTS: Guest.ListAll(executor); break; #ifdef REALITY_LVLS case LIST_RLEVELS: list_rlevels(executor); break; #endif } } void do_break(dbref executor, dbref caller, dbref enactor, int eval, int key, char *arg1) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); break_called = xlate(arg1); } // do_icmd: Ignore or disable commands on a per-player or per-room basis. // Used with express permission of RhostMUSH developers. // Bludgeoned into MUX by Jake Nelson 7/2002. // void do_icmd(dbref player, dbref cause, dbref enactor, int eval, int key, char *name, char *args[], int nargs) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cause); UNUSED_PARAMETER(enactor); CMDENT *cmdp; char *buff1, *pt1, *pt2, *pt3, *atrpt, *pt5; int x, aflags; size_t y; dbref target = NOTHING, aowner, zone; bool bFound, set; int loc_set = -1; if ( key == ICMD_IROOM || key == ICMD_DROOM || key == ICMD_CROOM || key == ICMD_LROOM || key == ICMD_LALLROOM) { if (key != ICMD_LALLROOM) { target = match_thing_quiet(player, name); } if ( key != ICMD_LALLROOM && ( !Good_obj(target) || !( isRoom(target) || isThing(target)))) { notify(player, "@icmd: Bad Location."); return; } if (key == ICMD_CROOM) { atr_clr(target, A_CMDCHECK); notify(player, "@icmd: Location - All cleared."); notify(player, "@icmd: Done."); return; } else if (key == ICMD_LROOM) { atrpt = atr_get(target, A_CMDCHECK, &aowner, &aflags); if (*atrpt) { notify(player,"Location CmdCheck attribute is:"); notify(player, atrpt); } else { notify(player, "Location CmdCheck attribute is empty."); } free_lbuf(atrpt); notify(player, "@icmd: Done."); return; } else if (key == ICMD_LALLROOM) { target = Location(player); if ( !Good_obj(target) || Going(target) || isPlayer(target)) { notify(player, "@icmd: Bad Location."); return; } notify(player, "Scanning all locations and zones from your current location:"); bFound = false; atrpt = atr_get(target, A_CMDCHECK, &aowner, &aflags); if (*atrpt) { notify(player, tprintf("%c --- At %s(#%d) :", (Zone(target) == target ? '*' : ' '), Name(target), target)); notify(player, atrpt); bFound = true; } free_lbuf(atrpt); if (Zone(target) != target) { zone = Zone(target); if ( Good_obj(zone) && ( isRoom(zone) || isThing(zone))) { atrpt = atr_get(zone, A_CMDCHECK, &aowner, &aflags); if (*atrpt) { notify(player,tprintf("%c z-- At %s(#%d) :", '*', Name(zone), zone)); notify(player, atrpt); bFound = true; } free_lbuf(atrpt); } } if (!bFound) { notify(player, "@icmd: Location - No icmd's found at current location."); } notify(player, "@icmd: Done."); return; } else if (key == ICMD_IROOM) { loc_set = 1; } else if (key == ICMD_DROOM) { loc_set = 0; } } if (loc_set == -1 ) { target = lookup_player(player, name, false); if (!Good_obj(target) || God(target)) { notify(player, "@icmd: Bad player."); return; } if ((key == ICMD_OFF) || (key == ICMD_CLEAR)) { s_Flags(target, FLAG_WORD3, Flags3(target) & ~CMDCHECK); if (key == ICMD_CLEAR) { atr_clr(target, A_CMDCHECK); } notify(player, "@icmd: All cleared."); notify(player, "@icmd: Done."); return; } else if (key == ICMD_ON) { s_Flags(target, FLAG_WORD3, Flags3(target) | CMDCHECK); notify(player, "@icmd: Activated."); notify(player, "@icmd: Done."); return; } else if (key == ICMD_CHECK) { if (CmdCheck(target)) { notify(player, "CmdCheck is active."); } else { notify(player, "CmdCheck is not active."); } atrpt = atr_get(target, A_CMDCHECK, &aowner, &aflags); if (*atrpt) { notify(player, "CmdCheck attribute is:"); notify(player, atrpt); } else { notify(player, "CmdCheck attribute is empty."); } free_lbuf(atrpt); notify(player, "@icmd: Done."); return; } } else { key = loc_set; } const char *message = ""; buff1 = alloc_lbuf("do_icmd"); for (x = 0; x < nargs; x++) { pt1 = args[x]; pt2 = buff1; while ( *pt1 && pt2 < buff1 + LBUF_SIZE) { *pt2++ = mux_tolower(*pt1++); } *pt2 = '\0'; if ( buff1[0] == '!' && buff1[1] != '\0') { pt1 = buff1 + 1; set = false; } else { pt1 = buff1; set = true; } if (*pt1) { bool bHome, bColon = false; if (!string_compare(pt1, "home")) { bHome = true; cmdp = NULL; } else { bHome = false; cmdp = (CMDENT *) hashfindLEN(pt1, strlen(pt1), &mudstate.command_htab); } if (cmdp || bHome) { atrpt = atr_get(target, A_CMDCHECK, &aowner, &aflags); if (cmdp) { aflags = (int)strlen(cmdp->cmdname); bColon = ( aflags == 1 && *(cmdp->cmdname) == ':'); } else { aflags = 4; } pt5 = atrpt; while (pt1) { if (cmdp) { if (bColon) { pt1 = strstr(pt5, "::"); if (pt1) { pt1++; } } else { pt1 = strstr(pt5, cmdp->cmdname); } } else { pt1 = strstr(pt5, "home"); } if ( pt1 && (pt1 > atrpt) && (*(pt1 - 1) == ':') && ( mux_isspace(*(pt1 + aflags)) || !*(pt1 + aflags))) { break; } else if (pt1) { if (*pt1) { pt5 = pt1 + 1; } else { pt1 = NULL; break; } } } if (set) { if (!pt1) { if (cmdp) { pt3 = tprintf(" %d:%s", key + 1, cmdp->cmdname); } else { pt3 = tprintf(" %d:home", key + 1); } size_t natrpt = strlen(atrpt); size_t npt3 = strlen(pt3); if ((natrpt + npt3) < LBUF_SIZE - 1) { mux_strncpy(atrpt + natrpt, pt3, LBUF_SIZE-natrpt-1); atr_add_raw(target, A_CMDCHECK, atrpt); if ( loc_set == -1 ) { s_Flags(target, FLAG_WORD3, Flags3(target) | CMDCHECK); } message = "Set"; } } else { message = "Command already present"; } } else { if (pt1) { pt2 = pt1 - 1; while ((pt2 > atrpt) && !mux_isspace(*pt2)) { pt2--; } y = pt2 - atrpt + 1; // Save the char that'll be nulled by mux_strncpy. // (Even though it may be unneeded by this point.) char cSave = buff1[y]; mux_strncpy(buff1, atrpt, y); buff1[y] = cSave; if (y == 1) { *atrpt = '\0'; } *(atrpt + y) = '\0'; pt2 = pt1 + aflags; if (*pt2) { while (*pt2 && mux_isspace(*pt2)) { pt2++; } if (*pt2) { size_t natrpt = strlen(atrpt); mux_strncpy(atrpt + natrpt, pt2, LBUF_SIZE-natrpt-1); } } if ((y > 1) && !*pt2) { pt2 = atrpt + y; while ((pt2 > atrpt) && mux_isspace(*pt2)) { pt2--; } *(pt2 + 1) = '\0'; } if ((y == 1) && !*pt2) { atr_clr(target, A_CMDCHECK); if (loc_set == -1) { s_Flags(target, FLAG_WORD3, Flags3(target) & ~CMDCHECK); } message = "Cleared"; } else { atr_add_raw(target, A_CMDCHECK, atrpt); message = "Cleared"; } } else { message = "Command not present"; } } free_lbuf(atrpt); } else { message = "Bad command"; } notify(player, tprintf("@icmd:%s %s.",(loc_set == -1) ? "" : " Location -", message)); } } free_lbuf(buff1); notify(player,"@icmd: Done."); } // do_train: show someone else in the same room what code you're entering and the result // From RhostMUSH, changed to use notify_all_from_inside. // void do_train(dbref executor, dbref caller, dbref enactor, int eval, int key, char *string) { UNUSED_PARAMETER(key); if (0 < mudstate.train_nest_lev) { notify(executor, "Train cannot be used to teach command, train."); return; } mudstate.train_nest_lev++; dbref loc = Location(executor); if (!Good_obj(loc)) { notify(executor, "Bad location."); mudstate.train_nest_lev--; return; } if ( !string || !*string) { notify(executor, "Train requires an argument."); mudstate.train_nest_lev--; return; } notify_all_from_inside(loc, executor, tprintf("%s types -=> %s", Moniker(executor), string)); process_command(executor, caller, enactor, eval, true, string, NULL, 0); mudstate.train_nest_lev--; } void do_moniker(dbref executor, dbref caller, dbref enactor, int key, int nfargs, char *name, char *instr) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nfargs); dbref thing = match_thing(executor, name); if (!Good_obj(thing)) { return; } if (!Controls(executor, thing)) { notify(executor, NOPERM_MESSAGE); return; } if ( instr == NULL || instr[0] == '\0') { notify_quiet(executor, "Moniker cleared."); s_Moniker(thing, NULL); } else { s_Moniker(thing, instr); if ( !Quiet(executor) && !Quiet(thing)) { notify_quiet(executor, "Moniker set."); } } set_modified(thing); } // do_hook: run softcode before or after running a hardcode command, or // softcode access. Original idea from TinyMUSH 3, code from RhostMUSH. // Used with express permission of RhostMUSH developers. // Bludgeoned into MUX by Jake Nelson 7/2002. // static void show_hook(char *bf, char *bfptr, int key) { if (key & HOOK_BEFORE) safe_str("before ", bf, &bfptr); if (key & HOOK_AFTER) safe_str("after ", bf, &bfptr); if (key & HOOK_PERMIT) safe_str("permit ", bf, &bfptr); if (key & HOOK_IGNORE) safe_str("ignore ", bf, &bfptr); if (key & HOOK_IGSWITCH) safe_str("igswitch ", bf, &bfptr); if (key & HOOK_AFAIL) safe_str("afail ", bf, &bfptr); *bfptr = '\0'; } static void hook_loop(dbref executor, CMDENT *cmdp, char *s_ptr, char *s_ptrbuff) { show_hook(s_ptrbuff, s_ptr, cmdp->hookmask); const char *pFmt = "%-32.32s | %s"; const char *pCmd = cmdp->cmdname; if ( pCmd[0] != '\0' && pCmd[1] == '\0') { switch (pCmd[0]) { case '"': pFmt = "S %-30.30s | %s"; pCmd = "('\"' hook on 'say')"; break; case ':': pFmt = "P %-30.30s | %s"; pCmd = "(':' hook on 'pose')"; break; case ';': pFmt = "P %-30.30s | %s"; pCmd = "(';' hook on 'pose')"; break; case '\\': pFmt = "E %-30.30s | %s"; pCmd = "('\\\\' hook on '@emit')"; break; case '#': pFmt = "F %-30.30s | %s"; pCmd = "('#' hook on '@force')"; break; case '&': pFmt = "V %-30.30s | %s"; pCmd = "('&' hook on '@set')"; break; case '-': pFmt = "M %-30.30s | %s"; pCmd = "('-' hook on '@mail')"; break; case '~': pFmt = "M %-30.30s | %s"; pCmd = "('~' hook on '@mail')"; break; } } notify(executor, tprintf(pFmt, pCmd, s_ptrbuff)); } void do_hook(dbref executor, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); bool negate, found; char *s_ptr, *s_ptrbuff, *cbuff, *p; const char *q; CMDENT *cmdp = (CMDENT *)NULL; if ( ( key && !(key & HOOK_LIST)) || ( ( !key || (key & HOOK_LIST)) && *name)) { cmdp = (CMDENT *)hashfindLEN(name, strlen(name), &mudstate.command_htab); if (!cmdp) { notify(executor, "@hook: Non-existent command name given."); return; } } if ( (key & HOOK_CLEAR) && (key & HOOK_LIST)) { notify(executor, "@hook: Incompatible switches."); return; } if (key & HOOK_CLEAR) { negate = true; key = key & ~HOOK_CLEAR; key = key & ~SW_MULTIPLE; } else { negate = false; } if (key & (HOOK_BEFORE|HOOK_AFTER|HOOK_PERMIT|HOOK_IGNORE|HOOK_IGSWITCH|HOOK_AFAIL)) { if (negate) { cmdp->hookmask = cmdp->hookmask & ~key; } else { cmdp->hookmask = cmdp->hookmask | key; } if (cmdp->hookmask) { s_ptr = s_ptrbuff = alloc_lbuf("@hook"); show_hook(s_ptrbuff, s_ptr, cmdp->hookmask); notify(executor, tprintf("@hook: New mask for '%s' -> %s", cmdp->cmdname, s_ptrbuff)); free_lbuf(s_ptrbuff); } else { notify(executor, tprintf("@hook: New mask for '%s' is empty.", cmdp->cmdname)); } } if ( (key & HOOK_LIST) || !key) { if (cmdp) { if (cmdp->hookmask) { s_ptr = s_ptrbuff = alloc_lbuf("@hook"); show_hook(s_ptrbuff, s_ptr, cmdp->hookmask); notify(executor, tprintf("@hook: Mask for hashed command '%s' -> %s", cmdp->cmdname, s_ptrbuff)); free_lbuf(s_ptrbuff); } else { notify(executor, tprintf("@hook: Mask for hashed command '%s' is empty.", cmdp->cmdname)); } } else { notify(executor, tprintf("%.32s-+-%s", "--------------------------------", "--------------------------------------------")); notify(executor, tprintf("%-32s | %s", "Built-in Command", "Hook Mask Values")); notify(executor, tprintf("%.32s-+-%s", "--------------------------------", "--------------------------------------------")); found = false; s_ptr = s_ptrbuff = alloc_lbuf("@hook"); { CMDENT_NO_ARG *cmdp2; for (cmdp2 = command_table_no_arg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_ONE_ARG *cmdp2; for (cmdp2 = command_table_one_arg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_ONE_ARG_CMDARG *cmdp2; for (cmdp2 = command_table_one_arg_cmdarg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_TWO_ARG *cmdp2; for (cmdp2 = command_table_two_arg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_TWO_ARG_ARGV *cmdp2; for (cmdp2 = command_table_two_arg_argv; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_TWO_ARG_CMDARG *cmdp2; for (cmdp2 = command_table_two_arg_cmdarg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_TWO_ARG_ARGV_CMDARG *cmdp2; for (cmdp2 = command_table_two_arg_argv_cmdarg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } if (!found) { notify(executor, tprintf("%26s -- No @hooks defined --", " ")); } found = false; /* We need to search the attribute table as well */ notify(executor, tprintf("%.32s-+-%s", "--------------------------------", "--------------------------------------------")); notify(executor, tprintf("%-32s | %s", "Built-in Attribute", "Hook Mask Values")); notify(executor, tprintf("%.32s-+-%s", "--------------------------------", "--------------------------------------------")); cbuff = alloc_sbuf("cbuff_hook"); for (ATTR *ap = AttrTable; ap->name; ap++) { if (ap->flags & AF_NOCMD) { continue; } s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; p = cbuff; safe_sb_chr('@', cbuff, &p); for (q = ap->name; *q; q++) { safe_sb_chr(mux_tolower(*q), cbuff, &p); } *p = '\0'; size_t ncbuff = p - cbuff; cmdp = (CMDENT *)hashfindLEN(cbuff, ncbuff, &mudstate.command_htab); if ( cmdp && cmdp->hookmask) { found = true; show_hook(s_ptrbuff, s_ptr, cmdp->hookmask); notify(executor, tprintf("%-32.32s | %s", cmdp->cmdname, s_ptrbuff)); } } free_sbuf(cbuff); if (!found) { notify(executor, tprintf("%26s -- No @hooks defined --", " ")); } free_lbuf(s_ptrbuff); notify(executor, tprintf("%.32s-+-%s", "--------------------------------", "--------------------------------------------")); notify(executor, tprintf("The hook object is currently: #%d (%s)", mudconf.hook_obj, ( ( Good_obj(mudconf.hook_obj) && !Going(mudconf.hook_obj)) ? "VALID" : "INVALID"))); } } } mux2.6/src/speech.cpp0000600000175000017500000010665011025753746014561 0ustar sdennissdennis// speech.cpp -- Commands which involve speaking. // // $Id: speech.cpp 3359 2008-03-03 06:24:18Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "interface.h" #include "powers.h" #ifdef REALITY_LVLS #include "levels.h" #endif char *modSpeech(dbref player, char *message, bool bWhich, char *command) { dbref aowner; int aflags; char *mod = atr_get(player, bWhich ? A_SPEECHMOD : A_SAYSTRING, &aowner, &aflags); if ( mod[0] == '\0' || MuxAlarm.bAlarmed) { free_lbuf(mod); return NULL; } char *mod_orig = mod; char *new_message = alloc_lbuf("modspeech"); char *t_ptr = new_message; char *args[2]; args[0] = message; args[1] = command; mux_exec(new_message, &t_ptr, player, player, player, AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP), &mod, args, 2); *t_ptr = '\0'; free_lbuf(mod_orig); return new_message; } static int idle_timeout_val(dbref player) { // If IDLETIMEOUT attribute is not present, the value // returned will be zero. // dbref aowner; int aflags; char *ITbuffer = atr_get(player, A_IDLETMOUT, &aowner, &aflags); int idle_timeout = mux_atol(ITbuffer); free_lbuf(ITbuffer); return idle_timeout; } static bool sp_ok(dbref player) { if ( Gagged(player) && !Wizard(player)) { notify(player, "Sorry. Gagged players cannot speak."); return false; } if (!mudconf.robot_speak) { if (Robot(player) && !Controls(player, Location(player))) { notify(player, "Sorry, robots may not speak in public."); return false; } } if (Auditorium(Location(player))) { if (!could_doit(player, Location(player), A_LSPEECH)) { notify(player, "Sorry, you may not speak in this place."); return false; } } return true; } static void wall_broadcast(int target, dbref player, char *message) { DESC *d; DESC_ITER_CONN(d) { switch (target) { case SHOUT_WIZARD: if (Wizard(d->player)) { notify_with_cause(d->player, player, message); } break; case SHOUT_ADMIN: if (WizRoy(d->player)) { notify_with_cause(d->player, player, message); } break; default: notify_with_cause(d->player, player, message); break; } } } static void say_shout(int target, const char *prefix, int flags, dbref player, char *message) { char *p; if (flags & SAY_NOTAG) { p = tprintf("%s%s", Moniker(player), message); } else { p = tprintf("%s%s%s", prefix, Moniker(player), message); } wall_broadcast(target, player, p); } static const char *announce_msg = "Announcement: "; static const char *broadcast_msg = "Broadcast: "; static const char *admin_msg = "Admin: "; void do_think(dbref executor, dbref caller, dbref enactor, int eval, int key, char *message) { UNUSED_PARAMETER(key); char *str, *buf, *bp; buf = bp = alloc_lbuf("do_think"); str = message; mux_exec(buf, &bp, executor, caller, enactor, eval|EV_FCHECK|EV_EVAL|EV_TOP, &str, NULL, 0); *bp = '\0'; notify(executor, buf); free_lbuf(buf); } void do_say(dbref executor, dbref caller, dbref enactor, int eval, int key, char *message) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); // Make sure speaker is somewhere if speaking in a place // dbref loc = where_is(executor); if ( !( Good_obj(loc) && sp_ok(executor))) { return; } int say_flags, depth; // Convert prefix-coded messages into the normal type // say_flags = key & (SAY_NOEVAL | SAY_NOTAG | SAY_HERE | SAY_ROOM | SAY_HTML); key &= ~(SAY_NOEVAL | SAY_NOTAG | SAY_HERE | SAY_ROOM | SAY_HTML); if (key == SAY_PREFIX) { switch (*message) { case '"': message++; key = SAY_SAY; break; case ':': message++; if (*message == ' ') { message++; key = SAY_POSE_NOSPC; } else { key = SAY_POSE; } break; case ';': message++; key = SAY_POSE_NOSPC; break; case '\\': message++; // FALLTHROUGH // default: key = SAY_EMIT; break; } } char *command = (char *)""; if (SAY_SAY == key) { command = (char *)"say"; } else if (SAY_POSE == key || SAY_POSE_NOSPC == key) { command = (char *)"pose"; } else if (SAY_EMIT == key) { command = (char *)"@emit"; } // Parse speechmod if present. // char *messageOrig = message; char *messageNew = NULL; if (!(say_flags & SAY_NOEVAL)) { messageNew = modSpeech(executor, message, true, command); if (messageNew) { message = messageNew; } } // Send the message on its way // char *saystring; switch (key) { case SAY_SAY: saystring = modSpeech(executor, messageOrig, false, command); if (saystring) { notify_saypose(executor, tprintf("%s %s \"%s\"", Moniker(executor), saystring, message)); #ifdef REALITY_LVLS notify_except_rlevel(loc, executor, executor, tprintf("%s %s \"%s\"", Moniker(executor), saystring, message), MSG_SAYPOSE); #else notify_except(loc, executor, executor, tprintf("%s %s \"%s\"", Moniker(executor), saystring, message), MSG_SAYPOSE); #endif free_lbuf(saystring); } else { notify_saypose(executor, tprintf("You say, \"%s\"", message)); #ifdef REALITY_LVLS notify_except_rlevel(loc, executor, executor, tprintf("%s says, \"%s\"", Moniker(executor), message), MSG_SAYPOSE); #else notify_except(loc, executor, executor, tprintf("%s says, \"%s\"", Moniker(executor), message), MSG_SAYPOSE); #endif } break; case SAY_POSE: #ifdef REALITY_LVLS notify_except_rlevel(loc, executor, -1, tprintf("%s %s", Moniker(executor), message), MSG_SAYPOSE); #else notify_all_from_inside_saypose(loc, executor, tprintf("%s %s", Moniker(executor), message)); #endif break; case SAY_POSE_NOSPC: #ifdef REALITY_LVLS notify_except_rlevel(loc, executor, -1, tprintf("%s%s", Moniker(executor), message), MSG_SAYPOSE); #else notify_all_from_inside_saypose(loc, executor, tprintf("%s%s", Moniker(executor), message)); #endif break; case SAY_EMIT: if ( (say_flags & SAY_HERE) || (say_flags & SAY_HTML) || !say_flags) { if (say_flags & SAY_HTML) { notify_all_from_inside_html(loc, executor, message); } else { #ifdef REALITY_LVLS notify_except_rlevel(loc, executor, -1, message, SAY_EMIT); #else notify_all_from_inside(loc, executor, message); #endif } } if (say_flags & SAY_ROOM) { if ( isRoom(loc) && (say_flags & SAY_HERE)) { if (messageNew) { free_lbuf(messageNew); } return; } for (depth = 0; !isRoom(loc) && (depth < 20); depth++) { loc = Location(loc); if ( !Good_obj(loc) || (loc == Location(loc))) { if (messageNew) { free_lbuf(messageNew); } return; } } if (isRoom(loc)) { #ifdef REALITY_LVLS notify_except_rlevel(loc, executor, -1, message, -1); #else notify_all_from_inside(loc, executor, message); #endif } } break; } if (messageNew) { free_lbuf(messageNew); } } void do_shout(dbref executor, dbref caller, dbref enactor, int eval, int key, char *message) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); char *p; char *buf2, *bp; int say_flags = key & (SAY_NOTAG | SAY_HERE | SAY_ROOM | SAY_HTML); key &= ~(SAY_NOTAG | SAY_HERE | SAY_ROOM | SAY_HTML); // Parse speechmod if present. // char *messageNew = modSpeech(executor, message, true, (char *)"@wall"); if (messageNew) { message = messageNew; } switch (key) { case SHOUT_SHOUT: switch (*message) { case ':': message[0] = ' '; say_shout(0, announce_msg, say_flags, executor, message); break; case ';': message++; say_shout(0, announce_msg, say_flags, executor, message); break; case '"': message++; default: buf2 = alloc_lbuf("do_shout.shout"); bp = buf2; safe_str(" shouts, \"", buf2, &bp); safe_str(message, buf2, &bp); safe_chr('"', buf2, &bp); *bp = '\0'; say_shout(0, announce_msg, say_flags, executor, buf2); free_lbuf(buf2); } STARTLOG(LOG_SHOUTS, "WIZ", "SHOUT"); log_name(executor); log_text(" shouts: "); log_text(message); ENDLOG; break; case SHOUT_WIZSHOUT: switch (*message) { case ':': message[0] = ' '; say_shout(SHOUT_WIZARD, broadcast_msg, say_flags, executor, message); break; case ';': message++; say_shout(SHOUT_WIZARD, broadcast_msg, say_flags, executor, message); break; case '"': message++; default: buf2 = alloc_lbuf("do_shout.wizshout"); bp = buf2; safe_str(" says, \"", buf2, &bp); safe_str(message, buf2, &bp); safe_chr('"', buf2, &bp); *bp = '\0'; say_shout(SHOUT_WIZARD, broadcast_msg, say_flags, executor, buf2); free_lbuf(buf2); } STARTLOG(LOG_SHOUTS, "WIZ", "BCAST"); log_name(executor); log_text(" broadcasts: '"); log_text(message); log_text("'"); ENDLOG; break; case SHOUT_ADMINSHOUT: switch (*message) { case ':': message[0] = ' '; say_shout(SHOUT_ADMIN, admin_msg, say_flags, executor, message); break; case ';': message++; say_shout(SHOUT_ADMIN, admin_msg, say_flags, executor, message); break; case '"': message++; default: buf2 = alloc_lbuf("do_shout.adminshout"); bp = buf2; safe_str(" says, \"", buf2, &bp); safe_str(message, buf2, &bp); safe_chr('"', buf2, &bp); *bp = '\0'; say_shout(SHOUT_ADMIN, admin_msg, say_flags, executor, buf2); free_lbuf(buf2); } STARTLOG(LOG_SHOUTS, "WIZ", "ASHOUT"); log_name(executor); log_text(" yells: "); log_text(message); ENDLOG; break; case SHOUT_WALLPOSE: if (say_flags & SAY_NOTAG) { p = tprintf("%s %s", Moniker(executor), message); } else { p = tprintf("Announcement: %s %s", Moniker(executor), message); } wall_broadcast(0, executor, p); STARTLOG(LOG_SHOUTS, "WIZ", "SHOUT"); log_name(executor); log_text(" WALLposes: "); log_text(message); ENDLOG; break; case SHOUT_WIZPOSE: if (say_flags & SAY_NOTAG) { p = tprintf("%s %s", Moniker(executor), message); } else { p = tprintf("Broadcast: %s %s", Moniker(executor), message); } wall_broadcast(SHOUT_WIZARD, executor, p); STARTLOG(LOG_SHOUTS, "WIZ", "BCAST"); log_name(executor); log_text(" WIZposes: "); log_text(message); ENDLOG; break; case SHOUT_WALLEMIT: if (say_flags & SAY_NOTAG) { p = tprintf("%s", message); } else { p = tprintf("Announcement: %s", message); } wall_broadcast(0, executor, p); STARTLOG(LOG_SHOUTS, "WIZ", "SHOUT"); log_name(executor); log_text(" WALLemits: "); log_text(message); ENDLOG; break; case SHOUT_WIZEMIT: if (say_flags & SAY_NOTAG) { p = tprintf("%s", message); } else { p = tprintf("Broadcast: %s", message); } wall_broadcast(SHOUT_WIZARD, executor, p); STARTLOG(LOG_SHOUTS, "WIZ", "BCAST"); log_name(executor); log_text(" WIZemit: "); log_text(message); ENDLOG; break; } if (messageNew) { free_lbuf(messageNew); } } /* --------------------------------------------------------------------------- * do_page: Handle the page command. * Page-pose code from shadow@prelude.cc.purdue. */ static void page_return(dbref player, dbref target, const char *tag, int anum, const char *dflt) { if (MuxAlarm.bAlarmed) { return; } dbref aowner; int aflags; char *str, *str2, *buf, *bp; str = atr_pget(target, anum, &aowner, &aflags); if (*str) { str2 = bp = alloc_lbuf("page_return"); buf = str; mux_exec(str2, &bp, target, player, player, AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP|EV_NO_LOCATION), &buf, NULL, 0); *bp = '\0'; if (*str2) { CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); FIELDEDTIME ft; ltaNow.ReturnFields(&ft); char *p = tprintf("%s message from %s: %s", tag, Moniker(target), str2); notify_with_cause_ooc(player, target, p); p = tprintf("[%d:%02d] %s message sent to %s.", ft.iHour, ft.iMinute, tag, Moniker(player)); notify_with_cause_ooc(target, player, p); } free_lbuf(str2); } else if (dflt && *dflt) { notify_with_cause_ooc(player, target, dflt); } free_lbuf(str); } static bool page_check(dbref player, dbref target) { if (!payfor(player, Guest(player) ? 0 : mudconf.pagecost)) { notify(player, tprintf("You don't have enough %s.", mudconf.many_coins)); } else if (!Connected(target)) { page_return(player, target, "Away", A_AWAY, tprintf("Sorry, %s is not connected.", Moniker(target))); } else if (!could_doit(player, target, A_LPAGE)) { if ( Can_Hide(target) && Hidden(target) && !See_Hidden(player)) { page_return(player, target, "Away", A_AWAY, tprintf("Sorry, %s is not connected.", Moniker(target))); } else { page_return(player, target, "Reject", A_REJECT, tprintf("Sorry, %s is not accepting pages.", Moniker(target))); } } else if (!could_doit(target, player, A_LPAGE)) { char *p; if (Wizard(player)) { p = tprintf("Warning: %s can't return your page.", Moniker(target)); notify(player, p); return true; } else { p = tprintf("Sorry, %s can't return your page.", Moniker(target)); notify(player, p); return false; } } else { return true; } return false; } // The combinations are: // // nargs arg1[0] arg2[0] // '' 1 '\0' '\0' Report LastPaged to player. // 'a' 1 'a' '\0' Page LastPaged with A // 'a=' 2 'a' '\0' Page A. LastPaged <- A // '=b' 2 '\0' 'b' Page LastPaged with B // 'a=b' 2 'a' 'b' Page A with B. LastPaged <- A // 'a=b1=[b2=]*...' All treated the same as 'a=b'. // void do_page ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *arg1, char *arg2 ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); int nPlayers = 0; dbref aPlayers[(LBUF_SIZE+1)/2]; // Either we have been given a recipient list, or we are relying on an // existing A_LASTPAGE. // bool bModified = false; if ( nargs == 2 && arg1[0] != '\0') { bModified = true; char *p = arg1; while (*p != '\0') { char *q = strchr(p, '"'); if (q) { *q = '\0'; } // Decode space-delimited or comma-delimited recipients. // MUX_STRTOK_STATE tts; mux_strtok_src(&tts, p); mux_strtok_ctl(&tts, ", "); char *r; for (r = mux_strtok_parse(&tts); r; r = mux_strtok_parse(&tts)) { dbref target = lookup_player(executor, r, true); if (target != NOTHING) { aPlayers[nPlayers++] = target; } else { notify(executor, tprintf("I don't recognize \"%s\".", r)); } } if (q) { p = q + 1; // Handle quoted named. // q = strchr(p, '"'); if (q) { *q = '\0'; } dbref target = lookup_player(executor, p, true); if (target != NOTHING) { aPlayers[nPlayers++] = target; } else { notify(executor, tprintf("I don't recognize \"%s\".", p)); } if (q) { p = q + 1; } else { break; } } else { break; } } } else { // Need to decode the A_LASTPAGE. // dbref aowner; int aflags; char *pLastPage = atr_get(executor, A_LASTPAGE, &aowner, &aflags); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, pLastPage); mux_strtok_ctl(&tts, " "); char *p; for (p = mux_strtok_parse(&tts); p; p = mux_strtok_parse(&tts)) { dbref target = mux_atol(p); if ( Good_obj(target) && isPlayer(target)) { aPlayers[nPlayers++] = target; } else { notify(executor, tprintf("I don't recognize #%d.", target)); bModified = true; } } free_lbuf(pLastPage); } int nValid = nPlayers; // Remove duplicate dbrefs. // int i; for (i = 0; i < nPlayers-1; i++) { if (aPlayers[i] != NOTHING) { int j; for (j = i+1; j < nPlayers; j++) { if (aPlayers[j] == aPlayers[i]) { aPlayers[j] = NOTHING; bModified = true; nValid--; } } } } // If we are doing more than reporting, we have some other dbref // validation to do. // if ( nargs == 2 || arg1[0] != '\0') { for (i = 0; i < nPlayers; i++) { if ( Good_obj(aPlayers[i]) && !page_check(executor, aPlayers[i])) { aPlayers[i] = NOTHING; bModified = true; nValid--; } } } if (bModified) { // Our aPlayers could be different than the one encoded on A_LASTPAGE. // Update the database. // ITL itl; char *pBuff = alloc_lbuf("do_page.lastpage"); char *pBufc = pBuff; ItemToList_Init(&itl, pBuff, &pBufc); for (i = 0; i < nPlayers; i++) { if ( Good_obj(aPlayers[i]) && !ItemToList_AddInteger(&itl, aPlayers[i])) { break; } } ItemToList_Final(&itl); atr_add_raw(executor, A_LASTPAGE, pBuff); free_lbuf(pBuff); } // Verify that the recipient list isn't empty. // if (nValid == 0) { if ( nargs == 1 && arg1[0] == '\0') { notify(executor, "You have not paged anyone."); } else { notify(executor, "No one to page."); } return; } // Build a friendly representation of the recipient list. // char *aFriendly = alloc_lbuf("do_page.friendly"); char *pFriendly = aFriendly; if (nValid > 1) { safe_chr('(', aFriendly, &pFriendly); } bool bFirst = true; for (i = 0; i < nPlayers; i++) { if (aPlayers[i] != NOTHING) { if (bFirst) { bFirst = false; } else { safe_copy_buf(", ", 2, aFriendly, &pFriendly); } safe_str(Moniker(aPlayers[i]), aFriendly, &pFriendly); } } if (nValid > 1) { safe_chr(')', aFriendly, &pFriendly); } *pFriendly = '\0'; // We may be able to proceed directly to the reporting case. // if ( nargs == 1 && arg1[0] == '\0') { notify(executor, tprintf("You last paged %s.", aFriendly)); free_lbuf(aFriendly); return; } // Build messages. // char *omessage = alloc_lbuf("do_page.omessage"); char *imessage = alloc_lbuf("do_page.imessage"); char *omp = omessage; char *imp = imessage; char *pMessage; if (nargs == 1) { // 'page A' form. // pMessage = arg1; } else { // 'page A=', 'page =B', and 'page A=B' forms. // pMessage = arg2; } int pageMode; switch (*pMessage) { case '\0': pageMode = 1; break; case ':': pMessage++; if (' ' != *pMessage) { pageMode = 2; break; } // FALL THROUGH case ';': pageMode = 3; pMessage++; break; case '"': pMessage++; // FALL THROUGH default: pageMode = 0; } char *newMessage = modSpeech(executor, pMessage, true, (char *)"page"); if (newMessage) { pMessage = newMessage; } switch (pageMode) { case 1: // 'page A=' form. // if (nValid == 1) { safe_tprintf_str(omessage, &omp, "From afar, %s pages you.", Moniker(executor)); } else { safe_tprintf_str(omessage, &omp, "From afar, %s pages %s.", Moniker(executor), aFriendly); } safe_tprintf_str(imessage, &imp, "You page %s.", aFriendly); break; case 2: safe_str("From afar, ", omessage, &omp); if (nValid > 1) { safe_tprintf_str(omessage, &omp, "to %s: ", aFriendly); } safe_tprintf_str(omessage, &omp, "%s %s", Moniker(executor), pMessage); safe_tprintf_str(imessage, &imp, "Long distance to %s: %s %s", aFriendly, Moniker(executor), pMessage); break; case 3: safe_str("From afar, ", omessage, &omp); if (nValid > 1) { safe_tprintf_str(omessage, &omp, "to %s: ", aFriendly); } safe_tprintf_str(omessage, &omp, "%s%s", Moniker(executor), pMessage); safe_tprintf_str(imessage, &imp, "Long distance to %s: %s%s", aFriendly, Moniker(executor), pMessage); break; default: if (nValid > 1) { safe_tprintf_str(omessage, &omp, "To %s, ", aFriendly); } safe_tprintf_str(omessage, &omp, "%s pages: %s", Moniker(executor), pMessage); safe_tprintf_str(imessage, &imp, "You paged %s with '%s'", aFriendly, pMessage); break; } free_lbuf(aFriendly); // Send message to recipients. // for (i = 0; i < nPlayers; i++) { dbref target = aPlayers[i]; if (target != NOTHING) { notify_with_cause_ooc(target, executor, omessage); int target_idle = fetch_idle(target); int target_idle_timeout_val = idle_timeout_val(target); if (target_idle >= target_idle_timeout_val) { page_return(executor, target, "Idle", A_IDLE, NULL); } } } free_lbuf(omessage); // Send message to sender. // notify(executor, imessage); free_lbuf(imessage); if (newMessage) { free_lbuf(newMessage); } } /* --------------------------------------------------------------------------- * do_pemit: Messages to specific players, or to all but specific players. */ static void whisper_pose(dbref player, dbref target, char *message, bool bSpace) { char *newMessage = modSpeech(player, message, true, (char *)"whisper"); if (newMessage) { message = newMessage; } char *buff = alloc_lbuf("do_pemit.whisper.pose"); mux_strncpy(buff, Moniker(player), LBUF_SIZE-1); notify(player, tprintf("%s senses \"%s%s%s\"", Moniker(target), buff, bSpace ? " " : "", message)); notify_with_cause(target, player, tprintf("You sense %s%s%s", buff, bSpace ? " " : "", message)); free_lbuf(buff); if (newMessage) { free_lbuf(newMessage); } } void do_pemit_single ( dbref player, int key, bool bDoContents, int pemit_flags, char *recipient, int chPoseType, char *message ) { dbref target, loc; char *buf2, *bp; int depth; bool ok_to_do = false; switch (key) { case PEMIT_FSAY: case PEMIT_FPOSE: case PEMIT_FPOSE_NS: case PEMIT_FEMIT: target = match_controlled(player, recipient); if (target == NOTHING) { return; } ok_to_do = true; break; default: init_match(player, recipient, TYPE_PLAYER); match_everything(0); target = match_result(); } char *newMessage = NULL; char *saystring = NULL; char *p; switch (target) { case NOTHING: switch (key) { case PEMIT_WHISPER: notify(player, "Whisper to whom?"); break; case PEMIT_PEMIT: notify(player, "Emit to whom?"); break; case PEMIT_OEMIT: notify(player, "Emit except to whom?"); break; default: notify(player, "Sorry."); break; } break; case AMBIGUOUS: notify(player, "I don't know who you mean!"); break; default: // Enforce locality constraints. // if ( !ok_to_do && ( nearby(player, target) || Long_Fingers(player) || Controls(player, target))) { ok_to_do = true; } if ( !ok_to_do && key == PEMIT_PEMIT && isPlayer(target) && mudconf.pemit_players) { if (!page_check(player, target)) { return; } ok_to_do = true; } if ( !ok_to_do && ( !mudconf.pemit_any || key != PEMIT_PEMIT)) { notify(player, "You are too far away to do that."); return; } if ( bDoContents && !Controls(player, target) && !mudconf.pemit_any) { notify(player, NOPERM_MESSAGE); return; } loc = where_is(target); switch (key) { case PEMIT_PEMIT: if (bDoContents) { if (Has_contents(target)) { notify_all_from_inside(target, player, message); } } else { if (pemit_flags & PEMIT_HTML) { notify_with_cause_html(target, player, message); } else { notify_with_cause(target, player, message); } } break; case PEMIT_OEMIT: notify_except(Location(target), player, target, message, 0); break; case PEMIT_WHISPER: if ( isPlayer(target) && !Connected(target)) { page_return(player, target, "Away", A_AWAY, tprintf("Sorry, %s is not connected.", Moniker(target))); return; } switch (chPoseType) { case ':': message++; whisper_pose(player, target, message, true); break; case ';': message++; whisper_pose(player, target, message, false); break; case '"': message++; default: newMessage = modSpeech(player, message, true, (char *)"whisper"); if (newMessage) { message = newMessage; } notify(player, tprintf("You whisper \"%s\" to %s.", message, Moniker(target))); notify_with_cause(target, player, tprintf("%s whispers \"%s\"", Moniker(player), message)); if (newMessage) { free_lbuf(newMessage); } } if ( !mudconf.quiet_whisper && !Wizard(player)) { loc = where_is(player); if (loc != NOTHING) { buf2 = alloc_lbuf("do_pemit.whisper.buzz"); bp = buf2; safe_str(Moniker(player), buf2, &bp); safe_str(" whispers something to ", buf2, &bp); safe_str(Moniker(target), buf2, &bp); *bp = '\0'; notify_except2(loc, player, player, target, buf2); free_lbuf(buf2); } } break; case PEMIT_FSAY: newMessage = modSpeech(target, message, true, (char *)"@fsay"); if (newMessage) { message = newMessage; } notify(target, tprintf("You say, \"%s\"", message)); if (loc != NOTHING) { saystring = modSpeech(target, message, false, (char *)"@fsay"); if (saystring) { p = tprintf("%s %s \"%s\"", Moniker(target), saystring, message); notify_except(loc, player, target, p, 0); } else { p = tprintf("%s says, \"%s\"", Moniker(target), message); notify_except(loc, player, target, p, 0); } } if (saystring) { free_lbuf(saystring); } if (newMessage) { free_lbuf(newMessage); } break; case PEMIT_FPOSE: newMessage = modSpeech(target, message, true, (char *)"@fpose"); if (newMessage) { message = newMessage; } p = tprintf("%s %s", Moniker(target), message); notify_all_from_inside(loc, player, p); if (newMessage) { free_lbuf(newMessage); } break; case PEMIT_FPOSE_NS: newMessage = modSpeech(target, message, true, (char *)"@fpose"); if (newMessage) { message = newMessage; } p = tprintf("%s%s", Moniker(target), message); notify_all_from_inside(loc, player, p); if (newMessage) { free_lbuf(newMessage); } break; case PEMIT_FEMIT: if ( (pemit_flags & PEMIT_HERE) || !pemit_flags) { notify_all_from_inside(loc, player, message); } if (pemit_flags & PEMIT_ROOM) { if ( isRoom(loc) && (pemit_flags & PEMIT_HERE)) { return; } depth = 0; while ( !isRoom(loc) && depth++ < 20) { loc = Location(loc); if ( loc == NOTHING || loc == Location(loc)) { return; } } if (isRoom(loc)) { notify_all_from_inside(loc, player, message); } } break; } } } void do_pemit_list ( dbref player, int key, bool bDoContents, int pemit_flags, char *list, int chPoseType, char *message ) { // Send a message to a list of dbrefs. The list is destructively // modified. // if ( message[0] == '\0' || list[0] == '\0') { return; } char *p; MUX_STRTOK_STATE tts; mux_strtok_src(&tts, list); mux_strtok_ctl(&tts, " "); for (p = mux_strtok_parse(&tts); p; p = mux_strtok_parse(&tts)) { do_pemit_single(player, key, bDoContents, pemit_flags, p, chPoseType, message); } } void do_pemit ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *recipient, char *message ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); if (nargs < 2) { return; } // Decode PEMIT_CONENTS and PEMIT_LIST and remove from key. // bool bDoContents = false; if (key & PEMIT_CONTENTS) { bDoContents = true; } bool bDoList = false; if (key & PEMIT_LIST) { bDoList = true; } key &= ~(PEMIT_CONTENTS | PEMIT_LIST); // Decode PEMIT_HERE, PEMIT_ROOM, PEMIT_HTML and remove from key. // int mask = PEMIT_HERE | PEMIT_ROOM | PEMIT_HTML; int pemit_flags = key & mask; key &= ~mask; int chPoseType = *message; if (key == PEMIT_WHISPER && chPoseType == ':') { message[0] = ' '; } if (bDoList) { do_pemit_list(executor, key, bDoContents, pemit_flags, recipient, chPoseType, message); } else { do_pemit_single(executor, key, bDoContents, pemit_flags, recipient, chPoseType, message); } } mux2.6/src/functions.h0000600000175000017500000001366211025753746014767 0ustar sdennissdennis// functions.h -- declarations for functions & function processing. // // $Id: functions.h 2734 2007-10-28 23:02:55Z brazilofmux $ // #include "copyright.h" #ifndef __FUNCTIONS_H #define __FUNCTIONS_H typedef struct tagFun { const char *name; // function name void (*fun)(char *buff, char **bufc, dbref executor, dbref caller, dbref enactor, int eval, char *fargs[], int nfargs, char *cargs[], int ncargs); // handler int maxArgsParsed;// Maximum number of arguments parsed. int minArgs; // Minimum number of args needed or expected int maxArgs; // Maximum number of arguments permitted int flags; // Function flags int perms; // Access to function } FUN; typedef struct ufun { char *name; /* function name */ dbref obj; /* Object ID */ int atr; /* Attribute ID */ int flags; /* Function flags */ int perms; /* Access to function */ struct ufun *next; /* Next ufun in chain */ } UFUN; #define FN_NOEVAL 2 // Don't evaluate args to function. #define FN_PRIV 4 // Perform user-def function as holding obj. #define FN_PRES 8 // Preseve r-regs before user-def functions. #define FN_LIST 1 // Corresponds to /list switch. -not- used in // UFUN structure. void init_functab(void); void list_functable(dbref); extern UFUN *ufun_head; /* Special handling of separators. */ #define print_sep(ps,b,p) safe_copy_buf((ps)->str,(ps)->n,(b),(p)) #define MAX_SEP_LEN 50 typedef struct { size_t n; char str[MAX_SEP_LEN+1]; } SEP; extern SEP sepSpace; // dflags in delim_check() accepts the following options. // #define DELIM_DFLT 0x0000 // Default processing. #define DELIM_EVAL 0x0001 // Evaluate delimiter. #define DELIM_NULL 0x0002 // Allow '@@'. #define DELIM_CRLF 0x0004 // Allow '%r'. #define DELIM_STRING 0x0008 // Multi-character. #define DELIM_INIT 0x0010 // The sep is initialized. bool delim_check ( char *buff, char **bufc, dbref executor, dbref caller, dbref enactor, int eval, char *fargs[], int nfargs, char *cargs[], int ncargs, int sep_arg, SEP *sep, int dflags ); void arr2list(char *arr[], int alen, char *list, char **bufc, SEP *psep); int list2arr(char *arr[], int maxlen, char *list, SEP *psep); char *trim_space_sep(char *str, SEP *psep); char *trim_space_sep_LEN(char *str, size_t nStr, SEP *psep, size_t *nTrim); char *next_token(char *str, SEP *psep); char *split_token(char **sp, SEP *psep); int countwords(char *str, SEP *psep); // This is the prototype for functions // #define FUNCTION(x) \ void x(char *buff, char **bufc, dbref executor, dbref caller, \ dbref enactor, int eval, char *fargs[], int nfargs, \ char *cargs[], int ncargs) // This is for functions that take an optional delimiter character. // #define OPTIONAL_DELIM(iSep, Sep, dflags) \ delim_check(buff, bufc, executor, caller, enactor, eval, \ fargs, nfargs, cargs, ncargs, (iSep), &(Sep), (dflags)) #define XFUNCTION(x) void x(char *buff, char **bufc, dbref executor, \ dbref caller, dbref enactor, int eval, char *fargs[], int nfargs, \ char *cargs[], int ncargs) // Interface for adding additional hardcode functions. // void function_add(FUN *fp); void functions_add(FUN funlist[]); // Function definitions from funceval.cpp // // In comsys.cpp XFUNCTION(fun_channels); XFUNCTION(fun_comalias); XFUNCTION(fun_comtitle); // In funceval.cpp XFUNCTION(fun_alphamax); XFUNCTION(fun_alphamin); XFUNCTION(fun_andflags); XFUNCTION(fun_ansi); XFUNCTION(fun_beep); XFUNCTION(fun_children); XFUNCTION(fun_columns); XFUNCTION(fun_cwho); XFUNCTION(fun_decrypt); XFUNCTION(fun_default); XFUNCTION(fun_die); XFUNCTION(fun_dumping); XFUNCTION(fun_edefault); XFUNCTION(fun_elements); XFUNCTION(fun_encrypt); XFUNCTION(fun_entrances); XFUNCTION(fun_fcount); XFUNCTION(fun_fdepth); XFUNCTION(fun_findable); XFUNCTION(fun_foreach); XFUNCTION(fun_grab); XFUNCTION(fun_graball); XFUNCTION(fun_grep); XFUNCTION(fun_grepi); XFUNCTION(fun_hasattr); XFUNCTION(fun_hasattrp); XFUNCTION(fun_hastype); XFUNCTION(fun_ifelse); XFUNCTION(fun_inzone); XFUNCTION(fun_isword); XFUNCTION(fun_last); XFUNCTION(fun_lit); XFUNCTION(fun_localize); XFUNCTION(fun_lparent); XFUNCTION(fun_lrand); XFUNCTION(fun_lrooms); XFUNCTION(fun_mail); XFUNCTION(fun_mailfrom); #if defined(FIRANMUX) XFUNCTION(fun_mailj); XFUNCTION(fun_mailsize); XFUNCTION(fun_mailsubj); #endif XFUNCTION(fun_matchall); XFUNCTION(fun_mix); XFUNCTION(fun_munge); XFUNCTION(fun_null); XFUNCTION(fun_objeval); XFUNCTION(fun_objmem); XFUNCTION(fun_orflags); XFUNCTION(fun_pack); XFUNCTION(fun_pickrand); XFUNCTION(fun_playmem); XFUNCTION(fun_ports); XFUNCTION(fun_regmatch); XFUNCTION(fun_regmatchi); XFUNCTION(fun_regrab); XFUNCTION(fun_regraball); XFUNCTION(fun_regraballi); XFUNCTION(fun_regrabi); XFUNCTION(fun_scramble); XFUNCTION(fun_shuffle); XFUNCTION(fun_sortby); XFUNCTION(fun_squish); XFUNCTION(fun_step); XFUNCTION(fun_strcat); XFUNCTION(fun_stripansi); XFUNCTION(fun_strtrunc); XFUNCTION(fun_table); XFUNCTION(fun_translate); XFUNCTION(fun_udefault); XFUNCTION(fun_unpack); XFUNCTION(fun_valid); XFUNCTION(fun_visible); XFUNCTION(fun_zfun); XFUNCTION(fun_zone); XFUNCTION(fun_zwho); #ifdef DEPRECATED XFUNCTION(fun_empty); XFUNCTION(fun_items); XFUNCTION(fun_lstack); XFUNCTION(fun_peek); XFUNCTION(fun_pop); XFUNCTION(fun_push); #endif // DEPRECATED #ifdef SIDE_EFFECT_FUNCTIONS XFUNCTION(fun_create); XFUNCTION(fun_emit); XFUNCTION(fun_link); XFUNCTION(fun_oemit); XFUNCTION(fun_pemit); XFUNCTION(fun_remit); XFUNCTION(fun_cemit); XFUNCTION(fun_set); XFUNCTION(fun_tel); XFUNCTION(fun_textfile); #if defined(FIRANMUX) XFUNCTION(fun_setparent); XFUNCTION(fun_setname); XFUNCTION(fun_trigger); #endif // FIRANMUX #endif // In netcommon.cpp XFUNCTION(fun_doing); XFUNCTION(fun_host); XFUNCTION(fun_motd); XFUNCTION(fun_poll); XFUNCTION(fun_siteinfo); // In quota.cpp XFUNCTION(fun_hasquota); #endif // !__FUNCTIONS_H mux2.6/src/alloc.cpp0000600000175000017500000004534111025753746014403 0ustar sdennissdennis/*! \file alloc.cpp * Memory Allocation Subsystem. * * $Id: alloc.cpp 492 2006-11-30 17:12:25Z brazilofmux $ * * The functions here manage pools of often-used buffers of fixed-size. It * adds value by greatly reducing the number and strength of calls to the * underlying platform's memory management. It also adds headers and footer to * detect misuse of buffers by its callers. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" // Do not use the following structure. It is only used to define the // POOLHDR that follows. The fields in the following structure must // match POOLHDR in type and order. Doing it this way is a workaround // for compilers not supporting #pragma pack(sizeof(INT64)). // typedef struct pool_header_unaligned { unsigned int magicnum; // For consistency check size_t pool_size; // For consistency check struct pool_header *next; // Next pool header in chain struct pool_header *nxtfree; // Next pool header in freelist char *buf_tag; // Debugging/trace tag } POOLHDR_UNALIGNED; // The following structure is 64-bit aligned. The fields in the // following structure must match POOLHDR_UNALIGNED in type and // order. // typedef struct pool_header { unsigned int magicnum; // For consistency check size_t pool_size; // For consistency check struct pool_header *next; // Next pool header in chain struct pool_header *nxtfree; // Next pool header in freelist char *buf_tag; // Debugging/trace tag char PaddingTo64bits[7 - ((sizeof(POOLHDR_UNALIGNED)-1) & 7)]; } POOLHDR; typedef struct pool_footer { unsigned int magicnum; // For consistency check } POOLFTR; typedef struct pooldata { size_t pool_client_size; // Size in bytes of a buffer as seen by client. size_t pool_alloc_size; // Size as allocated from system. unsigned int poolmagic; // Magic number specific to this pool POOLHDR *free_head; // Buffer freelist head POOLHDR *chain_head; // Buffer chain head UINT64 tot_alloc; // Total buffers allocated UINT64 num_alloc; // Number of buffers currently allocated UINT64 max_alloc; // Max # buffers allocated at one time UINT64 num_lost; // Buffers lost due to corruption } POOL; static POOL pools[NUM_POOLS]; static const char *poolnames[] = { "Lbufs", "Sbufs", "Mbufs", "Bools", "Descs", "Qentries", "Pcaches", "Lbufrefs", "Regrefs" }; void pool_init(int poolnum, int poolsize) { pools[poolnum].pool_client_size = poolsize; pools[poolnum].pool_alloc_size = poolsize + sizeof(POOLHDR) + sizeof(POOLFTR); mux_assert(pools[poolnum].pool_client_size < pools[poolnum].pool_alloc_size); pools[poolnum].poolmagic = CRC32_ProcessInteger2(poolnum, poolsize); pools[poolnum].free_head = NULL; pools[poolnum].chain_head = NULL; pools[poolnum].tot_alloc = 0; pools[poolnum].num_alloc = 0; pools[poolnum].max_alloc = 0; pools[poolnum].num_lost = 0; } static void pool_err ( const char *logsys, int logflag, int poolnum, const char *tag, POOLHDR *ph, const char *action, const char *reason, const char *file, const int line ) { if (mudstate.logging == 0) { STARTLOG(logflag, logsys, "ALLOC"); Log.tinyprintf("%s[%d] (tag %s) %s in %s line %d at %lx. (%s)", action, pools[poolnum].pool_client_size, tag, reason, file, line, (long)ph, mudstate.debug_cmd); ENDLOG; } else if (logflag != LOG_ALLOCATE) { Log.tinyprintf(ENDLINE "***< %s[%d] (tag %s) %s in %s line %d at %lx. >***", action, pools[poolnum].pool_client_size, tag, reason, file, line, (long)ph); } } static void pool_vfy(int poolnum, const char *tag, const char *file, const int line) { POOLHDR *ph, *lastph; POOLFTR *pf; char *h; lastph = NULL; size_t psize = pools[poolnum].pool_client_size; for (ph = pools[poolnum].chain_head; ph; lastph = ph, ph = ph->next) { h = (char *)ph; h += sizeof(POOLHDR); h += pools[poolnum].pool_client_size; pf = (POOLFTR *) h; if (ph->magicnum != pools[poolnum].poolmagic) { pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Verify", "header corrupted (clearing freelist)", file, line); // Break the header chain at this point so we don't // generate an error for EVERY alloc and free, also we // can't continue the scan because the next pointer might // be trash too. // if (lastph) { lastph->next = NULL; } else { pools[poolnum].chain_head = NULL; } // It's not safe to continue. // return; } if (pf->magicnum != pools[poolnum].poolmagic) { pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Verify", "footer corrupted", file, line); pf->magicnum = pools[poolnum].poolmagic; } if (ph->pool_size != psize) { pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Verify", "header has incorrect size", file, line); } } } static void pool_check(const char *tag, const char *file, const int line) { int i; for (i = 0; i < NUM_POOLS; i++) { pool_vfy(i, tag, file, line); } } char *pool_alloc(int poolnum, const char *tag, const char *file, const int line) { if (mudconf.paranoid_alloc) { pool_check(tag, file, line); } char *p; POOLFTR *pf; POOLHDR *ph = (POOLHDR *)pools[poolnum].free_head; if ( ph && ph->magicnum == pools[poolnum].poolmagic) { p = (char *)(ph + 1); pf = (POOLFTR *)(p + pools[poolnum].pool_client_size); pools[poolnum].free_head = ph->nxtfree; // Check for corrupted footer, just report and fix it. // if (pf->magicnum != pools[poolnum].poolmagic) { pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Alloc", "corrupted buffer footer", file, line); pf->magicnum = pools[poolnum].poolmagic; } } else { if (ph) { // Header is corrupt. Throw away the freelist and start a new // one. pool_err("BUG", LOG_ALWAYS, poolnum, tag, ph, "Alloc", "corrupted buffer header", file, line); // Start a new free list and record stats. // pools[poolnum].free_head = NULL; pools[poolnum].num_lost += (pools[poolnum].tot_alloc - pools[poolnum].num_alloc); pools[poolnum].tot_alloc = pools[poolnum].num_alloc; } ph = NULL; try { ph = reinterpret_cast(new char[pools[poolnum].pool_alloc_size]); } catch (...) { ; // Nothing. } if (NULL == ph) { ISOUTOFMEMORY(ph); return NULL; } p = (char *)(ph + 1); pf = (POOLFTR *)(p + pools[poolnum].pool_client_size); // Initialize. // ph->next = pools[poolnum].chain_head; ph->nxtfree = NULL; ph->magicnum = pools[poolnum].poolmagic; ph->pool_size = pools[poolnum].pool_client_size; pf->magicnum = pools[poolnum].poolmagic; *((unsigned int *)p) = pools[poolnum].poolmagic; pools[poolnum].chain_head = ph; pools[poolnum].max_alloc++; } ph->buf_tag = (char *)tag; pools[poolnum].tot_alloc++; pools[poolnum].num_alloc++; if ( (LOG_ALLOCATE & mudconf.log_options) && mudstate.logging == 0 && start_log("DBG", "ALLOC")) { Log.tinyprintf("Alloc[%d] (tag %s) in %s line %d buffer at %lx. (%s)", pools[poolnum].pool_client_size, tag, file, line, (long)ph, mudstate.debug_cmd); end_log(); } // If the buffer was modified after it was last freed, log it. // unsigned int *pui = (unsigned int *)p; if (*pui != pools[poolnum].poolmagic) { pool_err("BUG", LOG_PROBLEMS, poolnum, tag, ph, "Alloc", "buffer modified after free", file, line); } *pui = 0; return p; } char *pool_alloc_lbuf(const char *tag, const char *file, const int line) { if (mudconf.paranoid_alloc) { pool_check(tag, file, line); } char *p; POOLFTR *pf; POOLHDR *ph = (POOLHDR *)pools[POOL_LBUF].free_head; if ( ph && ph->magicnum == pools[POOL_LBUF].poolmagic) { p = (char *)(ph + 1); pf = (POOLFTR *)(p + LBUF_SIZE); pools[POOL_LBUF].free_head = ph->nxtfree; // Check for corrupted footer, just report and fix it. // if (pf->magicnum != pools[POOL_LBUF].poolmagic) { pool_err("BUG", LOG_ALWAYS, POOL_LBUF, tag, ph, "Alloc", "corrupted buffer footer", file, line); pf->magicnum = pools[POOL_LBUF].poolmagic; } } else { if (ph) { // Header is corrupt. Throw away the freelist and start a new // one. pool_err("BUG", LOG_ALWAYS, POOL_LBUF, tag, ph, "Alloc", "corrupted buffer header", file, line); // Start a new free list and record stats. // pools[POOL_LBUF].free_head = NULL; pools[POOL_LBUF].num_lost += (pools[POOL_LBUF].tot_alloc - pools[POOL_LBUF].num_alloc); pools[POOL_LBUF].tot_alloc = pools[POOL_LBUF].num_alloc; } ph = NULL; try { ph = reinterpret_cast(new char[LBUF_SIZE + sizeof(POOLHDR) + sizeof(POOLFTR)]); } catch (...) { ; // Nothing. } if (NULL == ph) { ISOUTOFMEMORY(ph); return NULL; } p = (char *)(ph + 1); pf = (POOLFTR *)(p + LBUF_SIZE); // Initialize. // ph->next = pools[POOL_LBUF].chain_head; ph->nxtfree = NULL; ph->magicnum = pools[POOL_LBUF].poolmagic; ph->pool_size = LBUF_SIZE; pf->magicnum = pools[POOL_LBUF].poolmagic; *((unsigned int *)p) = pools[POOL_LBUF].poolmagic; pools[POOL_LBUF].chain_head = ph; pools[POOL_LBUF].max_alloc++; } ph->buf_tag = (char *)tag; pools[POOL_LBUF].tot_alloc++; pools[POOL_LBUF].num_alloc++; if ( (LOG_ALLOCATE & mudconf.log_options) && mudstate.logging == 0 && start_log("DBG", "ALLOC")) { Log.tinyprintf("Alloc[%d] (tag %s) in %s line %d buffer at %lx. (%s)", LBUF_SIZE, tag, file, line, (long)ph, mudstate.debug_cmd); end_log(); } // If the buffer was modified after it was last freed, log it. // unsigned int *pui = (unsigned int *)p; if (*pui != pools[POOL_LBUF].poolmagic) { pool_err("BUG", LOG_PROBLEMS, POOL_LBUF, tag, ph, "Alloc", "buffer modified after free", file, line); } *pui = 0; return p; } void pool_free(int poolnum, char *buf, const char *file, const int line) { if (buf == NULL) { STARTLOG(LOG_PROBLEMS, "BUG", "ALLOC") log_text(tprintf("Attempt to free null pointer in %s line %d.", file, line)); ENDLOG return; } POOLHDR *ph = ((POOLHDR *)(buf)) - 1; POOLFTR *pf = (POOLFTR *)(buf + pools[poolnum].pool_client_size); unsigned int *pui = (unsigned int *)buf; if (mudconf.paranoid_alloc) { pool_check(ph->buf_tag, file, line); } // Make sure the buffer header is good. If it isn't, log the error and // throw away the buffer. // if (ph->magicnum != pools[poolnum].poolmagic) { pool_err("BUG", LOG_ALWAYS, poolnum, ph->buf_tag, ph, "Free", "corrupted buffer header", file, line); pools[poolnum].num_lost++; pools[poolnum].num_alloc--; pools[poolnum].tot_alloc--; return; } // Verify the buffer footer. Don't unlink if damaged, just repair. // if (pf->magicnum != pools[poolnum].poolmagic) { pool_err("BUG", LOG_ALWAYS, poolnum, ph->buf_tag, ph, "Free", "corrupted buffer footer", file, line); pf->magicnum = pools[poolnum].poolmagic; } // Verify that we are not trying to free someone else's buffer. // if (ph->pool_size != pools[poolnum].pool_client_size) { pool_err("BUG", LOG_ALWAYS, poolnum, ph->buf_tag, ph, "Free", "Attempt to free into a different pool.", file, line); return; } if ( (LOG_ALLOCATE & mudconf.log_options) && mudstate.logging == 0 && start_log("DBG", "ALLOC")) { Log.tinyprintf("Free[%d] (tag %s) in %s line %d buffer at %lx. (%s)", pools[poolnum].pool_client_size, ph->buf_tag, file, line, (long)ph, mudstate.debug_cmd); end_log(); } // Make sure we aren't freeing an already free buffer. If we are, log an // error, otherwise update the pool header and stats. // if (*pui == pools[poolnum].poolmagic) { pool_err("BUG", LOG_BUGS, poolnum, ph->buf_tag, ph, "Free", "buffer already freed", file, line); } else { *pui = pools[poolnum].poolmagic; ph->nxtfree = pools[poolnum].free_head; pools[poolnum].free_head = ph; pools[poolnum].num_alloc--; } } void pool_free_lbuf(char *buf, const char *file, const int line) { if (buf == NULL) { STARTLOG(LOG_PROBLEMS, "BUG", "ALLOC") log_text(tprintf("Attempt to free_lbuf null pointer in %s line %d.", file, line)); ENDLOG return; } POOLHDR *ph = ((POOLHDR *)(buf)) - 1; POOLFTR *pf = (POOLFTR *)(buf + LBUF_SIZE); unsigned int *pui = (unsigned int *)buf; if (mudconf.paranoid_alloc) { pool_check(ph->buf_tag, file, line); } if ( ph->magicnum != pools[POOL_LBUF].poolmagic || pf->magicnum != pools[POOL_LBUF].poolmagic || ph->pool_size != LBUF_SIZE || *pui == pools[POOL_LBUF].poolmagic) { if (ph->magicnum != pools[POOL_LBUF].poolmagic) { // The buffer header is damaged. Log the error and throw away the // buffer. // pool_err("BUG", LOG_ALWAYS, POOL_LBUF, ph->buf_tag, ph, "Free", "corrupted buffer header", file, line); pools[POOL_LBUF].num_lost++; pools[POOL_LBUF].num_alloc--; pools[POOL_LBUF].tot_alloc--; return; } else if (pf->magicnum != pools[POOL_LBUF].poolmagic) { // The buffer footer is damaged. Don't unlink, just repair. // pool_err("BUG", LOG_ALWAYS, POOL_LBUF, ph->buf_tag, ph, "Free", "corrupted buffer footer", file, line); pf->magicnum = pools[POOL_LBUF].poolmagic; } else if (ph->pool_size != LBUF_SIZE) { // We are trying to free someone else's buffer. // pool_err("BUG", LOG_ALWAYS, POOL_LBUF, ph->buf_tag, ph, "Free", "Attempt to free into a different pool.", file, line); return; } // If we are freeing a buffer that was already free, report an error. // if (*pui == pools[POOL_LBUF].poolmagic) { pool_err("BUG", LOG_BUGS, POOL_LBUF, ph->buf_tag, ph, "Free", "buffer already freed", file, line); return; } } if ( (LOG_ALLOCATE & mudconf.log_options) && mudstate.logging == 0 && start_log("DBG", "ALLOC")) { Log.tinyprintf("Free[%d] (tag %s) in %s line %d buffer at %lx. (%s)", LBUF_SIZE, ph->buf_tag, file, line, (long)ph, mudstate.debug_cmd); end_log(); } // Update the pool header and stats. // *pui = pools[POOL_LBUF].poolmagic; ph->nxtfree = pools[POOL_LBUF].free_head; pools[POOL_LBUF].free_head = ph; pools[POOL_LBUF].num_alloc--; } static void pool_trace(dbref player, int poolnum, const char *text) { POOLHDR *ph; int numfree = 0; notify(player, tprintf("----- %s -----", text)); for (ph = pools[poolnum].chain_head; ph != NULL; ph = ph->next) { if (ph->magicnum != pools[poolnum].poolmagic) { notify(player, "*** CORRUPTED BUFFER HEADER, ABORTING SCAN ***"); notify(player, tprintf("%d free %s (before corruption)", numfree, text)); return; } char *h = (char *)ph; h += sizeof(POOLHDR); unsigned int *ibuf = (unsigned int *)h; if (*ibuf != pools[poolnum].poolmagic) { notify(player, ph->buf_tag); } else { numfree++; } } notify(player, tprintf("%d free %s", numfree, text)); } void list_bufstats(dbref player) { notify(player, "Buffer Stats Size InUse Total Allocs Lost"); for (int i = 0; i < NUM_POOLS; i++) { char buff[MBUF_SIZE]; char *p = buff; p += LeftJustifyString(p, 12, poolnames[i]); *p++ = ' '; p += RightJustifyNumber(p, 5, pools[i].pool_client_size, ' '); *p++ = ' '; p += RightJustifyNumber(p, 10, pools[i].num_alloc, ' '); *p++ = ' '; p += RightJustifyNumber(p, 10, pools[i].max_alloc, ' '); *p++ = ' '; p += RightJustifyNumber(p, 16, pools[i].tot_alloc, ' '); *p++ = ' '; p += RightJustifyNumber(p, 6, pools[i].num_lost, ' '); *p++ = '\0'; notify(player, buff); } } void list_buftrace(dbref player) { int i; for (i = 0; i < NUM_POOLS; i++) { pool_trace(player, i, poolnames[i]); } } void pool_reset(void) { int i; for (i = 0; i < NUM_POOLS; i++) { POOLHDR *newchain = NULL; POOLHDR *phnext; POOLHDR *ph; for (ph = pools[i].chain_head; ph != NULL; ph = phnext) { char *h = (char *)ph; phnext = ph->next; h += sizeof(POOLHDR); unsigned int *ibuf = (unsigned int *)h; if (*ibuf == pools[i].poolmagic) { char *p = reinterpret_cast(ph); delete [] p; ph = NULL; } else { ph->next = newchain; newchain = ph; ph->nxtfree = NULL; } } pools[i].chain_head = newchain; pools[i].free_head = NULL; pools[i].max_alloc = pools[i].num_alloc; } } mux2.6/src/funceval.cpp0000600000175000017500000033503711025753746015120 0ustar sdennissdennis// funceval.cpp -- MUX function handlers. // // $Id: funceval.cpp 3691 2008-06-01 01:41:19Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include #include #include "ansi.h" #include "attrs.h" #include "command.h" #include "comsys.h" #include "functions.h" #include "misc.h" #include "pcre.h" #include "mail.h" #ifdef REALITY_LVLS #include "levels.h" #endif // REALITY_LVLS /* Note: Many functions in this file have been taken, whole or in part, from * PennMUSH 1.50, and TinyMUSH 2.2, for softcode compatibility. The * maintainers of MUX would like to thank those responsible for PennMUSH 1.50 * and TinyMUSH 2.2, and hope we have adequately noted in the source where * credit is due. */ bool parse_and_get_attrib ( dbref executor, char *fargs[], char **atext, dbref *thing, dbref *paowner, dbref *paflags, char *buff, char **bufc ) { ATTR *ap; // Two possibilities for the first arg: / and . // if (!parse_attrib(executor, fargs[0], thing, &ap)) { *thing = executor; ap = atr_str(fargs[0]); } // Make sure we got a good attribute. // if (!ap) { return false; } // Use it if we can access it, otherwise return an error. // if (!See_attr(executor, *thing, ap)) { safe_noperm(buff, bufc); return false; } *atext = atr_pget(*thing, ap->number, paowner, paflags); if (!*atext) { return false; } else if (!**atext) { free_lbuf(*atext); return false; } return true; } #define CWHO_ON 0 #define CWHO_OFF 1 #define CWHO_ALL 2 FUNCTION(fun_cwho) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); struct channel *ch = select_channel(fargs[0]); if (!ch) { safe_str("#-1 CHANNEL NOT FOUND", buff, bufc); return; } if ( !mudconf.have_comsys || ( !Comm_All(executor) && executor != ch->charge_who)) { safe_noperm(buff, bufc); return; } int match_type = CWHO_ON; if (nfargs == 2) { if (mux_stricmp(fargs[1], "all") == 0) { match_type = CWHO_ALL; } else if (mux_stricmp(fargs[1], "off") == 0) { match_type = CWHO_OFF; } else if (mux_stricmp(fargs[1], "on") == 0) { match_type = CWHO_ON; } } ITL pContext; struct comuser *user; ItemToList_Init(&pContext, buff, bufc, '#'); for (user = ch->on_users; user; user = user->on_next) { if ( ( match_type == CWHO_ALL || ( (Connected(user->who) || isThing(user->who)) && ( (match_type == CWHO_ON && user->bUserIsOn) || (match_type == CWHO_OFF && !(user->bUserIsOn))))) && !ItemToList_AddInteger(&pContext, user->who)) { break; } } ItemToList_Final(&pContext); } FUNCTION(fun_beep) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_chr(BEEP_CHAR, buff, bufc); } #define ANSI_F 0x00000001 #define ANSI_H 0x00000002 #define ANSI_U 0x00000004 #define ANSI_I 0x00000008 #define ANSI_FC 0x00000010 #define ANSI_BC 0x00000020 static const unsigned char ansi_have_table[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10-0x1F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x30-0x3F 0, 0, ANSI_BC, ANSI_BC, // 0x40-0x43 0, 0, 0, ANSI_BC, // 0x44-0x47 0, 0, 0, 0, // 0x48-0x4B 0, ANSI_BC, 0, 0, // 0x4B-0x4F 0, 0, ANSI_BC, 0, // 0x50-0x53 0, 0, 0, ANSI_BC, // 0x54-0x57 ANSI_BC, ANSI_BC, 0, 0, // 0x58-0x5B 0, 0, 0, 0, // 0x5B-0x5F 0, 0, ANSI_FC, ANSI_FC, // 0x60-0x63 0, 0, ANSI_F, ANSI_FC, // 0x64-0x67 ANSI_H, ANSI_I, 0, 0, // 0x68-0x6B 0, ANSI_FC, 0, 0, // 0x6C-0x6F 0, 0, ANSI_FC, 0, // 0x70-0x73 0, ANSI_U, 0, ANSI_FC, // 0x74-0x77 ANSI_FC, ANSI_FC, 0, 0, // 0x78-0x7B 0, 0, 0, 0, // 0x7B-0x7F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0-0xAF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0-0xBF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0-0xCF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0-0xDF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0-0xEF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF0-0xFF }; void SimplifyColorLetters(char Out[8], char *pIn) { char *pOut = Out; if ( pIn[0] == 'n' && pIn[1] == '\0') { pOut[0] = 'n'; pOut[1] = '\0'; return; } char *p; int have = 0; size_t nIn = strlen(pIn); for (p = pIn + nIn - 1; p >= pIn && *p != 'n'; p--) { int mask = ansi_have_table[(unsigned char)*p]; if ( mask && (have & mask) == 0) { *pOut++ = *p; have |= mask; } } *pOut = '\0'; } // This function was originally taken from PennMUSH 1.50 // FUNCTION(fun_ansi) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int iArg0; for (iArg0 = 0; iArg0 + 1 < nfargs; iArg0 += 2) { char pOut[8]; SimplifyColorLetters(pOut, fargs[iArg0]); char tmp[LBUF_SIZE]; char *bp = tmp; char *s = pOut; while (*s) { const char *pColor = ColorTable[(unsigned char)*s]; if (pColor) { safe_str(pColor, tmp, &bp); } s++; } safe_str(fargs[iArg0+1], tmp, &bp); *bp = '\0'; size_t nVisualWidth; size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; size_t nLen = ANSI_TruncateToField(tmp, nBufferAvailable, *bufc, LBUF_SIZE, &nVisualWidth, ANSI_ENDGOAL_NORMAL); *bufc += nLen; } } FUNCTION(fun_zone) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!mudconf.have_zones) { safe_str("#-1 ZONES DISABLED", buff, bufc); return; } dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); } else if (Examinable(executor, it)) { safe_tprintf_str(buff, bufc, "#%d", Zone(it)); } else { safe_nothing(buff, bufc); } } #ifdef SIDE_EFFECT_FUNCTIONS static bool check_command(dbref player, const char *name, char *buff, char **bufc) { CMDENT *cmdp = (CMDENT *)hashfindLEN(name, strlen(name), &mudstate.command_htab); if (cmdp) { // Perform checks similiar to (but not exactly like) the // ones in process_cmdent(): object type checks, permission // checks, ands global flags. // if ( Invalid_Objtype(player) || !check_access(player, cmdp->perms) || ( !Builder(player) && Protect(CA_GBL_BUILD) && !(mudconf.control_flags & CF_BUILD))) { safe_noperm(buff, bufc); return true; } } return false; } FUNCTION(fun_link) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (check_command(executor, "@link", buff, bufc)) { return; } do_link(executor, caller, enactor, 0, 2, fargs[0], fargs[1]); } #if defined(FIRANMUX) FUNCTION(fun_setparent) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (check_command(executor, "@parent", buff, bufc)) { return; } do_parent(executor, caller, enactor, 0, 2, fargs[0], fargs[1]); } FUNCTION(fun_setname) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if ( !fargs[0] || !fargs[1] || check_command(executor, "@name", buff, bufc)) { return; } do_name(executor, caller, enactor, 0, 2, fargs[0], fargs[1]); } FUNCTION(fun_trigger) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (check_command(executor, "@trigger", buff, bufc)) { return; } do_trigger(executor, caller, enactor, eval, 0, fargs[0], fargs+1, nfargs-1); } #endif // FIRANMUX FUNCTION(fun_tel) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (check_command(executor, "@teleport", buff, bufc)) { return; } do_teleport(executor, caller, enactor, 0, 2, fargs[0], fargs[1]); } FUNCTION(fun_pemit) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (check_command(executor, "@pemit", buff, bufc)) { return; } do_pemit_list(executor, PEMIT_PEMIT, false, 0, fargs[0], 0, fargs[1]); } FUNCTION(fun_oemit) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (check_command(executor, "@oemit", buff, bufc)) { return; } do_pemit_single(executor, PEMIT_OEMIT, false, 0, fargs[0], 0, fargs[1]); } FUNCTION(fun_emit) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (check_command(executor, "@emit", buff, bufc)) { return; } do_say(executor, caller, enactor, 0, SAY_EMIT, fargs[0]); } FUNCTION(fun_remit) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (check_command(executor, "@pemit", buff, bufc)) { return; } do_pemit_single(executor, PEMIT_PEMIT, true, 0, fargs[0], 0, fargs[1]); } FUNCTION(fun_cemit) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (check_command(executor, "@cemit", buff, bufc)) { return; } do_cemit(executor, caller, enactor, 0, nfargs, fargs[0], fargs[1]); } // ------------------------------------------------------------------------ // fun_create: Creates a room, thing or exit. // FUNCTION(fun_create) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT)) { return; } char *name = fargs[0]; if (!name || !*name) { safe_str("#-1 ILLEGAL NAME", buff, bufc); return; } if (nfargs >= 3 && *fargs[2]) { sep.str[0] = *fargs[2]; } else { sep.str[0] = 't'; } dbref thing; int cost; switch (sep.str[0]) { case 'r': if (check_command(executor, "@dig", buff, bufc)) { return; } thing = create_obj(executor, TYPE_ROOM, name, 0); if (thing != NOTHING) { local_data_create(thing); } break; case 'e': if (check_command(executor, "@open", buff, bufc)) { return; } thing = create_obj(executor, TYPE_EXIT, name, 0); if (thing != NOTHING) { s_Exits(thing, executor); s_Next(thing, Exits(executor)); s_Exits(executor, thing); local_data_create(thing); } break; default: if (check_command(executor, "@create", buff, bufc)) { return; } if (*fargs[1]) { cost = mux_atol(fargs[1]); if ( cost < mudconf.createmin || mudconf.createmax < cost) { safe_range(buff, bufc); return; } } else { cost = mudconf.createmin; } thing = create_obj(executor, TYPE_THING, name, cost); if (thing != NOTHING) { move_via_generic(thing, executor, NOTHING, 0); s_Home(thing, new_home(executor)); local_data_create(thing); } break; } safe_tprintf_str(buff, bufc, "#%d", thing); } FUNCTION(fun_textfile) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); mux_strlwr(fargs[0]); CMDENT_ONE_ARG *cmdp = (CMDENT_ONE_ARG *)hashfindLEN(fargs[0], strlen(fargs[0]), &mudstate.command_htab); if ( !cmdp || cmdp->handler != do_help) { safe_str("#-1 NOT FOUND", buff, bufc); return; } if (check_command(executor, fargs[0], buff, bufc)) { return; } help_helper(executor, cmdp->extra, fargs[1], buff, bufc); } /* --------------------------------------------------------------------------- * fun_set: sets an attribute on an object */ static void set_attr_internal(dbref player, dbref thing, int attrnum, char *attrtext, int key, char *buff, char **bufc) { if (!Good_obj(thing)) { safe_noperm(buff, bufc); notify_quiet(player, "You shouldn't be rummaging through the garbage."); return; } dbref aowner; int aflags; ATTR *pattr = atr_num(attrnum); atr_pget_info(thing, attrnum, &aowner, &aflags); if ( pattr && bCanSetAttr(player, thing, pattr)) { bool could_hear = Hearer(thing); atr_add(thing, attrnum, attrtext, Owner(player), aflags); handle_ears(thing, could_hear, Hearer(thing)); if ( !(key & SET_QUIET) && !Quiet(player) && !Quiet(thing)) { notify_quiet(player, "Set."); } } else { safe_noperm(buff, bufc); } } FUNCTION(fun_set) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (check_command(executor, "@set", buff, bufc)) { return; } dbref thing, aowner; int aflags; ATTR *pattr; // See if we have the / form, which is how you set // attribute flags. // if (parse_attrib(executor, fargs[0], &thing, &pattr)) { if ( pattr && See_attr(executor, thing, pattr)) { char *flagname = fargs[1]; // You must specify a flag name. // if (flagname[0] == '\0') { safe_str("#-1 UNSPECIFIED PARAMETER", buff, bufc); return; } // Check for clearing. // bool clear = false; if (flagname[0] == NOT_TOKEN) { flagname++; clear = true; } // Make sure player specified a valid attribute flag. // int flagvalue; if (!search_nametab(executor, indiv_attraccess_nametab, flagname, &flagvalue)) { safe_str("#-1 CANNOT SET", buff, bufc); return; } // Make sure the object has the attribute present. // if (!atr_get_info(thing, pattr->number, &aowner, &aflags)) { safe_str("#-1 ATTRIBUTE NOT PRESENT ON OBJECT", buff, bufc); return; } // Make sure we can write to the attribute. // if (!bCanSetAttr(executor, thing, pattr)) { safe_noperm(buff, bufc); return; } // Go do it. // if (clear) { aflags &= ~flagvalue; } else { aflags |= flagvalue; } atr_set_flags(thing, pattr->number, aflags); return; } } // Find thing. // thing = match_controlled_quiet(executor, fargs[0]); if (!Good_obj(thing)) { safe_nothing(buff, bufc); return; } // Check for attr set first. // char *p; for (p = fargs[1]; *p && *p != ':'; p++) { ; // Nothing } if (*p) { *p++ = 0; int atr = mkattr(executor, fargs[1]); if (atr <= 0) { safe_str("#-1 UNABLE TO CREATE ATTRIBUTE", buff, bufc); return; } pattr = atr_num(atr); if (!pattr) { safe_noperm(buff, bufc); return; } if (!bCanSetAttr(executor, thing, pattr)) { safe_noperm(buff, bufc); return; } char *buff2 = alloc_lbuf("fun_set"); // Check for _ // if (*p == '_') { ATTR *pattr2; dbref thing2; mux_strncpy(buff2, p + 1, LBUF_SIZE-1); if (!( parse_attrib(executor, p + 1, &thing2, &pattr2) && pattr2)) { free_lbuf(buff2); safe_nomatch(buff, bufc); return; } p = buff2; atr_pget_str(buff2, thing2, pattr2->number, &aowner, &aflags); if (!See_attr(executor, thing2, pattr2)) { free_lbuf(buff2); safe_noperm(buff, bufc); return; } } // Go set it. // set_attr_internal(executor, thing, atr, p, 0, buff, bufc); free_lbuf(buff2); return; } // Set/clear a flag. // flag_set(thing, executor, fargs[1], 0); } #endif // Generate a substitution array. // static size_t GenCode(char *pCode, size_t nCode, const char *pCodeASCII) { // Strip out the ANSI. // size_t nIn; char *pIn = strip_ansi(pCodeASCII, &nIn); // Process the printable characters. // size_t i = 0; size_t j = 0; while ( pIn[i] && j < nCode - 1) { unsigned char ch = pIn[i++]; if ( ' ' <= ch && ch <= '~') { pCode[j++] = static_cast(ch - ' '); } } pCode[j] = '\0'; return j; } static char *crypt_code(char *code, char *text, bool type) { if ( !text || text[0] == '\0') { return (char *)""; } if ( !code || code[0] == '\0') { return text; } char codebuff[LBUF_SIZE]; size_t nCode = GenCode(codebuff, sizeof(codebuff), code); if (0 == nCode) { return text; } static char textbuff[LBUF_SIZE]; char *p = strip_ansi(text); size_t nq = nCode; size_t ip = 0; size_t iq = 0; size_t ir = 0; int iMod = '~' - ' ' + 1; // Encryption loop: // while ( p[ip] && ir < sizeof(textbuff) - 1) { unsigned char ch = p[ip++]; if ( ' ' <= ch && ch <= '~') { int iCode = ch - ' '; if (type) { iCode += codebuff[iq++]; if (iMod <= iCode) { iCode -= iMod; } } else { iCode -= codebuff[iq++]; if (iCode < 0) { iCode += iMod; } } textbuff[ir++] = static_cast(iCode + ' '); nq--; if (0 == nq) { iq = 0; nq = nCode; } } } textbuff[ir] = '\0'; return textbuff; } // Code for encrypt() and decrypt() was taken from the DarkZone // server. // FUNCTION(fun_encrypt) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_str(crypt_code(fargs[1], fargs[0], true), buff, bufc); } FUNCTION(fun_decrypt) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_str(crypt_code(fargs[1], fargs[0], false), buff, bufc); } // Borrowed from DarkZone // static void scan_zone ( dbref executor, char *szZone, int ObjectType, char *buff, char **bufc ) { if (!mudconf.have_zones) { safe_str("#-1 ZONES DISABLED", buff, bufc); return; } dbref it = match_thing_quiet(executor, szZone); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } else if (!( WizRoy(executor) || Controls(executor, it))) { safe_noperm(buff, bufc); return; } dbref i; ITL pContext; ItemToList_Init(&pContext, buff, bufc, '#'); DO_WHOLE_DB(i) { if ( Typeof(i) == ObjectType && Zone(i) == it && !ItemToList_AddInteger(&pContext, i)) { break; } } ItemToList_Final(&pContext); } FUNCTION(fun_zwho) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); scan_zone(executor, fargs[0], TYPE_PLAYER, buff, bufc); } FUNCTION(fun_inzone) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); scan_zone(executor, fargs[0], TYPE_ROOM, buff, bufc); } // Borrowed from DarkZone // FUNCTION(fun_children) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } else if (!( WizRoy(executor) || Controls(executor, it))) { safe_noperm(buff, bufc); return; } dbref i; ITL pContext; ItemToList_Init(&pContext, buff, bufc, '#'); DO_WHOLE_DB(i) { if ( Parent(i) == it && !ItemToList_AddInteger(&pContext, i)) { break; } } ItemToList_Final(&pContext); } FUNCTION(fun_objeval) { UNUSED_PARAMETER(nfargs); if (!*fargs[0]) { return; } char *name = alloc_lbuf("fun_objeval"); char *bp = name; char *str = fargs[0]; mux_exec(name, &bp, executor, caller, enactor, eval|EV_FCHECK|EV_STRIP_CURLY|EV_EVAL, &str, cargs, ncargs); *bp = '\0'; dbref obj = match_thing_quiet(executor, name); free_lbuf(name); if (!Good_obj(obj)) { safe_match_result(obj, buff, bufc); return; } if (!Controls(executor, obj)) { // The right circumstances were not met, so we are evaluating // as the executor who gave the command instead of the // requested object. // obj = executor; } mudstate.nObjEvalNest++; str = fargs[1]; mux_exec(buff, bufc, obj, executor, enactor, eval|EV_FCHECK|EV_STRIP_CURLY|EV_EVAL, &str, cargs, ncargs); mudstate.nObjEvalNest--; } FUNCTION(fun_localize) { UNUSED_PARAMETER(nfargs); reg_ref **preserve = NULL; preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); char *str = fargs[0]; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_FCHECK|EV_STRIP_CURLY|EV_EVAL, &str, cargs, ncargs); restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); } FUNCTION(fun_null) { UNUSED_PARAMETER(buff); UNUSED_PARAMETER(bufc); UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); return; } FUNCTION(fun_squish) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (nfargs == 0) { return; } SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT)) { return; } char *p; char *q = fargs[0]; while ((p = strchr(q, sep.str[0])) != NULL) { p = p + 1; size_t nLen = p - q; safe_copy_buf(q, nLen, buff, bufc); q = p; while (*q == sep.str[0]) { q++; } } safe_str(q, buff, bufc); } FUNCTION(fun_stripansi) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_str(strip_ansi(fargs[0]), buff, bufc); } // Borrowed from PennMUSH 1.50 // FUNCTION(fun_zfun) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!mudconf.have_zones) { safe_str("#-1 ZONES DISABLED", buff, bufc); return; } dbref zone = Zone(executor); if (!Good_obj(zone)) { safe_str("#-1 INVALID ZONE", buff, bufc); return; } // Find the user function attribute. // int attrib = get_atr(fargs[0]); if (!attrib) { safe_str("#-1 NO SUCH USER FUNCTION", buff, bufc); return; } dbref aowner; int aflags; ATTR *pattr = atr_num(attrib); char *tbuf1 = atr_pget(zone, attrib, &aowner, &aflags); if ( !pattr || !See_attr(executor, zone, pattr)) { safe_noperm(buff, bufc); free_lbuf(tbuf1); return; } char *str = tbuf1; mux_exec(buff, bufc, zone, executor, enactor, AttrTrace(aflags, EV_EVAL|EV_STRIP_CURLY|EV_FCHECK), &str, &(fargs[1]), nfargs - 1); free_lbuf(tbuf1); } FUNCTION(fun_columns) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_STRING)) { return; } int nWidth = mux_atol(fargs[1]); int nIndent = 0; if (nfargs == 4) { nIndent = mux_atol(fargs[3]); if (nIndent < 0 || 77 < nIndent) { nIndent = 1; } } int nRight = nIndent + nWidth; if ( nWidth < 1 || 78 < nWidth || nRight < 1 || 78 < nRight) { safe_range(buff, bufc); return; } char *cp = trim_space_sep(fargs[0], &sep); if (!*cp) { return; } int nColumns = (78-nIndent)/nWidth; int iColumn = 0; size_t nBufferAvailable = LBUF_SIZE - (*bufc-buff) - 1; bool bNeedCRLF = false; while ( cp && 0 < nBufferAvailable) { if (iColumn == 0) { nBufferAvailable -= safe_fill(buff, bufc, ' ', nIndent); if (0 == nBufferAvailable) { break; } } char *objstring = split_token(&cp, &sep); size_t nVisualWidth; size_t nLen = ANSI_TruncateToField(objstring, nBufferAvailable, *bufc, nWidth, &nVisualWidth, ANSI_ENDGOAL_NORMAL); *bufc += nLen; nBufferAvailable -= nLen; if (nColumns-1 <= iColumn) { iColumn = 0; nBufferAvailable -= safe_copy_buf("\r\n", 2, buff, bufc); bNeedCRLF = false; } else { iColumn++; nBufferAvailable -= safe_fill(buff, bufc, ' ', nWidth - nVisualWidth); bNeedCRLF = true; } } if (bNeedCRLF) { safe_copy_buf("\r\n", 2, buff, bufc); } } // table(,,,,, ) // // Ported from PennMUSH 1.7.3 by Morgan. // // TODO: Support ANSI in output separator and padding. // FUNCTION(fun_table) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // Check argument numbers, assign values and defaults if necessary. // char *pPaddingStart = NULL; char *pPaddingEnd = NULL; if (nfargs == 6 && *fargs[5]) { pPaddingStart = strip_ansi(fargs[5]); pPaddingEnd = strchr(pPaddingStart, '\0'); } // Get single-character separator. // char cSeparator = ' '; if (nfargs >= 5 && fargs[4][0] != '\0') { if (fargs[4][1] == '\0') { cSeparator = *fargs[4]; } else { safe_str("#-1 SEPARATOR MUST BE ONE CHARACTER", buff, bufc); return; } } // Get single-character delimiter. // char cDelimiter = ' '; if (nfargs >= 4 && fargs[3][0] != '\0') { if (fargs[3][1] == '\0') { cDelimiter = *fargs[3]; } else { safe_str("#-1 DELIMITER MUST BE ONE CHARACTER", buff, bufc); return; } } // Get line length. // int nLineLength = 78; if (nfargs >= 3) { nLineLength = mux_atol(fargs[2]); } // Get field width. // int nFieldWidth = 10; if (nfargs >= 2) { nFieldWidth = mux_atol(fargs[1]); } else { nFieldWidth = 10; } // Validate nFieldWidth and nLineLength. // if ( nLineLength < 1 || LBUF_SIZE <= nLineLength || nFieldWidth < 1 || nLineLength < nFieldWidth) { safe_range(buff, bufc); return; } int nNumCols = nLineLength / nFieldWidth; SEP sep; sep.n = 1; sep.str[0] = cDelimiter; char *pNext = trim_space_sep(fargs[0], &sep); if (!*pNext) { return; } char *pCurrent = split_token(&pNext, &sep); if (!pCurrent) { return; } size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; size_t nCurrentCol = nNumCols - 1; for (;;) { size_t nVisibleLength, nPaddingLength; size_t nStringLength = ANSI_TruncateToField( pCurrent, nBufferAvailable, *bufc, nFieldWidth, &nVisibleLength, ANSI_ENDGOAL_NORMAL); *bufc += nStringLength; nBufferAvailable -= nStringLength; nPaddingLength = nFieldWidth - nVisibleLength; if (nPaddingLength > nBufferAvailable) { nPaddingLength = nBufferAvailable; } if (nPaddingLength) { nBufferAvailable -= nPaddingLength; if (pPaddingStart) { for ( char *pPaddingCurrent = pPaddingStart; nPaddingLength > 0; nPaddingLength--) { **bufc = *pPaddingCurrent; (*bufc)++; pPaddingCurrent++; if (pPaddingCurrent == pPaddingEnd) { pPaddingCurrent = pPaddingStart; } } } else { memset(*bufc, ' ', nPaddingLength); *bufc += nPaddingLength; } } pCurrent = split_token(&pNext, &sep); if (!pCurrent) { break; } if (!nCurrentCol) { nCurrentCol = nNumCols - 1; if (nBufferAvailable >= 2) { char *p = *bufc; p[0] = '\r'; p[1] = '\n'; nBufferAvailable -= 2; *bufc += 2; } else { // nBufferAvailable has less than 2 characters left, if there's // no room left just break out. // if (!nBufferAvailable) { break; } } } else { nCurrentCol--; if (!nBufferAvailable) { break; } **bufc = cSeparator; (*bufc)++; nBufferAvailable--; } } } // Code for objmem and playmem borrowed from PennMUSH 1.50 // static size_t mem_usage(dbref thing) { size_t k = sizeof(struct object) + strlen(Name(thing)) + 1; char *as; for (int ca = atr_head(thing, &as); ca; ca = atr_next(&as)) { size_t nLen; const char *str = atr_get_raw_LEN(thing, ca, &nLen); k += nLen+1; ATTR *pattr = atr_num(ca); if (pattr) { str = pattr->name; if ( str && *str) { k += strlen(str)+1; } } } return k; } FUNCTION(fun_objmem) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref thing = match_thing_quiet(executor, fargs[0]); if (!Good_obj(thing)) { safe_match_result(thing, buff, bufc); } else if (Examinable(executor, thing)) { safe_ltoa(static_cast(mem_usage(thing)), buff, bufc); } else { safe_noperm(buff, bufc); } } FUNCTION(fun_playmem) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref thing; if (nfargs == 1) { thing = match_thing_quiet(executor, fargs[0]); if (!Good_obj(thing)) { safe_match_result(thing, buff, bufc); return; } else if (!Examinable(executor, thing)) { safe_noperm(buff, bufc); return; } } else { thing = executor; } size_t tot = 0; dbref j; DO_WHOLE_DB(j) { if (Owner(j) == thing) { tot += mem_usage(j); } } safe_ltoa(static_cast(tot), buff, bufc); } // Code for andflags() and orflags() borrowed from PennMUSH 1.50 // false for orflags, true for andflags // static bool handle_flaglists(dbref player, char *name, char *fstr, bool type) { dbref it = match_thing_quiet(player, name); if (!Good_obj(it)) { return false; } char *s; char flagletter[2]; FLAGSET fset; FLAG p_type; bool negate = false; bool temp = false; bool ret = type; for (s = fstr; *s; s++) { // Check for a negation sign. If we find it, we note it and // increment the pointer to the next character. // if (*s == '!') { negate = true; s++; } else { negate = false; } if (!*s) { return false; } flagletter[0] = *s; flagletter[1] = '\0'; if (!convert_flags(player, flagletter, &fset, &p_type)) { // Either we got a '!' that wasn't followed by a letter, or we // couldn't find that flag. For AND, since we've failed a check, // we can return false. Otherwise we just go on. // if (type) { return false; } else { continue; } } else { // Does the object have this flag? // if ( (Flags(it) & fset.word[FLAG_WORD1]) || (Flags2(it) & fset.word[FLAG_WORD2]) || (Flags3(it) & fset.word[FLAG_WORD3]) || Typeof(it) == p_type) { if ( isPlayer(it) && fset.word[FLAG_WORD2] == CONNECTED && Hidden(it) && !See_Hidden(player)) { temp = false; } else { temp = true; } } else { temp = false; } if ( type && ( (negate && temp) || (!negate && !temp))) { // Too bad there's no NXOR function. At this point we've // either got a flag and we don't want it, or we don't have a // flag and we want it. Since it's AND, we return false. // return false; } else if ( !type && ( (!negate && temp) || (negate && !temp))) { // We've found something we want, in an OR. We OR a true with // the current value. // ret |= true; } // Otherwise, we don't need to do anything. // } } return ret; } FUNCTION(fun_orflags) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_bool(handle_flaglists(executor, fargs[0], fargs[1], false), buff, bufc); } FUNCTION(fun_andflags) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_bool(handle_flaglists(executor, fargs[0], fargs[1], true), buff, bufc); } FUNCTION(fun_strtrunc) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); long maxVisualWidth = mux_atol(fargs[1]); if (maxVisualWidth < 0) { safe_range(buff, bufc); return; } if (maxVisualWidth == 0) { return; } size_t nVisualWidth; char buf[LBUF_SIZE+1]; ANSI_TruncateToField(fargs[0], LBUF_SIZE, buf, maxVisualWidth, &nVisualWidth, ANSI_ENDGOAL_NORMAL); safe_str(buf, buff, bufc); } FUNCTION(fun_ifelse) { // This function assumes that its arguments have not been evaluated. // char *lbuff = alloc_lbuf("fun_ifelse"); char *bp = lbuff; char *str = fargs[0]; mux_exec(lbuff, &bp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *bp = '\0'; if (!xlate(lbuff)) { if (nfargs == 3) { str = fargs[2]; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); } } else { str = fargs[1]; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); } free_lbuf(lbuff); } // Mail functions borrowed from DarkZone. // // This function can take one of three formats: // // 1. mail(num) --> returns message for privs. // 2. mail(executor) --> returns number of messages for . // 3. mail(executor, num) --> returns message for . // 4. mail() --> returns number of messages for executor. // FUNCTION(fun_mail) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!mudconf.have_mailer) { safe_str("#-1 MAILER DISABLED.", buff, bufc); return; } dbref playerask; int num, rc, uc, cc; // Make sure we have the right number of arguments. // if (nfargs == 0 || !fargs[0] || !fargs[0][0]) { count_mail(executor, 0, &rc, &uc, &cc); safe_ltoa(rc + uc, buff, bufc); return; } else if (nfargs == 1) { if (!is_integer(fargs[0], NULL)) { // Handle the case of wanting to count the number of // messages. // playerask = lookup_player(executor, fargs[0], true); if (NOTHING == playerask) { playerask = match_thing_quiet(executor, fargs[0]); if (!isPlayer(playerask)) { safe_str("#-1 NO SUCH PLAYER", buff, bufc); return; } } if ( playerask == executor || Wizard(executor)) { count_mail(playerask, 0, &rc, &uc, &cc); safe_tprintf_str(buff, bufc, "%d %d %d", rc, uc, cc); } else { safe_noperm(buff, bufc); } return; } else { playerask = executor; num = mux_atol(fargs[0]); } } else // if (nfargs == 2) { playerask = lookup_player(executor, fargs[0], true); if (playerask == NOTHING) { safe_str("#-1 NO SUCH PLAYER", buff, bufc); return; } else if ( (playerask == executor && !mudstate.nObjEvalNest) || God(executor)) { num = mux_atol(fargs[1]); } else { safe_noperm(buff, bufc); return; } } if ( num < 1 || !isPlayer(playerask)) { safe_str("#-1 NO SUCH MESSAGE", buff, bufc); return; } const char *p = mail_fetch_message(playerask, num); if (p) { safe_str(p, buff, bufc); } else { safe_str("#-1 NO SUCH MESSAGE", buff, bufc); } } #ifdef FIRANMUX FUNCTION(fun_mailsize) { if (!mudconf.have_mailer) { safe_str("#-1 MAILER DISABLED.", buff, bufc); return; } dbref playerask = lookup_player(executor, fargs[0], 1); if (!Good_obj(playerask)) { safe_str("#-1 NO SUCH PLAYER", buff, bufc); } else if ( executor == playerask || Wizard(executor)) { int totalsize = 0; MailList ml(playerask); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { totalsize += MessageFetchSize(mp->number) + 1; } safe_ltoa(totalsize, buff, bufc); } else { safe_noperm(buff, bufc); } } FUNCTION(fun_mailsubj) { if (!mudconf.have_mailer) { safe_str("#-1 MAILER DISABLED.", buff, bufc); return; } dbref playerask; int num; if (1 == nfargs) { playerask = executor; num = mux_atol(fargs[0]); } else { playerask = lookup_player(executor, fargs[0], 1); if (NOTHING == playerask) { safe_str("#-1 NO SUCH PLAYER", buff, bufc); return; } else if ( executor == playerask || Wizard(executor)) { num = mux_atol(fargs[1]); } else { safe_noperm(buff, bufc); return; } } if ( num < 1 || !isPlayer(playerask)) { safe_str("#-1 NO SUCH MESSAGE", buff, bufc); } else { struct mail *mp = mail_fetch(playerask, num); if (mp) { safe_str(mp->subject, buff, bufc); } else { safe_str("#-1 NO SUCH MESSAGE", buff, bufc); } } } // This function can take one of three formats: // // 1. mailj(num) --> returns message for privs. // 2. mailj(executor) --> returns number of messages for . // 3. mailj(executor, num) --> returns message for . // // It can now take one more format: // // 4. mailj() --> returns number of messages for executor. // FUNCTION(fun_mailj) { if (!mudconf.have_mailer) { safe_str("#-1 MAILER DISABLED.", buff, bufc); return; } dbref playerask; int num; struct mail *mp; if ( 0 == nfargs || '\0' == fargs[0][0]) { int cnt = 0; MailList ml(executor); for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { cnt++; } safe_ltoa(cnt, buff, bufc); return; } else if (1 == nfargs) { if (!is_integer(fargs[0], NULL)) { // Handle the case of wanting to count the number of messages. // playerask = lookup_player(executor, fargs[0], 1); if (NOTHING == playerask) { safe_str("#-1 NO SUCH PLAYER", buff, bufc); } else if ( executor == playerask || Wizard(executor)) { int uc = 0; int rc = 0; int cc = 0; MailList ml(playerask); for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (Read(mp)) { rc++; } else { uc++; } if (Cleared(mp)) { cc++; } } safe_tprintf_str(buff, bufc, "%d %d %d", rc, uc, cc); } else { safe_noperm(buff, bufc); } return; } else { playerask = executor; num = mux_atol(fargs[0]); } } else { playerask = lookup_player(executor, fargs[0], 1); if (NOTHING == playerask) { safe_str("#-1 NO SUCH PLAYER", buff, bufc); return; } else if ( executor == playerask || God(executor)) { num = mux_atol(fargs[1]); } else { safe_noperm(buff, bufc); return; } } if ( num < 1 || !isPlayer(playerask)) { safe_str("#-1 NO SUCH MESSAGE", buff, bufc); return; } mp = mail_fetch(playerask, num); if (mp) { safe_str(MessageFetch(mp->number), buff, bufc); } else { safe_str("#-1 NO SUCH MESSAGE", buff, bufc); } } #endif // FIRANMUX // This function can take these formats: // // 1) mailfrom() // 2) mailfrom(,) // // It returns the dbref of the executor the mail is from. // FUNCTION(fun_mailfrom) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!mudconf.have_mailer) { safe_str("#-1 MAILER DISABLED.", buff, bufc); return; } // Make sure we have the right number of arguments. // int num; dbref playerask; if (nfargs == 1) { playerask = executor; num = mux_atol(fargs[0]); } else // if (nfargs == 2) { playerask = lookup_player(executor, fargs[0], true); if (playerask == NOTHING) { safe_str("#-1 NO SUCH PLAYER", buff, bufc); return; } if ( playerask == executor || Wizard(executor)) { num = mux_atol(fargs[1]); } else { safe_noperm(buff, bufc); return; } } if ( num < 1 || !isPlayer(playerask)) { safe_str("#-1 NO SUCH MESSAGE", buff, bufc); return; } int from = mail_fetch_from(playerask, num); if (NOTHING != from) { safe_tprintf_str(buff, bufc, "#%d", from); return; } // Ran off the end of the list without finding anything. // safe_str("#-1 NO SUCH MESSAGE", buff, bufc); } // --------------------------------------------------------------------------- // fun_hasattr: does object X have attribute Y. // Hasattr (and hasattrp, which is derived from hasattr) borrowed from // TinyMUSH 2.2. static void hasattr_handler(char *buff, char **bufc, dbref executor, char *fargs[], bool bCheckParent) { dbref thing = match_thing_quiet(executor, fargs[0]); if (!Good_obj(thing)) { safe_match_result(thing, buff, bufc); return; } ATTR *pattr = atr_str(fargs[1]); bool result = false; if (pattr) { if (!bCanReadAttr(executor, thing, pattr, bCheckParent)) { safe_noperm(buff, bufc); return; } else { if (bCheckParent) { dbref aowner; int aflags; char *tbuf = atr_pget(thing, pattr->number, &aowner, &aflags); result = (tbuf[0] != '\0'); free_lbuf(tbuf); } else { const char *tbuf = atr_get_raw(thing, pattr->number); result = (tbuf != NULL); } } } safe_bool(result, buff, bufc); } FUNCTION(fun_hasattr) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); hasattr_handler(buff, bufc, executor, fargs, false); } FUNCTION(fun_hasattrp) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); hasattr_handler(buff, bufc, executor, fargs, true); } /* --------------------------------------------------------------------------- * fun_default, fun_edefault, and fun_udefault: * These check for the presence of an attribute. If it exists, then it * is gotten, via the equivalent of get(), get_eval(), or u(), respectively. * Otherwise, the default message is used. * In the case of udefault(), the remaining arguments to the function * are used as arguments to the u(). */ // default(), edefault(), and udefault() borrowed from TinyMUSH 2.2 // #define DEFAULT_DEFAULT 1 #define DEFAULT_EDEFAULT 2 #define DEFAULT_UDEFAULT 4 static void default_handler(char *buff, char **bufc, dbref executor, dbref caller, dbref enactor, int eval, char *fargs[], int nfargs, char *cargs[], int ncargs, int key) { // Evaluating the first argument. // char *objattr = alloc_lbuf("default_handler"); char *bp = objattr; char *str = fargs[0]; mux_exec(objattr, &bp, executor, caller, enactor, eval|EV_EVAL|EV_STRIP_CURLY|EV_FCHECK, &str, cargs, ncargs); *bp = '\0'; // Parse the first argument as either / or . // dbref thing; ATTR *pattr; if (!parse_attrib(executor, objattr, &thing, &pattr)) { thing = executor; pattr = atr_str(objattr); } free_lbuf(objattr); if ( pattr && See_attr(executor, thing, pattr)) { dbref aowner; int aflags; char *atr_gotten = atr_pget(thing, pattr->number, &aowner, &aflags); if (atr_gotten[0] != '\0') { switch (key) { case DEFAULT_DEFAULT: safe_str(atr_gotten, buff, bufc); break; case DEFAULT_EDEFAULT: str = atr_gotten; mux_exec(buff, bufc, thing, executor, executor, AttrTrace(aflags, EV_FIGNORE|EV_EVAL), &str, NULL, 0); break; case DEFAULT_UDEFAULT: { char *xargs[MAX_ARG]; int nxargs = nfargs-2; int i; for (i = 0; i < nxargs; i++) { xargs[i] = alloc_lbuf("fun_udefault_args"); char *bp2 = xargs[i]; str = fargs[i+2]; mux_exec(xargs[i], &bp2, thing, caller, enactor, eval|EV_TOP|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *bp2 = '\0'; } str = atr_gotten; mux_exec(buff, bufc, thing, caller, enactor, AttrTrace(aflags, EV_FCHECK|EV_EVAL), &str, xargs, nxargs); for (i = 0; i < nxargs; i++) { free_lbuf(xargs[i]); } } break; } free_lbuf(atr_gotten); return; } free_lbuf(atr_gotten); } // If we've hit this point, we've not gotten anything useful, so // we go and evaluate the default. // str = fargs[1]; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_EVAL|EV_STRIP_CURLY|EV_FCHECK, &str, cargs, ncargs); } FUNCTION(fun_default) { default_handler(buff, bufc, executor, caller, enactor, eval, fargs, nfargs, cargs, ncargs, DEFAULT_DEFAULT); } FUNCTION(fun_edefault) { default_handler(buff, bufc, executor, caller, enactor, eval, fargs, nfargs, cargs, ncargs, DEFAULT_EDEFAULT); } FUNCTION(fun_udefault) { default_handler(buff, bufc, executor, caller, enactor, eval, fargs, nfargs, cargs, ncargs, DEFAULT_UDEFAULT); } /* --------------------------------------------------------------------------- * fun_findable: can X locate Y * Borrowed from PennMUSH 1.50 */ FUNCTION(fun_findable) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref obj = match_thing_quiet(executor, fargs[0]); if (!Good_obj(obj)) { safe_match_result(obj, buff, bufc); safe_str(" (ARG1)", buff, bufc); return; } dbref victim = match_thing_quiet(executor, fargs[1]); if (!Good_obj(victim)) { safe_match_result(victim, buff, bufc); safe_str(" (ARG2)", buff, bufc); return; } #ifndef WOD_REALMS #ifndef REALITY_LVLS safe_bool(locatable(obj, victim, obj), buff, bufc); #else if (IsReal(obj, victim)) { safe_bool(locatable(obj, victim, obj), buff, bufc); } else safe_chr('0', buff, bufc); #endif #else #ifndef REALITY_LVLS if (REALM_DO_HIDDEN_FROM_YOU != DoThingToThingVisibility(obj, victim, ACTION_IS_STATIONARY)) { safe_bool(locatable(obj, victim, obj), buff, bufc); } else { safe_chr('0', buff, bufc); } #else if (REALM_DO_HIDDEN_FROM_YOU != DoThingToThingVisibility(obj, victim, ACTION_IS_STATIONARY)) { safe_bool(locatable(obj, victim, obj), buff, bufc); } else if (IsReal(obj, victim)) { safe_bool(locatable(obj, victim, obj), buff, bufc); } else safe_chr('0', buff, bufc); #endif #endif } /* --------------------------------------------------------------------------- * isword: is every character in the argument a letter? * Borrowed from PennMUSH 1.50 */ FUNCTION(fun_isword) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *p; bool result = true; for (p = fargs[0]; *p; p++) { if (!mux_isalpha(*p)) { result = false; break; } } safe_bool(result, buff, bufc); } /* --------------------------------------------------------------------------- * fun_visible. Borrowed from PennMUSH 1.50 */ FUNCTION(fun_visible) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); safe_str(" (ARG1)", buff, bufc); return; } else if (!Controls(executor, it)) { safe_noperm(buff, bufc); return; } bool result = false; dbref thing; ATTR *pattr; if (!parse_attrib(executor, fargs[1], &thing, &pattr)) { thing = match_thing_quiet(executor, fargs[1]); if (!Good_obj(thing)) { safe_match_result(thing, buff, bufc); safe_str(" (ARG2)", buff, bufc); return; } } if (Good_obj(thing)) { if (pattr) { result = (See_attr(it, thing, pattr)); } else { result = (Examinable(it, thing)); } } safe_bool(result, buff, bufc); } /* --------------------------------------------------------------------------- * fun_elements: given a list of numbers, get corresponding elements from * the list. elements(ack bar eep foof yay,2 4) ==> bar foof * The function takes a separator, but the separator only applies to the * first list. * Borrowed from PennMUSH 1.50 */ FUNCTION(fun_elements) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT)) { return; } int nwords, cur; char *ptrs[LBUF_SIZE / 2]; char *wordlist, *s, *r; bool bFirst = true; // Turn the first list into an array. // wordlist = alloc_lbuf("fun_elements.wordlist"); mux_strncpy(wordlist, fargs[0], LBUF_SIZE-1); nwords = list2arr(ptrs, LBUF_SIZE / 2, wordlist, &sep); s = trim_space_sep(fargs[1], &sepSpace); // Go through the second list, grabbing the numbers and finding the // corresponding elements. // do { r = split_token(&s, &sepSpace); cur = mux_atol(r) - 1; if ( cur >= 0 && cur < nwords && ptrs[cur]) { if (!bFirst) { print_sep(&osep, buff, bufc); } else { bFirst = false; } safe_str(ptrs[cur], buff, bufc); } } while (s); free_lbuf(wordlist); } /* --------------------------------------------------------------------------- * fun_grab: a combination of extract() and match(), sortof. We grab the * single element that we match. * * grab(Test:1 Ack:2 Foof:3,*:2) => Ack:2 * grab(Test-1+Ack-2+Foof-3,*o*,+) => Foof-3 * Borrowed from PennMUSH 1.50 */ FUNCTION(fun_grab) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } // Walk the wordstring, until we find the word we want. // char *s = trim_space_sep(fargs[0], &sep); do { char *r = split_token(&s, &sep); mudstate.wild_invk_ctr = 0; if (quick_wild(fargs[1], r)) { safe_str(r, buff, bufc); return; } } while (s); } FUNCTION(fun_graball) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT)) { return; } bool bFirst = true; char *s = trim_space_sep(fargs[0], &sep); do { char *r = split_token(&s, &sep); mudstate.wild_invk_ctr = 0; if (quick_wild(fargs[1], r)) { if (!bFirst) { print_sep(&osep, buff, bufc); } else { bFirst = false; } safe_str(r, buff, bufc); } } while (s); } /* --------------------------------------------------------------------------- * fun_scramble: randomizes the letters in a string. * Borrowed from PennMUSH 1.50 */ FUNCTION(fun_scramble) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); size_t nStrip; char *old = strip_ansi(fargs[0], &nStrip); INT32 n = static_cast(nStrip); if (2 <= n) { INT32 i; for (i = 0; i < n-1; i++) { int j = RandomINT32(i, n-1); char c = old[i]; old[i] = old[j]; old[j] = c; } } safe_str(old, buff, bufc); } /* --------------------------------------------------------------------------- * fun_shuffle: randomize order of words in a list. * Borrowed from PennMUSH 1.50 */ FUNCTION(fun_shuffle) { SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(3, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT)) { return; } char **words = new char *[LBUF_SIZE]; ISOUTOFMEMORY(words); int n, i, j; n = list2arr(words, LBUF_SIZE, fargs[0], &sep); for (i = 0; i < n-1; i++) { j = RandomINT32(i, n-1); // Swap words[i] with words[j] // char *temp = words[i]; words[i] = words[j]; words[j] = temp; } arr2list(words, n, buff, bufc, &osep); delete [] words; } // pickrand -- choose a random item from a list. // FUNCTION(fun_pickrand) { if ( nfargs == 0 || fargs[0][0] == '\0') { return; } SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } char *s = trim_space_sep(fargs[0], &sep); char *t = s; if (s[0] == '\0') { return; } INT32 n; for (n = 0; t; t = next_token(t, &sep), n++) { ; // Nothing } if (n >= 1) { INT32 w = RandomINT32(0, n-1); for (n = 0; n < w; n++) { s = next_token(s, &sep); } t = split_token(&s, &sep); safe_str(t, buff, bufc); } } // sortby() code borrowed from TinyMUSH 2.2 // typedef struct { char *buff;; dbref executor; dbref caller; dbref enactor; int aflags; } ucomp_context; static int u_comp(ucomp_context *pctx, const void *s1, const void *s2) { if ( mudstate.func_invk_ctr > mudconf.func_invk_lim || mudstate.func_nest_lev > mudconf.func_nest_lim || MuxAlarm.bAlarmed) { return 0; } char *elems[2] = { (char *)s1, (char *)s2 }; char *tbuf = alloc_lbuf("u_comp"); mux_strncpy(tbuf, pctx->buff, LBUF_SIZE-1); char *result = alloc_lbuf("u_comp"); char *bp = result; char *str = tbuf; mux_exec(result, &bp, pctx->executor, pctx->caller, pctx->enactor, AttrTrace(pctx->aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, elems, 2); *bp = '\0'; int n = mux_atol(result); free_lbuf(result); free_lbuf(tbuf); return n; } static void sane_qsort(ucomp_context *pctx, void *array[], int left, int right) { // Andrew Molitor's qsort, which doesn't require transitivity between // comparisons (essential for preventing crashes due to boneheads // who write comparison functions where a > b doesn't mean b < a). // int i, last; void *tmp; loop: if ( left < 0 || right <= left) { return; } // Pick something at random at swap it into the leftmost slot // This is the pivot, we'll put it back in the right spot later. // i = RandomINT32(0, right - left); tmp = array[left + i]; array[left + i] = array[left]; array[left] = tmp; last = left; for (i = left + 1; i <= right; i++) { // Walk the array, looking for stuff that's less than our // pivot. If it is, swap it with the next thing along // if (u_comp(pctx, array[i], array[left]) < 0) { last++; if (last == i) { continue; } tmp = array[last]; array[last] = array[i]; array[i] = tmp; } } // Now we put the pivot back, it's now in the right spot, we never // need to look at it again, trust me. // tmp = array[last]; array[last] = array[left]; array[left] = tmp; // At this point everything underneath the 'last' index is < the // entry at 'last' and everything above it is not < it. // if (last - left < right - last) { sane_qsort(pctx, array, left, last - 1); left = last + 1; goto loop; } else { sane_qsort(pctx, array, last + 1, right); right = last - 1; goto loop; } } FUNCTION(fun_sortby) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT)) { return; } char *atext; dbref thing; dbref aowner; int aflags; if (!parse_and_get_attrib(executor, fargs, &atext, &thing, &aowner, &aflags, buff, bufc)) { return; } ucomp_context ctx; ctx.buff = alloc_lbuf("fun_sortby.ctx"); mux_strncpy(ctx.buff, atext, LBUF_SIZE-1); ctx.executor = thing; ctx.caller = executor; ctx.enactor = enactor; ctx.aflags = aflags; char *list = alloc_lbuf("fun_sortby"); mux_strncpy(list, fargs[1], LBUF_SIZE-1); char *ptrs[LBUF_SIZE / 2]; int nptrs = list2arr(ptrs, LBUF_SIZE / 2, list, &sep); if (nptrs > 1) { sane_qsort(&ctx, (void **)ptrs, 0, nptrs - 1); } arr2list(ptrs, nptrs, buff, bufc, &osep); free_lbuf(list); free_lbuf(ctx.buff); free_lbuf(atext); } // fun_last: Returns last word in a string. Borrowed from TinyMUSH 2.2. // FUNCTION(fun_last) { // If we are passed an empty arglist return a null string. // if (nfargs == 0) { return; } SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } char *str; char *lstr = trim_space_sep(fargs[0], &sep); while (NULL != (str = next_token(lstr, &sep))) { lstr = str; } safe_str(lstr, buff, bufc); } // Borrowed from TinyMUSH 2.2 // FUNCTION(fun_matchall) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } int wcount; char *r, *s, *old, tbuf[8]; old = *bufc; // Check each word individually, returning the word number of all that // match. If none match, return 0. // wcount = 1; s = trim_space_sep(fargs[0], &sep); do { r = split_token(&s, &sep); mudstate.wild_invk_ctr = 0; if (quick_wild(fargs[1], r)) { mux_ltoa(wcount, tbuf); if (old != *bufc) { safe_chr(' ', buff, bufc); } safe_str(tbuf, buff, bufc); } wcount++; } while (s); if (*bufc == old) { safe_chr('0', buff, bufc); } } // --------------------------------------------------------------------------- // fun_ports: Returns a list of ports for a user. // Borrowed from TinyMUSH 2.2 // FUNCTION(fun_ports) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref target = lookup_player(executor, fargs[0], true); if (Good_obj(target)) { if (target == executor || Wizard(executor)) { if (Connected(target)) { make_portlist(executor, target, buff, bufc); } } else { safe_noperm(buff, bufc); } } else { safe_nomatch(buff, bufc); } } /* --------------------------------------------------------------------------- * fun_mix: Like map, but operates on up to ten lists simultaneously, passing * the elements as %0 - %10. * Borrowed from PennMUSH 1.50, upgraded by RhostMUSH. */ FUNCTION(fun_mix) { // Check to see if we have an appropriate number of arguments. // If there are more than three arguments, the last argument is // ALWAYS assumed to be a delimiter. // SEP sep; int lastn; if (nfargs < 4) { sep.n = 1; sep.str[0] = ' '; sep.str[1] = '\0'; lastn = nfargs - 1; } else if (!OPTIONAL_DELIM(nfargs, sep, DELIM_DFLT|DELIM_STRING)) { return; } else { lastn = nfargs - 2; } // Get the attribute. Check the permissions. // dbref thing; char *atext; dbref aowner; int aflags; if (!parse_and_get_attrib(executor, fargs, &atext, &thing, &aowner, &aflags, buff, bufc)) { return; } // Process the lists, one element at a time. // int i; int nwords = 0; char *cp[NUM_ENV_VARS]; for (i = 0; i < lastn; i++) { cp[i] = trim_space_sep(fargs[i+1], &sep); int twords = countwords(cp[i], &sep); if (nwords < twords) { nwords = twords; } } char empty[1] = ""; char *atextbuf = alloc_lbuf("fun_mix"); char *os[NUM_ENV_VARS]; bool bFirst = true; for ( int wc = 0; wc < nwords && mudstate.func_invk_ctr < mudconf.func_invk_lim && !MuxAlarm.bAlarmed; wc++) { if (!bFirst) { print_sep(&sep, buff, bufc); } else { bFirst = false; } for (i = 0; i < lastn; i++) { os[i] = split_token(&cp[i], &sep); if (NULL == os[i]) { os[i] = empty; } } mux_strncpy(atextbuf, atext, LBUF_SIZE-1); char *str = atextbuf; mux_exec(buff, bufc, thing, executor, enactor, AttrTrace(aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, os, lastn); } free_lbuf(atext); free_lbuf(atextbuf); } /* --------------------------------------------------------------------------- * fun_step: A little like a fusion of iter() and mix(), it takes elements * of a list X at a time and passes them into a single function as %0, %1, * etc. step(,,,,) */ FUNCTION(fun_step) { int i; SEP isep; if (!OPTIONAL_DELIM(4, isep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = isep; if (!OPTIONAL_DELIM(5, osep, DELIM_NULL|DELIM_CRLF|DELIM_INIT|DELIM_STRING)) { return; } int step_size = mux_atol(fargs[2]); if ( step_size < 1 || NUM_ENV_VARS < step_size) { notify(executor, "Illegal step size."); return; } // Get attribute. Check permissions. // char *atext; dbref thing; dbref aowner; int aflags; if (!parse_and_get_attrib(executor, fargs, &atext, &thing, &aowner, &aflags, buff, bufc)) { return; } char *cp = trim_space_sep(fargs[1], &isep); char *atextbuf = alloc_lbuf("fun_step"); char *os[NUM_ENV_VARS]; bool bFirst = true; while ( cp && mudstate.func_invk_ctr < mudconf.func_invk_lim && !MuxAlarm.bAlarmed) { if (!bFirst) { print_sep(&osep, buff, bufc); } else { bFirst = false; } for (i = 0; cp && i < step_size; i++) { os[i] = split_token(&cp, &isep); } mux_strncpy(atextbuf, atext, LBUF_SIZE-1); char *str = atextbuf; mux_exec(buff, bufc, executor, caller, enactor, AttrTrace(aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, os, i); } free_lbuf(atext); free_lbuf(atextbuf); } /* --------------------------------------------------------------------------- * fun_foreach: like map(), but it operates on a string, rather than on a list, * calling a user-defined function for each character in the string. * No delimiter is inserted between the results. * Borrowed from TinyMUSH 2.2 */ FUNCTION(fun_foreach) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if ( nfargs != 2 && nfargs != 4) { safe_str("#-1 FUNCTION (FOREACH) EXPECTS 2 OR 4 ARGUMENTS", buff, bufc); return; } char *atext; dbref thing; dbref aowner; int aflags; if (!parse_and_get_attrib(executor, fargs, &atext, &thing, &aowner, &aflags, buff, bufc)) { return; } char *str; char cbuf[2], prev = '\0'; char *atextbuf = alloc_lbuf("fun_foreach"); SEP sep; sep.n = 1; sep.str[0] = ' '; sep.str[1] = '\0'; char *cp = trim_space_sep(fargs[1], &sep); char *bp = cbuf; cbuf[1] = '\0'; if (nfargs == 4) { bool flag = false; while ( cp && *cp && mudstate.func_invk_ctr < mudconf.func_invk_lim && !MuxAlarm.bAlarmed) { cbuf[0] = *cp++; if (flag) { if ( cbuf[0] == *fargs[3] && prev != '\\' && prev != '%') { flag = false; continue; } } else { if ( cbuf[0] == *fargs[2] && prev != '\\' && prev != '%') { flag = true; continue; } else { safe_chr(cbuf[0], buff, bufc); continue; } } mux_strncpy(atextbuf, atext, LBUF_SIZE-1); str = atextbuf; mux_exec(buff, bufc, thing, executor, enactor, AttrTrace(aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, &bp, 1); prev = cbuf[0]; } } else { while ( cp && *cp && mudstate.func_invk_ctr < mudconf.func_invk_lim && !MuxAlarm.bAlarmed) { cbuf[0] = *cp++; mux_strncpy(atextbuf, atext, LBUF_SIZE-1); str = atextbuf; mux_exec(buff, bufc, thing, executor, enactor, AttrTrace(aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, &bp, 1); } } free_lbuf(atextbuf); free_lbuf(atext); } /* --------------------------------------------------------------------------- * fun_munge: combines two lists in an arbitrary manner. * Borrowed from TinyMUSH 2.2 */ FUNCTION(fun_munge) { SEP sep; if (!OPTIONAL_DELIM(4, sep, DELIM_DFLT|DELIM_STRING)) { return; } // Find our object and attribute. // char *atext; dbref thing; dbref aowner; int aflags; if (!parse_and_get_attrib(executor, fargs, &atext, &thing, &aowner, &aflags, buff, bufc)) { return; } int nptrs1, nptrs2, nresults, i, j; char *list1, *list2, *rlist, *bp, *str; char *uargs[2]; char **ptrs1 = NULL; try { ptrs1 = new char *[LBUF_SIZE / 2]; } catch (...) { ; // Nothing. } if (NULL == ptrs1) { free_lbuf(atext); return; } char **ptrs2 = NULL; try { ptrs2 = new char *[LBUF_SIZE / 2]; } catch (...) { ; // Nothing. } if (NULL == ptrs2) { free_lbuf(atext); delete [] ptrs1; return; } // Copy our lists and chop them up. // list1 = alloc_lbuf("fun_munge.list1"); list2 = alloc_lbuf("fun_munge.list2"); mux_strncpy(list1, fargs[1], LBUF_SIZE-1); mux_strncpy(list2, fargs[2], LBUF_SIZE-1); nptrs1 = list2arr(ptrs1, LBUF_SIZE / 2, list1, &sep); nptrs2 = list2arr(ptrs2, LBUF_SIZE / 2, list2, &sep); if (nptrs1 != nptrs2) { safe_str("#-1 LISTS MUST BE OF EQUAL SIZE", buff, bufc); free_lbuf(atext); free_lbuf(list1); free_lbuf(list2); delete [] ptrs1; delete [] ptrs2; return; } // Call the u-function with the first list as %0. // bp = rlist = alloc_lbuf("fun_munge"); str = atext; uargs[0] = fargs[1]; uargs[1] = sep.str; mux_exec(rlist, &bp, executor, caller, enactor, AttrTrace(aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, uargs, 2); *bp = '\0'; // Now that we have our result, put it back into array form. // Search through list1 until we find the element position, then // copy the corresponding element from list2. // char **results = new char *[LBUF_SIZE / 2]; ISOUTOFMEMORY(results); nresults = list2arr(results, LBUF_SIZE / 2, rlist, &sep); bool bFirst = true; for (i = 0; i < nresults; i++) { for (j = 0; j < nptrs1; j++) { if (!strcmp(results[i], ptrs1[j])) { if (!bFirst) { print_sep(&sep, buff, bufc); } else { bFirst = false; } safe_str(ptrs2[j], buff, bufc); ptrs1[j][0] = '\0'; break; } } } free_lbuf(atext); free_lbuf(list1); free_lbuf(list2); free_lbuf(rlist); delete [] ptrs1; delete [] ptrs2; delete [] results; } FUNCTION(fun_die) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int n = mux_atol(fargs[0]); int die = mux_atol(fargs[1]); if ( n == 0 || die <= 0) { safe_chr('0', buff, bufc); return; } if ( n < 1 || LBUF_SIZE <= n) { safe_range(buff, bufc); return; } if ( 3 <= nfargs && isTRUE(mux_atol(fargs[2]))) { ITL pContext; ItemToList_Init(&pContext, buff, bufc); for (int count = 0; count < n; count++) { if (!ItemToList_AddInteger(&pContext, RandomINT32(1, die))) { break; } } ItemToList_Final(&pContext); return; } int total = 0; for (int count = 0; count < n; count++) { total += RandomINT32(1, die); } safe_ltoa(total, buff, bufc); } FUNCTION(fun_lrand) { SEP sep; if (!OPTIONAL_DELIM(4, sep, DELIM_NULL|DELIM_CRLF|DELIM_STRING)) { return; } int n_times = mux_atol(fargs[2]); if (n_times < 1) { return; } if (n_times > LBUF_SIZE) { n_times = LBUF_SIZE; } INT32 iLower = mux_atol(fargs[0]); INT32 iUpper = mux_atol(fargs[1]); if (iLower <= iUpper) { for (int i = 0; i < n_times-1; i++) { INT32 val = RandomINT32(iLower, iUpper); safe_ltoa(val, buff, bufc); print_sep(&sep, buff, bufc); } INT32 val = RandomINT32(iLower, iUpper); safe_ltoa(val, buff, bufc); } } // Borrowed from PennMUSH 1.50 // FUNCTION(fun_lit) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // Just returns the argument, literally. // safe_str(fargs[0], buff, bufc); } FUNCTION(fun_dumping) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); #ifdef WIN32 safe_chr('0', buff, bufc); #else // WIN32 safe_bool(mudstate.dumping, buff, bufc); #endif // WIN32 } // The following table contains 64 symbols, so this supports -a- // radix-64 encoding. It is not however 'unix-to-unix' encoding. // All of the following characters are valid for an attribute // name, but not for the first character of an attribute name. // static char aRadixTable[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"; FUNCTION(fun_unpack) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // Validate radix if present. // INT64 iRadix = 64; if (nfargs == 2) { if ( !is_integer(fargs[1], NULL) || (iRadix = mux_atoi64(fargs[1])) < 2 || 64 < iRadix) { safe_str("#-1 RADIX MUST BE A NUMBER BETWEEN 2 and 64", buff, bufc); return; } } // Build Table of valid characters. // char MatchTable[256]; memset(MatchTable, 0, sizeof(MatchTable)); for (int i = 0; i < iRadix; i++) { MatchTable[(unsigned char)aRadixTable[i]] = static_cast(i + 1); } // Validate that first argument contains only characters from the // subset of permitted characters. // char *pString = fargs[0]; INT64 sum; int c; int LeadingCharacter; // Leading whitespace // while (mux_isspace(*pString)) { pString++; } // Possible sign // LeadingCharacter = c = *pString++; if (c == '-' || c == '+') { c = *pString++; } sum = 0; // Convert symbols // for (int iValue = MatchTable[(unsigned int)c]; iValue; iValue = MatchTable[(unsigned int)c]) { sum = iRadix * sum + iValue - 1; c = *pString++; } // Interpret sign // if (LeadingCharacter == '-') { sum = -sum; } safe_i64toa(sum, buff, bufc); } static size_t mux_Pack(INT64 val, int iRadix, char *buf) { char *p = buf; // Handle sign. // if (val < 0) { *p++ = '-'; val = -val; } char *q = p; while (val > iRadix-1) { INT64 iDiv = val / iRadix; INT64 iTerm = val - iDiv * iRadix; val = iDiv; *p++ = aRadixTable[iTerm]; } *p++ = aRadixTable[val]; size_t nLength = p - buf; *p-- = '\0'; // The digits are in reverse order with a possible leading '-' // if the value was negative. q points to the first digit, // and p points to the last digit. // while (q < p) { // Swap characters are *p and *q // char temp = *p; *p = *q; *q = temp; // Move p and first digit towards the middle. // --p; ++q; // Stop when we reach or pass the middle. // } return nLength; } FUNCTION(fun_pack) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // Validate the arguments are numeric. // if ( !is_integer(fargs[0], NULL) || (nfargs == 2 && !is_integer(fargs[1], NULL))) { safe_str("#-1 ARGUMENTS MUST BE NUMBERS", buff, bufc); return; } INT64 val = mux_atoi64(fargs[0]); // Validate the radix is between 2 and 64. // int iRadix = 64; if (nfargs == 2) { iRadix = mux_atol(fargs[1]); if (iRadix < 2 || 64 < iRadix) { safe_str("#-1 RADIX MUST BE A NUMBER BETWEEN 2 and 64", buff, bufc); return; } } char TempBuffer[76]; // 1 '-', 63 binary digits, 1 '\0', 11 for safety. size_t nLength = mux_Pack(val, iRadix, TempBuffer); safe_copy_buf(TempBuffer, nLength, buff, bufc); } FUNCTION(fun_strcat) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int i; for (i = 0; i < nfargs; i++) { safe_str(fargs[i], buff, bufc); } } // grep() and grepi() code borrowed from PennMUSH 1.50 // static char *grep_util(dbref player, dbref thing, char *pattern, char *lookfor, size_t len, bool insensitive) { // Returns a list of attributes which match on // whose contents have . // dbref aowner; char *tbuf1, *buf; char *bp, *bufc; int ca, aflags; tbuf1 = alloc_lbuf("grep_util"); bufc = buf = alloc_lbuf("grep_util.parse_attrib"); bp = tbuf1; safe_tprintf_str(buf, &bufc, "#%d/%s", thing, pattern); olist_push(); if (parse_attrib_wild(player, buf, &thing, false, false, true)) { BMH_State bmhs; if (insensitive) { BMH_PrepareI(&bmhs, len, lookfor); } else { BMH_Prepare(&bmhs, len, lookfor); } for (ca = olist_first(); ca != NOTHING && !MuxAlarm.bAlarmed; ca = olist_next()) { size_t nText; char *attrib = atr_get_LEN(thing, ca, &aowner, &aflags, &nText); size_t i; bool bSucceeded; if (insensitive) { bSucceeded = BMH_ExecuteI(&bmhs, &i, len, lookfor, nText, attrib); } else { bSucceeded = BMH_Execute(&bmhs, &i, len, lookfor, nText, attrib); } if (bSucceeded) { if (bp != tbuf1) { safe_chr(' ', tbuf1, &bp); } ATTR *ap = atr_num(ca); const char *pName = "(WARNING: Bad Attribute Number)"; if (ap) { pName = ap->name; } safe_str(pName, tbuf1, &bp); } free_lbuf(attrib); } } free_lbuf(buf); *bp = '\0'; olist_pop(); return tbuf1; } static void grep_handler(char *buff, char **bufc, dbref executor, char *fargs[], bool bCaseInsens) { dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } if (!Examinable(executor, it)) { safe_noperm(buff, bufc); return; } // Make sure there's an attribute and a pattern // if (!fargs[1] || !*fargs[1]) { safe_str("#-1 NO SUCH ATTRIBUTE", buff, bufc); return; } if (!fargs[2] || !*fargs[2]) { safe_str("#-1 INVALID GREP PATTERN", buff, bufc); return; } char *tp = grep_util(executor, it, fargs[1], fargs[2], strlen(fargs[2]), bCaseInsens); safe_str(tp, buff, bufc); free_lbuf(tp); } FUNCTION(fun_grep) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); grep_handler(buff, bufc, executor, fargs, false); } FUNCTION(fun_grepi) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); grep_handler(buff, bufc, executor, fargs, true); } // Borrowed from PennMUSH 1.50 // FUNCTION(fun_alphamax) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *amax = fargs[0]; for (int i = 1; i < nfargs; i++) { if (fargs[i] && strcmp(amax, fargs[i]) < 0) { amax = fargs[i]; } } safe_str(amax, buff, bufc); } // Borrowed from PennMUSH 1.50 // FUNCTION(fun_alphamin) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *amin = fargs[0]; for (int i = 1; i < nfargs; i++) { if (fargs[i] && strcmp(amin, fargs[i]) > 0) { amin = fargs[i]; } } safe_str(amin, buff, bufc); } // Borrowed from PennMUSH 1.50 // FUNCTION(fun_valid) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // Checks to see if a given is valid as a parameter of // a given type (such as an object name) // size_t nValidName; bool bValid; if (!*fargs[0] || !*fargs[1]) { bValid = false; } else if (!mux_stricmp(fargs[0], "attrname")) { MakeCanonicalAttributeName(fargs[1], &nValidName, &bValid); } else if (!mux_stricmp(fargs[0], "comalias")) { MakeCanonicalComAlias(fargs[1], &nValidName, &bValid); } else if (!mux_stricmp(fargs[0], "doing")) { MakeCanonicalDoing(fargs[1], &nValidName, &bValid); } else if (!mux_stricmp(fargs[0], "exitname")) { MakeCanonicalExitName(fargs[1], &nValidName, &bValid); } else if (!mux_stricmp(fargs[0], "malias")) { MakeCanonicalMailAlias(fargs[1], &nValidName, &bValid); } else if (!mux_stricmp(fargs[0], "maliasdesc")) { size_t vw; MakeCanonicalMailAliasDesc(fargs[1], &nValidName, &bValid, &vw); } else if (!mux_stricmp(fargs[0], "name")) { MakeCanonicalObjectName(fargs[1], &nValidName, &bValid); } else if (!mux_stricmp(fargs[0], "password")) { const char *msg; bValid = ok_password(fargs[1], &msg); } else if (!mux_stricmp(fargs[0], "playername")) { bValid = ValidatePlayerName(fargs[1]); } else { safe_nothing(buff, bufc); return; } safe_bool(bValid, buff, bufc); } // Borrowed from PennMUSH 1.50 // FUNCTION(fun_hastype) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } bool bResult = false; switch (mux_tolower(fargs[1][0])) { case 'r': bResult = isRoom(it); break; case 'e': bResult = isExit(it); break; case 'p': bResult = isPlayer(it); break; case 't': bResult = isThing(it); break; default: safe_str("#-1 NO SUCH TYPE", buff, bufc); break; } safe_bool(bResult, buff, bufc); } // Borrowed from PennMUSH 1.50 // FUNCTION(fun_lparent) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } else if (!Examinable(executor, it)) { safe_noperm(buff, bufc); return; } ITL pContext; ItemToList_Init(&pContext, buff, bufc, '#'); if (!ItemToList_AddInteger(&pContext, it)) { ItemToList_Final(&pContext); return; } dbref par = Parent(it); int iNestLevel = 1; while ( Good_obj(par) && Examinable(executor, it) && iNestLevel < mudconf.parent_nest_lim) { if (!ItemToList_AddInteger(&pContext, par)) { break; } it = par; par = Parent(par); iNestLevel++; } ItemToList_Final(&pContext); } #ifdef DEPRECATED // stacksize - returns how many items are stuffed onto an object stack // static int stacksize(dbref doer) { int i; STACK *sp; for (i = 0, sp = Stack(doer); sp != NULL; sp = sp->next, i++) { // Nothing ; } return i; } FUNCTION(fun_lstack) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); STACK *sp; dbref doer; if (nfargs == 0 || !*fargs[0]) { doer = executor; } else { doer = match_thing_quiet(executor, fargs[0]); if (!Good_obj(doer)) { safe_match_result(doer, buff, bufc); return; } } if (!Controls(executor, doer)) { safe_noperm(buff, bufc); return; } for (sp = Stack(doer); sp != NULL; sp = sp->next) { safe_str(sp->data, buff, bufc); if (sp->next != NULL) { safe_chr(' ', buff, bufc); } } } // stack_clr - clear the stack. // void stack_clr(dbref obj) { // Clear the stack. // STACK *sp, *next; for (sp = Stack(obj); sp != NULL; sp = next) { next = sp->next; free_lbuf(sp->data); MEMFREE(sp); sp = NULL; } s_Stack(obj, NULL); } FUNCTION(fun_empty) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref doer; if (nfargs == 0 || !*fargs[0]) { doer = executor; } else { doer = match_thing_quiet(executor, fargs[0]); if (!Good_obj(doer)) { safe_match_result(doer, buff, bufc); return; } } if (!Controls(executor, doer)) { safe_noperm(buff, bufc); return; } stack_clr(doer); } FUNCTION(fun_items) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref doer; if (nfargs == 0 || !*fargs[0]) { doer = executor; } else { doer = match_thing_quiet(executor, fargs[0]); if (!Good_obj(doer)) { safe_match_result(doer, buff, bufc); return; } } if (!Controls(executor, doer)) { safe_noperm(buff, bufc); return; } safe_ltoa(stacksize(doer), buff, bufc); } FUNCTION(fun_peek) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); STACK *sp; dbref doer; int count, pos; if (nfargs <= 0 || !*fargs[0]) { doer = executor; } else { doer = match_thing_quiet(executor, fargs[0]); if (!Good_obj(doer)) { safe_match_result(doer, buff, bufc); return; } } if (!Controls(executor, doer)) { safe_noperm(buff, bufc); return; } if (nfargs <= 1 || !*fargs[1]) { pos = 0; } else { pos = mux_atol(fargs[1]); } if (stacksize(doer) == 0) { return; } if (pos > (stacksize(doer) - 1)) { safe_str("#-1 POSITION TOO LARGE", buff, bufc); return; } count = 0; sp = Stack(doer); while (count != pos) { if (sp == NULL) { return; } count++; sp = sp->next; } safe_str(sp->data, buff, bufc); } FUNCTION(fun_pop) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref doer; if (nfargs <= 0 || !*fargs[0]) { doer = executor; } else { doer = match_thing_quiet(executor, fargs[0]); if (!Good_obj(doer)) { safe_match_result(doer, buff, bufc); return; } } if (!Controls(executor, doer)) { safe_noperm(buff, bufc); return; } int pos; if (nfargs <= 1 || !*fargs[1]) { pos = 0; } else { pos = mux_atol(fargs[1]); } if (stacksize(doer) == 0) { return; } if (pos > (stacksize(doer) - 1)) { safe_str("#-1 POSITION TOO LARGE", buff, bufc); return; } STACK *sp = Stack(doer); STACK *prev = NULL; int count = 0; while (count != pos) { if (sp == NULL) { return; } prev = sp; sp = sp->next; count++; } safe_str(sp->data, buff, bufc); if (count == 0) { s_Stack(doer, sp->next); free_lbuf(sp->data); MEMFREE(sp); sp = NULL; } else { prev->next = sp->next; free_lbuf(sp->data); MEMFREE(sp); sp = NULL; } } FUNCTION(fun_push) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref doer; char *data; if (nfargs <= 1 || !*fargs[1]) { doer = executor; data = fargs[0]; } else { doer = match_thing_quiet(executor, fargs[0]); if (!Good_obj(doer)) { safe_match_result(doer, buff, bufc); return; } data = fargs[1]; } if (!Controls(executor, doer)) { safe_noperm(buff, bufc); return; } if (stacksize(doer) >= mudconf.stack_limit) { safe_str("#-1 STACK SIZE EXCEEDED", buff, bufc); return; } STACK *sp = (STACK *)MEMALLOC(sizeof(STACK)); ISOUTOFMEMORY(sp); sp->next = Stack(doer); sp->data = alloc_lbuf("push"); mux_strncpy(sp->data, data, LBUF_SIZE-1); s_Stack(doer, sp); } #endif // DEPRECATED /* --------------------------------------------------------------------------- * fun_regmatch: Return 0 or 1 depending on whether or not a regular * expression matches a string. If a third argument is specified, dump * the results of a regexp pattern match into a set of arbitrary r()-registers. * * regmatch(string, pattern, list of registers) * If the number of matches exceeds the registers, those bits are tossed * out. * If -1 is specified as a register number, the matching bit is tossed. * Therefore, if the list is "-1 0 3 5", the regexp $0 is tossed, and * the regexp $1, $2, and $3 become r(0), r(3), and r(5), respectively. */ static void real_regmatch(const char *search, const char *pattern, char *registers, int nfargs, char *buff, char **bufc, bool cis) { if (MuxAlarm.bAlarmed) { return; } const char *errptr; int erroffset; // To capture N substrings, you need space for 3(N+1) offsets in the // offset vector. We'll allow 2N-1 substrings and possibly ignore some. // const int ovecsize = 6 * MAX_GLOBAL_REGS; int ovec[ovecsize]; pcre *re = pcre_compile(pattern, cis ? PCRE_CASELESS : 0, &errptr, &erroffset, NULL); if (!re) { // Matching error. // safe_str("#-1 REGEXP ERROR ", buff, bufc); safe_str(errptr, buff, bufc); return; } int matches = pcre_exec(re, NULL, search, static_cast(strlen(search)), 0, 0, ovec, ovecsize); if (matches == 0) { // There were too many substring matches. See docs for // pcre_copy_substring(). // matches = ovecsize / 3; } safe_bool(matches > 0, buff, bufc); if (matches < 0) { matches = 0; } // If we don't have a third argument, we're done. // if (nfargs != 3) { MEMFREE(re); return; } // We need to parse the list of registers. If a register is // mentioned in the list, then either fill the register with the // subexpression, or if there wasn't a match, clear it. // const int NSUBEXP = 2 * MAX_GLOBAL_REGS; char *qregs[NSUBEXP]; SEP sep; sep.n = 1; memcpy(sep.str, " ", 2); int nqregs = list2arr(qregs, NSUBEXP, registers, &sep); int i; for (i = 0; i < nqregs; i++) { int curq; if ( qregs[i] && *qregs[i] && (curq = mux_RegisterSet[(unsigned char)qregs[i][0]]) != -1 && qregs[i][1] == '\0' && curq < MAX_GLOBAL_REGS) { char *p = alloc_lbuf("fun_regmatch"); int len = pcre_copy_substring(search, ovec, matches, i, p, LBUF_SIZE); len = (len > 0 ? len : 0); size_t n = len; RegAssign(&mudstate.global_regs[curq], n, p); free_lbuf(p); } } MEMFREE(re); } FUNCTION(fun_regmatch) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); real_regmatch(fargs[0], fargs[1], fargs[2], nfargs, buff, bufc, false); } FUNCTION(fun_regmatchi) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); real_regmatch(fargs[0], fargs[1], fargs[2], nfargs, buff, bufc, true); } /* --------------------------------------------------------------------------- * regrab(), regraball(). Like grab() and graball(), using a regular expression * instead of a wildcard pattern. The versions ending in i are case-insensitive. */ static void real_regrab(char *search, const char *pattern, SEP *psep, char *buff, char **bufc, bool cis, bool all) { if (MuxAlarm.bAlarmed) { return; } pcre *re; pcre_extra *study = NULL; const char *errptr; int erroffset; // To capture N substrings, you need space for 3(N+1) offsets in the // offset vector. We'll allow 2N-1 substrings and possibly ignore some. // const int ovecsize = 6 * MAX_GLOBAL_REGS; int ovec[ovecsize]; re = pcre_compile(pattern, cis ? PCRE_CASELESS : 0, &errptr, &erroffset, NULL); if (!re) { // Matching error. // safe_str("#-1 REGEXP ERROR ", buff, bufc); safe_str(errptr, buff, bufc); return; } if (all) { study = pcre_study(re, 0, &errptr); } bool first = true; char *s = trim_space_sep(search, psep); do { char *r = split_token(&s, psep); if ( !MuxAlarm.bAlarmed && pcre_exec(re, study, r, static_cast(strlen(r)), 0, 0, ovec, ovecsize) >= 0) { if (first) { first = false; } else { print_sep(psep, buff, bufc); } safe_str(r, buff, bufc); if (!all) { break; } } } while (s); MEMFREE(re); if (study) { MEMFREE(study); } } FUNCTION(fun_regrab) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } real_regrab(fargs[0], fargs[1], &sep, buff, bufc, false, false); } FUNCTION(fun_regrabi) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } real_regrab(fargs[0], fargs[1], &sep, buff, bufc, true, false); } FUNCTION(fun_regraball) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } real_regrab(fargs[0], fargs[1], &sep, buff, bufc, false, true); } FUNCTION(fun_regraballi) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } real_regrab(fargs[0], fargs[1], &sep, buff, bufc, true, true); } /* --------------------------------------------------------------------------- * fun_translate: Takes a string and a second argument. If the second argument * is 0 or s, control characters are converted to spaces. If it's 1 or p, * they're converted to percent substitutions. */ FUNCTION(fun_translate) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int ch = fargs[1][0]; bool type = (ch == 'p' || ch == '1'); safe_str(translate_string(fargs[0], type), buff, bufc); } // Construct a CBitField to hold (nMaximum_arg+1) bits numbered 0 through // nMaximum_arg. // CBitField::CBitField(unsigned int nMaximum_arg) { nMaximum = 0; nInts = 0; pInts = NULL; pMasks = NULL; nBitsPer = sizeof(UINT32)*8; // Calculate Shift // nShift = 0; unsigned int i = 1; while (i < nBitsPer) { nShift++; i <<= 1; } // Calculate Mask // nMask = nBitsPer - 1; // Allocate array of UINT32s. // Resize(nMaximum_arg); } #define MINIMUM_RESIZE (4096*sizeof(UINT32)) void CBitField::Resize(unsigned int nMaximum_arg) { if ( 0 < nMaximum_arg && nMaximum < nMaximum_arg) { unsigned int nNewMaximum = nMaximum_arg; // This provides some assurances that we are not resizing too often. // if ( pMasks && nNewMaximum < nMaximum + MINIMUM_RESIZE) { nNewMaximum = nMaximum + MINIMUM_RESIZE; } size_t nNewInts = (nNewMaximum+nBitsPer) >> nShift; UINT32 *pNewMasks = (UINT32 *)MEMALLOC((nNewInts+nBitsPer) * sizeof(UINT32)); ISOUTOFMEMORY(pNewMasks); UINT32 *pNewInts = pNewMasks + nBitsPer; // Is this the first sizing or a re-sizing? // if (pMasks) { // Copy existing masks and bits to the new location, and // clear the new bits. // memcpy(pNewMasks, pMasks, (nInts+nBitsPer)*sizeof(UINT32)); memset(pNewInts + nInts, 0, (nNewInts - nInts)*sizeof(UINT32)); // Free the previous allocation. // MEMFREE(pMasks); // A reallocation. // nMaximum = nNewMaximum; nInts = nNewInts; pMasks = pNewMasks; pInts = pNewInts; } else { // First allocation. // nMaximum = nNewMaximum; nInts = nNewInts; pMasks = pNewMasks; pInts = pNewInts; // Initialize masks by calculating all possible single bits. // for (unsigned int i = 0; i < nBitsPer; i++) { pMasks[i] = ((UINT32)1) << i; } // Initialize bits by clearing them all. // ClearAll(); } } } CBitField::~CBitField(void) { pInts = NULL; if (pMasks) { MEMFREE(pMasks); pMasks = NULL; } } void CBitField::ClearAll(void) { memset(pInts, 0, nInts*sizeof(UINT32)); } void CBitField::Set(unsigned int i) { if (i <= nMaximum) { pInts[i>>nShift] |= pMasks[i&nMask]; } } void CBitField::Clear(unsigned int i) { if (i <= nMaximum) { pInts[i>>nShift] &= ~pMasks[i&nMask]; } } bool CBitField::IsSet(unsigned int i) { if (i <= nMaximum) { if (pInts[i>>nShift] & pMasks[i&nMask]) { return true; } } return false; } // ------------------------------------------------------------------------- // fun_lrooms: Takes a dbref (room), an int (N), and an optional bool (B). // // MUX Syntax: lrooms( [,[,]]) // // Returns a list of rooms -levels deep from . If == 1, it will // return all room dbrefs between 0 and levels, while == 0 will // return only the room dbrefs on the Nth level. The default is to show all // rooms dbrefs between 0 and levels. // // Written by Marlek. Idea from RhostMUSH. // static void room_list ( dbref player, dbref enactor, dbref room, int level, int maxlevels, bool showall ) { // Make sure the player can really see this room from their location. // if ( ( level == maxlevels || showall) && ( Examinable(player, room) || Location(player) == room || room == enactor)) { mudstate.bfReport.Set(room); } // If the Nth level has been reach, stop this branch in the recursion // if (level >= maxlevels) { return; } // Return info for all parent levels. // int lev; dbref parent; ITER_PARENTS(room, parent, lev) { // Look for exits at each level. // if (!Has_exits(parent)) { continue; } int key = 0; if (Examinable(player, parent)) { key |= VE_LOC_XAM; } if (Dark(parent)) { key |= VE_LOC_DARK; } if (Dark(room)) { key |= VE_BASE_DARK; } dbref thing; DOLIST(thing, Exits(parent)) { dbref loc = Location(thing); if ( exit_visible(thing, player, key) && !mudstate.bfTraverse.IsSet(loc)) { mudstate.bfTraverse.Set(loc); room_list(player, enactor, loc, (level + 1), maxlevels, showall); } } } } FUNCTION(fun_lrooms) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref room = match_thing_quiet(executor, fargs[0]); if (!Good_obj(room)) { safe_match_result(room, buff, bufc); return; } else if (!isRoom(room)) { safe_str("#-1 FIRST ARGUMENT MUST BE A ROOM", buff, bufc); return; } int N = 1; if (nfargs >= 2) { N = mux_atol(fargs[1]); if (N < 0) { safe_str("#-1 SECOND ARGUMENT MUST BE A POSITIVE NUMBER", buff, bufc); return; } else if (N > 50) { // Maybe this can be turned into a config parameter to prevent // misuse by putting in really large values. // safe_str("#-1 SECOND ARGUMENT IS TOO LARGE", buff, bufc); return; } } bool B = true; if (nfargs == 3) { B = xlate(fargs[2]); } mudstate.bfReport.Resize(mudstate.db_top-1); mudstate.bfTraverse.Resize(mudstate.db_top-1); mudstate.bfReport.ClearAll(); mudstate.bfTraverse.ClearAll(); mudstate.bfTraverse.Set(room); room_list(executor, enactor, room, 0, N, B); mudstate.bfReport.Clear(room); ITL pContext; ItemToList_Init(&pContext, buff, bufc, '#'); dbref i; DO_WHOLE_DB(i) { if ( mudstate.bfReport.IsSet(i) && !ItemToList_AddInteger(&pContext, i)) { break; } } ItemToList_Final(&pContext); } mux2.6/src/db.h0000600000175000017500000002065311025753746013342 0ustar sdennissdennis// db.h // // $Id: db.h 2734 2007-10-28 23:02:55Z brazilofmux $ // #ifndef __DB_H #define __DB_H #ifndef MEMORY_BASED #define SYNC cache_sync() #define CLOSE cache_close() #else // !MEMORY_BASED #define SYNC #define CLOSE #endif // !MEMORY_BASED #include "attrcache.h" #include "flags.h" #include "timeutil.h" #define ITER_PARENTS(t,p,l) for ((l)=0, (p)=(t); \ (Good_obj(p) && \ ((l) < mudconf.parent_nest_lim)); \ (p)=Parent(p), (l)++) int get_atr(const char *name); typedef struct attr ATTR; struct attr { const char *name; // This has to be first. braindeath. int number; // attr number int flags; }; #ifdef MEMORY_BASED typedef struct atrlist ATRLIST; struct atrlist { char *data; /* Attribute text. */ int size; /* Length of attribute */ int number; /* Attribute number. */ }; #endif // MEMORY_BASED char *MakeCanonicalAttributeName(const char *pName, size_t *pnName, bool *pbValid); char *MakeCanonicalAttributeCommand(const char *pName, size_t *pnName, bool *pbValid); typedef struct stack STACK; struct stack { char *data; STACK *next; }; extern ATTR *atr_num(int anum); extern ATTR *atr_str(const char *s); extern ATTR AttrTable[]; extern ATTR **anum_table; #define anum_get(x) (anum_table[(x)]) #define anum_set(x,v) anum_table[(x)] = v extern void anum_extend(int); #define ATR_INFO_CHAR '\1' /* Leadin char for attr control data */ /* Boolean expressions, for locks */ #define BOOLEXP_AND 0 #define BOOLEXP_OR 1 #define BOOLEXP_NOT 2 #define BOOLEXP_CONST 3 #define BOOLEXP_ATR 4 #define BOOLEXP_INDIR 5 #define BOOLEXP_CARRY 6 #define BOOLEXP_IS 7 #define BOOLEXP_OWNER 8 #define BOOLEXP_EVAL 9 typedef struct boolexp BOOLEXP; struct boolexp { boolexp_type type; struct boolexp *sub1; struct boolexp *sub2; dbref thing; /* thing refers to an object */ }; #define TRUE_BOOLEXP ((BOOLEXP *) 0) /* Database format information */ #define F_UNKNOWN 0 /* Unknown database format */ #define F_MUX 5 /* MUX format */ #define V_MASK 0x000000ff /* Database version */ #define V_ZONE 0x00000100 /* ZONE/DOMAIN field */ #define V_LINK 0x00000200 /* LINK field (exits from objs) */ #define V_DATABASE 0x00000400 /* attrs in a separate database */ #define V_ATRNAME 0x00000800 /* NAME is an attr, not in the hdr */ #define V_ATRKEY 0x00001000 /* KEY is an attr, not in the hdr */ #define V_PARENT 0x00002000 /* db has the PARENT field */ #define V_ATRMONEY 0x00008000 /* Money is kept in an attribute */ #define V_XFLAGS 0x00010000 /* An extra word of flags */ #define V_POWERS 0x00020000 /* Powers? */ #define V_3FLAGS 0x00040000 /* Adding a 3rd flag word */ #define V_QUOTED 0x00080000 /* Quoted strings, ala PennMUSH */ /* Some defines for DarkZone's flavor of PennMUSH */ #define DB_CHANNELS 0x2 /* Channel system */ #define DB_SLOCK 0x4 /* Slock */ #define DB_MC 0x8 /* Master Create Time + modifed */ #define DB_MPAR 0x10 /* Multiple Parent Code */ #define DB_CLASS 0x20 /* Class System */ #define DB_RANK 0x40 /* Rank */ #define DB_DROPLOCK 0x80 /* Drop/TelOut Lock */ #define DB_GIVELOCK 0x100 /* Give/TelIn Lock */ #define DB_GETLOCK 0x200 /* Get Lock */ #define DB_THREEPOW 0x400 /* Powers have Three Long Words */ /* special dbref's */ #define NOTHING (-1) /* null dbref */ #define AMBIGUOUS (-2) /* multiple possibilities, for matchers */ #define HOME (-3) /* virtual room, represents mover's home */ #define NOPERM (-4) /* Error status, no permission */ extern const char *aszSpecialDBRefNames[1-NOPERM]; typedef struct object OBJ; struct object { dbref location; /* PLAYER, THING: where it is */ /* ROOM: dropto: */ /* EXIT: where it goes to */ dbref contents; /* PLAYER, THING, ROOM: head of contentslist */ /* EXIT: unused */ dbref exits; /* PLAYER, THING, ROOM: head of exitslist */ /* EXIT: where it is */ dbref next; /* PLAYER, THING: next in contentslist */ /* EXIT: next in exitslist */ /* ROOM: unused */ dbref link; /* PLAYER, THING: home location */ /* ROOM, EXIT: unused */ dbref parent; /* ALL: defaults for attrs, exits, $cmds, */ dbref owner; /* PLAYER: domain number + class + moreflags */ /* THING, ROOM, EXIT: owning player number */ dbref zone; /* Whatever the object is zoned to.*/ FLAGSET fs; // ALL: Flags set on the object. POWER powers; /* ALL: Powers on object */ POWER powers2; /* ALL: even more powers */ #ifdef DEPRECATED STACK *stackhead; /* Every object has a stack. */ #endif // DEPRECATED CLinearTimeDelta cpu_time_used; /* ALL: CPU time eaten */ // ALL: When to refurbish throttled counters. // CLinearTimeAbsolute tThrottleExpired; int throttled_attributes; int throttled_mail; char *purename; char *moniker; #ifdef MEMORY_BASED ATRLIST *pALHead; /* The head of the attribute list. */ int nALAlloc; /* Size of the allocated attribute list. */ int nALUsed; /* Used portion of the attribute list. */ #else char *name; #endif // MEMORY_BASED }; const int INITIAL_ATRLIST_SIZE = 10; extern OBJ *db; #define Location(t) db[t].location #define Zone(t) db[t].zone #define Contents(t) db[t].contents #define Exits(t) db[t].exits #define Next(t) db[t].next #define Link(t) db[t].link #define Owner(t) db[t].owner #define Parent(t) db[t].parent #define Flags(t) db[t].fs.word[FLAG_WORD1] #define Flags2(t) db[t].fs.word[FLAG_WORD2] #define Flags3(t) db[t].fs.word[FLAG_WORD3] #define Powers(t) db[t].powers #define Powers2(t) db[t].powers2 #define Home(t) Link(t) #define Dropto(t) Location(t) #define ThAttrib(t) db[t].throttled_attributes #define ThMail(t) db[t].throttled_mail #define s_Location(t,n) db[t].location = (n) #define s_Zone(t,n) db[t].zone = (n) #define s_Contents(t,n) db[t].contents = (n) #define s_Exits(t,n) db[t].exits = (n) #define s_Next(t,n) db[t].next = (n) #define s_Link(t,n) db[t].link = (n) #define s_Owner(t,n) db[t].owner = (n) #define s_Parent(t,n) db[t].parent = (n) #define s_Flags(t,f,n) db[t].fs.word[f] = (n) #define s_Powers(t,n) db[t].powers = (n) #define s_Powers2(t,n) db[t].powers2 = (n) #define s_Home(t,n) s_Link(t,n) #define s_Dropto(t,n) s_Location(t,n) #define s_ThAttrib(t,n) db[t].throttled_attributes = (n); #define s_ThMail(t,n) db[t].throttled_mail = (n); #ifdef DEPRECATED #define Stack(t) db[t].stackhead #define s_Stack(t,n) db[t].stackhead = (n) #endif // DEPRECATED int Pennies(dbref obj); void s_Pennies(dbref obj, int howfew); void s_PenniesDirect(dbref obj, int howfew); #ifndef WIN32 void load_restart_db(void); #endif // !WIN32 dbref getref(FILE *); void putref(FILE *, dbref); void free_boolexp(BOOLEXP *); dbref parse_dbref(const char *); bool ThrottleMail(dbref executor); bool ThrottleAttributeNames(dbref executor); bool ThrottlePlayerCreate(void); int mkattr(dbref executor, const char *); void al_store(void); void db_grow(dbref); void db_free(void); void db_make_minimal(void); dbref db_read(FILE *, int *, int *, int *); dbref db_write(FILE *, int, int); void destroy_thing(dbref); void destroy_exit(dbref); void putstring(FILE *f, const char *s); char *getstring_noalloc(FILE *f, bool new_strings, size_t *pnBuffer); void init_attrtab(void); int GrowFiftyPercent(int x, int low, int high); #define DOLIST(thing,list) \ for ((thing)=(list); \ ((thing)!=NOTHING) && (Next(thing)!=(thing)); \ (thing)=Next(thing)) #define SAFE_DOLIST(thing,next,list) \ for ((thing)=(list),(next)=((thing)==NOTHING ? NOTHING: Next(thing)); \ (thing)!=NOTHING && (Next(thing)!=(thing)); \ (thing)=(next), (next)=Next(next)) #define DO_WHOLE_DB(thing) \ for ((thing)=0; (thing)=0; (thing)--) #endif // !__DB_H mux2.6/src/netcommon.cpp0000600000175000017500000024647611025753746015324 0ustar sdennissdennis// netcommon.cpp // // $Id: netcommon.cpp 2823 2007-11-28 03:33:36Z brazilofmux $ // // This file contains routines used by the networking code that do not // depend on the implementation of the networking code. The network-specific // portions of the descriptor data structure are not used. // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include #include "ansi.h" #include "attrs.h" #include "command.h" #include "comsys.h" #include "file_c.h" #include "functions.h" #include "mguests.h" #include "powers.h" #include "svdreport.h" #ifdef REALITY_LVLS #include "levels.h" #endif // REALITY_LVLS /* --------------------------------------------------------------------------- * make_portlist: Make a list of ports for PORTS(). */ void make_portlist(dbref player, dbref target, char *buff, char **bufc) { UNUSED_PARAMETER(player); ITL itl; ItemToList_Init(&itl, buff, bufc); DESC *d; DESC_ITER_CONN(d) { if ( d->player == target && !ItemToList_AddInteger64(&itl, d->descriptor)) { break; } } ItemToList_Final(&itl); } // --------------------------------------------------------------------------- // make_port_ulist: Make a list of connected user numbers for the LPORTS function. // --------------------------------------------------------------------------- void make_port_ulist(dbref player, char *buff, char **bufc) { DESC *d; ITL itl; char *tmp = alloc_sbuf("make_port_ulist"); ItemToList_Init(&itl, buff, bufc, '#'); DESC_ITER_CONN(d) { if ( !See_Hidden(player) && Hidden(d->player)) { continue; } // printf format: printf("%d:%d", d->player, d->descriptor); // char *p = tmp; p += mux_ltoa(d->player, p); *p++ = ':'; p += mux_i64toa(d->descriptor, p); size_t n = p - tmp; if (!ItemToList_AddStringLEN(&itl, n, tmp)) { break; } } ItemToList_Final(&itl); free_sbuf(tmp); } /* --------------------------------------------------------------------------- * update_quotas: Update timeslice quotas */ void update_quotas(CLinearTimeAbsolute& ltaLast, const CLinearTimeAbsolute& ltaCurrent) { if (ltaCurrent < ltaLast) { ltaLast = ltaCurrent; return; } CLinearTimeDelta ltdDiff = ltaCurrent - ltaLast; if (ltdDiff < mudconf.timeslice) { return; } int nSlices = ltdDiff / mudconf.timeslice; int nExtraQuota = mudconf.cmd_quota_incr * nSlices; if (nExtraQuota > 0) { DESC *d; DESC_ITER_ALL(d) { d->quota += nExtraQuota; if (d->quota > mudconf.cmd_quota_max) { d->quota = mudconf.cmd_quota_max; } } } ltaLast += mudconf.timeslice * nSlices; } /* raw_notify_html() -- raw_notify() without the newline */ void raw_notify_html(dbref player, const char *msg) { if (!msg || !*msg) { return; } if ( mudstate.inpipe && player == mudstate.poutobj) { safe_str(msg, mudstate.poutnew, &mudstate.poutbufc); return; } if ( !Connected(player) || !Html(player)) { return; } DESC *d; DESC_ITER_PLAYER(player, d) { queue_string(d, msg); } } /* --------------------------------------------------------------------------- * raw_notify: write a message to a player */ void raw_notify(dbref player, const char *msg) { DESC *d; if (!msg || !*msg) { return; } if ( mudstate.inpipe && player == mudstate.poutobj) { safe_str(msg, mudstate.poutnew, &mudstate.poutbufc); safe_str("\r\n", mudstate.poutnew, &mudstate.poutbufc); return; } if (!Connected(player)) { return; } DESC_ITER_PLAYER(player, d) { queue_string(d, msg); queue_write_LEN(d, "\r\n", 2); } } void raw_notify_newline(dbref player) { if ( mudstate.inpipe && player == mudstate.poutobj) { safe_str("\r\n", mudstate.poutnew, &mudstate.poutbufc); return; } if (!Connected(player)) { return; } DESC *d; DESC_ITER_PLAYER(player, d) { queue_write_LEN(d, "\r\n", 2); } } /* --------------------------------------------------------------------------- * raw_broadcast: Send message to players who have indicated flags */ void DCL_CDECL raw_broadcast(int inflags, const char *fmt, ...) { if (!fmt || !*fmt) { return; } char buff[LBUF_SIZE]; va_list ap; va_start(ap, fmt); mux_vsnprintf(buff, LBUF_SIZE, fmt, ap); va_end(ap); DESC *d; DESC_ITER_CONN(d) { if ((Flags(d->player) & inflags) == inflags) { queue_string(d, buff); queue_write_LEN(d, "\r\n", 2); process_output(d, false); } } } /* --------------------------------------------------------------------------- * clearstrings: clear out prefix and suffix strings */ void clearstrings(DESC *d) { if (d->output_prefix) { free_lbuf(d->output_prefix); d->output_prefix = NULL; } if (d->output_suffix) { free_lbuf(d->output_suffix); d->output_suffix = NULL; } } static void add_to_output_queue(DESC *d, const char *b, size_t n) { TBLOCK *tp; size_t left; // Allocate an output buffer if needed. // if (d->output_head == NULL) { tp = (TBLOCK *)MEMALLOC(OUTPUT_BLOCK_SIZE); if (NULL != tp) { tp->hdr.nxt = NULL; tp->hdr.start = tp->data; tp->hdr.end = tp->data; tp->hdr.nchars = 0; d->output_head = tp; d->output_tail = tp; } else { ISOUTOFMEMORY(tp); return; } } else { tp = d->output_tail; } // Now tp points to the last buffer in the chain. // do { // See if there is enough space in the buffer to hold the // string. If so, copy it and update the pointers.. // left = OUTPUT_BLOCK_SIZE - (tp->hdr.end - (char *)tp + 1); if (n <= left) { memcpy(tp->hdr.end, b, n); tp->hdr.end += n; tp->hdr.nchars += n; n = 0; } else { // It didn't fit. Copy what will fit and then allocate // another buffer and retry. // if (left > 0) { memcpy(tp->hdr.end, b, left); tp->hdr.end += left; tp->hdr.nchars += left; b += left; n -= left; } tp = (TBLOCK *)MEMALLOC(OUTPUT_BLOCK_SIZE); if (NULL != tp) { tp->hdr.nxt = NULL; tp->hdr.start = tp->data; tp->hdr.end = tp->data; tp->hdr.nchars = 0; d->output_tail->hdr.nxt = tp; d->output_tail = tp; } else { ISOUTOFMEMORY(tp); return; } } } while (n > 0); } /* --------------------------------------------------------------------------- * queue_write: Add text to the output queue for the indicated descriptor. */ void queue_write_LEN(DESC *d, const char *b, size_t n) { if (n <= 0) { return; } if (static_cast(mudconf.output_limit) < d->output_size + n) { process_output(d, false); } if (static_cast(mudconf.output_limit) < d->output_size + n) { TBLOCK *tp = d->output_head; if (tp == NULL) { STARTLOG(LOG_PROBLEMS, "QUE", "WRITE"); log_text("Flushing when output_head is null!"); ENDLOG; } else { STARTLOG(LOG_NET, "NET", "WRITE"); char *buf = alloc_lbuf("queue_write.LOG"); mux_sprintf(buf, LBUF_SIZE, "[%u/%s] Output buffer overflow, %d chars discarded by ", d->descriptor, d->addr, tp->hdr.nchars); log_text(buf); free_lbuf(buf); if (d->flags & DS_CONNECTED) { log_name(d->player); } ENDLOG; d->output_size -= tp->hdr.nchars; d->output_head = tp->hdr.nxt; d->output_lost += tp->hdr.nchars; if (d->output_head == NULL) { d->output_tail = NULL; } MEMFREE(tp); tp = NULL; } } add_to_output_queue(d, b, n); d->output_size += n; d->output_tot += n; #ifdef WIN32 if ( bUseCompletionPorts && !d->bWritePending && !d->bConnectionDropped) { d->bCallProcessOutputLater = true; } #endif } void queue_write(DESC *d, const char *b) { queue_write_LEN(d, b, strlen(b)); } static const char *encode_iac(const char *szString) { static char Buffer[2*LBUF_SIZE]; char *pBuffer = Buffer; const char *pString = szString; if (pString) { while (*pString) { const char *p = strchr(pString, NVT_IAC); if (!p) { // NVT_IAC does not appear in the buffer. This is by far the most-common case. // if (pString == szString) { // Avoid copying to the static buffer, and just return the original buffer. // return szString; } else { mux_strncpy(pBuffer, pString, 2*LBUF_SIZE-1); return Buffer; } } else { // Copy up to and including the IAC. // size_t n = p - pString + 1; memcpy(pBuffer, pString, n); pBuffer += n; pString += n; // Add another IAC. // safe_copy_chr(NVT_IAC, Buffer, &pBuffer, sizeof(Buffer)-1); } } } *pBuffer = '\0'; return Buffer; } void queue_string(DESC *d, const char *s) { const char *p = s; if (d->flags & DS_CONNECTED) { if ( !Ansi(d->player) && strchr(s, ESC_CHAR)) { p = strip_ansi(p); } else if (NoBleed(d->player)) { p = normal_to_white(p); } if (NoAccents(d->player)) { p = strip_accents(p); } } else { if (strchr(s, ESC_CHAR)) { p = strip_ansi(p); } p = strip_accents(p); } p = encode_iac(p); queue_write(d, p); } void freeqs(DESC *d) { TBLOCK *tb, *tnext; CBLK *cb, *cnext; tb = d->output_head; while (tb) { tnext = tb->hdr.nxt; MEMFREE(tb); tb = tnext; } d->output_head = NULL; d->output_tail = NULL; cb = d->input_head; while (cb) { cnext = (CBLK *) cb->hdr.nxt; free_lbuf(cb); cb = cnext; } d->input_head = NULL; d->input_tail = NULL; if (d->raw_input) { free_lbuf(d->raw_input); } d->raw_input = NULL; d->raw_input_at = NULL; d->nOption = 0; d->raw_input_state = NVT_IS_NORMAL; d->nvt_sga_him_state = OPTION_NO; d->nvt_sga_us_state = OPTION_NO; d->nvt_eor_him_state = OPTION_NO; d->nvt_eor_us_state = OPTION_NO; d->nvt_naws_him_state = OPTION_NO; d->nvt_naws_us_state = OPTION_NO; d->height = 24; d->width = 78; } /* --------------------------------------------------------------------------- * desc_addhash: Add a net descriptor to its player hash list. */ void desc_addhash(DESC *d) { dbref player = d->player; DESC *hdesc = (DESC *)hashfindLEN(&player, sizeof(player), &mudstate.desc_htab); if (hdesc == NULL) { d->hashnext = NULL; hashaddLEN(&player, sizeof(player), d, &mudstate.desc_htab); } else { d->hashnext = hdesc; hashreplLEN(&player, sizeof(player), d, &mudstate.desc_htab); } } /* --------------------------------------------------------------------------- * desc_delhash: Remove a net descriptor from its player hash list. */ static void desc_delhash(DESC *d) { dbref player = d->player; DESC *last = NULL; DESC *hdesc = (DESC *)hashfindLEN(&player, sizeof(player), &mudstate.desc_htab); while (hdesc != NULL) { if (d == hdesc) { if (last == NULL) { if (d->hashnext == NULL) { hashdeleteLEN(&player, sizeof(player), &mudstate.desc_htab); } else { hashreplLEN(&player, sizeof(player), d->hashnext, &mudstate.desc_htab); } } else { last->hashnext = d->hashnext; } break; } last = hdesc; hdesc = hdesc->hashnext; } d->hashnext = NULL; } void welcome_user(DESC *d) { if (d->host_info & H_REGISTRATION) { fcache_dump(d, FC_CONN_REG); } else { fcache_dump(d, FC_CONN); } } void save_command(DESC *d, CBLK *command) { command->hdr.nxt = NULL; if (d->input_tail == NULL) { d->input_head = command; // We have added our first command to an empty list. Go process it later. // scheduler.DeferImmediateTask(PRIORITY_SYSTEM, Task_ProcessCommand, d, 0); } else { d->input_tail->hdr.nxt = command; } d->input_tail = command; } static void set_userstring(char **userstring, const char *command) { while (mux_isspace(*command)) { command++; } if (!*command) { if (*userstring != NULL) { free_lbuf(*userstring); *userstring = NULL; } } else { if (*userstring == NULL) { *userstring = alloc_lbuf("set_userstring"); } mux_strncpy(*userstring, command, LBUF_SIZE-1); } } static void parse_connect(const char *msg, char command[LBUF_SIZE], char user[LBUF_SIZE], char pass[LBUF_SIZE]) { size_t nmsg = strlen(msg); size_t i = 0; if (nmsg > MBUF_SIZE) { *command = '\0'; *user = '\0'; *pass = '\0'; return; } while ( i < nmsg && mux_isspace(msg[i])) { i++; } char *p = command; while ( i < nmsg && !mux_isspace(msg[i])) { safe_copy_chr(msg[i], command, &p, LBUF_SIZE-1); i++; } *p = '\0'; while ( i < nmsg && mux_isspace(msg[i])) { i++; } p = user; if ( mudconf.name_spaces && i < nmsg && msg[i] == '\"') { for (; i < nmsg && (msg[i] == '\"' || mux_isspace(msg[i])); i++) { // Nothing. } while ( i < nmsg && msg[i] != '\"') { while ( i < nmsg && !mux_isspace(msg[i]) && msg[i] != '\"') { safe_copy_chr(msg[i], user, &p, LBUF_SIZE-1); i++; } if ( nmsg <= i || msg[i] == '\"') { break; } while ( i < nmsg && mux_isspace(msg[i])) { i++; } if ( i < nmsg && msg[i] != '\"') { safe_copy_chr(' ', user, &p, LBUF_SIZE-1); } } while ( i < nmsg && msg[i] == '\"') { i++; } } else { while ( i < nmsg && !mux_isspace(msg[i])) { safe_copy_chr(msg[i], user, &p, LBUF_SIZE-1); i++; } } *p = '\0'; while ( i < nmsg && mux_isspace(msg[i])) { i++; } p = pass; while ( i < nmsg && !mux_isspace(msg[i])) { safe_copy_chr(msg[i], pass, &p, LBUF_SIZE-1); i++; } *p = '\0'; } static void announce_connect(dbref player, DESC *d) { desc_addhash(d); DESC *dtemp; int count = 0; DESC_ITER_CONN(dtemp) { count++; } if (mudstate.record_players < count) { mudstate.record_players = count; } char *buf = alloc_lbuf("announce_connect"); dbref aowner; int aflags; size_t nLen; atr_pget_str_LEN(buf, player, A_TIMEOUT, &aowner, &aflags, &nLen); if (nLen) { d->timeout = mux_atol(buf); if (d->timeout <= 0) { d->timeout = mudconf.idle_timeout; } } dbref loc = Location(player); s_Connected(player); if (d->flags & DS_PUEBLOCLIENT) { s_Html(player); } if ('\0' != mudconf.motd_msg[0]) { raw_notify( player, tprintf("\n%sMOTD:%s %s\n", ANSI_HILITE, ANSI_NORMAL, mudconf.motd_msg)); } if (Wizard(player)) { if ('\0' != mudconf.wizmotd_msg[0]) { raw_notify(player, tprintf("%sWIZMOTD:%s %s\n", ANSI_HILITE, ANSI_NORMAL, mudconf.wizmotd_msg)); } if (!(mudconf.control_flags & CF_LOGIN)) { raw_notify(player, "*** Logins are disabled."); } } atr_get_str_LEN(buf, player, A_LPAGE, &aowner, &aflags, &nLen); if (nLen) { raw_notify(player, "Your PAGE LOCK is set. You may be unable to receive some pages."); } int num = 0; DESC_ITER_PLAYER(player, dtemp) { num++; } // Reset vacation flag. // s_Flags(player, FLAG_WORD2, Flags2(player) & ~VACATION); const char *pRoomAnnounceFmt; const char *pMonitorAnnounceFmt; if (num < 2) { pRoomAnnounceFmt = "%s has connected."; if (mudconf.have_comsys) { do_comconnect(player); } if ( Hidden(player) && Can_Hide(player)) { pMonitorAnnounceFmt = "GAME: %s has DARK-connected."; } else { pMonitorAnnounceFmt = "GAME: %s has connected."; } if ( Suspect(player) || (d->host_info & H_SUSPECT)) { raw_broadcast(WIZARD, "[Suspect] %s has connected.", Moniker(player)); } } else { pRoomAnnounceFmt = "%s has reconnected."; pMonitorAnnounceFmt = "GAME: %s has reconnected."; if ( Suspect(player) || (d->host_info & H_SUSPECT)) { raw_broadcast(WIZARD, "[Suspect] %s has reconnected.", Moniker(player)); } } mux_sprintf(buf, LBUF_SIZE, pRoomAnnounceFmt, Moniker(player)); raw_broadcast(MONITOR, pMonitorAnnounceFmt, Moniker(player)); int key = MSG_INV; if ( loc != NOTHING && !( Hidden(player) && Can_Hide(player))) { key |= (MSG_NBR | MSG_NBR_EXITS | MSG_LOC | MSG_FWDLIST); } dbref temp = mudstate.curr_enactor; mudstate.curr_enactor = player; #ifdef REALITY_LVLS if(loc == NOTHING) notify_check(player, player, buf, key); else notify_except_rlevel(loc, player, player, buf, 0); #else notify_check(player, player, buf, key); #endif // REALITY_LVLS atr_pget_str_LEN(buf, player, A_ACONNECT, &aowner, &aflags, &nLen); CLinearTimeAbsolute lta; dbref zone, obj; if (nLen) { wait_que(player, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buf, 0, NULL, NULL); } if (mudconf.master_room != NOTHING) { atr_pget_str_LEN(buf, mudconf.master_room, A_ACONNECT, &aowner, &aflags, &nLen); if (nLen) { wait_que(mudconf.master_room, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buf, 0, NULL, NULL); } DOLIST(obj, Contents(mudconf.master_room)) { atr_pget_str_LEN(buf, obj, A_ACONNECT, &aowner, &aflags, &nLen); if (nLen) { wait_que(obj, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buf, 0, NULL, NULL); } } } // Do the zone of the player's location's possible aconnect. // if ( mudconf.have_zones && Good_obj(zone = Zone(loc))) { switch (Typeof(zone)) { case TYPE_THING: atr_pget_str_LEN(buf, zone, A_ACONNECT, &aowner, &aflags, &nLen); if (nLen) { wait_que(zone, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buf, 0, NULL, NULL); } break; case TYPE_ROOM: // check every object in the room for a connect action. // DOLIST(obj, Contents(zone)) { atr_pget_str_LEN(buf, obj, A_ACONNECT, &aowner, &aflags, &nLen); if (nLen) { wait_que(obj, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buf, 0, NULL, NULL); } } break; default: log_text(tprintf("Invalid zone #%d for %s(#%d) has bad type %d", zone, Name(player), player, Typeof(zone))); } } free_lbuf(buf); CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); char *time_str = ltaNow.ReturnDateString(7); record_login(player, true, time_str, d->addr, d->username, inet_ntoa((d->address).sin_addr)); if (mudconf.have_mailer) { check_mail(player, 0, false); } look_in(player, Location(player), (LK_SHOWEXIT|LK_OBEYTERSE|LK_SHOWVRML)); mudstate.curr_enactor = temp; if (Guest(player)) { db[player].fs.word[FLAG_WORD1] &= ~DARK; } } void announce_disconnect(dbref player, DESC *d, const char *reason) { int num = 0, key; DESC *dtemp; DESC_ITER_PLAYER(player, dtemp) { num++; } #ifdef FIRANMUX // Modified so that %# would be the dbref of the object which @booted you, // if such is the case. #else dbref temp = mudstate.curr_enactor; mudstate.curr_enactor = player; #endif dbref loc = Location(player); if (num < 2) { if ( Suspect(player) || (d->host_info & H_SUSPECT)) { raw_broadcast(WIZARD, "[Suspect] %s has disconnected.", Moniker(player)); } char *buf = alloc_lbuf("announce_disconnect.only"); mux_sprintf(buf, LBUF_SIZE, "%s has disconnected.", Moniker(player)); key = MSG_INV; if ( loc != NOTHING && !( Hidden(player) && Can_Hide(player))) { key |= (MSG_NBR | MSG_NBR_EXITS | MSG_LOC | MSG_FWDLIST); } #ifdef REALITY_LVLS if(loc == NOTHING) notify_check(player, player, buf, key); else notify_except_rlevel(loc, player, player, buf, 0); #else notify_check(player, player, buf, key); #endif // REALITY_LVLS if (mudconf.have_mailer) { do_mail_purge(player); } raw_broadcast(MONITOR, "GAME: %s has disconnected. <%s>", Moniker(player), reason); c_Connected(player); if (mudconf.have_comsys) { do_comdisconnect(player); } dbref aowner, zone, obj; int aflags; size_t nLen; char *argv[1]; argv[0] = (char *)reason; CLinearTimeAbsolute lta; atr_pget_str_LEN(buf, player, A_ADISCONNECT, &aowner, &aflags, &nLen); if (nLen) { #if defined(FIRANMUX) wait_que(player, player, mudstate.curr_enactor, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buf, 1, argv, NULL); #else wait_que(player, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buf, 1, argv, NULL); #endif // FIRANMUX } if (mudconf.master_room != NOTHING) { atr_pget_str_LEN(buf, mudconf.master_room, A_ADISCONNECT, &aowner, &aflags, &nLen); if (nLen) { wait_que(mudconf.master_room, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buf, 0, NULL, NULL); } DOLIST(obj, Contents(mudconf.master_room)) { atr_pget_str_LEN(buf, obj, A_ADISCONNECT, &aowner, &aflags, &nLen); if (nLen) { wait_que(obj, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buf, 0, NULL, NULL); } } } // Do the zone of the player's location's possible adisconnect. // if (mudconf.have_zones && Good_obj(zone = Zone(loc))) { switch (Typeof(zone)) { case TYPE_THING: atr_pget_str_LEN(buf, zone, A_ADISCONNECT, &aowner, &aflags, &nLen); if (nLen) { wait_que(zone, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buf, 0, NULL, NULL); } break; case TYPE_ROOM: // check every object in the room for a connect action. // DOLIST(obj, Contents(zone)) { atr_pget_str_LEN(buf, obj, A_ADISCONNECT, &aowner, &aflags, &nLen); if (nLen) { wait_que(obj, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buf, 0, NULL, NULL); } } break; default: log_text(tprintf("Invalid zone #%d for %s(#%d) has bad type %d", zone, Name(player), player, Typeof(zone))); } } free_lbuf(buf); if (d->flags & DS_AUTODARK) { d->flags &= ~DS_AUTODARK; db[player].fs.word[FLAG_WORD1] &= ~DARK; } if (Guest(player)) { db[player].fs.word[FLAG_WORD1] |= DARK; halt_que(NOTHING, player); } } else { if ( Suspect(player) || (d->host_info & H_SUSPECT)) { raw_broadcast(WIZARD, "[Suspect] %s has partially disconnected.", Moniker(player)); } char *mbuf = alloc_mbuf("announce_disconnect.partial"); mux_sprintf(mbuf, MBUF_SIZE, "%s has partially disconnected.", Moniker(player)); key = MSG_INV; if ( loc != NOTHING && !( Hidden(player) && Can_Hide(player))) { key |= (MSG_NBR | MSG_NBR_EXITS | MSG_LOC | MSG_FWDLIST); } #ifdef REALITY_LVLS if(loc == NOTHING) notify_check(player, player, mbuf, key); else notify_except_rlevel(loc, player, player, mbuf, 0); #else notify_check(player, player, mbuf, key); #endif // REALITY_LVLS raw_broadcast(MONITOR, "GAME: %s has partially disconnected.", Moniker(player)); free_mbuf(mbuf); } #if !defined(FIRANMUX) mudstate.curr_enactor = temp; #endif // FIRANMUX desc_delhash(d); local_disconnect(player, num); } int boot_off(dbref player, const char *message) { DESC *d, *dnext; int count = 0; DESC_SAFEITER_PLAYER(player, d, dnext) { if (message && *message) { queue_string(d, message); queue_write_LEN(d, "\r\n", 2); } shutdownsock(d, R_BOOT); count++; } return count; } int boot_by_port(SOCKET port, bool bGod, const char *message) { DESC *d, *dnext; int count = 0; DESC_SAFEITER_ALL(d, dnext) { if ( d->descriptor == port && ( bGod || !(d->flags & DS_CONNECTED) || !God(d->player))) { if ( message && *message) { queue_string(d, message); queue_write_LEN(d, "\r\n", 2); } shutdownsock(d, R_BOOT); count++; } } return count; } /* --------------------------------------------------------------------------- * desc_reload: Reload parts of net descriptor that are based on db info. */ void desc_reload(dbref player) { DESC *d; char *buf; dbref aowner; FLAG aflags; DESC_ITER_PLAYER(player, d) { buf = atr_pget(player, A_TIMEOUT, &aowner, &aflags); if (buf) { d->timeout = mux_atol(buf); if (d->timeout <= 0) { d->timeout = mudconf.idle_timeout; } } free_lbuf(buf); } } // --------------------------------------------------------------------------- // fetch_session: Return number of sessions (or 0 if not logged in). // int fetch_session(dbref target) { DESC *d; int nCount = 0; DESC_ITER_PLAYER(target, d) { nCount++; } return nCount; } static DESC *find_least_idle(dbref target) { CLinearTimeAbsolute ltaNewestLastTime; DESC *d; DESC *dLeastIdle = NULL; DESC_ITER_PLAYER(target, d) { if ( NULL == dLeastIdle || ltaNewestLastTime < d->last_time) { dLeastIdle = d; ltaNewestLastTime = d->last_time; } } return dLeastIdle; } int fetch_height(dbref target) { DESC *d = find_least_idle(target); if (NULL != d) { return d->height; } return 24; } int fetch_width(dbref target) { DESC *d = find_least_idle(target); if (NULL != d) { return d->width; } return 78; } // --------------------------------------------------------------------------- // fetch_idle: Return smallest idle time for a player (or -1 if not logged in). // int fetch_idle(dbref target) { CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); DESC *d = find_least_idle(target); if (NULL != d) { CLinearTimeDelta ltdResult; ltdResult = ltaNow - d->last_time; return ltdResult.ReturnSeconds(); } else { return -1; } } // --------------------------------------------------------------------------- // find_oldest: Return descriptor with the oldeset connected_at (or NULL if // not logged in). // void find_oldest(dbref target, DESC *dOldest[2]) { dOldest[0] = NULL; dOldest[1] = NULL; DESC *d; bool bFound = false; DESC_ITER_PLAYER(target, d) { if ( !bFound || d->connected_at < dOldest[0]->connected_at) { bFound = true; dOldest[1] = dOldest[0]; dOldest[0] = d; } } } // --------------------------------------------------------------------------- // fetch_connect: Return largest connect time for a player (or -1 if not // logged in). // int fetch_connect(dbref target) { DESC *dOldest[2]; find_oldest(target, dOldest); if (dOldest[0]) { CLinearTimeAbsolute ltaNow; CLinearTimeDelta ltdOldest; ltaNow.GetUTC(); ltdOldest = ltaNow - dOldest[0]->connected_at; return ltdOldest.ReturnSeconds(); } else { return -1; } } // A NOTE about AUTODARK: It only works for wizard players. Wizard players // are automatically set DARK if they are not already set DARK and they have // no session which is unidle. // // The AUTODARK state is cleared when at least one session becomes unidle. // The AUTODARK state is also cleared when the last idle session is // disconnected from the server (session shutdown or @shutdown). // void check_idle(void) { DESC *d, *dnext; CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); DESC_SAFEITER_ALL(d, dnext) { if ( (d->flags & DS_CONNECTED) && KeepAlive(d->player)) { // Send a Telnet NOP code - creates traffic to keep NAT routers // happy. Hopefully this only runs once a minute. // const char aNOP[2] = { NVT_IAC, NVT_NOP }; queue_write_LEN(d, aNOP, sizeof(aNOP)); } if (d->flags & DS_AUTODARK) { continue; } if (d->flags & DS_CONNECTED) { if (mudconf.idle_timeout <= 0) { // Idle timeout checking on connected players is effectively disabled. // PennMUSH uses idle_timeout == 0. Rhost uses idel_timeout == -1. // We will be disabled for either setting. // continue; } CLinearTimeDelta ltdIdle = ltaNow - d->last_time; if (Can_Idle(d->player)) { if ( mudconf.idle_wiz_dark && (Flags(d->player) & (WIZARD|DARK)) == WIZARD && ltdIdle.ReturnSeconds() > mudconf.idle_timeout) { // Make sure this Wizard player does not have some other // active session. // DESC *d1; bool bFound = false; DESC_ITER_PLAYER(d->player, d1) { if (d1 != d) { CLinearTimeDelta ltd = ltaNow - d1->last_time; if (ltd.ReturnSeconds() <= mudconf.idle_timeout) { bFound = true; break; } } } if (!bFound) { db[d->player].fs.word[FLAG_WORD1] |= DARK; DESC_ITER_PLAYER(d->player, d1) { d1->flags |= DS_AUTODARK; } } } } else if (ltdIdle.ReturnSeconds() > d->timeout) { queue_write(d, "*** Inactivity Timeout ***\r\n"); shutdownsock(d, R_TIMEOUT); } } else if (0 < mudconf.conn_timeout) { CLinearTimeDelta ltdIdle = ltaNow - d->connected_at; if (ltdIdle.ReturnSeconds() > mudconf.conn_timeout) { queue_write(d, "*** Login Timeout ***\r\n"); shutdownsock(d, R_TIMEOUT); } } } } void check_events(void) { dbref thing, parent; int lev; CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); FIELDEDTIME ft; if (!ltaNow.ReturnFields(&ft)) { return; } // Resetting every midnight. // static int iLastHourChecked = 25; if ( iLastHourChecked == 23 && ft.iHour < iLastHourChecked) { mudstate.events_flag &= ~ET_DAILY; } iLastHourChecked = ft.iHour; if ( ft.iHour == mudconf.events_daily_hour && !(mudstate.events_flag & ET_DAILY)) { mudstate.events_flag |= ET_DAILY; DO_WHOLE_DB(thing) { if (Going(thing)) { continue; } ITER_PARENTS(thing, parent, lev) { if (H_Daily(thing)) { did_it(Owner(thing), thing, 0, NULL, 0, NULL, A_DAILY, 0, NULL, 0); break; } } } } } #define MAX_TRIMMED_NAME_LENGTH 16 static const char *trimmed_name(dbref player, size_t *pvw) { static char cbuff[MBUF_SIZE]; ANSI_TruncateToField( Moniker(player), sizeof(cbuff), cbuff, MAX_TRIMMED_NAME_LENGTH, pvw, ANSI_ENDGOAL_NORMAL ); return cbuff; } static char *trimmed_site(char *szName) { static char buff[MBUF_SIZE]; size_t nLen = strlen(szName); if ( mudconf.site_chars <= 0 || nLen <= mudconf.site_chars) { return szName; } nLen = mudconf.site_chars; if (nLen > sizeof(buff)-1) { nLen = sizeof(buff)-1; } memcpy(buff, szName, nLen); buff[nLen] = '\0'; return buff; } static void dump_users(DESC *e, char *match, int key) { DESC *d; int count; char *buf, *fp, *sp, flist[4], slist[4]; dbref room_it; if (match) { while (mux_isspace(*match)) { match++; } if (!*match) { match = NULL; } } if ( (e->flags & (DS_PUEBLOCLIENT|DS_CONNECTED)) && Html(e->player)) { queue_write(e, "
");
    }

    buf = alloc_mbuf("dump_users");
    if (key == CMD_SESSION)
    {
        queue_write(e, "                               ");
        queue_write(e, "     Characters Input----  Characters Output---\r\n");
    }
    queue_write(e, "Player Name        On For Idle ");
    if (key == CMD_SESSION)
    {
        queue_write(e, "Port Pend  Lost     Total  Pend  Lost     Total\r\n");
    }
    else if (  (e->flags & DS_CONNECTED)
            && Wizard_Who(e->player)
            && key == CMD_WHO)
    {
        queue_write(e, "  Room    Cmds   Host\r\n");
    }
    else
    {
        if (  Wizard_Who(e->player)
           || See_Hidden(e->player))
        {
            queue_write(e, "  ");
        }
        else
        {
            queue_write(e, " ");
        }
        queue_string(e, mudstate.doing_hdr);
        queue_write_LEN(e, "\r\n", 2);
    }
    count = 0;

    CLinearTimeAbsolute ltaNow;
    ltaNow.GetUTC();

    DESC_ITER_ALL(d)
    {
        if (!(  (  (e->flags & DS_CONNECTED)
                && SiteMon(e->player))
             || (d->flags & DS_CONNECTED)))
        {
            continue;
        }
        if (  !(d->flags & DS_CONNECTED)
           || !Hidden(d->player)
           || (  (e->flags & DS_CONNECTED)
              && (  Wizard_Who(e->player)
                 || See_Hidden(e->player))))
        {
            count++;
            if (  match
               && (  !(d->flags & DS_CONNECTED)
                  || string_prefix(Name(d->player), match) == 0))
            {
                continue;
            }
            if (  key == CMD_SESSION
               && (  !(e->flags & DS_CONNECTED)
                  || !Wizard_Who(e->player))
               && (  !(e->flags & DS_CONNECTED)
                  || !(d->flags & DS_CONNECTED)
                  || d->player != e->player))
            {
                continue;
            }

            // Get choice flags for wizards.
            //
            fp = flist;
            sp = slist;
            if (  (e->flags & DS_CONNECTED)
               && Wizard_Who(e->player))
            {
                if (  (d->flags & DS_CONNECTED)
                   && Hidden(d->player))
                {
                    if (d->flags & DS_AUTODARK)
                    {
                        safe_copy_chr('d', flist, &fp, sizeof(flist)-1);
                    }
                    else
                    {
                        safe_copy_chr('D', flist, &fp, sizeof(flist)-1);
                    }
                }
                if (d->flags & DS_CONNECTED)
                {
                    if (Hideout(d->player))
                    {
                        safe_copy_chr('U', flist, &fp, sizeof(flist)-1);
                    }
                    else
                    {
                        room_it = where_room(d->player);
                        if (Good_obj(room_it))
                        {
                            if (Hideout(room_it))
                            {
                                safe_copy_chr('u', flist, &fp, sizeof(flist)-1);
                            }
                        }
                        else
                        {
                            safe_copy_chr('u', flist, &fp, sizeof(flist)-1);
                        }
                    }

                    if (Suspect(d->player))
                    {
                        safe_copy_chr('+', flist, &fp, sizeof(flist)-1);
                    }
                }
                if (d->host_info & H_FORBIDDEN)
                {
                    safe_copy_chr('F', slist, &sp, sizeof(slist)-1);
                }
                if (d->host_info & H_REGISTRATION)
                {
                    safe_copy_chr('R', slist, &sp, sizeof(slist)-1);
                }
                if (d->host_info & H_SUSPECT)
                {
                    safe_copy_chr('+', slist, &sp, sizeof(slist)-1);
                }
                if (d->host_info & H_GUEST)
                {
                    safe_copy_chr('G', slist, &sp, sizeof(slist)-1);
                }
            }
            else if (  (e->flags & DS_CONNECTED)
                    && (d->flags & DS_CONNECTED)
                    && See_Hidden(e->player)
                    && Hidden(d->player))
            {
                if (d->flags & DS_AUTODARK)
                {
                    safe_copy_chr('d', flist, &fp, sizeof(flist)-1);
                }
                else
                {
                    safe_copy_chr('D', flist, &fp, sizeof(flist)-1);
                }
            }
            *fp = '\0';
            *sp = '\0';

            CLinearTimeDelta ltdConnected = ltaNow - d->connected_at;
            CLinearTimeDelta ltdLastTime  = ltaNow - d->last_time;

            const char *pNameField = "";
            size_t vwNameField = strlen(pNameField);
            if (d->flags & DS_CONNECTED)
            {
                pNameField = trimmed_name(d->player, &vwNameField);
            }

            // How many spaces between the name field and the 'On For' field.
            //
            size_t nFill;
            if (13 <= vwNameField)
            {
                nFill = 1;
            }
            else
            {
                nFill = 14-vwNameField;
            }
            char aFill[15];
            memset(aFill, ' ', nFill);
            aFill[nFill] = '\0';

            // The width size allocated to the 'On For' field.
            //
            size_t nOnFor = 25 - nFill - vwNameField;

            const char *pTimeStamp1 = time_format_1(ltdConnected.ReturnSeconds(), nOnFor);
            const char *pTimeStamp2 = time_format_2(ltdLastTime.ReturnSeconds());

            if (  (e->flags & DS_CONNECTED)
               && Wizard_Who(e->player)
               && key == CMD_WHO)
            {
                mux_sprintf(buf, MBUF_SIZE, "%s%s%s %4s%-3s#%-6d%5d%3s%s\r\n",
                    pNameField, aFill,
                    pTimeStamp1,
                    pTimeStamp2,
                    flist,
                    ((d->flags & DS_CONNECTED) ? Location(d->player) : -1),
                    d->command_count,
                    slist,
                    trimmed_site(((d->username[0] != '\0') ? tprintf("%s@%s", d->username, d->addr) : d->addr)));
            }
            else if (key == CMD_SESSION)
            {
                mux_sprintf(buf, MBUF_SIZE, "%s%s%s %4s%5u%5d%6d%10d%6d%6d%10d\r\n",
                    pNameField, aFill,
                    pTimeStamp1,
                    pTimeStamp2,
                    d->descriptor,
                    d->input_size, d->input_lost,
                    d->input_tot,
                    d->output_size, d->output_lost,
                    d->output_tot);
            }
            else if (  Wizard_Who(e->player)
                    || See_Hidden(e->player))
            {
                mux_sprintf(buf, MBUF_SIZE, "%s%s%s %4s%-3s%s\r\n",
                    pNameField, aFill,
                    pTimeStamp1,
                    pTimeStamp2,
                    flist,
                    d->doing);
            }
            else
            {
                mux_sprintf(buf, MBUF_SIZE, "%s%s%s %4s  %s\r\n",
                    pNameField, aFill,
                    pTimeStamp1,
                    pTimeStamp2,
                    d->doing);
            }
            queue_string(e, buf);
        }
    }

    // Sometimes I like the ternary operator.
    //
    mux_sprintf(buf, MBUF_SIZE, "%d Player%slogged in, %d record, %s maximum.\r\n", count,
        (count == 1) ? " " : "s ", mudstate.record_players,
        (mudconf.max_players == -1) ? "no" : mux_ltoa_t(mudconf.max_players));
    queue_write(e, buf);

    if (  (e->flags & (DS_PUEBLOCLIENT|DS_CONNECTED))
       && Html(e->player))
    {
        queue_write(e, "
"); } free_mbuf(buf); } static const char *DumpInfoTable[] = { #if defined(DEPRECATED) "DEPRECATED", #endif #if defined(FIRANMUX) "FIRANMUX", #endif #if defined(FIRANMUX_CONVERT) "FIRANMUX_CONVERT", #endif #if defined(MEMORY_BASED) "MEMORY_BASED", #endif #if defined(REALITY_LVLS) "REALITY_LVLS", #endif #if defined(WOD_REALMS) "WOD_REALMS", #endif NULL }; static void dump_info(DESC *arg_desc) { int nDumpInfoTable = 0; while ( nDumpInfoTable < sizeof(DumpInfoTable)/sizeof(DumpInfoTable[0]) && NULL != DumpInfoTable[nDumpInfoTable]) { nDumpInfoTable++; } const char **LocalDumpInfoTable = local_get_info_table(); int nLocalDumpInfoTable = 0; while (NULL != LocalDumpInfoTable[nLocalDumpInfoTable]) { nLocalDumpInfoTable++; } if ( 0 == nDumpInfoTable && 0 == nLocalDumpInfoTable) { queue_write(arg_desc, "### Begin INFO 1\r\n"); } else { queue_write(arg_desc, "### Begin INFO 1.1\r\n"); } queue_string(arg_desc, tprintf("Name: %s\r\n", mudconf.mud_name)); char *temp = mudstate.start_time.ReturnDateString(); queue_write(arg_desc, tprintf("Uptime: %s\r\n", temp)); DESC *d; int count = 0; DESC_ITER_CONN(d) { if (!Good_obj(d->player)) { continue; } if ( !Hidden(d->player) || ( (arg_desc->flags & DS_CONNECTED) && See_Hidden(arg_desc->player))) { count++; } } queue_write(arg_desc, tprintf("Connected: %d\r\n", count)); queue_write(arg_desc, tprintf("Size: %d\r\n", mudstate.db_top)); queue_write(arg_desc, tprintf("Version: %s\r\n", mudstate.short_ver)); if ( 0 != nDumpInfoTable || 0 != nLocalDumpInfoTable) { char *buf = alloc_lbuf("dump_info"); char *bp = buf; int i; bool bFirst = true; safe_str("Patches: ", buf, &bp); for (i = 0; i < nDumpInfoTable; i++) { if (!bFirst) { safe_chr(' ', buf, &bp); } else { bFirst = false; } safe_str(DumpInfoTable[i], buf, &bp); } for (i = 0; i < nLocalDumpInfoTable; i++) { if (!bFirst) { safe_chr(' ', buf, &bp); } else { bFirst = false; } safe_str(LocalDumpInfoTable[i], buf, &bp); } *bp = '\0'; queue_write(arg_desc, buf); free_lbuf(buf); queue_write(arg_desc, "\r\n"); } queue_write(arg_desc, "### End INFO\r\n"); } char *MakeCanonicalDoing(char *pDoing, size_t *pnValidDoing, bool *pbValidDoing) { *pnValidDoing = 0; *pbValidDoing = false; if (!pDoing) { return NULL; } // First, remove all '\r\n\t' from the string. // char *Buffer = RemoveSetOfCharacters(pDoing, "\r\n\t"); // Optimize/terminate any ANSI in the string. // size_t nVisualWidth; static char szFittedDoing[SIZEOF_DOING_STRING]; *pnValidDoing = ANSI_TruncateToField ( Buffer, SIZEOF_DOING_STRING, szFittedDoing, WIDTHOF_DOING_STRING, &nVisualWidth, ANSI_ENDGOAL_NORMAL ); *pbValidDoing = true; return szFittedDoing; } // --------------------------------------------------------------------------- // do_doing: Set the doing string that appears in the WHO report. // Idea from R'nice@TinyTIM. // void do_doing(dbref executor, dbref caller, dbref enactor, int eval, int key, char *arg) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); // Make sure there can be no embedded newlines from %r // static char *Empty = (char *)""; char *szValidDoing = Empty; bool bValidDoing; size_t nValidDoing = 0; if (arg) { szValidDoing = MakeCanonicalDoing(arg, &nValidDoing, &bValidDoing); if (!bValidDoing) { szValidDoing = Empty; nValidDoing = 0; } } bool bQuiet = ((key & DOING_QUIET) == DOING_QUIET); key &= DOING_MASK; if (key == DOING_MESSAGE) { DESC *d; bool bFound = false; DESC_ITER_PLAYER(executor, d) { memcpy(d->doing, szValidDoing, nValidDoing+1); bFound = true; } if (bFound) { if ( !bQuiet && !Quiet(executor)) { notify(executor, "Set."); } } else { notify(executor, "Not connected."); } } else if (key == DOING_UNIQUE) { DESC *d; DESC *dMax = NULL; CLinearTimeAbsolute ltaMax; DESC_ITER_PLAYER(executor, d) { if ( !dMax && ltaMax < d->last_time) { ltaMax = d->last_time; dMax = d; } } if (dMax) { memcpy(dMax->doing, szValidDoing, nValidDoing+1); if ( !bQuiet && !Quiet(executor)) { notify(executor, "Set."); } } else { notify(executor, "Not connected."); } } else if (key == DOING_HEADER) { if (!Can_Poll(executor)) { notify(executor, NOPERM_MESSAGE); return; } if (nValidDoing == 0) { mux_strncpy(mudstate.doing_hdr, "Doing", SIZEOF_DOING_STRING-1); } else { memcpy(mudstate.doing_hdr, szValidDoing, nValidDoing+1); } if ( !bQuiet && !Quiet(executor)) { notify(executor, "Set."); } } else // if (key == DOING_POLL) { notify(executor, tprintf("Poll: %s", mudstate.doing_hdr)); } } NAMETAB logout_cmdtable[] = { {(char *)"DOING", 5, CA_PUBLIC, CMD_DOING}, {(char *)"LOGOUT", 6, CA_PUBLIC, CMD_LOGOUT}, {(char *)"OUTPUTPREFIX", 12, CA_PUBLIC, CMD_PREFIX|CMD_NOxFIX}, {(char *)"OUTPUTSUFFIX", 12, CA_PUBLIC, CMD_SUFFIX|CMD_NOxFIX}, {(char *)"QUIT", 4, CA_PUBLIC, CMD_QUIT}, {(char *)"SESSION", 7, CA_PUBLIC, CMD_SESSION}, {(char *)"WHO", 3, CA_PUBLIC, CMD_WHO}, {(char *)"PUEBLOCLIENT", 12, CA_PUBLIC, CMD_PUEBLOCLIENT}, {(char *)"INFO", 4, CA_PUBLIC, CMD_INFO}, {NULL, 0, 0, 0} }; void init_logout_cmdtab(void) { NAMETAB *cp; // Make the htab bigger than the number of entries so that we find things // on the first check. Remember that the admin can add aliases. // for (cp = logout_cmdtable; cp->flag; cp++) { hashaddLEN(cp->name, strlen(cp->name), cp, &mudstate.logout_cmd_htab); } } static void failconn(const char *logcode, const char *logtype, const char *logreason, DESC *d, int disconnect_reason, dbref player, int filecache, char *motd_msg, char *command, char *user, char *password, const char *cmdsave) { STARTLOG(LOG_LOGIN | LOG_SECURITY, logcode, "RJCT"); char *buff = alloc_mbuf("failconn.LOG"); mux_sprintf(buff, MBUF_SIZE, "[%u/%s] %s rejected to ", d->descriptor, d->addr, logtype); log_text(buff); free_mbuf(buff); if (player != NOTHING) { log_name(player); } else { log_text(user); } log_text(" ("); log_text(logreason); log_text(")"); ENDLOG; fcache_dump(d, filecache); if (*motd_msg) { queue_string(d, motd_msg); queue_write_LEN(d, "\r\n", 2); } free_lbuf(command); free_lbuf(user); free_lbuf(password); shutdownsock(d, disconnect_reason); mudstate.debug_cmd = cmdsave; return; } static const char *connect_fail = "Either that player does not exist, or has a different password.\r\n"; static bool check_connect(DESC *d, char *msg) { char *buff; dbref player, aowner; int aflags, nplayers; DESC *d2; const char *p; bool isGuest = false; const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< check_connect >"; // Hide the password length from SESSION. // d->input_tot -= (strlen(msg) + 1); // Crack the command apart. // char *command = alloc_lbuf("check_conn.cmd"); char *user = alloc_lbuf("check_conn.user"); char *password = alloc_lbuf("check_conn.pass"); parse_connect(msg, command, user, password); // At this point, command, user, and password are all less than // MBUF_SIZE. // if ( strncmp(command, "co", 2) == 0 || strncmp(command, "cd", 2) == 0) { if (string_prefix(user, mudconf.guest_prefix)) { if ( (d->host_info & H_GUEST) || ( !mudconf.allow_guest_from_registered_site && (d->host_info & H_REGISTRATION))) { // Someone from an IP with guest restrictions is // trying to use a guest account. Give them the blurb // most likely to have instructions about requesting a // character by other means and then fail this // connection. // // The guest 'power' is handled separately further // down. // failconn("CONN", "Connect", "Guest Site Forbidden", d, R_GAMEDOWN, NOTHING, FC_CONN_REG, mudconf.downmotd_msg, command, user, password, cmdsave); return false; } if ( mudconf.guest_char != NOTHING && (mudconf.control_flags & CF_LOGIN)) { if (!(mudconf.control_flags & CF_GUEST)) { queue_write(d, "Guest logins are disabled.\r\n"); free_lbuf(command); free_lbuf(user); free_lbuf(password); mudstate.debug_cmd = cmdsave; return false; } if ((p = Guest.Create(d)) == NULL) { queue_write(d, "All guests are tied up, please try again later.\r\n"); free_lbuf(command); free_lbuf(user); free_lbuf(password); mudstate.debug_cmd = cmdsave; return false; } mux_strncpy(user, p, LBUF_SIZE-1); mux_strncpy(password, GUEST_PASSWORD, LBUF_SIZE-1); isGuest = true; } } // See if this connection would exceed the max #players. // if (mudconf.max_players < 0) { nplayers = mudconf.max_players - 1; } else { nplayers = 0; DESC_ITER_CONN(d2) { nplayers++; } } player = connect_player(user, password, d->addr, d->username, inet_ntoa((d->address).sin_addr)); if ( player == NOTHING || (!isGuest && Guest.CheckGuest(player))) { // Not a player, or wrong password. // queue_write(d, connect_fail); STARTLOG(LOG_LOGIN | LOG_SECURITY, "CON", "BAD"); buff = alloc_lbuf("check_conn.LOG.bad"); mux_sprintf(buff, LBUF_SIZE, "[%u/%s] Failed connect to '%s'", d->descriptor, d->addr, user); log_text(buff); free_lbuf(buff); ENDLOG; if (--(d->retries_left) <= 0) { free_lbuf(command); free_lbuf(user); free_lbuf(password); shutdownsock(d, R_BADLOGIN); mudstate.debug_cmd = cmdsave; return false; } } else if ( ( (mudconf.control_flags & CF_LOGIN) && (nplayers < mudconf.max_players)) || RealWizRoy(player) || God(player)) { if ( strncmp(command, "cd", 2) == 0 && ( RealWizard(player) || God(player))) { db[player].fs.word[FLAG_WORD1] |= DARK; } // Make sure we don't have a guest from an unwanted host. // The majority of these are handled above. // // The following code handles the case where a staffer // (#1-only by default) has specifically given the guest 'power' // to an existing player. // // In this case, the player -already- has an account complete // with password. We still fail the connection to -this- player // but if the site isn't register_sited, this player can simply // auto-create another player. So, the procedure is not much // different from @newpassword'ing them. Oh well. We are just // following orders. ;) // if ( Guest(player) && ( (d->host_info & H_GUEST) || ( !mudconf.allow_guest_from_registered_site && (d->host_info & H_REGISTRATION)))) { failconn("CON", "Connect", "Guest Site Forbidden", d, R_GAMEDOWN, player, FC_CONN_SITE, mudconf.downmotd_msg, command, user, password, cmdsave); return false; } // Logins are enabled, or wiz or god. // STARTLOG(LOG_LOGIN, "CON", "LOGIN"); buff = alloc_mbuf("check_conn.LOG.login"); mux_sprintf(buff, MBUF_SIZE, "[%u/%s] Connected to ", d->descriptor, d->addr); log_text(buff); log_name_and_loc(player); free_mbuf(buff); ENDLOG; d->flags |= DS_CONNECTED; d->connected_at.GetUTC(); d->player = player; // Check to see if the player is currently running an // @program. If so, drop the new descriptor into it. // DESC_ITER_PLAYER(player, d2) { if ( NULL != d2->program_data && NULL == d->program_data) { d->program_data = d2->program_data; } else if (NULL != d2->program_data) { // Enforce that all program_data pointers for this player // are the same. // mux_assert(d->program_data == d2->program_data); } } // Give the player the MOTD file and the settable MOTD // message(s). Use raw notifies so the player doesn't try // to match on the text. // if (Guest(player)) { fcache_dump(d, FC_CONN_GUEST); } else { buff = atr_get(player, A_LAST, &aowner, &aflags); if (*buff == '\0') fcache_dump(d, FC_CREA_NEW); else fcache_dump(d, FC_MOTD); if (Wizard(player)) fcache_dump(d, FC_WIZMOTD); free_lbuf(buff); } announce_connect(player, d); DESC* dtemp; int num_con = 0; DESC_ITER_PLAYER(player, dtemp) { num_con++; } local_connect(player, 0, num_con); // If stuck in an @prog, show the prompt. // if (NULL != d->program_data) { queue_write_LEN(d, ">\377\371", 3); } } else if (!(mudconf.control_flags & CF_LOGIN)) { failconn("CON", "Connect", "Logins Disabled", d, R_GAMEDOWN, player, FC_CONN_DOWN, mudconf.downmotd_msg, command, user, password, cmdsave); return false; } else { failconn("CON", "Connect", "Game Full", d, R_GAMEFULL, player, FC_CONN_FULL, mudconf.fullmotd_msg, command, user, password, cmdsave); return false; } } else if (strncmp(command, "cr", 2) == 0) { // Enforce game down. // if (!(mudconf.control_flags & CF_LOGIN)) { failconn("CRE", "Create", "Logins Disabled", d, R_GAMEDOWN, NOTHING, FC_CONN_DOWN, mudconf.downmotd_msg, command, user, password, cmdsave); return false; } // Enforce max #players. // if (mudconf.max_players < 0) { nplayers = mudconf.max_players; } else { nplayers = 0; DESC_ITER_CONN(d2) { nplayers++; } } if (nplayers > mudconf.max_players) { // Too many players on, reject the attempt. // failconn("CRE", "Create", "Game Full", d, R_GAMEFULL, NOTHING, FC_CONN_FULL, mudconf.fullmotd_msg, command, user, password, cmdsave); return false; } if (d->host_info & H_REGISTRATION) { fcache_dump(d, FC_CREA_REG); } else { const char *pmsg; player = create_player(user, password, NOTHING, false, &pmsg); if (player == NOTHING) { queue_write(d, pmsg); queue_write(d, "\r\n"); STARTLOG(LOG_SECURITY | LOG_PCREATES, "CON", "BAD"); buff = alloc_lbuf("check_conn.LOG.badcrea"); mux_sprintf(buff, LBUF_SIZE, "[%u/%s] Create of '%s' failed", d->descriptor, d->addr, user); log_text(buff); free_lbuf(buff); ENDLOG; } else { AddToPublicChannel(player); STARTLOG(LOG_LOGIN | LOG_PCREATES, "CON", "CREA"); buff = alloc_mbuf("check_conn.LOG.create"); mux_sprintf(buff, MBUF_SIZE, "[%u/%s] Created ", d->descriptor, d->addr); log_text(buff); log_name(player); free_mbuf(buff); ENDLOG; move_object(player, mudconf.start_room); d->flags |= DS_CONNECTED; d->connected_at.GetUTC(); d->player = player; fcache_dump(d, FC_CREA_NEW); announce_connect(player, d); // Since it is on the create call, assume connection count // is 0 and indicate the connect is a new character. // local_connect(player, 1, 0); } } } else { welcome_user(d); STARTLOG(LOG_LOGIN | LOG_SECURITY, "CON", "BAD"); buff = alloc_mbuf("check_conn.LOG.bad"); msg[150] = '\0'; mux_sprintf(buff, MBUF_SIZE, "[%u/%s] Failed connect: '%s'", d->descriptor, d->addr, msg); log_text(buff); free_mbuf(buff); ENDLOG; } free_lbuf(command); free_lbuf(user); free_lbuf(password); mudstate.debug_cmd = cmdsave; return true; } static void do_logged_out_internal(DESC *d, int key, char *arg) { switch (key) { case CMD_QUIT: shutdownsock(d, R_QUIT); break; case CMD_LOGOUT: shutdownsock(d, R_LOGOUT); break; case CMD_WHO: case CMD_DOING: case CMD_SESSION: #if defined(FIRANMUX) if ((d->flags & DS_CONNECTED) == 0) { queue_string(d, "This command is disabled on login."); queue_write_LEN(d, "\r\n", 2); } else #endif // FIRANMUX { dump_users(d, arg, key); } break; case CMD_PREFIX: set_userstring(&d->output_prefix, arg); break; case CMD_SUFFIX: set_userstring(&d->output_suffix, arg); break; case CMD_INFO: dump_info(d); break; case CMD_PUEBLOCLIENT: // Set the descriptor's flag. // d->flags |= DS_PUEBLOCLIENT; queue_string(d, mudconf.pueblo_msg); queue_write_LEN(d, "\r\n", 2); break; default: { char buf[LBUF_SIZE * 2]; STARTLOG(LOG_BUGS, "BUG", "PARSE"); mux_sprintf(buf, sizeof(buf), "Logged-out command with no handler: '%s'", mudstate.debug_cmd); log_text(buf); ENDLOG; } } } void do_command(DESC *d, char *command) { const char *cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< do_command >"; if (d->flags & DS_CONNECTED) { // Normal logged-in command processing. // d->command_count++; if (d->output_prefix) { queue_string(d, d->output_prefix); queue_write_LEN(d, "\r\n", 2); } mudstate.curr_executor = d->player; mudstate.curr_enactor = d->player; for (int i = 0; i < MAX_GLOBAL_REGS; i++) { if (mudstate.global_regs[i]) { RegRelease(mudstate.global_regs[i]); mudstate.global_regs[i] = NULL; } } CLinearTimeAbsolute ltaBegin; ltaBegin.GetUTC(); MuxAlarm.Set(mudconf.max_cmdsecs); char *log_cmdbuf = process_command(d->player, d->player, d->player, 0, true, command, NULL, 0); CLinearTimeAbsolute ltaEnd; ltaEnd.GetUTC(); if (MuxAlarm.bAlarmed) { notify(d->player, "GAME: Expensive activity abbreviated."); halt_que(d->player, NOTHING); s_Flags(d->player, FLAG_WORD1, Flags(d->player) | HALT); } MuxAlarm.Clear(); CLinearTimeDelta ltd = ltaEnd - ltaBegin; if (ltd > mudconf.rpt_cmdsecs) { STARTLOG(LOG_PROBLEMS, "CMD", "CPU"); log_name_and_loc(d->player); char *logbuf = alloc_lbuf("do_command.LOG.cpu"); mux_sprintf(logbuf, LBUF_SIZE, " queued command taking %s secs: ", ltd.ReturnSecondsString(4)); log_text(logbuf); free_lbuf(logbuf); log_text(log_cmdbuf); ENDLOG; } mudstate.curr_cmd = (char *) ""; if (d->output_suffix) { queue_string(d, d->output_suffix); queue_write_LEN(d, "\r\n", 2); } mudstate.debug_cmd = cmdsave; return; } // Login screen (logged-out) command processing. // // Split off the command from the arguments. // char *arg = command; while (*arg && !mux_isspace(*arg)) { arg++; } if (*arg) { *arg++ = '\0'; } // Look up the command in the logged-out command table. // NAMETAB *cp = (NAMETAB *)hashfindLEN(command, strlen(command), &mudstate.logout_cmd_htab); if (cp == NULL) { // Not in the logged-out command table, so maybe a connect attempt. // if (*arg) { // Restore nullified space // *--arg = ' '; } mudstate.curr_executor = NOTHING; mudstate.curr_enactor = NOTHING; mudstate.debug_cmd = cmdsave; check_connect(d, command); return; } // The command was in the logged-out command table. Perform // prefix and suffix processing, and invoke the command // handler. // d->command_count++; if (!(cp->flag & CMD_NOxFIX)) { if (d->output_prefix) { queue_string(d, d->output_prefix); queue_write_LEN(d, "\r\n", 2); } } if (cp->perm != CA_PUBLIC) { queue_write(d, "Permission denied.\r\n"); } else { mudstate.debug_cmd = cp->name; do_logged_out_internal(d, cp->flag & CMD_MASK, arg); } // QUIT or LOGOUT will close the connection and cause the // descriptor to be freed! // if ( ((cp->flag & CMD_MASK) != CMD_QUIT) && ((cp->flag & CMD_MASK) != CMD_LOGOUT) && !(cp->flag & CMD_NOxFIX)) { if (d->output_suffix) { queue_string(d, d->output_suffix); queue_write_LEN(d, "\r\n", 2); } } mudstate.debug_cmd = cmdsave; } void logged_out1(dbref executor, dbref caller, dbref enactor, int eval, int key, char *arg) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); // PUEBLOCLIENT affects all the player's connections. // if (key == CMD_PUEBLOCLIENT) { DESC *d; DESC_ITER_PLAYER(executor, d) { do_logged_out_internal(d, key, arg); } // Set the player's flag. // s_Html(executor); return; } // Other logged-out commands affect only the player's most recently // used connection. // DESC *d; DESC *dLatest = NULL; DESC_ITER_PLAYER(executor, d) { if ( dLatest == NULL || dLatest->last_time < d->last_time) { dLatest = d; } } if (dLatest != NULL) { do_logged_out_internal(dLatest, key, arg); } } void logged_out0(dbref executor, dbref caller, dbref enactor, int key) { logged_out1(executor, caller, enactor, 0, key, (char *)""); } void Task_ProcessCommand(void *arg_voidptr, int arg_iInteger) { UNUSED_PARAMETER(arg_iInteger); DESC *d = (DESC *)arg_voidptr; if (d) { CBLK *t = d->input_head; if (t) { if (d->quota > 0) { d->quota--; d->input_head = (CBLK *) t->hdr.nxt; if (d->input_head) { // There are still commands to process, so schedule another looksee. // scheduler.DeferImmediateTask(PRIORITY_SYSTEM, Task_ProcessCommand, d, 0); } else { d->input_tail = NULL; } d->input_size -= strlen(t->cmd); d->last_time.GetUTC(); if (d->program_data != NULL) { handle_prog(d, t->cmd); } else { do_command(d, t->cmd); } free_lbuf(t); } else { // Don't bother looking for more quota until at least this much time has past. // CLinearTimeAbsolute lsaWhen; lsaWhen.GetUTC(); scheduler.DeferTask(lsaWhen + mudconf.timeslice, PRIORITY_SYSTEM, Task_ProcessCommand, d, 0); } } } } /* --------------------------------------------------------------------------- * site_check: Check for site flags in a site list. */ int site_check(struct in_addr host, SITE *site_list) { SITE *this0; for (this0 = site_list; this0; this0 = this0->next) { if ((host.s_addr & this0->mask.s_addr) == this0->address.s_addr) { return this0->flag; } } return 0; } /* -------------------------------------------------------------------------- * list_sites: Display information in a site list */ #define S_SUSPECT 1 #define S_ACCESS 2 static const char *stat_string(int strtype, int flag) { const char *str; switch (strtype) { case S_SUSPECT: if (flag) { str = "Suspected"; } else { str = "Trusted"; } break; case S_ACCESS: switch (flag) { case H_FORBIDDEN: str = "Forbidden"; break; case H_REGISTRATION: str = "Registration"; break; case H_GUEST: str = "NoGuest"; break; case H_NOSITEMON: str = "NoSiteMon"; break; case 0: str = "Unrestricted"; break; default: str = "Strange"; break; } break; default: str = "Strange"; break; } return str; } static void list_sites(dbref player, SITE *site_list, const char *header_txt, int stat_type) { char *buff, *buff1, *str; SITE *this0; buff = alloc_mbuf("list_sites.buff"); buff1 = alloc_sbuf("list_sites.addr"); mux_sprintf(buff, MBUF_SIZE, "----- %s -----", header_txt); notify(player, buff); notify(player, "Address Mask Status"); for (this0 = site_list; this0; this0 = this0->next) { str = (char *)stat_string(stat_type, this0->flag); mux_strncpy(buff1, inet_ntoa(this0->mask), SBUF_SIZE-1); mux_sprintf(buff, MBUF_SIZE, "%-20s %-20s %s", inet_ntoa(this0->address), buff1, str); notify(player, buff); } free_mbuf(buff); free_sbuf(buff1); } /* --------------------------------------------------------------------------- * list_siteinfo: List information about specially-marked sites. */ void list_siteinfo(dbref player) { list_sites(player, mudstate.access_list, "Site Access", S_ACCESS); list_sites(player, mudstate.suspect_list, "Suspected Sites", S_SUSPECT); } /* --------------------------------------------------------------------------- * make_ulist: Make a list of connected user numbers for the LWHO function. */ void make_ulist(dbref player, char *buff, char **bufc, bool bPorts) { DESC *d; if (bPorts) { make_port_ulist(player, buff, bufc); } else { ITL pContext; ItemToList_Init(&pContext, buff, bufc, '#'); DESC_ITER_CONN(d) { if ( !See_Hidden(player) && Hidden(d->player)) { continue; } if (!ItemToList_AddInteger(&pContext, d->player)) { break; } } ItemToList_Final(&pContext); } } /* --------------------------------------------------------------------------- * find_connected_name: Resolve a playername from the list of connected * players using prefix matching. We only return a match if the prefix * was unique. */ dbref find_connected_name(dbref player, char *name) { DESC *d; dbref found = NOTHING; DESC_ITER_CONN(d) { if ( Good_obj(player) && !See_Hidden(player) && Hidden(d->player)) { continue; } if (!string_prefix(Name(d->player), name)) { continue; } if ( found != NOTHING && found != d->player) { return NOTHING; } found = d->player; } return found; } FUNCTION(fun_doing) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (is_rational(fargs[0])) { SOCKET s = mux_atol(fargs[0]); bool bFound = false; DESC *d; DESC_ITER_CONN(d) { if (d->descriptor == s) { bFound = true; break; } } if ( bFound && ( d->player == executor || Wizard_Who(executor))) { safe_str(d->doing, buff, bufc); } else { safe_nothing(buff, bufc); } } else { dbref victim = lookup_player(executor, fargs[0], true); if (victim == NOTHING) { safe_str("#-1 PLAYER DOES NOT EXIST", buff, bufc); return; } if ( Wizard_Who(executor) || !Hidden(victim)) { DESC *d; DESC_ITER_CONN(d) { if (d->player == victim) { safe_str(d->doing, buff, bufc); return; } } } safe_str("#-1 NOT A CONNECTED PLAYER", buff, bufc); } } // --------------------------------------------------------------------------- // fun_host: Return hostname of player or port descriptor. // --------------------------------------------------------------------------- FUNCTION(fun_host) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!Wizard_Who(executor)) { safe_noperm(buff, bufc); return; } bool isPort = is_rational(fargs[0]); bool bFound = false; DESC *d; if (isPort) { SOCKET s = mux_atol(fargs[0]); DESC_ITER_CONN(d) { if (d->descriptor == s) { bFound = true; break; } } } else { dbref victim = lookup_player(executor, fargs[0], true); if (victim == NOTHING) { safe_str("#-1 PLAYER DOES NOT EXIST", buff, bufc); return; } DESC_ITER_CONN(d) { if (d->player == victim) { bFound = true; break; } } } if (bFound) { char *hostname = ((d->username[0] != '\0') ? tprintf("%s@%s", d->username, d->addr) : d->addr); safe_str(hostname, buff, bufc); return; } if (isPort) { safe_str("#-1 NOT AN ACTIVE PORT", buff, bufc); } else { safe_str("#-1 NOT A CONNECTED PLAYER", buff, bufc); } } FUNCTION(fun_poll) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_str(mudstate.doing_hdr, buff, bufc); } FUNCTION(fun_motd) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_str(mudconf.motd_msg, buff, bufc); } // --------------------------------------------------------------------------- // fun_siteinfo: Return special site flags of player or port descriptor. // Same output as wizard-accessible WHO. // --------------------------------------------------------------------------- FUNCTION(fun_siteinfo) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!Wizard_Who(executor)) { safe_noperm(buff, bufc); return; } bool isPort = is_rational(fargs[0]); bool bFound = false; DESC *d; if (isPort) { SOCKET s = mux_atol(fargs[0]); DESC_ITER_CONN(d) { if (d->descriptor == s) { bFound = true; break; } } } else { dbref victim = lookup_player(executor, fargs[0], true); if (victim == NOTHING) { safe_str("#-1 PLAYER DOES NOT EXIST", buff, bufc); return; } DESC_ITER_CONN(d) { if (d->player == victim) { bFound = true; break; } } } if (bFound) { if (d->host_info & H_FORBIDDEN) { safe_chr('F', buff, bufc); } if (d->host_info & H_REGISTRATION) { safe_chr('R', buff, bufc); } if (d->host_info & H_SUSPECT) { safe_chr('+', buff, bufc); } if (d->host_info & H_GUEST) { safe_chr('G', buff, bufc); } return; } if (isPort) { safe_str("#-1 NOT AN ACTIVE PORT", buff, bufc); } else { safe_str("#-1 NOT A CONNECTED PLAYER", buff, bufc); } } // fetch_cmds - Retrieve Player's number of commands entered. // int fetch_cmds(dbref target) { int sum = 0; bool bFound = false; DESC *d; DESC_ITER_PLAYER(target, d) { sum += d->command_count; bFound = true; } if (bFound) { return sum; } else { return -1; } } static void ParseConnectionInfoString(char *pConnInfo, char *pFields[5]) { MUX_STRTOK_STATE tts; mux_strtok_src(&tts, pConnInfo); mux_strtok_ctl(&tts, " "); for (int i = 0; i < 5; i++) { pFields[i] = mux_strtok_parse(&tts); } } void fetch_ConnectionInfoFields(dbref target, long anFields[4]) { dbref aowner; int aflags; char *pConnInfo = atr_get(target, A_CONNINFO, &aowner, &aflags); char *aFields[5]; ParseConnectionInfoString(pConnInfo, aFields); for (int i = 0; i < 4; i++) { long result; if ( !aFields[i] || (result = mux_atol(aFields[i])) < 0) { result = 0; } anFields[i] = result; } free_lbuf(pConnInfo); } void put_ConnectionInfoFields ( dbref target, long anFields[4], CLinearTimeAbsolute <aLogout ) { char *pConnInfo = alloc_lbuf("put_CIF"); char *p = pConnInfo; for (int i = 0; i < 4; i++) { p += mux_ltoa(anFields[i], p); *p++ = ' '; } p += mux_i64toa(ltaLogout.ReturnSeconds(), p); *p++ = 0; atr_add_raw_LEN(target, A_CONNINFO, pConnInfo, p - pConnInfo); free_lbuf(pConnInfo); } long fetch_ConnectionInfoField(dbref target, int iField) { dbref aowner; int aflags; char *pConnInfo = atr_get(target, A_CONNINFO, &aowner, &aflags); char *aFields[5]; ParseConnectionInfoString(pConnInfo, aFields); long result; if ( !aFields[iField] || (result = mux_atol(aFields[iField])) < 0) { result = 0; } free_lbuf(pConnInfo); return result; } #define CIF_LOGOUTTIME 4 CLinearTimeAbsolute fetch_logouttime(dbref target) { dbref aowner; int aflags; char *pConnInfo = atr_get(target, A_CONNINFO, &aowner, &aflags); char *aFields[5]; ParseConnectionInfoString(pConnInfo, aFields); CLinearTimeAbsolute lta; if (aFields[CIF_LOGOUTTIME]) { lta.SetSecondsString(aFields[CIF_LOGOUTTIME]); } else { lta.SetSeconds(0); } free_lbuf(pConnInfo); return lta; } mux2.6/src/move.cpp0000600000175000017500000006617211025753746014264 0ustar sdennissdennis// move.cpp -- Routines for moving about. // // $Id: move.cpp 2734 2007-10-28 23:02:55Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "interface.h" #include "powers.h" #ifdef REALITY_LVLS #include "levels.h" #endif // REALITY_LVLS /* --------------------------------------------------------------------------- * process_leave_loc: Generate messages and actions resulting from leaving a * place. */ static void process_leave_loc(dbref thing, dbref dest, dbref cause, bool canhear, int hush) { dbref loc = Location(thing); if ((loc == NOTHING) || (loc == dest)) { return; } if (dest == HOME) { dest = Home(thing); } if (Html(thing)) { notify_html(thing, ""); } // Run the LEAVE attributes in the current room if we meet any of // following criteria: // // - The current room has wizard privs. // - Neither the current room nor the moving object are dark. // - The moving object can hear and does not hav wizard privs. // // EXCEPT if we were called with the HUSH_LEAVE key. // #ifdef REALITY_LVLS bool quiet = ( (hush & HUSH_LEAVE) || !IsReal(loc, thing) #else bool quiet = ( (hush & HUSH_LEAVE) #endif // REALITY_LVLS || ( !Wizard(loc) && ( Dark(thing) || Dark(loc)) && ( !canhear || ( Wizard(thing) && Dark(thing))))); int oattr = quiet ? 0 : A_OLEAVE; int aattr = quiet ? 0 : A_ALEAVE; int pattr = (!mudconf.terse_movemsg && Terse(thing)) ? 0 : A_LEAVE; did_it(thing, loc, pattr, NULL, oattr, NULL, aattr, 0, NULL, 0); // Do OXENTER for receiving room // if ((dest != NOTHING) && !quiet) { did_it(thing, dest, 0, NULL, A_OXENTER, NULL, 0, 0, NULL, 0); } // Display the 'has left' message if we meet any of the following // criteria: // // - Neither the current room nor the moving object are dark. // - The object can hear and is not a dark wizard. // if ( !quiet && !Blind(thing) && !Blind(loc)) { if ( ( !Dark(thing) && !Dark(loc)) || ( canhear #if defined(FIRANMUX) && !Dark(thing))) #else && !(Wizard(thing) && Dark(thing)))) #endif // FIRANMUX { #ifdef REALITY_LVLS notify_except2_rlevel(loc, thing, thing, cause, #else notify_except2(loc, thing, thing, cause, #endif // REALITY_LVLS tprintf("%s has left.", Moniker(thing))); } } } /*--------------------------------------------------------------------------- * process_enter_loc: Generate messages and actions resulting from entering * a place. */ static void process_enter_loc(dbref thing, dbref src, dbref cause, bool canhear, int hush) { dbref loc = Location(thing); if ( loc == NOTHING || loc == src) { return; } show_vrml_url(thing, loc); // Run the ENTER attributes in the current room if we meet any of following // criteria: // // - The current room has wizard privs. // - Neither the current room nor the moving object are dark. // - The moving object can hear and does not have wizard privs. // // EXCEPT if we were called with the HUSH_ENTER key. // #ifdef REALITY_LVLS bool quiet = ( (hush & HUSH_ENTER) || !IsReal(loc, thing) #else bool quiet = ( (hush & HUSH_ENTER) #endif // REALITY_LVLS || ( !Wizard(loc) && ( Dark(thing) || Dark(loc)) && ( !canhear #if defined(FIRANMUX) || Dark(thing)))); #else || ( Wizard(thing) && Dark(thing))))); #endif // FIRANMUX int oattr = quiet ? 0 : A_OENTER; #if defined(FIRANMUX) int aattr = (hush & HUSH_ENTER) ? 0 : A_AENTER; #else int aattr = quiet ? 0 : A_AENTER; #endif // FIRANMUX int pattr = (!mudconf.terse_movemsg && Terse(thing)) ? 0 : A_ENTER; did_it(thing, loc, pattr, NULL, oattr, NULL, aattr, 0, NULL, 0); // Do OXLEAVE for sending room. // if ( src != NOTHING && !quiet) { did_it(thing, src, 0, NULL, A_OXLEAVE, NULL, 0, 0, NULL, 0); } // Display the 'has arrived' message if we meet all of the following // criteria: // // - The moving object can hear. // - The object is not a dark wizard. // if ( !quiet && canhear && !Blind(thing) && !Blind(loc) #if defined(FIRANMUX) && !Dark(thing)) #else && !(Dark(thing) && Wizard(thing))) #endif // FIRANMUX { #ifdef REALITY_LVLS notify_except2_rlevel(loc, thing, thing, cause, #else notify_except2(loc, thing, thing, cause, #endif // REALITY_LVLS tprintf("%s has arrived.", Moniker(thing))); } } /* --------------------------------------------------------------------------- * move_object: Physically move an object from one place to another. * Does not generate any messages or actions. */ void move_object(dbref thing, dbref dest) { dbref src = Location(thing); // Remove from the source location // if (src != NOTHING) { s_Contents(src, remove_first(Contents(src), thing)); } // Special check for HOME // if (dest == HOME) { dest = Home(thing); } // Add to destination location // if (dest != NOTHING) { s_Contents(dest, insert_first(Contents(dest), thing)); } else { s_Next(thing, NOTHING); } s_Location(thing, dest); // Look around and do the penny check // look_in(thing, dest, (LK_SHOWEXIT | LK_OBEYTERSE)); if ( isPlayer(thing) && mudconf.payfind > 0 && Pennies(thing) < mudconf.paylimit && !Controls(thing, dest) && RandomINT32(0, mudconf.payfind-1) == 0) { giveto(thing, 1); notify(thing, tprintf("You found a %s!", mudconf.one_coin)); } } // move_the_exit: Move an exit silently from its location to its destination // static void move_the_exit(dbref thing, dbref dest) { dbref exitloc = Exits(thing); s_Exits(exitloc, remove_first(Exits(exitloc), thing)); s_Exits(dest, insert_first(Exits(dest), thing)); s_Exits(thing, dest); } /* --------------------------------------------------------------------------- * send_dropto, process_sticky_dropto, process_dropped_dropto, * process_sacrifice_dropto: Check for and process droptos. */ // send_dropto: Send an object through the dropto of a room // static void send_dropto(dbref thing, dbref player) { if (!Sticky(thing)) { move_via_generic(thing, Dropto(Location(thing)), player, 0); } else { move_via_generic(thing, HOME, player, 0); } divest_object(thing); } // process_sticky_dropto: Call when an object leaves the room to see if // we should empty the room // static void process_sticky_dropto(dbref loc, dbref player) { dbref dropto, thing, next; // Do nothing if checking anything but a sticky room // if (!Good_obj(loc) || !Has_dropto(loc) || !Sticky(loc)) return; // Make sure dropto loc is valid // dropto = Dropto(loc); if ((dropto == NOTHING) || (dropto == loc)) return; // Make sure no players hanging out // DOLIST(thing, Contents(loc)) { if ((Connected(Owner(thing)) && Hearer(thing))) return; } // Send everything through the dropto // s_Contents(loc, reverse_list(Contents(loc))); SAFE_DOLIST(thing, next, Contents(loc)) { send_dropto(thing, player); } } // process_dropped_dropto: Check what to do when someone drops an object. // static void process_dropped_dropto(dbref thing, dbref player) { // If STICKY, send home // if (Sticky(thing)) { move_via_generic(thing, HOME, player, 0); divest_object(thing); return; } // Process the dropto if location is a room and is not STICKY // dbref loc = Location(thing); if (Has_dropto(loc) && (Dropto(loc) != NOTHING) && !Sticky(loc)) send_dropto(thing, player); } /* --------------------------------------------------------------------------- * move_via_generic: Generic move routine, generates standard messages and * actions. */ void move_via_generic(dbref thing, dbref dest, dbref cause, int hush) { if (dest == HOME) { dest = Home(thing); } dbref src = Location(thing); bool canhear = Hearer(thing); process_leave_loc(thing, dest, cause, canhear, hush); move_object(thing, dest); did_it(thing, thing, A_MOVE, NULL, A_OMOVE, NULL, A_AMOVE, 0, NULL, 0); #if defined(FIRANMUX) did_it(thing, thing, A_LEAD, NULL, A_OLEAD, NULL, A_ALEAD, 0, NULL, 0); #endif // FIRANMUX process_enter_loc(thing, src, cause, canhear, hush); } /* --------------------------------------------------------------------------- * move_via_exit: Exit move routine, generic + exit messages + dropto check. */ static void move_via_exit(dbref thing, dbref dest, dbref cause, dbref exit, int hush) { if (dest == HOME) { dest = Home(thing); } dbref src = Location(thing); bool canhear = Hearer(thing); #if defined(FIRANMUX) bool quiet = Dark(thing) || (hush & HUSH_EXIT); int aattr = (hush & HUSH_EXIT) ? 0 : A_ASUCC; #else // Dark wizards don't trigger OSUCC/ASUCC bool quiet = ( (Wizard(thing) && Dark(thing)) || (hush & HUSH_EXIT)); int aattr = quiet ? 0 : A_ASUCC; #endif // FIRANMUX int oattr = quiet ? 0 : A_OSUCC; int pattr = (!mudconf.terse_movemsg && Terse(thing)) ? 0 : A_SUCC; did_it(thing, exit, pattr, NULL, oattr, NULL, aattr, 0, NULL, 0); process_leave_loc(thing, dest, cause, canhear, hush); move_object(thing, dest); #if defined(FIRANMUX) aattr = (hush & HUSH_EXIT) ? 0 : A_ADROP; #else aattr = quiet ? 0 : A_ADROP; #endif // FIRANMUX oattr = quiet ? 0 : A_ODROP; pattr = (!mudconf.terse_movemsg && Terse(thing)) ? 0 : A_DROP; did_it(thing, exit, pattr, NULL, oattr, NULL, aattr, 0, NULL, 0); did_it(thing, thing, A_MOVE, NULL, A_OMOVE, NULL, A_AMOVE, 0, NULL, 0); #if defined(FIRANMUX) did_it(thing, thing, A_LEAD, NULL, A_OLEAD, NULL, A_ALEAD, 0, NULL, 0); #endif process_enter_loc(thing, src, cause, canhear, hush); process_sticky_dropto(src, thing); } /* --------------------------------------------------------------------------- * move_via_teleport: Teleport move routine, generic + teleport messages + * divestiture + dropto check. */ bool move_via_teleport(dbref thing, dbref dest, dbref cause, int hush) { dbref curr; int count; const char *failmsg; dbref src = Location(thing); if ((dest != HOME) && Good_obj(src)) { curr = src; for (count = mudconf.ntfy_nest_lim; count > 0; count--) { if (!could_doit(thing, curr, A_LTELOUT)) { if ((thing == cause) || (cause == NOTHING)) { failmsg = "You can't teleport out!"; } else { failmsg = "You can't be teleported out!"; notify_quiet(cause, "You can't teleport that out!"); } did_it(thing, src, A_TOFAIL, failmsg, A_OTOFAIL, NULL, A_ATOFAIL, 0, NULL, 0); return false; } if (isRoom(curr)) { break; } curr = Location(curr); } } if (isExit(thing)) { move_the_exit(thing, dest); return true; } if (dest == HOME) { dest = Home(thing); } bool canhear = Hearer(thing); if (!(hush & HUSH_LEAVE)) { did_it(thing, thing, 0, NULL, A_OXTPORT, NULL, 0, 0, NULL, 0); } process_leave_loc(thing, dest, NOTHING, canhear, hush); move_object(thing, dest); if (!(hush & HUSH_ENTER)) { did_it(thing, thing, A_TPORT, NULL, A_OTPORT, NULL, A_ATPORT, 0, NULL, 0); } did_it(thing, thing, A_MOVE, NULL, A_OMOVE, NULL, A_AMOVE, 0, NULL, 0); #if defined(FIRANMUX) did_it(thing, thing, A_LEAD, NULL, A_OLEAD, NULL, A_ALEAD, 0, NULL, 0); #endif // FIRANMUX process_enter_loc(thing, src, NOTHING, canhear, hush); divest_object(thing); process_sticky_dropto(src, thing); return true; } /* --------------------------------------------------------------------------- * move_exit: Try to move a player through an exit. */ static dbref get_exit_dest(dbref executor, dbref exit) { dbref aowner; int aflags; char *atr_gotten = atr_pget(exit, A_EXITVARDEST, &aowner, &aflags); char *result = alloc_lbuf("get_exit_dest"); char *ref = result; char *str = atr_gotten; mux_exec(result, &ref, exit, executor, executor, AttrTrace(aflags, EV_TOP|EV_FCHECK|EV_EVAL), &str, NULL, 0); free_lbuf(atr_gotten); *ref = '\0'; dbref dest = NOTHING; if (*result == NUMBER_TOKEN) { dest = mux_atol(result + 1); } free_lbuf(result); return dest; } void move_exit(dbref player, dbref exit, bool divest, const char *failmsg, int hush) { int oattr, aattr; bool bDoit = false; dbref loc = Location(exit); if (atr_get_raw(exit, A_EXITVARDEST) != NULL) { loc = get_exit_dest(player, exit); } if (loc == HOME) { loc = Home(player); } #ifdef WOD_REALMS if (Good_obj(loc) && (REALM_DO_HIDDEN_FROM_YOU != DoThingToThingVisibility(player, exit, ACTION_IS_MOVING))) { if (isShroud(player)) { bDoit = true; int iShroudWarded = get_atr("SHROUD_WARDED"); if (iShroudWarded > 0) { int owner, flags; char *buff = atr_pget(exit, iShroudWarded, &owner, &flags); if (buff) { if (*buff) { bDoit = false; } free_lbuf(buff); } } } if (!bDoit && isUmbra(player)) { bDoit = true; int iUmbraWarded = get_atr("UMBRA_WARDED"); if (iUmbraWarded > 0) { int owner, flags; char *buff = atr_pget(exit, iUmbraWarded, &owner, &flags); if (buff) { if (*buff) { bDoit = false; } free_lbuf(buff); } } } if (!bDoit && could_doit(player, exit, A_LOCK)) { bDoit = true; } } #else #if defined(FIRANMUX) if (Immobile(player)) { notify(player, mudconf.immobile_msg); return; } #endif // FIRANMUX if (Good_obj(loc) && could_doit(player, exit, A_LOCK)) { bDoit = true; } #endif if (bDoit) { switch (Typeof(loc)) { case TYPE_ROOM: move_via_exit(player, loc, NOTHING, exit, hush); if (divest) divest_object(player); break; case TYPE_PLAYER: case TYPE_THING: if (Going(loc)) { notify(player, "You can't go that way."); return; } move_via_exit(player, loc, NOTHING, exit, hush); divest_object(player); break; case TYPE_EXIT: notify(player, "You can't go that way."); return; } } else { if ((Wizard(player) && Dark(player)) || (hush & HUSH_EXIT)) { oattr = 0; #if defined(FIRANMUX) aattr = (hush & HUSH_EXIT) ? 0 : A_AFAIL; #else aattr = 0; #endif // FIRANMUX } else { oattr = A_OFAIL; aattr = A_AFAIL; } did_it(player, exit, A_FAIL, failmsg, oattr, NULL, aattr, 0, NULL, 0); } } /* --------------------------------------------------------------------------- * do_move: Move from one place to another via exits or 'home'. */ void do_move(dbref executor, dbref caller, dbref enactor, int eval, int key, char *direction) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); dbref exit, loc; int i, quiet; if (!string_compare(direction, "home")) { // Go home w/o stuff. // if ( ( Fixed(executor) || Fixed(Owner(executor))) && !(WizRoy(executor))) { notify(executor, mudconf.fixed_home_msg); return; } #if defined(FIRANMUX) if (Immobile(executor)) { notify(executor, mudconf.immobile_msg); return; } #endif // FIRANMUX if ( (loc = Location(executor)) != NOTHING && !Dark(executor) && !Dark(loc)) { // Tell all // notify_except(loc, executor, executor, tprintf("%s goes home.", Moniker(executor)), 0); } // Give the player the messages // for (i = 0; i < 3; i++) notify(executor, "There's no place like home..."); move_via_generic(executor, HOME, NOTHING, 0); divest_object(executor); process_sticky_dropto(loc, executor); return; } // Find the exit. // init_match_check_keys(executor, direction, TYPE_EXIT); #if defined(FIRANMUX) match_exit_with_parents(); #else match_exit(); #endif // FIRANMUX exit = match_result(); switch (exit) { case NOTHING: // Try to force the object notify(executor, "You can't go that way."); break; case AMBIGUOUS: notify(executor, "I don't know which way you mean!"); break; default: quiet = 0; if ((key & MOVE_QUIET) && Controls(executor, exit)) quiet = HUSH_EXIT; move_exit(executor, exit, false, "You can't go that way.", quiet); } } /* --------------------------------------------------------------------------- * do_get: Get an object. */ void do_get(dbref executor, dbref caller, dbref enactor, int eval, int key, char *what) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); dbref playerloc; if ( !Has_location(executor) || !Good_obj(playerloc = Location(executor))) { return; } // You can only pick up things in rooms and ENTER_OK objects/players. // if ( !isRoom(playerloc) && !Enter_ok(playerloc) && !Controls(executor, playerloc)) { notify(executor, NOPERM_MESSAGE); return; } // Look for the thing locally. // init_match_check_keys(executor, what, TYPE_THING); match_neighbor(); match_exit(); if (Long_Fingers(executor)) { match_absolute(); } dbref thing = match_result(); // Look for the thing in other people's inventories. // if (!Good_obj(thing)) { thing = match_status(executor, match_possessed(executor, executor, what, thing, true)); if (!Good_obj(thing)) { return; } } // If we found it, check to see if we can get it. // dbref thingloc = Location(thing); if (Good_obj(thingloc)) { if (!could_doit(executor, thingloc, A_LGET)) { notify(executor, NOPERM_MESSAGE); return; } } // If we can get it, get it. // const char *failmsg; int oattr, aattr; bool quiet = false; switch (Typeof(thing)) { case TYPE_PLAYER: case TYPE_THING: // You can't take what you already have. // if (thingloc == executor) { notify(executor, "You already have that!"); break; } if ( (key & GET_QUIET) && Controls(executor, thing)) { quiet = true; } if (thing == executor) { notify(executor, "You cannot get yourself!"); } else if (could_doit(executor, thing, A_LOCK)) { if (thingloc != playerloc) { notify(thingloc, tprintf("%s was taken from you.", Moniker(thing))); } move_via_generic(thing, executor, executor, 0); notify(thing, "Taken."); oattr = quiet ? 0 : A_OSUCC; aattr = quiet ? 0 : A_ASUCC; did_it(executor, thing, A_SUCC, "Taken.", oattr, NULL, aattr, 0, NULL, 0); } else { oattr = quiet ? 0 : A_OFAIL; aattr = quiet ? 0 : A_AFAIL; if (thingloc != playerloc) { failmsg = "You can't take that from there."; } else { failmsg = "You can't pick that up."; } did_it(executor, thing, A_FAIL, failmsg, oattr, NULL, aattr, 0, NULL, 0); } break; case TYPE_EXIT: // You can't take what you already have. // thingloc = Exits(thing); if (thingloc == executor) { notify(executor, "You already have that!"); break; } // You must control either the exit or the location. // if ( !Controls(executor, thing) && !Controls(executor, playerloc)) { notify(executor, NOPERM_MESSAGE); break; } // Do it. // s_Exits(thingloc, remove_first(Exits(thingloc), thing)); s_Exits(executor, insert_first(Exits(executor), thing)); s_Exits(thing, executor); if (!Quiet(executor)) { notify(executor, "Exit taken."); } break; default: notify(executor, "You can't take that!"); break; } } /* --------------------------------------------------------------------------- * do_drop: Drop an object. */ void do_drop(dbref executor, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); dbref loc = Location(executor); if (!Good_obj(loc)) return; dbref exitloc, thing; char *buf, *bp; int oattr, aattr; bool quiet; init_match(executor, name, TYPE_THING); match_possession(); match_carried_exit(); switch (thing = match_result()) { case NOTHING: notify(executor, "You don't have that!"); return; case AMBIGUOUS: notify(executor, "I don't know which you mean!"); return; } switch (Typeof(thing)) { case TYPE_THING: case TYPE_PLAYER: // You have to be carrying it. // if ( ( Location(thing) != executor && !Wizard(executor)) || !could_doit(executor, thing, A_LDROP)) { did_it(executor, thing, A_DFAIL, "You can't drop that.", A_ODFAIL, NULL, A_ADFAIL, 0, NULL, 0); return; } // Move it // move_via_generic(thing, Location(executor), executor, 0); notify(thing, "Dropped."); quiet = false; if ((key & DROP_QUIET) && Controls(executor, thing)) quiet = true; bp = buf = alloc_lbuf("do_drop.did_it"); safe_tprintf_str(buf, &bp, "dropped %s.", Moniker(thing)); oattr = quiet ? 0 : A_ODROP; aattr = quiet ? 0 : A_ADROP; did_it(executor, thing, A_DROP, "Dropped.", oattr, buf, aattr, 0, NULL, 0); free_lbuf(buf); // Process droptos // process_dropped_dropto(thing, executor); break; case TYPE_EXIT: // You have to be carrying it. // if ((Exits(thing) != executor) && !Wizard(executor)) { notify(executor, "You can't drop that."); return; } if (!Controls(executor, loc)) { notify(executor, NOPERM_MESSAGE); return; } // Do it // exitloc = Exits(thing); s_Exits(exitloc, remove_first(Exits(exitloc), thing)); s_Exits(loc, insert_first(Exits(loc), thing)); s_Exits(thing, loc); if (!Quiet(executor)) notify(executor, "Exit dropped."); break; default: notify(executor, "You can't drop that."); } } /* --------------------------------------------------------------------------- * do_enter, do_leave: The enter and leave commands. */ void do_enter_internal(dbref player, dbref thing, bool quiet) { int oattr, aattr; if (!Enter_ok(thing) && !Controls(player, thing)) { oattr = quiet ? 0 : A_OEFAIL; aattr = quiet ? 0 : A_AEFAIL; did_it(player, thing, A_EFAIL, NOPERM_MESSAGE, oattr, NULL, aattr, 0, NULL, 0); } else if (player == thing) { notify(player, "You can't enter yourself!"); } else if (could_doit(player, thing, A_LENTER)) { dbref loc = Location(player); oattr = quiet ? HUSH_ENTER : 0; move_via_generic(player, thing, NOTHING, oattr); divest_object(player); process_sticky_dropto(loc, player); } else { oattr = quiet ? 0 : A_OEFAIL; aattr = quiet ? 0 : A_AEFAIL; did_it(player, thing, A_EFAIL, "You can't enter that.", oattr, NULL, aattr, 0, NULL, 0); } } void do_enter(dbref executor, dbref caller, dbref enactor, int eval, int key, char *what) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); init_match(executor, what, TYPE_THING); match_neighbor(); if (Long_Fingers(executor)) match_absolute(); // the wizard has long fingers dbref thing = noisy_match_result(); bool bQuiet = false; if (thing == NOTHING) return; switch (Typeof(thing)) { case TYPE_PLAYER: case TYPE_THING: if ((key & MOVE_QUIET) && Controls(executor, thing)) bQuiet = true; do_enter_internal(executor, thing, bQuiet); break; default: notify(executor, NOPERM_MESSAGE); } return; } void do_leave(dbref executor, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); dbref loc = Location(executor); dbref newLoc = loc; if ( !Good_obj(loc) || Going(loc) || !Has_location(loc) || !Good_obj(newLoc = Location(loc)) || Going(newLoc)) { notify(executor, "You can't leave."); return; } int quiet = 0; if ( (key & MOVE_QUIET) && Controls(executor, loc)) { quiet = HUSH_LEAVE; } if (could_doit(executor, loc, A_LLEAVE)) { move_via_generic(executor, newLoc, NOTHING, quiet); } else { int oattr = quiet ? 0 : A_OLFAIL; int aattr = quiet ? 0 : A_ALFAIL; did_it(executor, loc, A_LFAIL, "You can't leave.", oattr, NULL, aattr, 0, NULL, 0); } } mux2.6/src/player.cpp0000600000175000017500000006020411025753746014600 0ustar sdennissdennis// player.cpp // // $Id: player.cpp 2734 2007-10-28 23:02:55Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "comsys.h" #include "functions.h" #include "interface.h" #include "powers.h" #include "svdreport.h" #include "sha1.h" #define NUM_GOOD 4 // # of successful logins to save data for. #define NUM_BAD 3 // # of failed logins to save data for. typedef struct hostdtm HOSTDTM; struct hostdtm { char *host; char *dtm; }; typedef struct logindata LDATA; struct logindata { HOSTDTM good[NUM_GOOD]; HOSTDTM bad[NUM_BAD]; int tot_good; int tot_bad; int new_bad; }; /* --------------------------------------------------------------------------- * decrypt_logindata, encrypt_logindata: Decode and encode login info. */ static void decrypt_logindata(char *atrbuf, LDATA *info) { int i; info->tot_good = 0; info->tot_bad = 0; info->new_bad = 0; for (i = 0; i < NUM_GOOD; i++) { info->good[i].host = NULL; info->good[i].dtm = NULL; } for (i = 0; i < NUM_BAD; i++) { info->bad[i].host = NULL; info->bad[i].dtm = NULL; } if (*atrbuf == '#') { atrbuf++; info->tot_good = mux_atol(grabto(&atrbuf, ';')); for (i = 0; i < NUM_GOOD; i++) { info->good[i].host = grabto(&atrbuf, ';'); info->good[i].dtm = grabto(&atrbuf, ';'); } info->new_bad = mux_atol(grabto(&atrbuf, ';')); info->tot_bad = mux_atol(grabto(&atrbuf, ';')); for (i = 0; i < NUM_BAD; i++) { info->bad[i].host = grabto(&atrbuf, ';'); info->bad[i].dtm = grabto(&atrbuf, ';'); } } } static void encrypt_logindata(char *atrbuf, LDATA *info) { // Make sure the SPRINTF call tracks NUM_GOOD and NUM_BAD for the number // of host/dtm pairs of each type. // char nullc = '\0'; int i; for (i = 0; i < NUM_GOOD; i++) { if (!info->good[i].host) info->good[i].host = &nullc; if (!info->good[i].dtm) info->good[i].dtm = &nullc; } for (i = 0; i < NUM_BAD; i++) { if (!info->bad[i].host) info->bad[i].host = &nullc; if (!info->bad[i].dtm) info->bad[i].dtm = &nullc; } char *bp = alloc_lbuf("encrypt_logindata"); mux_sprintf(bp, LBUF_SIZE, "#%d;%s;%s;%s;%s;%s;%s;%s;%s;%d;%d;%s;%s;%s;%s;%s;%s;", info->tot_good, info->good[0].host, info->good[0].dtm, info->good[1].host, info->good[1].dtm, info->good[2].host, info->good[2].dtm, info->good[3].host, info->good[3].dtm, info->new_bad, info->tot_bad, info->bad[0].host, info->bad[0].dtm, info->bad[1].host, info->bad[1].dtm, info->bad[2].host, info->bad[2].dtm); mux_strncpy(atrbuf, bp, LBUF_SIZE-1); free_lbuf(bp); } /* --------------------------------------------------------------------------- * record_login: Record successful or failed login attempt. * If successful, report last successful login and number of failures since * last successful login. */ void record_login ( dbref player, bool isgood, char *ldate, char *lhost, char *lusername, char *lipaddr ) { LDATA login_info; dbref aowner; int aflags, i; char *atrbuf = atr_get(player, A_LOGINDATA, &aowner, &aflags); decrypt_logindata(atrbuf, &login_info); if (isgood) { if (login_info.new_bad > 0) { notify(player, ""); notify(player, tprintf("**** %d failed connect%s since your last successful connect. ****", login_info.new_bad, (login_info.new_bad == 1 ? "" : "s"))); notify(player, tprintf("Most recent attempt was from %s on %s.", login_info.bad[0].host, login_info.bad[0].dtm)); notify(player, ""); login_info.new_bad = 0; } if ( login_info.good[0].host && *login_info.good[0].host && login_info.good[0].dtm && *login_info.good[0].dtm) { notify(player, tprintf("Last connect was from %s on %s.", login_info.good[0].host, login_info.good[0].dtm)); } for (i = NUM_GOOD - 1; i > 0; i--) { login_info.good[i].dtm = login_info.good[i - 1].dtm; login_info.good[i].host = login_info.good[i - 1].host; } login_info.good[0].dtm = ldate; login_info.good[0].host = lhost; login_info.tot_good++; if (*lusername) { atr_add_raw(player, A_LASTSITE, tprintf("%s@%s", lusername, lhost)); } else { atr_add_raw(player, A_LASTSITE, lhost); } // Add the players last IP too. // atr_add_raw(player, A_LASTIP, lipaddr); } else { for (i = NUM_BAD - 1; i > 0; i--) { login_info.bad[i].dtm = login_info.bad[i - 1].dtm; login_info.bad[i].host = login_info.bad[i - 1].host; } login_info.bad[0].dtm = ldate; login_info.bad[0].host = lhost; login_info.tot_bad++; login_info.new_bad++; } encrypt_logindata(atrbuf, &login_info); atr_add_raw(player, A_LOGINDATA, atrbuf); free_lbuf(atrbuf); } const char Base64Table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; #define ENCODED_LENGTH(x) ((((x)+2)/3)*4) static void EncodeBase64(size_t nIn, const char *pIn, char *pOut) { size_t nTriples = nIn/3; size_t nLeftover = nIn%3; UINT32 stage; const UINT8 *p = (const UINT8 *)pIn; UINT8 *q = ( UINT8 *)pOut; while (nTriples--) { stage = (p[0] << 16) | (p[1] << 8) | p[2]; q[0] = Base64Table[(stage >> 18) ]; q[1] = Base64Table[(stage >> 12) & 0x3F]; q[2] = Base64Table[(stage >> 6) & 0x3F]; q[3] = Base64Table[(stage ) & 0x3F]; q += 4; p += 3; } switch (nLeftover) { case 1: stage = p[0] << 16; q[0] = Base64Table[(stage >> 18) ]; q[1] = Base64Table[(stage >> 12) & 0x3F]; q[2] = '='; q[3] = '='; q += 4; break; case 2: stage = (p[0] << 16) | (p[1] << 8); q[0] = Base64Table[(stage >> 18) ]; q[1] = Base64Table[(stage >> 12) & 0x3F]; q[2] = Base64Table[(stage >> 6) & 0x3F]; q[3] = '='; q += 4; break; } q[0] = '\0'; } #define SHA1_PREFIX_LENGTH 6 const char szSHA1Prefix[SHA1_PREFIX_LENGTH+1] = "$SHA1$"; #define ENCODED_HASH_LENGTH ENCODED_LENGTH(5*sizeof(UINT32)) #define MD5_PREFIX_LENGTH 3 const char szMD5Prefix[MD5_PREFIX_LENGTH+1] = "$1$"; #define BLOWFISH_PREFIX_LENGTH 4 const char szBlowfishPrefix[BLOWFISH_PREFIX_LENGTH+1] = "$2a$"; #define SALT_LENGTH 9 #define ENCODED_SALT_LENGTH ENCODED_LENGTH(SALT_LENGTH) static const char *GenerateSalt(void) { char szSaltRaw[SALT_LENGTH+1]; int i; for (i = 0; i < SALT_LENGTH; i++) { szSaltRaw[i] = (char)RandomINT32(0, 255); } szSaltRaw[SALT_LENGTH] = '\0'; static char szSaltEncoded[SHA1_PREFIX_LENGTH + ENCODED_SALT_LENGTH+1]; mux_strncpy(szSaltEncoded, szSHA1Prefix, SHA1_PREFIX_LENGTH); EncodeBase64(SALT_LENGTH, szSaltRaw, szSaltEncoded + SHA1_PREFIX_LENGTH); return szSaltEncoded; } void ChangePassword(dbref player, const char *szPassword) { int iType; s_Pass(player, mux_crypt(szPassword, GenerateSalt(), &iType)); } #define CRYPT_FAIL 0 #define CRYPT_SHA1 1 #define CRYPT_MD5 2 #define CRYPT_DES 3 #define CRYPT_DES_EXT 4 #define CRYPT_BLOWFISH 5 #define CRYPT_CLEARTEXT 6 #define CRYPT_OTHER 7 const char szFail[] = "$FAIL$$"; // REMOVE: After 2006-JUL-23, remove support for DES-encrypted passwords on // Win32 build. This should allow support for DES-encrypted passwords to // strattle three distinct versions of MUX. After that, to convert the older // passwords automatically would require going through one of these three // older versions of the server. Alternatively, since crypt and DES-encrypted // passwords should be supported on Unix for even longer, converting the // flatfile on a Unix box remains an option. // const char *mux_crypt(const char *szPassword, const char *szSetting, int *piType) { const char *pSaltField = NULL; size_t nSaltField = 0; *piType = CRYPT_FAIL; if (szSetting[0] == '$') { const char *p = strchr(szSetting+1, '$'); if (p) { p++; size_t nAlgo = p - szSetting; if ( nAlgo == SHA1_PREFIX_LENGTH && memcmp(szSetting, szSHA1Prefix, SHA1_PREFIX_LENGTH) == 0) { // SHA-1 // pSaltField = p; p = strchr(pSaltField, '$'); if (p) { nSaltField = p - pSaltField; } else { nSaltField = strlen(pSaltField); } if (nSaltField <= ENCODED_SALT_LENGTH) { *piType = CRYPT_SHA1; } } else if ( nAlgo == MD5_PREFIX_LENGTH && memcmp(szSetting, szMD5Prefix, MD5_PREFIX_LENGTH) == 0) { *piType = CRYPT_MD5; } else if ( nAlgo == BLOWFISH_PREFIX_LENGTH && memcmp(szSetting, szBlowfishPrefix, BLOWFISH_PREFIX_LENGTH) == 0) { *piType = CRYPT_BLOWFISH; } else { *piType = CRYPT_OTHER; } } } else if (szSetting[0] == '_') { *piType = CRYPT_DES_EXT; } else { #if 0 // Strictly speaking, we can say the algorithm is DES. // *piType = CRYPT_DES; #else // However, in order to support clear-text passwords, we restrict // ourselves to only verifying an existing DES-encrypted password and // we assume a fixed salt of 'XX'. If you have been using a different // salt, or if you need to generate a DES-encrypted password, the // following code won't work. // size_t nSetting = strlen(szSetting); if ( nSetting == 13 && memcmp(szSetting, "XX", 2) == 0) { *piType = CRYPT_DES; } else { *piType = CRYPT_CLEARTEXT; } #endif } switch (*piType) { case CRYPT_FAIL: return szFail; case CRYPT_CLEARTEXT: return szPassword; case CRYPT_MD5: case CRYPT_BLOWFISH: case CRYPT_OTHER: case CRYPT_DES_EXT: #ifdef WIN32 // The WIN32 release only supports SHA1 and clear-text. // return szFail; #endif // WIN32 case CRYPT_DES: #if defined(HAVE_LIBCRYPT) \ || defined(HAVE_CRYPT) return crypt(szPassword, szSetting); #else return szFail; #endif } // Calculate SHA-1 Hash. // SHA1_CONTEXT shac; SHA1_Init(&shac); SHA1_Compute(&shac, nSaltField, pSaltField); SHA1_Compute(&shac, strlen(szPassword), szPassword); SHA1_Final(&shac); // Serialize 5 UINT32 words into big-endian. // char szHashRaw[21]; char *p = szHashRaw; int i; for (i = 0; i <= 4; i++) { *p++ = (UINT8)(shac.H[i] >> 24); *p++ = (UINT8)(shac.H[i] >> 16); *p++ = (UINT8)(shac.H[i] >> 8); *p++ = (UINT8)(shac.H[i] ); } *p = '\0'; // 1 2 3 4 // 12345678901234567890123456789012345678901234567 // $SHA1$ssssssssssss$hhhhhhhhhhhhhhhhhhhhhhhhhhhh // static char buf[SHA1_PREFIX_LENGTH + ENCODED_SALT_LENGTH + 1 + ENCODED_HASH_LENGTH + 1 + 16]; mux_strncpy(buf, szSHA1Prefix, SHA1_PREFIX_LENGTH); memcpy(buf + SHA1_PREFIX_LENGTH, pSaltField, nSaltField); buf[SHA1_PREFIX_LENGTH + nSaltField] = '$'; EncodeBase64(20, szHashRaw, buf + SHA1_PREFIX_LENGTH + nSaltField + 1); return buf; } /* --------------------------------------------------------------------------- * check_pass: Test a password to see if it is correct. */ static bool check_pass(dbref player, const char *pPassword) { bool bValidPass = false; int iType; int aflags; dbref aowner; char *pTarget = atr_get(player, A_PASS, &aowner, &aflags); if (*pTarget) { if (strcmp(mux_crypt(pPassword, pTarget, &iType), pTarget) == 0) { bValidPass = true; if (iType != CRYPT_SHA1) { ChangePassword(player, pPassword); } } } #if 0 else if (GOD == player) { // When GOD doesn't have a password, we need to a way to set one. // bValidPass = true; ChangePassword(player, pPassword); } #endif free_lbuf(pTarget); return bValidPass; } /* --------------------------------------------------------------------------- * connect_player: Try to connect to an existing player. */ dbref connect_player(char *name, char *password, char *host, char *username, char *ipaddr) { CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); char *time_str = ltaNow.ReturnDateString(7); dbref player = lookup_player(NOTHING, name, false); if (player == NOTHING) { return NOTHING; } if (!check_pass(player, password)) { record_login(player, false, time_str, host, username, ipaddr); return NOTHING; } // Compare to last connect see if player gets salary. // int aflags; dbref aowner; char *player_last = atr_get(player, A_LAST, &aowner, &aflags); if (strncmp(player_last, time_str, 10) != 0) { char *allowance = atr_pget(player, A_ALLOWANCE, &aowner, &aflags); if (*allowance == '\0') { giveto(player, mudconf.paycheck); } else { giveto(player, mux_atol(allowance)); } free_lbuf(allowance); } free_lbuf(player_last); atr_add_raw(player, A_LAST, time_str); return player; } void AddToPublicChannel(dbref player) { if ( mudconf.public_channel[0] != '\0' && mudconf.public_channel_alias[0] != '\0') { do_addcom(player, player, player, 0, 2, mudconf.public_channel_alias, mudconf.public_channel); } } /* --------------------------------------------------------------------------- * create_player: Create a new player. */ dbref create_player ( const char *name, const char *password, dbref creator, bool isrobot, const char **pmsg ) { *pmsg = NULL; // Potentially throttle the rate of player creation. // if (ThrottlePlayerCreate()) { *pmsg = "The limit of new players for this hour has been reached. Please try again later."; return NOTHING; } // Make sure the password is OK. Name is checked in create_obj. // char *pbuf = trim_spaces(password); if (!ok_password(pbuf, pmsg)) { free_lbuf(pbuf); return NOTHING; } // If so, go create him. // dbref player = create_obj(creator, TYPE_PLAYER, name, isrobot); if (player == NOTHING) { *pmsg = "Either there is already a player with that name, or that name is illegal."; free_lbuf(pbuf); return NOTHING; } // Initialize everything. // ChangePassword(player, pbuf); s_Home(player, start_home()); free_lbuf(pbuf); local_data_create(player); return player; } /* --------------------------------------------------------------------------- * do_password: Change the password for a player */ void do_password ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *oldpass, char *newpass ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nargs); dbref aowner; int aflags; char *target = atr_get(executor, A_PASS, &aowner, &aflags); const char *pmsg; if ( !*target || !check_pass(executor, oldpass)) { notify(executor, "Sorry."); } else if (ok_password(newpass, &pmsg)) { ChangePassword(executor, newpass); notify(executor, "Password changed."); } else { notify(executor, pmsg); } free_lbuf(target); } /* --------------------------------------------------------------------------- * do_last: Display login history data. */ static void disp_from_on(dbref player, char *dtm_str, char *host_str) { if (dtm_str && *dtm_str && host_str && *host_str) { notify(player, tprintf(" From: %s On: %s", dtm_str, host_str)); } } void do_last(dbref executor, dbref caller, dbref enactor, int eval, int key, char *who) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); dbref target, aowner; int i, aflags; if ( !who || !*who) { target = Owner(executor); } else if (string_compare(who, "me") == 0) { target = Owner(executor); } else { target = lookup_player(executor, who, true); } if (target == NOTHING) { notify(executor, "I couldn't find that player."); } else if (!Controls(executor, target)) { notify(executor, NOPERM_MESSAGE); } else { char *atrbuf = atr_get(target, A_LOGINDATA, &aowner, &aflags); LDATA login_info; decrypt_logindata(atrbuf, &login_info); notify(executor, tprintf("Total successful connects: %d", login_info.tot_good)); for (i = 0; i < NUM_GOOD; i++) { disp_from_on(executor, login_info.good[i].host, login_info.good[i].dtm); } notify(executor, tprintf("Total failed connects: %d", login_info.tot_bad)); for (i = 0; i < NUM_BAD; i++) { disp_from_on(executor, login_info.bad[i].host, login_info.bad[i].dtm); } free_lbuf(atrbuf); } } /* --------------------------------------------------------------------------- * add_player_name, delete_player_name, lookup_player: * Manage playername->dbref mapping */ bool add_player_name(dbref player, const char *name) { bool stat = false; char *temp, *tp; // Convert to all lowercase. // tp = temp = alloc_lbuf("add_player_name"); safe_str(name, temp, &tp); *tp = '\0'; mux_strlwr(temp); dbref *p = (int *)hashfindLEN(temp, strlen(temp), &mudstate.player_htab); if (p) { // Entry found in the hashtable. If a player, succeed if the // numbers match (already correctly in the hash table), fail // if they don't. // if (Good_obj(*p) && isPlayer(*p)) { free_lbuf(temp); if (*p == player) { return true; } else { return false; } } // It's an alias (or an incorrect entry). Clobber it. // delete p; p = NULL; try { p = new dbref; } catch (...) { ; // Nothing. } if (NULL != p) { *p = player; stat = hashreplLEN(temp, strlen(temp), p, &mudstate.player_htab); } else { ISOUTOFMEMORY(p); } free_lbuf(temp); } else { p = NULL; try { p = new dbref; } catch (...) { ; // Nothing. } if (NULL != p) { *p = player; stat = hashaddLEN(temp, strlen(temp), p, &mudstate.player_htab); } else { ISOUTOFMEMORY(p); } free_lbuf(temp); } return stat; } bool delete_player_name(dbref player, const char *name) { char *temp, *tp; tp = temp = alloc_lbuf("delete_player_name"); safe_str(name, temp, &tp); *tp = '\0'; mux_strlwr(temp); dbref *p = (int *)hashfindLEN(temp, strlen(temp), &mudstate.player_htab); if ( !p || *p == NOTHING || ( player != NOTHING && *p != player)) { free_lbuf(temp); return false; } delete p; p = NULL; hashdeleteLEN(temp, strlen(temp), &mudstate.player_htab); free_lbuf(temp); return true; } dbref lookup_player(dbref doer, char *name, bool check_who) { if (string_compare(name, "me") == 0) { return doer; } while (*name == LOOKUP_TOKEN) { name++; } dbref thing; if (*name == NUMBER_TOKEN) { name++; if (!is_integer(name, NULL)) { return NOTHING; } thing = mux_atol(name); if (!Good_obj(thing)) { return NOTHING; } if ( !( isPlayer(thing) || God(doer))) { thing = NOTHING; } return thing; } char *temp, *tp; tp = temp = alloc_lbuf("lookup_player"); safe_str(name, temp, &tp); *tp = '\0'; mux_strlwr(temp); dbref *p = (int *)hashfindLEN(temp, strlen(temp), &mudstate.player_htab); free_lbuf(temp); if (!p) { if (check_who) { thing = find_connected_name(doer, name); if (Hidden(thing)) { thing = NOTHING; } } else { thing = NOTHING; } } else if (!Good_obj(*p)) { thing = NOTHING; } else { thing = *p; } return thing; } void load_player_names(void) { dbref i; DO_WHOLE_DB(i) { if (isPlayer(i)) { add_player_name(i, Name(i)); } } char *alias = alloc_lbuf("load_player_names"); DO_WHOLE_DB(i) { if (isPlayer(i)) { dbref aowner; int aflags; alias = atr_pget_str(alias, i, A_ALIAS, &aowner, &aflags); if (*alias) { add_player_name(i, alias); } } } free_lbuf(alias); } /* --------------------------------------------------------------------------- * badname_add, badname_check, badname_list: Add/look for/display bad names. */ void badname_add(char *bad_name) { // Make a new node and link it in at the top. // BADNAME *bp = NULL; try { bp = new BADNAME; } catch (...) { ; // Nothing. } if (NULL != bp) { bp->name = StringClone(bad_name); bp->next = mudstate.badname_head; mudstate.badname_head = bp; } else { ISOUTOFMEMORY(bp); } } void badname_remove(char *bad_name) { // Look for an exact match on the bad name and remove if found. // BADNAME *bp; BADNAME *backp = NULL; for (bp = mudstate.badname_head; bp; backp = bp, bp = bp->next) { if (!string_compare(bad_name, bp->name)) { if (backp) { backp->next = bp->next; } else { mudstate.badname_head = bp->next; } MEMFREE(bp->name); bp->name = NULL; delete bp; bp = NULL; return; } } } bool badname_check(char *bad_name) { BADNAME *bp; // Walk the badname list, doing wildcard matching. If we get a hit then // return false. If no matches in the list, return true. // for (bp = mudstate.badname_head; bp; bp = bp->next) { mudstate.wild_invk_ctr = 0; if (quick_wild(bp->name, bad_name)) { return false; } } return true; } void badname_list(dbref player, const char *prefix) { BADNAME *bp; char *buff, *bufp; // Construct an lbuf with all the names separated by spaces. // buff = bufp = alloc_lbuf("badname_list"); safe_str(prefix, buff, &bufp); for (bp = mudstate.badname_head; bp; bp = bp->next) { safe_chr(' ', buff, &bufp); safe_str(bp->name, buff, &bufp); } *bufp = '\0'; // Now display it. // notify(player, buff); free_lbuf(buff); } mux2.6/src/svdrand.h0000600000175000017500000000066111025753746014413 0ustar sdennissdennis// svdrand.h -- Random Numbers. // // $Id: svdrand.h 8 2006-09-05 01:55:58Z brazilofmux $ // // Random Numbers based on algorithms presented in "Numerical Recipes in C", // Cambridge Press, 1992. // #ifndef SVDRAND_H #define SVDRAND_H void SeedRandomNumberGenerator(void); double RandomFloat(double flLow, double flHigh); INT32 RandomINT32(INT32 lLow, INT32 lHigh); #ifdef WIN32 extern bool bCryptoAPI; #endif #endif // SVDRAND_H mux2.6/src/comsys.h0000600000175000017500000000676411025753746014301 0ustar sdennissdennis// comsys.h // // $Id: comsys.h 3052 2007-12-30 06:36:27Z brazilofmux $ // #ifndef __COMSYS_H__ #define __COMSYS_H__ typedef struct chanentry CHANENT; struct chanentry { char *channame; struct channel *chan; }; #define NUM_COMSYS 500 #define MAX_USERS_PER_CHANNEL 1000000 #define MAX_CHANNEL_LEN 50 #define MAX_HEADER_LEN 100 #define MAX_TITLE_LEN 200 #define MAX_ALIAS_LEN 5 #define ALIAS_SIZE (MAX_ALIAS_LEN+1) #define MAX_COST 32767 struct comuser { dbref who; bool bUserIsOn; char *title; bool ComTitleStatus; struct comuser *on_next; }; struct channel { char name[MAX_CHANNEL_LEN+1]; char header[MAX_HEADER_LEN+1]; int type; int temp1; int temp2; int charge; dbref charge_who; int amount_col; int num_users; int max_users; dbref chan_obj; struct comuser **users; struct comuser *on_users; /* Linked list of who is on */ int num_messages; }; typedef struct tagComsys { dbref who; int numchannels; int maxchannels; char *alias; char **channels; struct tagComsys *next; } comsys_t; void save_comsys(char *filename); void load_comsys(char *filename); void del_comsys(dbref who); void add_comsys(comsys_t *c); bool test_join_access(dbref player, struct channel *chan); bool test_transmit_access(dbref player, struct channel *chan); bool test_receive_access(dbref player, struct channel *chan); void do_joinchannel(dbref player, struct channel *ch); void do_comdisconnectchannel(dbref player, char *channel); void load_channels_V0123(FILE *fp); void load_channels_V4(FILE *fp); void purge_comsystem(void); void save_channels(FILE *fp); void destroy_comsys(comsys_t *c); void sort_com_aliases(comsys_t *c); void load_comsystem_V0123(FILE *fp); void load_comsystem_V4(FILE *fp); void save_comsystem(FILE *fp); void SendChannelMessage ( dbref player, struct channel *ch, char *msgNormal, char *msgNoComtitle ); void do_comwho(dbref player, struct channel *ch); void do_comlast(dbref player, struct channel *ch, int arg); void do_leavechannel(dbref player, struct channel *ch); void do_delcomchannel(dbref player, char *channel, bool bQuiet); #if 0 void do_cleanupchannels(void); #endif // 0 void do_channelnuke(dbref player); void sort_users(struct channel *ch); void do_comdisconnect(dbref player); void do_comconnect(dbref player); void do_clearcom(dbref executor, dbref caller, dbref enactor, int unused2); void do_cheader(dbref player, char *channel, char *header); void do_addcom ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *arg1, char *arg2 ); comsys_t *create_new_comsys (); struct channel *select_channel(char *channel); struct comuser *select_user(struct channel *ch, dbref player); char *get_channel_from_alias(); char *MakeCanonicalComAlias ( const char *pAlias, size_t *nValidAlias, bool *bValidAlias ); bool do_comsystem(dbref who, char *cmd); #define CHANNEL_PLAYER_JOIN (0x00000001UL) #define CHANNEL_PLAYER_TRANSMIT (0x00000002UL) #define CHANNEL_PLAYER_RECEIVE (0x00000004UL) #define CHANNEL_OBJECT_JOIN (0x00000010UL) #define CHANNEL_OBJECT_TRANSMIT (0x00000020UL) #define CHANNEL_OBJECT_RECEIVE (0x00000040UL) #define CHANNEL_LOUD (0x00000100UL) #define CHANNEL_PUBLIC (0x00000200UL) #define CHANNEL_SPOOF (0x00000400UL) // Connected players and non-garbage objects are ok. // #define UNDEAD(x) (Good_obj(x) && ((Typeof(x) != TYPE_PLAYER) || Connected(x))) #endif // __COMSYS_H__ mux2.6/src/rob.cpp0000600000175000017500000002725611025753746014100 0ustar sdennissdennis// rob.cpp -- Commands dealing with giving/taking/killing things or money. // // $Id: rob.cpp 492 2006-11-30 17:12:25Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "powers.h" void do_kill ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *what, char *costchar ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); char *buf1, *buf2; init_match(executor, what, TYPE_PLAYER); match_neighbor(); match_me(); match_here(); if (Long_Fingers(executor)) { match_player(); match_absolute(); } dbref victim = match_result(); switch (victim) { case NOTHING: notify(executor, "I don't see that player here."); break; case AMBIGUOUS: notify(executor, "I don't know who you mean!"); break; default: if ( !isPlayer(victim) && !isThing(victim)) { notify(executor, "Sorry, you can only kill players and things."); break; } if ( ( Haven(Location(victim)) && !Wizard(executor)) || ( Controls(victim, Location(victim)) && !Controls(executor, Location(victim))) || Unkillable(victim)) { notify(executor, "Sorry."); break; } // Go for it. // int cost = 0; if (key == KILL_KILL) { cost = mux_atol(costchar); if (cost < mudconf.killmin) { cost = mudconf.killmin; } if (cost > mudconf.killmax) { cost = mudconf.killmax; } // See if it works. // if (!payfor(executor, cost)) { notify(executor, tprintf("You don't have enough %s.", mudconf.many_coins)); return; } } if ( RealWizard(victim) || ( 0 < mudconf.killguarantee && !( RandomINT32(0, mudconf.killguarantee-1) < cost || key == KILL_SLAY))) { // Failure: notify player and victim only. // notify(executor, "Your murder attempt failed."); buf1 = alloc_lbuf("do_kill.failed"); mux_sprintf(buf1, LBUF_SIZE, "%s tried to kill you!", Moniker(executor)); notify_with_cause_ooc(victim, executor, buf1); if (Suspect(executor)) { mux_strncpy(buf1, Moniker(executor), LBUF_SIZE-1); if (executor == Owner(executor)) { raw_broadcast(WIZARD, "[Suspect] %s tried to kill %s(#%d).", buf1, Moniker(victim), victim); } else { buf2 = alloc_lbuf("do_kill.SUSP.failed"); mux_strncpy(buf2, Moniker(Owner(executor)), LBUF_SIZE-1); raw_broadcast(WIZARD, "[Suspect] %s tried to kill %s(#%d).", buf2, buf1, executor, Moniker(victim), victim); free_lbuf(buf2); } } free_lbuf(buf1); break; } // Success! You killed him // buf1 = alloc_lbuf("do_kill.succ.1"); buf2 = alloc_lbuf("do_kill.succ.2"); if (Suspect(executor)) { mux_strncpy(buf1, Moniker(executor), LBUF_SIZE-1); if (executor == Owner(executor)) { raw_broadcast(WIZARD, "[Suspect] %s killed %s(#%d).", buf1, Moniker(victim), victim); } else { mux_strncpy(buf2, Moniker(Owner(executor)), LBUF_SIZE-1); raw_broadcast(WIZARD, "[Suspect] %s killed %s(#%d).", buf2, buf1, executor, Moniker(victim), victim); } } mux_sprintf(buf1, LBUF_SIZE, "You killed %s!", Moniker(victim)); mux_sprintf(buf2, LBUF_SIZE, "killed %s!", Moniker(victim)); if (!isPlayer(victim)) { if (halt_que(NOTHING, victim) > 0) { if (!Quiet(victim)) { notify(Owner(victim), "Halted."); } } } did_it(executor, victim, A_KILL, buf1, A_OKILL, buf2, A_AKILL, 0, NULL, 0); // notify victim // mux_sprintf(buf1, LBUF_SIZE, "%s killed you!", Moniker(executor)); notify_with_cause_ooc(victim, executor, buf1); // Pay off the bonus. // if (key == KILL_KILL) { cost /= 2; // Victim gets half. if (Pennies(Owner(victim)) < mudconf.paylimit) { mux_sprintf(buf1, LBUF_SIZE, "Your insurance policy pays %d %s.", cost, mudconf.many_coins); notify(victim, buf1); giveto(Owner(victim), cost); } else { notify(victim, "Your insurance policy has been revoked."); } } free_lbuf(buf1); free_lbuf(buf2); // Send him home. // move_via_generic(victim, HOME, NOTHING, 0); divest_object(victim); break; } } /* * --------------------------------------------------------------------------- * * give_thing, give_money, do_give: Give away money or things. */ static void give_thing(dbref giver, dbref recipient, int key, char *what) { init_match(giver, what, TYPE_THING); match_possession(); match_me(); dbref thing = match_result(); switch (thing) { case NOTHING: notify(giver, "You don't have that!"); return; case AMBIGUOUS: notify(giver, "I don't know which you mean!"); return; } if (thing == giver) { notify(giver, "You can't give yourself away!"); return; } if (thing == recipient) { notify(giver, "You can't give an object to itself."); return; } if ( (!isThing(thing) && !isPlayer(thing)) || !( Enter_ok(recipient) || Controls(giver, recipient)) || isGarbage(recipient)) { notify(giver, NOPERM_MESSAGE); return; } char *str, *sp; if (!could_doit(giver, thing, A_LGIVE)) { sp = str = alloc_lbuf("do_give.gfail"); safe_str("You can't give ", str, &sp); safe_str(Moniker(thing), str, &sp); safe_str(" away.", str, &sp); *sp = '\0'; did_it(giver, thing, A_GFAIL, str, A_OGFAIL, NULL, A_AGFAIL, 0, NULL, 0); free_lbuf(str); return; } if (!could_doit(thing, recipient, A_LRECEIVE)) { sp = str = alloc_lbuf("do_give.rfail"); safe_str(Moniker(recipient), str, &sp); safe_str(" doesn't want ", str, &sp); safe_str(Moniker(thing), str, &sp); safe_chr('.', str, &sp); *sp = '\0'; did_it(giver, recipient, A_RFAIL, str, A_ORFAIL, NULL, A_ARFAIL, 0, NULL, 0); free_lbuf(str); return; } move_via_generic(thing, recipient, giver, 0); divest_object(thing); if (!(key & GIVE_QUIET)) { str = alloc_lbuf("do_give.thing.ok"); mux_strncpy(str, Moniker(giver), LBUF_SIZE-1); notify_with_cause_ooc(recipient, giver, tprintf("%s gave you %s.", str, Moniker(thing))); notify(giver, "Given."); notify_with_cause_ooc(thing, giver, tprintf("%s gave you to %s.", str, Moniker(recipient))); free_lbuf(str); } did_it(giver, thing, A_DROP, NULL, A_ODROP, NULL, A_ADROP, 0, NULL, 0); did_it(recipient, thing, A_SUCC, NULL, A_OSUCC, NULL, A_ASUCC, 0, NULL, 0); } static void give_money(dbref giver, dbref recipient, int key, int amount) { // Do amount consistency check. // if ( amount < 0 && !Steal(giver)) { notify(giver, tprintf("You look through your pockets. Nope, no negative %s.", mudconf.many_coins)); return; } if (!amount) { notify(giver, tprintf("You must specify a positive number of %s.", mudconf.many_coins)); return; } if (!Wizard(giver)) { if ( isPlayer(recipient) && (Pennies(recipient) + amount > mudconf.paylimit)) { notify(giver, tprintf("That player doesn't need that many %s!", mudconf.many_coins)); return; } if (!could_doit(giver, recipient, A_LUSE)) { notify(giver, tprintf("%s won't take your money.", Moniker(recipient))); return; } } // Try to do the give. // if (!payfor(giver, amount)) { notify(giver, tprintf("You don't have that many %s to give!", mudconf.many_coins)); return; } // Find out cost if an object. // int cost; if (isThing(recipient)) { dbref aowner; int aflags; char *str = atr_pget(recipient, A_COST, &aowner, &aflags); cost = mux_atol(str); free_lbuf(str); // Can't afford it? // if (amount < cost) { notify(giver, "Feeling poor today?"); giveto(giver, amount); return; } // Negative cost // if (cost < 0) { return; } } else { cost = amount; } if (!(key & GIVE_QUIET)) { if (amount == 1) { notify(giver, tprintf("You give a %s to %s.", mudconf.one_coin, Moniker(recipient))); notify_with_cause_ooc(recipient, giver, tprintf("%s gives you a %s.", Moniker(giver), mudconf.one_coin)); } else { notify(giver, tprintf("You give %d %s to %s.", amount, mudconf.many_coins, Moniker(recipient))); notify_with_cause_ooc(recipient, giver, tprintf("%s gives you %d %s.", Moniker(giver), amount, mudconf.many_coins)); } } // Report change given // if ((amount - cost) == 1) { notify(giver, tprintf("You get 1 %s in change.", mudconf.one_coin)); giveto(giver, 1); } else if (amount != cost) { notify(giver, tprintf("You get %d %s in change.", (amount - cost), mudconf.many_coins)); giveto(giver, (amount - cost)); } // Transfer the money and run PAY attributes // giveto(recipient, cost); did_it(giver, recipient, A_PAY, NULL, A_OPAY, NULL, A_APAY, 0, NULL, 0); return; } void do_give ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *who, char *amnt ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); // Check recipient. // init_match(executor, who, TYPE_PLAYER); match_neighbor(); match_possession(); match_me(); if (Long_Fingers(executor)) { match_player(); match_absolute(); } dbref recipient = match_result(); switch (recipient) { case NOTHING: notify(executor, "Give to whom?"); return; case AMBIGUOUS: notify(executor, "I don't know who you mean!"); return; } if (isExit(recipient)) { notify(executor, "You can't give anything to an exit."); return; } if (Guest(recipient)) { notify(executor, "Guests really don't need money or anything."); return; } if (is_rational(amnt)) { give_money(executor, recipient, key, mux_atol(amnt)); } else { give_thing(executor, recipient, key, amnt); } } mux2.6/src/.depend0000600000175000017500000002420111025753746014035 0ustar sdennissdennis_build.o: _build.cpp _build.h alloc.o: alloc.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrcache.o: attrcache.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h boolexp.o: boolexp.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h bsd.o: bsd.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h file_c.h interface.h slave.h command.o: command.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h ansi.h attrs.h command.h comsys.h functions.h mguests.h interface.h powers.h vattr.h help.h pcre.h comsys.o: comsys.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h ansi.h attrs.h command.h comsys.h functions.h interface.h powers.h conf.o: conf.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h interface.h cque.o: cque.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h interface.h powers.h create.o: create.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h powers.h db.o: db.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h comsys.h interface.h powers.h vattr.h ansi.h db_rw.o: db_rw.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h vattr.h eval.o: eval.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h ansi.h attrs.h functions.h file_c.o: file_c.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h command.h file_c.h interface.h flags.o: flags.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h command.h powers.h ansi.h funceval.o: funceval.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h ansi.h attrs.h command.h comsys.h functions.h misc.h powers.h pcre.h mail.h functions.o: functions.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h ansi.h attrs.h command.h functions.h funmath.h interface.h misc.h powers.h pcre.h funmath.o: funmath.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h functions.h funmath.h sha1.h game.o: game.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h functions.h comsys.h file_c.h interface.h mguests.h muxcli.h pcre.h powers.h help.h help.o: help.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h help.h command.h htab.o: htab.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h local.o: local.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h functions.h command.h log.o: log.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h command.h look.o: look.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h ansi.h attrs.h command.h interface.h powers.h mail.o: mail.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h powers.h mail.h match.o: match.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h powers.h mguests.o: mguests.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h mguests.h interface.h powers.h comsys.h move.o: move.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h interface.h powers.h muxcli.o: muxcli.cpp copyright.h muxcli.h netcommon.o: netcommon.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h ansi.h attrs.h command.h comsys.h file_c.h interface.h functions.h mguests.h powers.h svdreport.h object.o: object.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h mguests.h interface.h powers.h predicates.o: predicates.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h ansi.h attrs.h command.h interface.h powers.h player.o: player.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h comsys.h functions.h interface.h powers.h svdreport.h sha1.h player_c.o: player_c.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h plusemail.o: plusemail.cpp autoconf.h copyright.h config.h _build.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h powers.o: powers.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h command.h powers.h quota.o: quota.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h functions.h powers.h rob.o: rob.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h powers.h pcre.o: pcre.cpp autoconf.h copyright.h config.h pcre.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h set.o: set.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h ansi.h attrs.h command.h powers.h sha1.o: sha1.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h sha1.h speech.o: speech.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h interface.h powers.h stringutil.o: stringutil.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h ansi.h pcre.h strtod.o: strtod.cpp autoconf.h copyright.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h svdrand.o: svdrand.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h svdhash.o: svdhash.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h svdreport.o: svdreport.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h timer.o: timer.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h command.h mguests.h interface.h timeutil.o: timeutil.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h unparse.o: unparse.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h vattr.o: vattr.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h functions.h vattr.h walkdb.o: walkdb.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h misc.h powers.h attrs.h command.h wild.o: wild.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h wiz.o: wiz.cpp copyright.h autoconf.h config.h externs.h db.h attrcache.h flags.h timeutil.h match.h mudconf.h alloc.h htab.h svdhash.h stringutil.h svdrand.h attrs.h command.h file_c.h interface.h powers.h unsplit.o: unsplit.cpp copyright.h slave.o: slave.cpp autoconf.h copyright.h config.h slave.h mux2.6/src/configure0000700000175000017500000121562611025753746014520 0ustar sdennissdennis#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.61. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) as_nl=' ' IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH if test "x$CONFIG_SHELL" = x; then if (eval ":") 2>/dev/null; then as_have_required=yes else as_have_required=no fi if test $as_have_required = yes && (eval ": (as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=\$LINENO as_lineno_2=\$LINENO test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } ") 2> /dev/null; then : else as_candidate_shells= as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. case $as_dir in /*) for as_base in sh bash ksh sh5; do as_candidate_shells="$as_candidate_shells $as_dir/$as_base" done;; esac done IFS=$as_save_IFS for as_shell in $as_candidate_shells $SHELL; do # Try only shells that exist, to save several forks. if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { ("$as_shell") 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : _ASEOF }; then CONFIG_SHELL=$as_shell as_have_required=yes if { "$as_shell" 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : (as_func_return () { (exit $1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = "$1" ); then : else exitcode=1 echo positional parameters were not saved. fi test $exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } _ASEOF }; then break fi fi done if test "x$CONFIG_SHELL" != x; then for as_var in BASH_ENV ENV do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test $as_have_required = no; then echo This script requires a shell more modern than all the echo shells that I found on your system. Please install a echo modern shell, or manually run the script under such a echo shell if you do have one. { (exit 1); exit 1; } fi fi fi (eval "as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0") || { echo No shell found that supports shell functions. echo Please tell autoconf@gnu.org about your system, echo including any error possibly output before this echo message } as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir fi echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= ac_unique_file="mudconf.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datarootdir datadir sysconfdir sharedstatedir localstatedir includedir oldincludedir docdir infodir htmldir dvidir pdfdir psdir libdir localedir mandir DEFS ECHO_C ECHO_N ECHO_T LIBS build_alias host_alias target_alias REALITY_LVLS REALITY_SRC REALITY_OBJ WOD_REALMS MEMORY_BASED FIRANMUX FIRANLIBS FIRANMUX_CONVERT DEPRECATED build build_cpu build_vendor build_os host host_cpu host_vendor host_os CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT CXXCPP CC CFLAGS ac_ct_CC CPP GREP EGREP def_force_c_compiler LIBOBJS LTLIBOBJS' ac_subst_files='' ac_precious_vars='build_alias host_alias target_alias CXX CXXFLAGS LDFLAGS LIBS CPPFLAGS CCC CXXCPP CC CFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` eval enable_$ac_feature=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` eval enable_$ac_feature=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/[-.]/_/g'` eval with_$ac_package=\$ac_optarg ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/[-.]/_/g'` eval with_$ac_package=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute directory names. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; } done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || { echo "$as_me: error: Working directory cannot be determined" >&2 { (exit 1); exit 1; }; } test "X$ac_ls_di" = "X$ac_pwd_ls_di" || { echo "$as_me: error: pwd does not report name of working directory" >&2 { (exit 1); exit 1; }; } # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$0" || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 { (exit 1); exit 1; }; } pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-realitylvls enable Reality Levels (default is NO) --enable-wodrealms enable WOD Realms (default is NO) --enable-memorybased enable Memory-Based Database (default is NO) --enable-firanmux enable Firan MUX (default is NO) --enable-firanmuxconvert enable Firan MUX Conversion (default is NO) --enable-deprecated enable deprecated features (default is NO) Some influential environment variables: CXX C++ compiler command CXXFLAGS C++ compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXXCPP C++ preprocessor CC C compiler command CFLAGS C compiler flags CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------------- ## ## File substitutions. ## ## ------------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo cat confdefs.h echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then set x "$CONFIG_SITE" elif test "x$prefix" != xNONE; then set x "$prefix/share/config.site" "$prefix/etc/config.site" else set x "$ac_default_prefix/share/config.site" \ "$ac_default_prefix/etc/config.site" fi shift for ac_site_file do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers autoconf.h" { echo "$as_me:$LINENO: checking whether to enable Reality Levels" >&5 echo $ECHO_N "checking whether to enable Reality Levels... $ECHO_C" >&6; } # Check whether --enable-realitylvls was given. if test "${enable_realitylvls+set}" = set; then enableval=$enable_realitylvls; if test "x$enableval" = "xno"; then { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } else REALITY_LVLS="-DREALITY_LVLS" LIBS="-lstdc++" REALITY_SRC="levels.cpp" REALITY_OBJ="levels.o" { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } fi else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi { echo "$as_me:$LINENO: checking whether to enable WOD Realms" >&5 echo $ECHO_N "checking whether to enable WOD Realms... $ECHO_C" >&6; } # Check whether --enable-wodrealms was given. if test "${enable_wodrealms+set}" = set; then enableval=$enable_wodrealms; if test "x$enableval" = "xno"; then { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } else WOD_REALMS="-DWOD_REALMS" { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } fi else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi { echo "$as_me:$LINENO: checking whether to enable Memory-Based Database" >&5 echo $ECHO_N "checking whether to enable Memory-Based Database... $ECHO_C" >&6; } # Check whether --enable-memorybased was given. if test "${enable_memorybased+set}" = set; then enableval=$enable_memorybased; if test "x$enableval" = "xno"; then { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } else MEMORY_BASED="-DMEMORY_BASED" { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } fi else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi { echo "$as_me:$LINENO: checking whether to enable Firan MUX" >&5 echo $ECHO_N "checking whether to enable Firan MUX... $ECHO_C" >&6; } # Check whether --enable-firanmux was given. if test "${enable_firanmux+set}" = set; then enableval=$enable_firanmux; if test "x$enableval" = "xno"; then { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } else FIRANMUX="-DFIRANMUX" FIRANLIBS="-lmysqlclient" { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } fi else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi { echo "$as_me:$LINENO: checking whether to enable Firan MUX Conversion" >&5 echo $ECHO_N "checking whether to enable Firan MUX Conversion... $ECHO_C" >&6; } # Check whether --enable-firanmuxconvert was given. if test "${enable_firanmuxconvert+set}" = set; then enableval=$enable_firanmuxconvert; if test "x$enableval" = "xno"; then { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } else FIRANMUX_CONVERT="-DFIRANMUX_CONVERT" { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } fi else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi { echo "$as_me:$LINENO: checking whether to enable deprecated features" >&5 echo $ECHO_N "checking whether to enable deprecated features... $ECHO_C" >&6; } # Check whether --enable-deprecated was given. if test "${enable_deprecated+set}" = set; then enableval=$enable_deprecated; if test "x$enableval" = "xno"; then { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } else DEPRECATED="-DDEPRECATED" { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } fi else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} { (exit 1); exit 1; }; } fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} { (exit 1); exit 1; }; } { echo "$as_me:$LINENO: checking build system type" >&5 echo $ECHO_N "checking build system type... $ECHO_C" >&6; } if test "${ac_cv_build+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 echo "$as_me: error: cannot guess build type; you must specify one" >&2;} { (exit 1); exit 1; }; } ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} { (exit 1); exit 1; }; } fi { echo "$as_me:$LINENO: result: $ac_cv_build" >&5 echo "${ECHO_T}$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 echo "$as_me: error: invalid value of canonical build" >&2;} { (exit 1); exit 1; }; };; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { echo "$as_me:$LINENO: checking host system type" >&5 echo $ECHO_N "checking host system type... $ECHO_C" >&6; } if test "${ac_cv_host+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} { (exit 1); exit 1; }; } fi fi { echo "$as_me:$LINENO: result: $ac_cv_host" >&5 echo "${ECHO_T}$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 echo "$as_me: error: invalid value of canonical host" >&2;} { (exit 1); exit 1; }; };; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_CXX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { echo "$as_me:$LINENO: result: $CXX" >&5 echo "${ECHO_T}$CXX" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 echo "${ECHO_T}$ac_ct_CXX" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&5 echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. echo "$as_me:$LINENO: checking for C++ compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (ac_try="$ac_compiler --version >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compiler --version >&5") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -v >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compiler -v >&5") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -V >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compiler -V >&5") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { echo "$as_me:$LINENO: checking for C++ compiler default output file name" >&5 echo $ECHO_N "checking for C++ compiler default output file name... $ECHO_C" >&6; } ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # # List of possible output files, starting from the most likely. # The algorithm is not robust to junk in `.', hence go to wildcards (a.*) # only as a last resort. b.out is created by i960 compilers. ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' # # The IRIX 6 linker writes into existing files which may not be # executable, retaining their permissions. Remove them first so a # subsequent execution test works. ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { (ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link_default") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi { echo "$as_me:$LINENO: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6; } if test -z "$ac_file"; then echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: C++ compiler cannot create executables See \`config.log' for more details." >&5 echo "$as_me: error: C++ compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { echo "$as_me:$LINENO: checking whether the C++ compiler works" >&5 echo $ECHO_N "checking whether the C++ compiler works... $ECHO_C" >&6; } # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C++ compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C++ compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi fi { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } { echo "$as_me:$LINENO: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6; } { echo "$as_me:$LINENO: checking for suffix of executables" >&5 echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext { echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT { echo "$as_me:$LINENO: checking for suffix of object files" >&5 echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; } if test "${ac_cv_cxx_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; } GXX=`test $ac_compiler_gnu = yes && echo yes` ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; } if test "${ac_cv_prog_cxx_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cxx_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 CXXFLAGS="" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cxx_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6; } if test -z "$CXXCPP"; then if test "${ac_cv_prog_CXXCPP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { echo "$as_me:$LINENO: result: $CXXCPP" >&5 echo "${ECHO_T}$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details." >&5 echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&5 echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&5 echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:$LINENO: checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (ac_try="$ac_compiler --version >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compiler --version >&5") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -v >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compiler -v >&5") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -V >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compiler -V >&5") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 CFLAGS="" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_c89=$ac_arg else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { echo "$as_me:$LINENO: result: none needed" >&5 echo "${ECHO_T}none needed" >&6; } ;; xno) { echo "$as_me:$LINENO: result: unsupported" >&5 echo "${ECHO_T}unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { echo "$as_me:$LINENO: result: $CPP" >&5 echo "${ECHO_T}$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&5 echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu case "$host" in *irix*) LIBS="-lm" ;; esac { echo "$as_me:$LINENO: checking for library containing strerror" >&5 echo $ECHO_N "checking for library containing strerror... $ECHO_C" >&6; } if test "${ac_cv_search_strerror+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strerror (); int main () { return strerror (); ; return 0; } _ACEOF for ac_lib in '' cposix; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_search_strerror=$ac_res else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_strerror+set}" = set; then break fi done if test "${ac_cv_search_strerror+set}" = set; then : else ac_cv_search_strerror=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_search_strerror" >&5 echo "${ECHO_T}$ac_cv_search_strerror" >&6; } ac_res=$ac_cv_search_strerror if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } if test "${ac_cv_path_GREP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Extract the first word of "grep ggrep" to use in msg output if test -z "$GREP"; then set dummy grep ggrep; ac_prog_name=$2 if test "${ac_cv_path_GREP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ac_count=`expr $ac_count + 1` if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS fi GREP="$ac_cv_path_GREP" if test -z "$GREP"; then { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} { (exit 1); exit 1; }; } fi else ac_cv_path_GREP=$GREP fi fi { echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 echo "${ECHO_T}$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { echo "$as_me:$LINENO: checking for egrep" >&5 echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } if test "${ac_cv_path_EGREP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else # Extract the first word of "egrep" to use in msg output if test -z "$EGREP"; then set dummy egrep; ac_prog_name=$2 if test "${ac_cv_path_EGREP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ac_count=`expr $ac_count + 1` if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS fi EGREP="$ac_cv_path_EGREP" if test -z "$EGREP"; then { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} { (exit 1); exit 1; }; } fi else ac_cv_path_EGREP=$EGREP fi fi fi { echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { echo "$as_me:$LINENO: checking for AIX" >&5 echo $ECHO_N "checking for AIX... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef _AIX yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } cat >>confdefs.h <<\_ACEOF #define _ALL_SOURCE 1 _ACEOF else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi rm -f conftest* { echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi { echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done if test "${ac_cv_header_minix_config_h+set}" = set; then { echo "$as_me:$LINENO: checking for minix/config.h" >&5 echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6; } if test "${ac_cv_header_minix_config_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi { echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5 echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6; } else # Is the header compilable? { echo "$as_me:$LINENO: checking minix/config.h usability" >&5 echo $ECHO_N "checking minix/config.h usability... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6; } # Is the header present? { echo "$as_me:$LINENO: checking minix/config.h presence" >&5 echo $ECHO_N "checking minix/config.h presence... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: minix/config.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: minix/config.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: minix/config.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: minix/config.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: minix/config.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: minix/config.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: minix/config.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: minix/config.h: in the future, the compiler will take precedence" >&2;} ;; esac { echo "$as_me:$LINENO: checking for minix/config.h" >&5 echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6; } if test "${ac_cv_header_minix_config_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_minix_config_h=$ac_header_preproc fi { echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5 echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6; } fi if test $ac_cv_header_minix_config_h = yes; then MINIX=yes else MINIX= fi if test "$MINIX" = yes; then cat >>confdefs.h <<\_ACEOF #define _POSIX_SOURCE 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define _POSIX_1_SOURCE 2 _ACEOF cat >>confdefs.h <<\_ACEOF #define _MINIX 1 _ACEOF fi ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_hdr that defines DIR" >&5 echo $ECHO_N "checking for $ac_hdr that defines DIR... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { echo "$as_me:$LINENO: checking for library containing opendir" >&5 echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6; } if test "${ac_cv_search_opendir+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_search_opendir=$ac_res else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_opendir+set}" = set; then break fi done if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 echo "${ECHO_T}$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { echo "$as_me:$LINENO: checking for library containing opendir" >&5 echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6; } if test "${ac_cv_search_opendir+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_search_opendir=$ac_res else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_opendir+set}" = set; then break fi done if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 echo "${ECHO_T}$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi { echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi { echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi { echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5 echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6; } if test "${ac_cv_header_time+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_header_time=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_time=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5 echo "${ECHO_T}$ac_cv_header_time" >&6; } if test $ac_cv_header_time = yes; then cat >>confdefs.h <<\_ACEOF #define TIME_WITH_SYS_TIME 1 _ACEOF fi for ac_header in unistd.h memory.h string.h errno.h malloc.h sys/select.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } else # Is the header compilable? { echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6; } # Is the header present? { echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in fcntl.h limits.h sys/file.h sys/ioctl.h sys/time.h sys/stat.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } else # Is the header compilable? { echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6; } # Is the header present? { echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in fpu_control.h ieeefp.h fenv.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } else # Is the header compilable? { echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6; } # Is the header present? { echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in netinet/in.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } else # Is the header compilable? { echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6; } # Is the header present? { echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { echo "$as_me:$LINENO: checking for sys_errlist decl..." >&5 echo "$as_me: checking for sys_errlist decl..." >&6;} if test $ac_cv_header_errno_h = no; then cat >>confdefs.h <<\_ACEOF #define NEED_SYS_ERRLIST_DCL 1 _ACEOF else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "sys_errlist" >/dev/null 2>&1; then : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "sys_errlist" >/dev/null 2>&1; then : else cat >>confdefs.h <<\_ACEOF #define NEED_SYS_ERRLIST_DCL 1 _ACEOF fi rm -f conftest* fi rm -f conftest* fi { echo "$as_me:$LINENO: checking for main in -lcrypt" >&5 echo $ECHO_N "checking for main in -lcrypt... $ECHO_C" >&6; } if test "${ac_cv_lib_crypt_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypt $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_lib_crypt_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_crypt_main=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_lib_crypt_main" >&5 echo "${ECHO_T}$ac_cv_lib_crypt_main" >&6; } if test $ac_cv_lib_crypt_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBCRYPT 1 _ACEOF LIBS="-lcrypt $LIBS" fi for ac_func in strftime do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval echo '${'$as_ac_var'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else # strftime is in -lintl on SCO UNIX. { echo "$as_me:$LINENO: checking for strftime in -lintl" >&5 echo $ECHO_N "checking for strftime in -lintl... $ECHO_C" >&6; } if test "${ac_cv_lib_intl_strftime+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strftime (); int main () { return strftime (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_lib_intl_strftime=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_intl_strftime=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_lib_intl_strftime" >&5 echo "${ECHO_T}$ac_cv_lib_intl_strftime" >&6; } if test $ac_cv_lib_intl_strftime = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_STRFTIME 1 _ACEOF LIBS="-lintl $LIBS" fi fi done for ac_func in vprintf do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval echo '${'$as_ac_var'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF { echo "$as_me:$LINENO: checking for _doprnt" >&5 echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6; } if test "${ac_cv_func__doprnt+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define _doprnt to an innocuous variant, in case declares _doprnt. For example, HP-UX 11i declares gettimeofday. */ #define _doprnt innocuous__doprnt /* System header to define __stub macros and hopefully few prototypes, which can conflict with char _doprnt (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef _doprnt /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char _doprnt (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub__doprnt || defined __stub____doprnt choke me #endif int main () { return _doprnt (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_func__doprnt=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func__doprnt=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5 echo "${ECHO_T}$ac_cv_func__doprnt" >&6; } if test $ac_cv_func__doprnt = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_DOPRNT 1 _ACEOF fi fi done for ac_func in setrlimit getrusage srandom do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval echo '${'$as_ac_var'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in getdtablesize socket gethostbyaddr do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval echo '${'$as_ac_var'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in gettimeofday select socket localtime_r do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval echo '${'$as_ac_var'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in getpagesize usleep nanosleep setitimer crypt do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval echo '${'$as_ac_var'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "getpagesize" >/dev/null 2>&1; then : else cat >>confdefs.h <<\_ACEOF #define NEED_GETPAGESIZE_DCL 1 _ACEOF fi rm -f conftest* if test $ac_cv_header_ieeefp_h = yes; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { int main(int argc, char *argv[]) { fp_prec_t a = fpgetprec(); fpsetprec(FP_PD); return 0; } ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >>confdefs.h <<\_ACEOF #define IEEEFP_H_USEABLE 1 _ACEOF else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_header_fenv_h = yes; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "fesetprec" >/dev/null 2>&1; then cat >>confdefs.h <<\_ACEOF #define HAVE_FESETPREC 1 _ACEOF fi rm -f conftest* cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "fegetprec" >/dev/null 2>&1; then cat >>confdefs.h <<\_ACEOF #define HAVE_FEGETPREC 1 _ACEOF fi rm -f conftest* fi { echo "$as_me:$LINENO: checking for off_t" >&5 echo $ECHO_N "checking for off_t... $ECHO_C" >&6; } if test "${ac_cv_type_off_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef off_t ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_off_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_off_t=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_off_t" >&5 echo "${ECHO_T}$ac_cv_type_off_t" >&6; } if test $ac_cv_type_off_t = yes; then : else cat >>confdefs.h <<_ACEOF #define off_t long int _ACEOF fi { echo "$as_me:$LINENO: checking for pid_t" >&5 echo $ECHO_N "checking for pid_t... $ECHO_C" >&6; } if test "${ac_cv_type_pid_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef pid_t ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_pid_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_pid_t=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5 echo "${ECHO_T}$ac_cv_type_pid_t" >&6; } if test $ac_cv_type_pid_t = yes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi { echo "$as_me:$LINENO: checking return type of signal handlers" >&5 echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6; } if test "${ac_cv_type_signal+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { return *(signal (0, 0)) (0) == 1; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_signal=int else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_signal=void fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 echo "${ECHO_T}$ac_cv_type_signal" >&6; } cat >>confdefs.h <<_ACEOF #define RETSIGTYPE $ac_cv_type_signal _ACEOF cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { struct sigcontext scp; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >>confdefs.h <<\_ACEOF #define HAVE_STRUCT_SIGCONTEXT 1 _ACEOF else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5 echo $ECHO_N "checking for sys/wait.h that is POSIX.1 compatible... $ECHO_C" >&6; } if test "${ac_cv_header_sys_wait_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main () { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_header_sys_wait_h=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5 echo "${ECHO_T}$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_SYS_WAIT_H 1 _ACEOF fi { echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5 echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6; } if test "${ac_cv_struct_tm+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_struct_tm=time.h else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5 echo "${ECHO_T}$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then cat >>confdefs.h <<\_ACEOF #define TM_IN_SYS_TIME 1 _ACEOF fi { echo "$as_me:$LINENO: checking for struct tm.tm_zone" >&5 echo $ECHO_N "checking for struct tm.tm_zone... $ECHO_C" >&6; } if test "${ac_cv_member_struct_tm_tm_zone+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include <$ac_cv_struct_tm> int main () { static struct tm ac_aggr; if (ac_aggr.tm_zone) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_member_struct_tm_tm_zone=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include <$ac_cv_struct_tm> int main () { static struct tm ac_aggr; if (sizeof ac_aggr.tm_zone) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_member_struct_tm_tm_zone=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_member_struct_tm_tm_zone=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_member_struct_tm_tm_zone" >&5 echo "${ECHO_T}$ac_cv_member_struct_tm_tm_zone" >&6; } if test $ac_cv_member_struct_tm_tm_zone = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 _ACEOF fi if test "$ac_cv_member_struct_tm_tm_zone" = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_TM_ZONE 1 _ACEOF else { echo "$as_me:$LINENO: checking whether tzname is declared" >&5 echo $ECHO_N "checking whether tzname is declared... $ECHO_C" >&6; } if test "${ac_cv_have_decl_tzname+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { #ifndef tzname (void) tzname; #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_have_decl_tzname=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_have_decl_tzname=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_have_decl_tzname" >&5 echo "${ECHO_T}$ac_cv_have_decl_tzname" >&6; } if test $ac_cv_have_decl_tzname = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_DECL_TZNAME 1 _ACEOF else cat >>confdefs.h <<_ACEOF #define HAVE_DECL_TZNAME 0 _ACEOF fi { echo "$as_me:$LINENO: checking for tzname" >&5 echo $ECHO_N "checking for tzname... $ECHO_C" >&6; } if test "${ac_cv_var_tzname+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #if !HAVE_DECL_TZNAME extern char *tzname[]; #endif int main () { return tzname[0][0]; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_var_tzname=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_var_tzname=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_var_tzname" >&5 echo "${ECHO_T}$ac_cv_var_tzname" >&6; } if test $ac_cv_var_tzname = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_TZNAME 1 _ACEOF fi fi { echo "$as_me:$LINENO: checking for extended string dcls..." >&5 echo "$as_me: checking for extended string dcls..." >&6;} cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "rindex" >/dev/null 2>&1; then : else cat >>confdefs.h <<\_ACEOF #define NEED_INDEX_DCL 1 _ACEOF fi rm -f conftest* { echo "$as_me:$LINENO: checking for malloc dcl..." >&5 echo "$as_me: checking for malloc dcl..." >&6;} querymalloc=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "realloc" >/dev/null 2>&1; then cat >>confdefs.h <<\_ACEOF #define MALLOC_IN_STDLIB_H 1 _ACEOF else querymalloc=yes fi rm -f conftest* if test $ac_cv_header_malloc_h = no && test $querymalloc = yes; then cat >>confdefs.h <<\_ACEOF #define NEED_MALLOC_DCL 1 _ACEOF else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "realloc" >/dev/null 2>&1; then : else cat >>confdefs.h <<\_ACEOF #define NEED_MALLOC_DCL 1 _ACEOF fi rm -f conftest* fi { echo "$as_me:$LINENO: checking for vsprintf dcl..." >&5 echo "$as_me: checking for vsprintf dcl..." >&6;} cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "vsprintf" >/dev/null 2>&1; then : else cat >>confdefs.h <<\_ACEOF #define NEED_VSPRINTF_DCL 1 _ACEOF fi rm -f conftest* { echo "$as_me:$LINENO: checking for sprintf dcl..." >&5 echo "$as_me: checking for sprintf dcl..." >&6;} cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "\/dev/null 2>&1; then : else cat >>confdefs.h <<\_ACEOF #define NEED_SPRINTF_DCL 1 _ACEOF fi rm -f conftest* { echo "$as_me:$LINENO: checking for extended stdio dcls..." >&5 echo "$as_me: checking for extended stdio dcls..." >&6;} cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "fread" >/dev/null 2>&1; then cat >>confdefs.h <<\_ACEOF #define EXTENDED_STDIO_DCLS 1 _ACEOF fi rm -f conftest* { echo "$as_me:$LINENO: checking for extended socket dcls..." >&5 echo "$as_me: checking for extended socket dcls..." >&6;} cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "setsockopt" >/dev/null 2>&1; then cat >>confdefs.h <<\_ACEOF #define EXTENDED_SOCKET_DCLS 1 _ACEOF fi rm -f conftest* { echo "$as_me:$LINENO: checking for socklen_t dcls..." >&5 echo "$as_me: checking for socklen_t dcls..." >&6;} cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "socklen_t" >/dev/null 2>&1; then cat >>confdefs.h <<\_ACEOF #define SOCKLEN_T_DCL 1 _ACEOF fi rm -f conftest* { echo "$as_me:$LINENO: checking for gettimeofday dcl..." >&5 echo "$as_me: checking for gettimeofday dcl..." >&6;} if test $ac_cv_header_time = yes && test $ac_cv_header_sys_time_h = yes ; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "gettimeofday" >/dev/null 2>&1; then : else cat >>confdefs.h <<\_ACEOF #define NEED_GETTIMEOFDAY_DCL 1 _ACEOF fi rm -f conftest* elif test $ac_cv_header_sys_time_h = yes ; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "gettimeofday" >/dev/null 2>&1; then : else cat >>confdefs.h <<\_ACEOF #define NEED_GETTIMEOFDAY_DCL 1 _ACEOF fi rm -f conftest* else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "gettimeofday" >/dev/null 2>&1; then : else cat >>confdefs.h <<\_ACEOF #define NEED_GETTIMEOFDAY_DCL 1 _ACEOF fi rm -f conftest* fi { echo "$as_me:$LINENO: checking for signal SIGCHLD braindamage..." >&5 echo "$as_me: checking for signal SIGCHLD braindamage..." >&6;} if test "$cross_compiling" = yes; then cat >>confdefs.h <<\_ACEOF #define SIGNAL_SIGCHLD_BRAINDAMAGE 1 _ACEOF else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #ifndef SIGCHLD #define SIGCHLD SIGCLD #endif int rlev; RETSIGTYPE sighand(int sig, int code) { int stat; if (rlev++ > 2) exit(1); signal(SIGCHLD, sighand); wait(&stat); return; } int main(int argc, char *argv[]) { rlev = 0; signal(SIGCHLD, sighand); if (fork()) { sleep(10); } else { sleep(2); exit(1); } exit(0); } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) cat >>confdefs.h <<\_ACEOF #define SIGNAL_SIGCHLD_BRAINDAMAGE 1 _ACEOF fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: checking whether sys_siglist is declared" >&5 echo $ECHO_N "checking whether sys_siglist is declared... $ECHO_C" >&6; } if test "${ac_cv_have_decl_sys_siglist+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include /* NetBSD declares sys_siglist in unistd.h. */ #ifdef HAVE_UNISTD_H # include #endif int main () { #ifndef sys_siglist (void) sys_siglist; #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_have_decl_sys_siglist=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_have_decl_sys_siglist=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_have_decl_sys_siglist" >&5 echo "${ECHO_T}$ac_cv_have_decl_sys_siglist" >&6; } if test $ac_cv_have_decl_sys_siglist = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SYS_SIGLIST 1 _ACEOF else cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SYS_SIGLIST 0 _ACEOF fi { echo "$as_me:$LINENO: checking for sys_signame decl" >&5 echo $ECHO_N "checking for sys_signame decl... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "sys_signame" >/dev/null 2>&1; then cat >>confdefs.h <<\_ACEOF #define HAVE_SYS_SIGNAME 1 _ACEOF { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi rm -f conftest* { echo "$as_me:$LINENO: checking for IEEE floating-point format..." >&5 echo "$as_me: checking for IEEE floating-point format..." >&6;} if test "$cross_compiling" = yes; then cat >>confdefs.h <<\_ACEOF #define NO_IEEE_FP_FORMAT 1 _ACEOF else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main(int argc, char *argv[]) { const double d_in = -1e-125; const unsigned long long i64_out = 0xA5FB13AC9AAF4C0Full; union { unsigned long long i64; double d; } u; u.d = d_in; if (u.i64 == i64_out) { return 0; } return 1; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define HAVE_IEEE_FP_FORMAT 1 _ACEOF else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) cat >>confdefs.h <<\_ACEOF #define NO_IEEE_FP_FORMAT 1 _ACEOF fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: checking for IEEE floating-point exception handling..." >&5 echo "$as_me: checking for IEEE floating-point exception handling..." >&6;} if test "$cross_compiling" = yes; then cat >>confdefs.h <<\_ACEOF #define NO_IEEE_FP_SNAN 1 _ACEOF else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include double rZero = 0.0; int main(int argc, char *argv[]) { double d_in; const unsigned long long i64_out = 0x7FF0000000000000ull; union { unsigned long long i64; double d; } u; signal(SIGFPE, SIG_IGN); d_in = 1.0/rZero; u.d = d_in; if (u.i64 == i64_out) { return 0; } return 1; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define HAVE_IEEE_FP_SNAN 1 _ACEOF else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) cat >>confdefs.h <<\_ACEOF #define NO_IEEE_FP_SNAN 1 _ACEOF fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: checking for how division/moduli of negative quotients are handled..." >&5 echo "$as_me: checking for how division/moduli of negative quotients are handled..." >&6;} if test "$cross_compiling" = yes; then cat >>confdefs.h <<\_ACEOF #define LARGEST_INT_LTE_NEG_QUOTIENT 1 _ACEOF else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main(int argc, char *argv[]) { int top = -9; int bot = 5; int quotient = top/bot; if (quotient == -1) { return 0; } return 1; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define SMALLEST_INT_GTE_NEG_QUOTIENT 1 _ACEOF else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) cat >>confdefs.h <<\_ACEOF #define LARGEST_INT_LTE_NEG_QUOTIENT 1 _ACEOF fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: checking for getrusage dcl..." >&5 echo "$as_me: checking for getrusage dcl..." >&6;} cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "getrusage" >/dev/null 2>&1; then : else cat >>confdefs.h <<\_ACEOF #define NEED_GETRUSAGE_DCL 1 _ACEOF fi rm -f conftest* { echo "$as_me:$LINENO: checking for getrlimit dcl..." >&5 echo "$as_me: checking for getrlimit dcl..." >&6;} cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "getrlimit" >/dev/null 2>&1; then : else cat >>confdefs.h <<\_ACEOF #define NEED_GETRLIMIT_DCL 1 _ACEOF fi rm -f conftest* { echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6; } if test "${ac_cv_c_const+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { /* FIXME: Include the comments suggested by Paul. */ #ifndef __cplusplus /* Ultrix mips cc rejects this. */ typedef int charset[2]; const charset cs; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this. */ char *t; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; }; struct s *b; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_c_const=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 echo "${ECHO_T}$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then cat >>confdefs.h <<\_ACEOF #define const _ACEOF fi { echo "$as_me:$LINENO: checking for inline" >&5 echo $ECHO_N "checking for inline... $ECHO_C" >&6; } if test "${ac_cv_c_inline+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_c_inline=$ac_kw else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 echo "${ECHO_T}$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac { echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; } if test "${ac_cv_c_bigendian+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # See if sys/param.h defines the BYTE_ORDER macro. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \ && BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then # It does; now see whether it defined to BIG_ENDIAN or not. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_c_bigendian=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # It does not; compile a test program. if test "$cross_compiling" = yes; then # try to guess the endianness by grepping values into an object file ac_cv_c_bigendian=unknown cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } int main () { _ascii (); _ebcdic (); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_c_bigendian=no else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 echo "${ECHO_T}$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in yes) cat >>confdefs.h <<\_ACEOF #define WORDS_BIGENDIAN 1 _ACEOF ;; no) cat >>confdefs.h <<\_ACEOF #define WORDS_LITTLEENDIAN 1 _ACEOF ;; *) cat >>confdefs.h <<\_ACEOF #define WORDS_UNKNOWN 1 _ACEOF ;; esac { echo "$as_me:$LINENO: checking for short" >&5 echo $ECHO_N "checking for short... $ECHO_C" >&6; } if test "${ac_cv_type_short+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef short ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_short=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_short=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_short" >&5 echo "${ECHO_T}$ac_cv_type_short" >&6; } # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { echo "$as_me:$LINENO: checking size of short" >&5 echo $ECHO_N "checking size of short... $ECHO_C" >&6; } if test "${ac_cv_sizeof_short+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef short ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=0 ac_mid=0 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef short ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr $ac_mid + 1` if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef short ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=-1 ac_mid=-1 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef short ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_hi=`expr '(' $ac_mid ')' - 1` if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef short ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in ?*) ac_cv_sizeof_short=$ac_lo;; '') if test "$ac_cv_type_short" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (short) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (short) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_short=0 fi ;; esac else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef short ac__type_sizeof_; static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (((long int) (sizeof (ac__type_sizeof_))) < 0) { long int i = longval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%ld\n", i); } else { unsigned long int i = ulongval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%lu\n", i); } return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_sizeof_short=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) if test "$ac_cv_type_short" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (short) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (short) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_short=0 fi fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.val fi { echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5 echo "${ECHO_T}$ac_cv_sizeof_short" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_SHORT $ac_cv_sizeof_short _ACEOF { echo "$as_me:$LINENO: checking for unsigned short" >&5 echo $ECHO_N "checking for unsigned short... $ECHO_C" >&6; } if test "${ac_cv_type_unsigned_short+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned short ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_unsigned_short=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_unsigned_short=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_unsigned_short" >&5 echo "${ECHO_T}$ac_cv_type_unsigned_short" >&6; } # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { echo "$as_me:$LINENO: checking size of unsigned short" >&5 echo $ECHO_N "checking size of unsigned short... $ECHO_C" >&6; } if test "${ac_cv_sizeof_unsigned_short+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned short ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=0 ac_mid=0 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned short ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr $ac_mid + 1` if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned short ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=-1 ac_mid=-1 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned short ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_hi=`expr '(' $ac_mid ')' - 1` if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned short ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in ?*) ac_cv_sizeof_unsigned_short=$ac_lo;; '') if test "$ac_cv_type_unsigned_short" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (unsigned short) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (unsigned short) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_unsigned_short=0 fi ;; esac else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned short ac__type_sizeof_; static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (((long int) (sizeof (ac__type_sizeof_))) < 0) { long int i = longval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%ld\n", i); } else { unsigned long int i = ulongval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%lu\n", i); } return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_sizeof_unsigned_short=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) if test "$ac_cv_type_unsigned_short" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (unsigned short) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (unsigned short) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_unsigned_short=0 fi fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.val fi { echo "$as_me:$LINENO: result: $ac_cv_sizeof_unsigned_short" >&5 echo "${ECHO_T}$ac_cv_sizeof_unsigned_short" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UNSIGNED_SHORT $ac_cv_sizeof_unsigned_short _ACEOF { echo "$as_me:$LINENO: checking for int" >&5 echo $ECHO_N "checking for int... $ECHO_C" >&6; } if test "${ac_cv_type_int+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef int ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_int=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_int=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5 echo "${ECHO_T}$ac_cv_type_int" >&6; } # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { echo "$as_me:$LINENO: checking size of int" >&5 echo $ECHO_N "checking size of int... $ECHO_C" >&6; } if test "${ac_cv_sizeof_int+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef int ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=0 ac_mid=0 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef int ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr $ac_mid + 1` if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef int ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=-1 ac_mid=-1 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef int ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_hi=`expr '(' $ac_mid ')' - 1` if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef int ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in ?*) ac_cv_sizeof_int=$ac_lo;; '') if test "$ac_cv_type_int" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (int) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (int) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_int=0 fi ;; esac else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef int ac__type_sizeof_; static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (((long int) (sizeof (ac__type_sizeof_))) < 0) { long int i = longval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%ld\n", i); } else { unsigned long int i = ulongval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%lu\n", i); } return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_sizeof_int=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) if test "$ac_cv_type_int" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (int) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (int) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_int=0 fi fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.val fi { echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5 echo "${ECHO_T}$ac_cv_sizeof_int" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT $ac_cv_sizeof_int _ACEOF { echo "$as_me:$LINENO: checking for unsigned int" >&5 echo $ECHO_N "checking for unsigned int... $ECHO_C" >&6; } if test "${ac_cv_type_unsigned_int+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned int ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_unsigned_int=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_unsigned_int=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_unsigned_int" >&5 echo "${ECHO_T}$ac_cv_type_unsigned_int" >&6; } # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { echo "$as_me:$LINENO: checking size of unsigned int" >&5 echo $ECHO_N "checking size of unsigned int... $ECHO_C" >&6; } if test "${ac_cv_sizeof_unsigned_int+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned int ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=0 ac_mid=0 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned int ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr $ac_mid + 1` if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned int ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=-1 ac_mid=-1 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned int ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_hi=`expr '(' $ac_mid ')' - 1` if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned int ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in ?*) ac_cv_sizeof_unsigned_int=$ac_lo;; '') if test "$ac_cv_type_unsigned_int" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (unsigned int) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (unsigned int) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_unsigned_int=0 fi ;; esac else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned int ac__type_sizeof_; static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (((long int) (sizeof (ac__type_sizeof_))) < 0) { long int i = longval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%ld\n", i); } else { unsigned long int i = ulongval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%lu\n", i); } return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_sizeof_unsigned_int=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) if test "$ac_cv_type_unsigned_int" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (unsigned int) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (unsigned int) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_unsigned_int=0 fi fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.val fi { echo "$as_me:$LINENO: result: $ac_cv_sizeof_unsigned_int" >&5 echo "${ECHO_T}$ac_cv_sizeof_unsigned_int" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UNSIGNED_INT $ac_cv_sizeof_unsigned_int _ACEOF { echo "$as_me:$LINENO: checking for long" >&5 echo $ECHO_N "checking for long... $ECHO_C" >&6; } if test "${ac_cv_type_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef long ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_long=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_long=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5 echo "${ECHO_T}$ac_cv_type_long" >&6; } # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { echo "$as_me:$LINENO: checking size of long" >&5 echo $ECHO_N "checking size of long... $ECHO_C" >&6; } if test "${ac_cv_sizeof_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef long ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=0 ac_mid=0 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef long ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr $ac_mid + 1` if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef long ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=-1 ac_mid=-1 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef long ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_hi=`expr '(' $ac_mid ')' - 1` if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef long ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in ?*) ac_cv_sizeof_long=$ac_lo;; '') if test "$ac_cv_type_long" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (long) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (long) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_long=0 fi ;; esac else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef long ac__type_sizeof_; static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (((long int) (sizeof (ac__type_sizeof_))) < 0) { long int i = longval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%ld\n", i); } else { unsigned long int i = ulongval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%lu\n", i); } return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_sizeof_long=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) if test "$ac_cv_type_long" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (long) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (long) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_long=0 fi fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.val fi { echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 echo "${ECHO_T}$ac_cv_sizeof_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG $ac_cv_sizeof_long _ACEOF { echo "$as_me:$LINENO: checking for unsigned long" >&5 echo $ECHO_N "checking for unsigned long... $ECHO_C" >&6; } if test "${ac_cv_type_unsigned_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned long ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_unsigned_long=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_unsigned_long=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_unsigned_long" >&5 echo "${ECHO_T}$ac_cv_type_unsigned_long" >&6; } # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { echo "$as_me:$LINENO: checking size of unsigned long" >&5 echo $ECHO_N "checking size of unsigned long... $ECHO_C" >&6; } if test "${ac_cv_sizeof_unsigned_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned long ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=0 ac_mid=0 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned long ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr $ac_mid + 1` if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned long ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=-1 ac_mid=-1 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned long ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_hi=`expr '(' $ac_mid ')' - 1` if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned long ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in ?*) ac_cv_sizeof_unsigned_long=$ac_lo;; '') if test "$ac_cv_type_unsigned_long" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (unsigned long) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (unsigned long) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_unsigned_long=0 fi ;; esac else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef unsigned long ac__type_sizeof_; static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (((long int) (sizeof (ac__type_sizeof_))) < 0) { long int i = longval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%ld\n", i); } else { unsigned long int i = ulongval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%lu\n", i); } return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_sizeof_unsigned_long=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) if test "$ac_cv_type_unsigned_long" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (unsigned long) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (unsigned long) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_unsigned_long=0 fi fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.val fi { echo "$as_me:$LINENO: result: $ac_cv_sizeof_unsigned_long" >&5 echo "${ECHO_T}$ac_cv_sizeof_unsigned_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long _ACEOF { echo "$as_me:$LINENO: checking whether unaligned 'short' access is permitted..." >&5 echo "$as_me: checking whether unaligned 'short' access is permitted..." >&6;} if test "$cross_compiling" = yes; then { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling See \`config.log' for more details." >&5 echo "$as_me: error: cannot run test program while cross compiling See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main(int argc, char *argv[]) { char foo[sizeof(short)+1]; short *ps = (short *)(foo+1); *ps = 0; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define CAN_UNALIGN_SHORT 1 _ACEOF else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: checking whether unaligned 'int' access is permitted..." >&5 echo "$as_me: checking whether unaligned 'int' access is permitted..." >&6;} if test "$cross_compiling" = yes; then { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling See \`config.log' for more details." >&5 echo "$as_me: error: cannot run test program while cross compiling See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main(int argc, char *argv[]) { char foo[sizeof(int)+1]; int *pi = (int *)(foo+1); *pi = 0; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define CAN_UNALIGN_INT 1 _ACEOF else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: checking whether unaligned 'long' access is permitted..." >&5 echo "$as_me: checking whether unaligned 'long' access is permitted..." >&6;} if test "$cross_compiling" = yes; then { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling See \`config.log' for more details." >&5 echo "$as_me: error: cannot run test program while cross compiling See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main(int argc, char *argv[]) { char foo[sizeof(long)+1]; long *pl = (long *)(foo+1); *pl = 0; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define CAN_UNALIGN_LONG 1 _ACEOF else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: checking whether unaligned 'long long' access is permitted..." >&5 echo "$as_me: checking whether unaligned 'long long' access is permitted..." >&6;} if test "$cross_compiling" = yes; then { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling See \`config.log' for more details." >&5 echo "$as_me: error: cannot run test program while cross compiling See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main(int argc, char *argv[]) { char foo[sizeof(long long)+1]; long long *pll = (long long *)(foo+1); *pll = 0; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cat >>confdefs.h <<\_ACEOF #define CAN_UNALIGN_LONGLONG 1 _ACEOF else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: checking for pread and pwrite..." >&5 echo "$as_me: checking for pread and pwrite..." >&6;} if test "$cross_compiling" = yes; then { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling See \`config.log' for more details." >&5 echo "$as_me: error: cannot run test program while cross compiling See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include main() { pwrite(0, "abc", 3, 0); exit(0); } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then pwrite_works=yes else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) pwrite_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi if test $pwrite_works = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_PREAD 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define HAVE_PWRITE 1 _ACEOF fi cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { struct linger ling; ling.l_onoff = 1; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >>confdefs.h <<\_ACEOF #define HAVE_LINGER 1 _ACEOF else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: checking for main in -lresolv" >&5 echo $ECHO_N "checking for main in -lresolv... $ECHO_C" >&6; } if test "${ac_cv_lib_resolv_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lresolv $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_lib_resolv_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_resolv_main=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_main" >&5 echo "${ECHO_T}$ac_cv_lib_resolv_main" >&6; } if test $ac_cv_lib_resolv_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF LIBS="-lresolv $LIBS" fi { echo "$as_me:$LINENO: checking for getpwnam in -lsun" >&5 echo $ECHO_N "checking for getpwnam in -lsun... $ECHO_C" >&6; } if test "${ac_cv_lib_sun_getpwnam+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsun $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getpwnam (); int main () { return getpwnam (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_lib_sun_getpwnam=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_sun_getpwnam=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_lib_sun_getpwnam" >&5 echo "${ECHO_T}$ac_cv_lib_sun_getpwnam" >&6; } if test $ac_cv_lib_sun_getpwnam = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBSUN 1 _ACEOF LIBS="-lsun $LIBS" fi { echo "$as_me:$LINENO: checking for main in -lseq" >&5 echo $ECHO_N "checking for main in -lseq... $ECHO_C" >&6; } if test "${ac_cv_lib_seq_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lseq $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_lib_seq_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_seq_main=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_lib_seq_main" >&5 echo "${ECHO_T}$ac_cv_lib_seq_main" >&6; } if test $ac_cv_lib_seq_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBSEQ 1 _ACEOF LIBS="-lseq $LIBS" fi { echo "$as_me:$LINENO: checking for main in -lintl" >&5 echo $ECHO_N "checking for main in -lintl... $ECHO_C" >&6; } if test "${ac_cv_lib_intl_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_lib_intl_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_intl_main=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_lib_intl_main" >&5 echo "${ECHO_T}$ac_cv_lib_intl_main" >&6; } if test $ac_cv_lib_intl_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBINTL 1 _ACEOF LIBS="-lintl $LIBS" fi { echo "$as_me:$LINENO: checking for main in -lnsl" >&5 echo $ECHO_N "checking for main in -lnsl... $ECHO_C" >&6; } if test "${ac_cv_lib_nsl_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_lib_nsl_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_nsl_main=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_main" >&5 echo "${ECHO_T}$ac_cv_lib_nsl_main" >&6; } if test $ac_cv_lib_nsl_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSL 1 _ACEOF LIBS="-lnsl $LIBS" fi if test $ac_cv_func_gethostbyaddr = no; then { echo "$as_me:$LINENO: checking for main in -linet" >&5 echo $ECHO_N "checking for main in -linet... $ECHO_C" >&6; } if test "${ac_cv_lib_inet_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-linet $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_lib_inet_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_inet_main=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_lib_inet_main" >&5 echo "${ECHO_T}$ac_cv_lib_inet_main" >&6; } if test $ac_cv_lib_inet_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBINET 1 _ACEOF LIBS="-linet $LIBS" fi fi if test $ac_cv_func_socket = no; then { echo "$as_me:$LINENO: checking for main in -lsocket" >&5 echo $ECHO_N "checking for main in -lsocket... $ECHO_C" >&6; } if test "${ac_cv_lib_socket_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_lib_socket_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_socket_main=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_lib_socket_main" >&5 echo "${ECHO_T}$ac_cv_lib_socket_main" >&6; } if test $ac_cv_lib_socket_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi fi { echo "$as_me:$LINENO: checking for main in -lm" >&5 echo $ECHO_N "checking for main in -lm... $ECHO_C" >&6; } if test "${ac_cv_lib_m_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_lib_m_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_m_main=no fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_lib_m_main" >&5 echo "${ECHO_T}$ac_cv_lib_m_main" >&6; } if test $ac_cv_lib_m_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi { echo "$as_me:$LINENO: checking for /dev/urandom..." >&5 echo "$as_me: checking for /dev/urandom..." >&6;} if test -c /dev/urandom; then cat >>confdefs.h <<\_ACEOF #define HAVE_DEV_URANDOM 1 _ACEOF fi { echo "$as_me:$LINENO: checking for in_addr_t" >&5 echo $ECHO_N "checking for in_addr_t... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #if HAVE_NETINET_IN_H #include #endif int main () { in_addr_t foo; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >>confdefs.h <<\_ACEOF #define HAVE_IN_ADDR_T 1 _ACEOF { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { echo "$as_me:$LINENO: updating cache $cache_file" >&5 echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) as_nl=' ' IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir fi echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 # Save the log message, to keep $[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2006 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) echo "$ac_cs_version"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header { echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF if \$ac_cs_recheck; then echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 CONFIG_SHELL=$SHELL export CONFIG_SHELL exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "autoconf.h") CONFIG_HEADERS="$CONFIG_HEADERS autoconf.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } # # Set up the sed scripts for CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "$CONFIG_FILES"; then _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF SHELL!$SHELL$ac_delim PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim PACKAGE_NAME!$PACKAGE_NAME$ac_delim PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim PACKAGE_STRING!$PACKAGE_STRING$ac_delim PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim exec_prefix!$exec_prefix$ac_delim prefix!$prefix$ac_delim program_transform_name!$program_transform_name$ac_delim bindir!$bindir$ac_delim sbindir!$sbindir$ac_delim libexecdir!$libexecdir$ac_delim datarootdir!$datarootdir$ac_delim datadir!$datadir$ac_delim sysconfdir!$sysconfdir$ac_delim sharedstatedir!$sharedstatedir$ac_delim localstatedir!$localstatedir$ac_delim includedir!$includedir$ac_delim oldincludedir!$oldincludedir$ac_delim docdir!$docdir$ac_delim infodir!$infodir$ac_delim htmldir!$htmldir$ac_delim dvidir!$dvidir$ac_delim pdfdir!$pdfdir$ac_delim psdir!$psdir$ac_delim libdir!$libdir$ac_delim localedir!$localedir$ac_delim mandir!$mandir$ac_delim DEFS!$DEFS$ac_delim ECHO_C!$ECHO_C$ac_delim ECHO_N!$ECHO_N$ac_delim ECHO_T!$ECHO_T$ac_delim LIBS!$LIBS$ac_delim build_alias!$build_alias$ac_delim host_alias!$host_alias$ac_delim target_alias!$target_alias$ac_delim REALITY_LVLS!$REALITY_LVLS$ac_delim REALITY_SRC!$REALITY_SRC$ac_delim REALITY_OBJ!$REALITY_OBJ$ac_delim WOD_REALMS!$WOD_REALMS$ac_delim MEMORY_BASED!$MEMORY_BASED$ac_delim FIRANMUX!$FIRANMUX$ac_delim FIRANLIBS!$FIRANLIBS$ac_delim FIRANMUX_CONVERT!$FIRANMUX_CONVERT$ac_delim DEPRECATED!$DEPRECATED$ac_delim build!$build$ac_delim build_cpu!$build_cpu$ac_delim build_vendor!$build_vendor$ac_delim build_os!$build_os$ac_delim host!$host$ac_delim host_cpu!$host_cpu$ac_delim host_vendor!$host_vendor$ac_delim host_os!$host_os$ac_delim CXX!$CXX$ac_delim CXXFLAGS!$CXXFLAGS$ac_delim LDFLAGS!$LDFLAGS$ac_delim CPPFLAGS!$CPPFLAGS$ac_delim ac_ct_CXX!$ac_ct_CXX$ac_delim EXEEXT!$EXEEXT$ac_delim OBJEXT!$OBJEXT$ac_delim CXXCPP!$CXXCPP$ac_delim CC!$CC$ac_delim CFLAGS!$CFLAGS$ac_delim ac_ct_CC!$ac_ct_CC$ac_delim CPP!$CPP$ac_delim GREP!$GREP$ac_delim EGREP!$EGREP$ac_delim def_force_c_compiler!$def_force_c_compiler$ac_delim LIBOBJS!$LIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 71; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` if test -n "$ac_eof"; then ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` ac_eof=`expr $ac_eof + 1` fi cat >>$CONFIG_STATUS <<_ACEOF cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof /@[a-zA-Z_][a-zA-Z_0-9]*@/!b end _ACEOF sed ' s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g s/^/s,@/; s/!/@,|#_!!_#|/ :n t n s/'"$ac_delim"'$/,g/; t s/$/\\/; p N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n ' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF :end s/|#_!!_#|//g CEOF$ac_eof _ACEOF # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/ s/:*\${srcdir}:*/:/ s/:*@srcdir@:*/:/ s/^\([^=]*=[ ]*\):*/\1/ s/:*$// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF fi # test -n "$CONFIG_FILES" for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 echo "$as_me: error: Invalid tag $ac_tag." >&2;} { (exit 1); exit 1; }; };; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 echo "$as_me: error: cannot find input file: $ac_f" >&2;} { (exit 1); exit 1; }; };; esac ac_file_inputs="$ac_file_inputs $ac_f" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input="Generated from "`IFS=: echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} fi case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin";; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` { as_dir="$ac_dir" case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 echo "$as_me: error: cannot create directory $as_dir" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= case `sed -n '/datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p ' $ac_file_inputs` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s&@configure_input@&$configure_input&;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&5 echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out"; rm -f "$tmp/out";; *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; esac ;; :H) # # CONFIG_HEADER # _ACEOF # Transform confdefs.h into a sed script `conftest.defines', that # substitutes the proper values into config.h.in to produce config.h. rm -f conftest.defines conftest.tail # First, append a space to every undef/define line, to ease matching. echo 's/$/ /' >conftest.defines # Then, protect against being on the right side of a sed subst, or in # an unquoted here document, in config.status. If some macros were # called several times there might be several #defines for the same # symbol, which is useless. But do not sort them, since the last # AC_DEFINE must be honored. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* # These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where # NAME is the cpp macro being defined, VALUE is the value it is being given. # PARAMS is the parameter list in the macro definition--in most cases, it's # just an empty string. ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' ac_dB='\\)[ (].*,\\1define\\2' ac_dC=' ' ac_dD=' ,' uniq confdefs.h | sed -n ' t rset :rset s/^[ ]*#[ ]*define[ ][ ]*// t ok d :ok s/[\\&,]/\\&/g s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p ' >>conftest.defines # Remove the space that was appended to ease matching. # Then replace #undef with comments. This is necessary, for # example, in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. # (The regexp can be short, since the line contains either #define or #undef.) echo 's/ $// s,^[ #]*u.*,/* & */,' >>conftest.defines # Break up conftest.defines: ac_max_sed_lines=50 # First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" # Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" # Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" # et cetera. ac_in='$ac_file_inputs' ac_out='"$tmp/out1"' ac_nxt='"$tmp/out2"' while : do # Write a here document: cat >>$CONFIG_STATUS <<_ACEOF # First, check the format of the line: cat >"\$tmp/defines.sed" <<\\CEOF /^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def /^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def b :def _ACEOF sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS echo 'CEOF sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail grep . conftest.tail >/dev/null || break rm -f conftest.defines mv conftest.tail conftest.defines done rm -f conftest.defines conftest.tail echo "ac_result=$ac_in" >>$CONFIG_STATUS cat >>$CONFIG_STATUS <<\_ACEOF if test x"$ac_file" != x-; then echo "/* $configure_input */" >"$tmp/config.h" cat "$ac_result" >>"$tmp/config.h" if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 echo "$as_me: $ac_file is unchanged" >&6;} else rm -f $ac_file mv "$tmp/config.h" $ac_file fi else echo "/* $configure_input */" cat "$ac_result" fi rm -f "$tmp/out12" ;; esac done # for ac_tag { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi mux2.6/src/player_c.cpp0000600000175000017500000002214611025753746015105 0ustar sdennissdennis/*! \file player_c.cpp * Player cache routines. * * $Id: player_c.cpp 1104 2007-02-03 04:14:48Z brazilofmux $ * * Frequenty-used items which appear on every object generally find a home in * the db[] structure managed in db.cpp. However, there are a few items * related only to players which are still accessed frequently enough that * they should be cached. These items are money, current number of queued * commands, and the limit on the number of queued commands. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" /*! \brief structure to hold cached data for player-type objects. */ typedef struct player_cache { dbref player; int money; int queue; int qmax; int cflags; struct player_cache *next; } PCACHE; /*! \brief Hash Table which maps player dbref to PCACHE entry. */ static CHashTable pcache_htab; /*! \brief The head of a singly-linked list of all PCACHE entries. */ static PCACHE *pcache_head; #define PF_REF 0x0002 #define PF_MONEY_CH 0x0004 /*! \brief Initializes the player cache. * * This is called once to initialize the player cache and supporting * data structures: Player cache structures are pooled, the Hash Table * initializes itself, and the singly-linked list is started. * * \return None. */ void pcache_init(void) { pool_init(POOL_PCACHE, sizeof(PCACHE)); pcache_head = NULL; } /*! \brief Updates player cache items from the database. * * The Money and QueueMax attributes are used to initialize the corresponding * items in the player cache. If a Money attribute does not exist for some * strange reason, it it initialized to zero and marked as dirty. If a * QueueMax attribute doesn't exist or is negative, then the game will * choose a reasonable limit later in QueueMax(). * * \param player player object to begin caching. * \param pp pointer to PCACHE structure. * \return None. */ static void pcache_reload1(dbref player, PCACHE *pp) { const char *cp = atr_get_raw(player, A_MONEY); if (cp && *cp) { pp->money = mux_atol(cp); } else { pp->cflags |= PF_MONEY_CH; pp->money = 0; } int m = -1; cp = atr_get_raw(player, A_QUEUEMAX); if (cp && *cp) { m = mux_atol(cp); if (m < 0) { m = -1; } } pp->qmax = m; } /*! \brief Returns a player's cache record. * * Whether created from scratch or found in the cache, pcache_find() always * returns a valid player cache record for the requested player object dbref. * This function uses Hash Table access primarily, but it maintains the * singly-linked list as well. * * \param player player object dbref. * \return Pointer to new or existing player cache record. */ static PCACHE *pcache_find(dbref player) { PCACHE *pp = (PCACHE *)hashfindLEN(&player, sizeof(player), &pcache_htab); if (pp) { pp->cflags |= PF_REF; return pp; } pp = alloc_pcache("pcache_find"); pp->queue = 0; pp->cflags = PF_REF; pp->player = player; pcache_reload1(player, pp); pp->next = pcache_head; pcache_head = pp; hashaddLEN(&player, sizeof(player), pp, &pcache_htab); return pp; } /*! \brief Saves any dirty player data items to the database. * * \param pp pointer to potentially dirty PCACHE structure. * \return None. */ static void pcache_save(PCACHE *pp) { if (pp->cflags & PF_MONEY_CH) { IBUF tbuf; mux_ltoa(pp->money, tbuf); atr_add_raw(pp->player, A_MONEY, tbuf); pp->cflags &= ~PF_MONEY_CH; } } /*! \brief Re-initializes Money and QueueMax items from the database. * * \param player player object dbref. * \return None. */ void pcache_reload(dbref player) { if ( Good_obj(player) && OwnsOthers(player)) { PCACHE *pp = pcache_find(player); pcache_save(pp); pcache_reload1(player, pp); } } /*! \brief Ages and trims the player cache of stale entries. * * pcache_trim() relies primarily on the singly-linked list, but it also * maintains the Hash Table. To be trimmed, a player cache record must * not have outstanding commands in the command queue. * * The one level of aging is accomplished with PR_REF. On the first pass * through the linked list, the PR_REF bit is removed. On the second pass * through the list, the record is trimmed. * * \return None. */ void pcache_trim(void) { PCACHE *pp = pcache_head; PCACHE *pplast = NULL; while (pp) { PCACHE *ppnext = pp->next; if ( pp->queue || (pp->cflags & PF_REF)) { // This entry either has outstanding commands in the queue or we // need to let it age. // pp->cflags &= ~PF_REF; pplast = pp; } else { // Unlink and destroy this entry. // if (pplast) { pplast->next = ppnext; } else { pcache_head = ppnext; } pcache_save(pp); hashdeleteLEN(&(pp->player), sizeof(pp->player), &pcache_htab); free_pcache(pp); } pp = ppnext; } } /*! \brief Flushes any dirty player items to the database. * * The primary access is via the singly-linked list. Upon return, all the * player cache records are marked as clean. * * \return None. */ void pcache_sync(void) { PCACHE *pp = pcache_head; while (pp) { pcache_save(pp); pp = pp->next; } } /*! \brief Adjusts the count of queued commands up or down. * * cque.cpp uses this as it schedules and performs queued commands. * * \param player dbref of player object responsible for command. * \param adj new (+) or completed (-) commands being queued. * \return None. */ int a_Queue(dbref player, int adj) { if ( Good_obj(player) && OwnsOthers(player)) { PCACHE *pp = pcache_find(player); pp->queue += adj; return pp->queue; } return 0; } /*! \brief Returns the player's upper limit of queued commands. * * If a QueueMax is set on the player, we use that. Otherwise, there is * a configurable game-wide limit (given by player_queue_limit) unless the * player is a Wizard in which case, we reason that well behaved Wizard code * should be able to schedule as much work as there are objects in the * database -- larger game, more work to be expected in the queue. * * \param player dbref of player object. * \return None. */ int QueueMax(dbref player) { int m = 0; if ( Good_obj(player) && OwnsOthers(player)) { PCACHE *pp = pcache_find(player); if (pp->qmax >= 0) { m = pp->qmax; } else { // @queuemax was not valid so we use the game-wide limit. // m = mudconf.queuemax; if ( Wizard(player) && m < mudstate.db_top + 1) { m = mudstate.db_top + 1; } } } return m; } /*! \brief Returns how many coins are in a player's or things's purse. * * \param obj dbref of player object. * \return None. */ int Pennies(dbref obj) { if (Good_obj(obj)) { if ( !mudstate.bStandAlone && OwnsOthers(obj)) { PCACHE *pp = pcache_find(obj); return pp->money; } else { const char *cp = atr_get_raw(obj, A_MONEY); if (cp) { return mux_atol(cp); } } } return 0; } /*! \brief Sets the number of coins in a player's or thing's purse. * * This changes the number of coins a player holds and sets this attribute * as dirty so that it will be updated in the attribute database later. * * \param obj dbref of player object responsible for command. * \param howfew Number of coins * \return None. */ void s_Pennies(dbref obj, int howfew) { if (Good_obj(obj)) { if ( !mudstate.bStandAlone && OwnsOthers(obj)) { PCACHE *pp = pcache_find(obj); pp->money = howfew; pp->cflags |= PF_MONEY_CH; } else { IBUF tbuf; mux_ltoa(howfew, tbuf); atr_add_raw(obj, A_MONEY, tbuf); } } } /*! \brief A shortcut method of initializing the coins in a object's purse. * * This method should only be used from db_rw.cpp while loading the database. * From there, the object will be in a half-way state, and has not been fully * loaded. The object type is not known. Likewise, at database load time, * using the player cache is ineffective -- causing a read request for A_MONEY * to obtain a value for coins (probably zero) that we immediate change again. * * \param obj dbref of object. * \param howfew Number of coins * \return None. */ void s_PenniesDirect(dbref obj, int howfew) { IBUF tbuf; mux_ltoa(howfew, tbuf); atr_add_raw(obj, A_MONEY, tbuf); } mux2.6/src/mail.h0000600000175000017500000000471411025753746013677 0ustar sdennissdennis// mail.h // // $Id: mail.h 373 2006-11-06 06:26:34Z brazilofmux $ // #ifndef _MAIL_H #define _MAIL_H #include "copyright.h" /* Some of this isn't implemented yet, but heralds the future! */ #define M_ISREAD 0x0001 #define M_UNREAD 0x0FFE #define M_CLEARED 0x0002 #define M_URGENT 0x0004 #define M_MASS 0x0008 #define M_SAFE 0x0010 //#define M_RECEIPT 0x0020 #define M_TAG 0x0040 #define M_FORWARD 0x0080 /* 0x0100 - 0x0F00 reserved for folder numbers */ #define M_FMASK 0xF0FF #define M_ALL 0x1000 /* Used in mail_selectors */ #define M_MSUNREAD 0x2000 /* Mail selectors */ /* 0x4000 - 0x8000 available */ #define M_REPLY 0x4000 #define MAX_FOLDERS 15 #define FOLDER_NAME_LEN MBUF_SIZE #define FolderBit(f) (256 * (f)) #define Urgent(m) (m->read & M_URGENT) #define Mass(m) (m->read & M_MASS) #define M_Safe(m) (m->read & M_SAFE) //#define Receipt(m) (m->read & M_RECEIPT) #define Forward(m) (m->read & M_FORWARD) #define Tagged(m) (m->read & M_TAG) #define Folder(m) ((m->read & ~M_FMASK) >> 8) #define Read(m) (m->read & M_ISREAD) #define Cleared(m) (m->read & M_CLEARED) #define Unread(m) (!Read(m)) #define All(ms) (ms.flags & M_ALL) #define ExpMail(x) (Wizard(x)) //#define Reply(m) (m->read & M_REPLY) #define MA_INC 2 /* what interval to increase the malias list */ #define DASH_LINE \ "---------------------------------------------------------------------------" typedef unsigned int mail_flag; struct mail { struct mail *next; struct mail *prev; dbref to; dbref from; int number; char *time; char *subject; char *tolist; int read; }; struct mail_selector { int low; int high; mail_flag flags; dbref player; int days; int day_comp; }; struct muser { dbref who; char *fwd; char *vacation; dbref *afilter; int status; }; typedef struct mail_body MAILBODY; struct mail_body { size_t m_nMessage; char *m_pMessage; int m_nRefs; }; class MailList { private: struct mail *m_miHead; struct mail *m_mi; dbref m_player; bool m_bRemoved; public: MailList(dbref player); struct mail *FirstItem(void); struct mail *NextItem(void); bool IsEnd(void); void RemoveItem(void); void RemoveAll(void); void AppendItem(struct mail *newp); }; #endif // !_MAIL_H mux2.6/src/tools/0000700000175000017500000000000011025753746013734 5ustar sdennissdennismux2.6/src/tools/muxlocks.dat0000600000175000017500000000036611025753746016302 0ustar sdennissdennisA_LOCK 42 A_LENTER 59 A_LLEAVE 60 A_LPAGE 61 A_LUSE 62 A_LGIVE 63 A_LTPORT 85 A_LDROP 86 A_LRECEIVE 87 A_LLINK 93 A_LTELOUT 94 A_LUSER 97 A_LPARENT 98 A_LCONTROL 99 A_LGET 127 A_LSPEECH 209 A_LCHOWN 217 A_LMAIL 225 A_LOPEN 226 mux2.6/src/tools/announce.c0000600000175000017500000000555711025753746015724 0ustar sdennissdennis/* * announce - sits listening on a port, and whenever anyone connects * announces a message and disconnects them * * Usage: announce [port] < message_file * * Author: Lawrence Brown Aug 90 * * Bits of code are adapted from the Berkeley telnetd sources */ #define PORT 2860 #include #include #include #include #include #include #include #include #include #include char *Name; // name of this program for error messages. char msg[8192]; size_t nmsg; int main(int argc, char *argv[]) { int s; int ns; int foo; static struct sockaddr_in sin = {AF_INET}; char *host; char *inet_ntoa(); long ct; int ch; char *p; int opt; // Save program name for error messages. // Name = argv[0]; // Assume PORT, but let command-line override. // sin.sin_port = htons((u_short) PORT); argc--; argv++; if (argc > 0) { // unless specified on command-line. // sin.sin_port = atoi(*argv); sin.sin_port = htons((u_short) sin.sin_port); } // Read in message and translate CRLF/NL to something reasonable. // p = msg; while ( (ch = getchar()) != EOF && p + 2 < msg + sizeof(msg)) { if (ch != '\r') { if (ch == '\n') { *p++ = '\r'; } *p++ = ch; } } *p = '\0'; nmsg = p - msg; signal(SIGHUP, SIG_IGN); s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { perror("announce: socket"); exit(1); } opt = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) { perror("setsockopt"); } if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) { perror("bind"); exit(1); } if ((foo = fork()) != 0) { fprintf(stderr, "announce: pid %d running on port %d\n", foo, ntohs((u_short) sin.sin_port)); _exit(0); } else { setpriority(PRIO_PROCESS, getpid(), 10); } if (listen(s, 1) < 0) { // start listening on port. // perror("announce: listen"); _exit(1); } foo = sizeof sin; for (;;) { // loop forever, accepting requests & printing msg. // ns = accept(s, (struct sockaddr *)&sin, &foo); if (ns < 0) { perror("announce: accept"); _exit(1); } host = inet_ntoa(sin.sin_addr); ct = time(0L); fprintf(stderr, "CONNECTION made from %s at %s", host, ctime(&ct)); write(ns, msg, nmsg); sleep(5); close(ns); } } mux2.6/src/tools/dbpuller.c0000600000175000017500000005161511025753746015723 0ustar sdennissdennis/*! \file dbpuller.c * \brief Offline flatfile-to-softcode converter. * * $Id$ * * Db puller - used to pull data from a TinyMUX flatfile and dump it into a * file in \@decompile format. * * \version 1.01 * \author Ashen-Shugar (08/16/2005) * * \verbatim * Modifications: List modifications below * 11/02/05 : filenames are now saved with _ extensions. * the name of the object starts the file with a '@@' comment prefix. * \endverbatim */ #include #include #include #include // The following should match LBUF_SIZE and SBUF_SIZE in alloc.h // #define LBUF_SIZE 8000 #define SBUF_SIZE 64 #define ESC_CHAR '\033' // As buffers are written to a flatfile, some characters are escaped. The // worst-case contents of an lbuf can be twice as long as what is allowed within // the game. Further, there are four additional characters plus trailing null. // // " ==> 1 // Encoded LBUF ==> 2*LBUF_SIZE // "\r\n\0 ==> 4 // #define MALSIZE_IN (2*LBUF_SIZE+5) // 3-byte color code points turn into 3-byte %x-subs. // 5-byte ANSI sequences also turn into 3-byte %x-subs. // There is some punctuation and the attribute name in front. // #define MALSIZE_OUT (2*LBUF_SIZE + SBUF_SIZE + 6) #define COLOR_RESET 256 #define COLOR_INTENSE 257 #define COLOR_UNDERLINE 258 #define COLOR_BLINK 259 #define COLOR_INVERSE 260 #define COLOR_FG_BLACK 261 #define COLOR_FG_RED 262 #define COLOR_FG_GREEN 263 #define COLOR_FG_YELLOW 264 #define COLOR_FG_BLUE 265 #define COLOR_FG_MAGENTA 266 #define COLOR_FG_CYAN 267 #define COLOR_FG_WHITE 268 #define COLOR_BG_BLACK 269 #define COLOR_BG_RED 270 #define COLOR_BG_GREEN 271 #define COLOR_BG_YELLOW 272 #define COLOR_BG_BLUE 273 #define COLOR_BG_MAGENTA 274 #define COLOR_BG_CYAN 275 #define COLOR_BG_WHITE 276 int stricmp(const char *buf1, const char *buf2) { const char *p1 = buf1; const char *p2 = buf2; while ( '\0' != *p1 && '\0' != *p2 && tolower(*p1) == tolower(*p2)) { p1++; p2++; } if ( '\0' == *p1 && '\0' == *p2) { return 0; } if ('\0' == *p1) { return -1; } if ('\0' == *p2) { return 1; } if (*p1 < *p2) { return -1; } return 1; } char g_line[MALSIZE_IN]; int main(int argc, char **argv) { FILE *f_muxflat = NULL; FILE *f_mymuxfile = NULL; FILE *f_muxattrs = NULL; FILE *f_muxout = NULL; FILE *f_muxlock = NULL; char *spt3; char *pt3; char s_attrib[SBUF_SIZE+1]; char s_filename[80]; char s_attrval[SBUF_SIZE+1]; char s_attr[SBUF_SIZE+1]; char s_finattr[SBUF_SIZE+1]; int i_chk = 0; int i_lck = 1; int i_atrcntr = 0; int i_atrcntr2 = 0; int i_pullname = 0; int i; if (argc < 3) { fprintf(stderr, "Syntax: %s mux-flatfile dbref# (no preceeding # character) [optional attribute-name]\n", argv[0]); exit(1); } f_muxflat = fopen(argv[1], "r"); if (NULL == f_muxflat) { fprintf(stderr, "ERROR: Unable to open %s for reading.\n", argv[1]); exit(1); } for (i = 0; argv[2][i]; i++) { if (!isdigit(argv[2][i])) { fprintf(stderr, "ERROR: Dbref# must be an integer (no # preceeding) [optional attribute-name]\n"); fclose(f_muxflat); exit(1); } } f_mymuxfile = fopen("mymuxfile.dat", "w"); if (NULL == f_mymuxfile) { fprintf(stderr, "ERROR: Unable to open output file for attribute header information (mymuxfile.dat)\n"); fclose(f_muxflat); exit(1); } memset(s_attrib, '\0', sizeof(s_attrib)); if ( 4 <= argc && '\0' != *argv[3]) { strncpy(s_attrib, argv[3], SBUF_SIZE); } memset(s_attr, '\0', sizeof(s_attr)); memset(s_attrval, '\0', sizeof(s_attr)); while (!feof(f_muxflat)) { fgets(g_line, sizeof(g_line), f_muxflat); if (i_chk) { i_chk = 0; strtok(g_line, ":"); sprintf(s_attr, "%s", strtok(NULL, ":")); s_attr[strlen(s_attr)-2]='\0'; fprintf(f_mymuxfile, "%s %d \n", s_attr, atoi(s_attrval)); } if ( 3 < strlen(g_line) && '+' == g_line[0] && 'A' == g_line[1] && isdigit(g_line[2])) { i_chk = 1; sprintf(s_attrval, "%s", &g_line[2]); } if ('!' == g_line[0]) { break; } } fclose(f_mymuxfile); f_mymuxfile = fopen("mymuxfile.dat", "r"); if (NULL == f_mymuxfile) { fclose(f_muxflat); fprintf(stderr, "ERROR: Unable to open attribute header information (mymuxfile.dat)\n"); exit(1); } f_muxattrs = fopen("muxattrs.dat", "r"); if (NULL == f_muxattrs) { fclose(f_muxflat); fclose(f_mymuxfile); fprintf(stderr, "ERROR: Unable to open attribute header information (muxattrs.dat)\n"); exit(1); } memset(s_filename, '\0', sizeof(s_filename)); sprintf(s_filename, "muxout_%d.txt", atoi(argv[2])); f_muxout = fopen(s_filename, "w"); if (NULL == f_muxout) { fclose(f_muxflat); fclose(f_mymuxfile); fclose(f_muxattrs); fprintf(stderr, "ERROR: Unable to open output file (%s)\n", s_filename); exit(1); } f_muxlock = fopen("muxlocks.dat", "r"); if (NULL == f_muxlock) { fclose(f_muxflat); fclose(f_mymuxfile); fclose(f_muxattrs); fclose(f_muxout); fprintf(stderr, "ERROR: Unable to open mux lock file (muxlocks.dat)\n"); exit(1); } spt3 = malloc(MALSIZE_OUT); memset(spt3, '\0', MALSIZE_OUT); pt3 = spt3; fseek(f_muxflat, 0L, SEEK_SET); fprintf(stderr, "Step 1: Quering for dbref #%d\n", atoi(argv[2])); i_chk = 0; while (!feof(f_muxflat)) { fgets(g_line, sizeof(g_line), f_muxflat); if (i_pullname) { i_pullname = 0; fprintf(f_muxout, "@@ %s\n", g_line); } if ( '<' == g_line[0] && i_chk) { break; } if ( '!' == g_line[0] && (atoi(&g_line[1]) == atoi(argv[2]))) { i_chk = 1; i_pullname = 1; continue; } if ( i_chk && '>' == g_line[0] && isdigit(g_line[1])) { i_chk = 2; i_atrcntr++; sprintf(s_attrval, " %d ", atoi(&g_line[1])); memset(s_finattr, '\0', sizeof(s_finattr)); fseek(f_muxattrs, 0L, SEEK_SET); while (!feof(f_muxattrs)) { fgets(g_line, sizeof(g_line), f_muxattrs); if (strstr(g_line, s_attrval) != NULL) { strcpy(s_finattr, (char *)strtok(g_line, " ")); break; } } if ('\0' == s_finattr[0]) { fseek(f_mymuxfile, 0L, SEEK_SET); while (!feof(f_mymuxfile)) { fgets(g_line, sizeof(g_line), f_mymuxfile); if (strstr(g_line, s_attrval) != NULL) { strcpy(s_finattr, (char *)strtok(g_line, " ")); break; } } } if ('\0' == s_finattr[0]) { fprintf(stderr, "ERROR: Unknown error in attribute handler."); exit(1); } fseek(f_muxlock, 0L, SEEK_SET); i_lck = 0; while (!feof(f_muxlock)) { fgets(g_line, sizeof(g_line), f_muxlock); if (NULL != strstr(g_line, s_attrval)) { i_lck = 1; break; } } if ( '\0' == *s_attrib || !stricmp(s_finattr, s_attrib) || strstr(s_finattr, s_attrib)) { i_atrcntr2++; if (i_lck) { fprintf(f_muxout, "@lock/%s #%s=", s_finattr, argv[2]); } else if (atoi(s_attrval) < 256) { fprintf(f_muxout, "@%s #%s=", s_finattr, argv[2]); } else { fprintf(f_muxout, "&%s #%s=", s_finattr, argv[2]); } } } else if (2 == i_chk) { int i = 0; if ('"' == g_line[i]) { i++; } if ('\001' == g_line[i]) { while ( '\0' != g_line[i] && ':' != g_line[i]) { i++; } i++; while ( '\0' != g_line[i] && ':' != g_line[i]) { i++; } i++; } memset(spt3, '\0', MALSIZE_OUT); pt3 = spt3; while ( '\0' != g_line[i] && '"' != g_line[i]) { int ch = g_line[i++]; if ('\\' == ch) { ch = g_line[i++]; switch (ch) { case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 'e': ch = ESC_CHAR; break; case 't': ch = '\t'; break; } } if (ESC_CHAR == ch) { if ( '[' == g_line[i] && '\0' != g_line[i+1] && 'm' == g_line[i+2]) { if ('0' == g_line[i+1]) { ch = COLOR_RESET; } else if ('1' == g_line[i+1]) { ch = COLOR_INTENSE; } else if ('4' == g_line[i+1]) { ch = COLOR_UNDERLINE; } else if ('5' == g_line[i+1]) { ch = COLOR_BLINK; } else if ('7' == g_line[i+1]) { ch = COLOR_INVERSE; } else { continue; } i += 3; } else if ( '[' == g_line[i] && '\0' != g_line[i+1] && '\0' != g_line[i+2] && 'm' == g_line[i+3]) { if ('3' == g_line[i+1]) { if ('0' == g_line[i+2]) { ch = COLOR_FG_BLACK; } else if ('1' == g_line[i+2]) { ch = COLOR_FG_RED; } else if ('2' == g_line[i+2]) { ch = COLOR_FG_GREEN; } else if ('3' == g_line[i+2]) { ch = COLOR_FG_YELLOW; } else if ('4' == g_line[i+2]) { ch = COLOR_FG_BLUE; } else if ('5' == g_line[i+2]) { ch = COLOR_FG_MAGENTA; } else if ('6' == g_line[i+2]) { ch = COLOR_FG_CYAN; } else if ('7' == g_line[i+2]) { ch = COLOR_FG_WHITE; } else { continue; } } else if ('4' == g_line[i+1]) { if ('0' == g_line[i+2]) { ch = COLOR_BG_BLACK; } else if ('1' == g_line[i+2]) { ch = COLOR_BG_RED; } else if ('2' == g_line[i+2]) { ch = COLOR_BG_GREEN; } else if ('3' == g_line[i+2]) { ch = COLOR_BG_YELLOW; } else if ('4' == g_line[i+2]) { ch = COLOR_BG_BLUE; } else if ('5' == g_line[i+2]) { ch = COLOR_BG_MAGENTA; } else if ('6' == g_line[i+2]) { ch = COLOR_BG_CYAN; } else if ('7' == g_line[i+2]) { ch = COLOR_BG_WHITE; } else { continue; } } else { continue; } i += 4; } else { continue; } } switch (ch) { default: *pt3 = ch; pt3++; break; case '\t': *pt3 = '%'; pt3++; *pt3 = 't'; pt3++; break; case '\n': *pt3 = '%'; pt3++; *pt3 = 'r'; pt3++; break; case '\r': break; case COLOR_RESET: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'n'; pt3++; break; case COLOR_INTENSE: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'h'; pt3++; break; case COLOR_UNDERLINE: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'u'; pt3++; break; case COLOR_BLINK: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'f'; pt3++; break; case COLOR_INVERSE: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'i'; pt3++; break; case COLOR_FG_BLACK: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'x'; pt3++; break; case COLOR_FG_RED: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'r'; pt3++; break; case COLOR_FG_GREEN: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'g'; pt3++; break; case COLOR_FG_YELLOW: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'y'; pt3++; break; case COLOR_FG_BLUE: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'b'; pt3++; break; case COLOR_FG_MAGENTA: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'm'; pt3++; break; case COLOR_FG_CYAN: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'c'; pt3++; break; case COLOR_FG_WHITE: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'w'; pt3++; break; case COLOR_BG_BLACK: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'X'; pt3++; break; case COLOR_BG_RED: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'R'; pt3++; break; case COLOR_BG_GREEN: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'G'; pt3++; break; case COLOR_BG_YELLOW: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'Y'; pt3++; break; case COLOR_BG_BLUE: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'B'; pt3++; break; case COLOR_BG_MAGENTA: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'M'; pt3++; break; case COLOR_BG_CYAN: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'C'; pt3++; break; case COLOR_BG_WHITE: *pt3 = '%'; pt3++; *pt3 = 'x'; pt3++; *pt3 = 'W'; pt3++; break; } } *pt3 = '\0'; if ( '\0' == *s_attrib || !stricmp(s_finattr, s_attrib) || strstr(s_finattr, s_attrib)) { fprintf(f_muxout, "%s\n", spt3); } } } if ('\0' == *s_attrib) { fprintf(stderr, "Step 2: Writing %d attributes\n", i_atrcntr); } else { fprintf(stderr, "Step 2: Writing %d (of %d) attributes\n", i_atrcntr2, i_atrcntr); } fclose(f_muxlock); fclose(f_muxout); fclose(f_muxattrs); fclose(f_mymuxfile); fclose(f_muxflat); free(spt3); fprintf(stderr, "Step 3: Completed (file is: %s).\n", s_filename); return 0; } mux2.6/src/tools/README.muxdbpuller0000600000175000017500000000045711025753746017166 0ustar sdennissdennisThe db puller file will read in a standard MUX 2.x flatfile and output the specified dbref# in @decompile format. To compile, just type: gcc dbpuller.c -o dbpuller or... cc dbpuller.c -o dbpuller Syntax: ./dbpuller muxflatfile Example: ./dbpuller netmux.db.FLAT 123 mux2.6/src/tools/muxattrs.dat0000600000175000017500000000405411025753746016322 0ustar sdennissdennisOsucc 1 Ofail 2 Fail 3 Succ 4 *Password 5 Desc 6 Sex 7 Odrop 8 Drop 9 Okill 10 Kill 11 Asucc 12 Afail 13 Adrop 14 Akill 15 Ause 16 Charges 17 Runout 18 Startup 19 Aclone 20 Apay 21 Opay 22 Pay 23 Cost 24 *Money 25 Listen 26 Aahear 27 Amhear 28 Ahear 29 Last 30 QueueMax 31 Idesc 32 Enter 33 Oxenter 34 Aenter 35 Adesc 36 Odesc 37 Rquota 38 Aconnect 39 Adisconnect 40 Allowance 41 DefaultLock 42 Name 43 Comment 44 Use 45 Ouse 46 Semaphore 47 Timeout 48 Quota 49 Leave 50 Oleave 51 Aleave 52 Oenter 53 Oxleave 54 Move 55 Omove 56 Amove 57 Alias 58 EnterLock 59 LeaveLock 60 PageLock 61 UseLock 62 GiveLock 63 Ealias 64 Lalias 65 Efail 66 Oefail 67 Aefail 68 Lfail 69 Olfail 70 Alfail 71 Reject 72 Away 73 Idle 74 Ufail 75 Oufail 76 Aufail 77 PFAIL 78 Tport 79 Otport 80 Oxtport 81 Atport 82 *Privileges 83 Logindata 84 TportLock 85 DropLock 86 ReceiveLock 87 Lastsite 88 Inprefix 89 Prefix 90 Infilter 91 Filter 92 LinkLock 93 TeloutLock 94 Forwardlist 95 Mailfolders 96 UserLock 97 ParentLock 98 LCONTROL 99 VA 100 VB 101 VC 102 VD 103 VE 104 VF 105 VG 106 VH 107 VI 108 VJ 109 VK 110 VL 111 VM 112 VN 113 VO 114 VP 115 VQ 116 VR 117 VS 118 VT 119 VU 120 VV 121 VW 122 VX 123 VY 124 VZ 125 GetFromLock 127 Gfail 129 Ogfail 130 Agfail 131 Rfail 132 Orfail 133 Arfail 134 Dfail 135 Odfail 136 Adfail 137 Tfail 138 Otfail 139 Atfail 140 Tofail 141 Otofail 142 Atofail 143 LastIP 144 UMBRADESC 145 WRAITHDESC 146 FAEDESC 147 MATRIXDESC 148 CmdCheck 198 Moniker 199 Lastpage 200 Mailsucc 201 Amail 202 Signature 203 Daily 204 Mailto 205 Mailmsg 206 Mailsub 207 Mailcurf 208 SpeechLock 209 ProgCmd 210 Mailflags 211 Destroyer 212 NEWOBJS 213 SayString 214 SpeechMod 215 ExitTo 216 LCHOWN 217 Created 218 Modified 219 VRML_URL 220 HTDesc 221 Reason 222 RegInfo 223 ConnInfo 224 MailLock 225 OpenLock 226 Color 236 Alead 237 Lead 238 Olead 239 IdleTimeout 240 ExitFormat 241 ConFormat 242 NameFormat 243 DescFormat 244 mux2.6/src/buildnum.data0000600000175000017500000000000211025753746015240 0ustar sdennissdennis0 mux2.6/src/create.cpp0000600000175000017500000006424211025753746014555 0ustar sdennissdennis/*! \file create.cpp * Commands that create new objects. * * $Id: create.cpp 571 2006-12-27 17:56:12Z brazilofmux $ * * This affects creation and destruction of all object types as well as their * initial and final relationships with other objects. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "powers.h" // --------------------------------------------------------------------------- // parse_linkable_room: Get a location to link to. // static dbref parse_linkable_room(dbref player, char *room_name) { init_match(player, room_name, NOTYPE); match_everything(MAT_NO_EXITS | MAT_NUMERIC | MAT_HOME); dbref room = match_result(); // HOME is always linkable // if (room == HOME) { return HOME; } // Make sure we can link to it // if (!Good_obj(room)) { notify_quiet(player, "That's not a valid object."); return NOTHING; } else if ( !Has_contents(room) || !Linkable(player, room)) { notify_quiet(player, "You can't link to that."); return NOTHING; } else { return room; } } // --------------------------------------------------------------------------- // open_exit, do_open: Open a new exit and optionally link it somewhere. // static void open_exit(dbref player, dbref loc, char *direction, char *linkto) { if (!Good_obj(loc)) { return; } if (!direction || !*direction) { notify_quiet(player, "Open where?"); return; } else if (!Controls(player, loc)) { if(!(Open_ok(loc) && could_doit(player, loc, A_LOPEN))) { notify_quiet(player, NOPERM_MESSAGE); return; } } dbref exit = create_obj(player, TYPE_EXIT, direction, 0); if (exit == NOTHING) { return; } // Initialize everything and link it in. // s_Exits(exit, loc); s_Next(exit, Exits(loc)); s_Exits(loc, exit); local_data_create(exit); // and we're done // notify_quiet(player, "Opened."); // See if we should do a link // if (!linkto || !*linkto) { return; } loc = parse_linkable_room(player, linkto); if (Good_obj(loc) || loc == HOME) { // Make sure the player passes the link lock // if (!could_doit(player, loc, A_LLINK)) { notify_quiet(player, "You can't link to there."); return; } // Link it if the player can pay for it // if (!payfor(player, mudconf.linkcost)) { notify_quiet(player, tprintf("You don't have enough %s to link.", mudconf.many_coins)); } else { s_Location(exit, loc); notify_quiet(player, "Linked."); } } } void do_open(dbref executor, dbref caller, dbref enactor, int eval, int key, char *direction, char *links[], int nlinks) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); char *dest; // Create the exit and link to the destination, if there is one // if (nlinks >= 1) { dest = links[0]; } else { dest = NULL; } dbref loc; if (key == OPEN_INVENTORY) { loc = executor; } else { loc = Location(executor); } open_exit(executor, loc, direction, dest); // Open the back link if we can. // if (nlinks >= 2) { dbref destnum = parse_linkable_room(executor, dest); if (Good_obj(destnum) || destnum == HOME) { char buff[12]; mux_ltoa(loc, buff); open_exit(executor, destnum, links[1], buff); } } } // --------------------------------------------------------------------------- // link_exit, do_link: Set destination(exits), dropto(rooms) or // home(player,thing) static void link_exit(dbref player, dbref exit, dbref dest) { // Make sure we can link there // if ( dest != HOME && ( ( !Controls(player, dest) && !Link_ok(dest)) || !could_doit(player, dest, A_LLINK))) { notify_quiet(player, NOPERM_MESSAGE); return; } // Exit must be unlinked or controlled by you // if ( Location(exit) != NOTHING && !Controls(player, exit)) { notify_quiet(player, NOPERM_MESSAGE); return; } // Handle costs // int cost = mudconf.linkcost; int quot = 0; if (Owner(exit) != Owner(player)) { cost += mudconf.opencost; quot += mudconf.exit_quota; } if (!canpayfees(player, player, cost, quot)) { return; } // Pay the owner for his loss. // if (Owner(exit) != Owner(player)) { giveto(Owner(exit), mudconf.opencost); add_quota(Owner(exit), quot); s_Owner(exit, Owner(player)); db[exit].fs.word[FLAG_WORD1] &= ~(INHERIT | WIZARD); db[exit].fs.word[FLAG_WORD1] |= HALT; } // Link has been validated and paid for, do it and tell the player // s_Location(exit, dest); if (!Quiet(player)) { notify_quiet(player, "Linked."); } } void do_link ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *what, char *where ) { UNUSED_PARAMETER(nargs); // Find the thing to link // init_match(executor, what, TYPE_EXIT); match_everything(0); dbref thing = noisy_match_result(); if (thing == NOTHING) { return; } // Allow unlink if where is not specified // if (!where || !*where) { do_unlink(executor, caller, enactor, 0, key, what); return; } dbref room; char *buff; switch (Typeof(thing)) { case TYPE_EXIT: // Set destination // room = parse_linkable_room(executor, where); if (Good_obj(room) || room == HOME) { link_exit(executor, thing, room); } break; case TYPE_PLAYER: case TYPE_THING: // Set home. // if (!Controls(executor, thing)) { notify_quiet(executor, NOPERM_MESSAGE); break; } init_match(executor, where, NOTYPE); match_everything(MAT_NO_EXITS); room = noisy_match_result(); if (!Good_obj(room)) { break; } if (!Has_contents(room)) { notify_quiet(executor, "Can't link to an exit."); break; } if ( !can_set_home(executor, thing, room) || !could_doit(executor, room, A_LLINK)) { notify_quiet(executor, NOPERM_MESSAGE); } else if (room == HOME) { notify_quiet(executor, "Can't set home to home."); } else { dbref nHomeOrig = Home(thing); dbref nHomeNew = room; s_Home(thing, nHomeNew); if (!Quiet(executor)) { char *buff1 = alloc_lbuf("do_link.notify"); char *bp = buff1; char *p; p = tprintf("Home of %s(#%d) changed from ", Name(thing), thing); safe_str(p, buff1, &bp); p = tprintf("%s(#%d) to ", Name(nHomeOrig), nHomeOrig); safe_str(p, buff1, &bp); p = tprintf("%s(#%d).", Name(nHomeNew), nHomeNew); safe_str(p, buff1, &bp); *bp = '\0'; notify_quiet(executor, buff1); free_lbuf(buff1); } } break; case TYPE_ROOM: // Set dropto. // if (!Controls(executor, thing)) { notify_quiet(executor, NOPERM_MESSAGE); break; } room = parse_linkable_room(executor, where); if ( !Good_obj(room) && room != HOME) { break; } if ( room != HOME && !isRoom(room)) { notify_quiet(executor, "That is not a room!"); } else if ( room != HOME && ( ( !Controls(executor, room) && !Link_ok(room)) || !could_doit(executor, room, A_LLINK))) { notify_quiet(executor, NOPERM_MESSAGE); } else { dbref nDroptoOrig = Dropto(thing); dbref nDroptoNew = room; s_Dropto(thing, room); if (!Quiet(executor)) { char *buff1 = alloc_lbuf("do_link2.notify"); char *bp = buff1; char *p; p = tprintf("Dropto of %s(#%d) changed from ", Name(thing), thing); safe_str(p, buff1, &bp); p = tprintf("%s(#%d) to ", Name(nDroptoOrig), nDroptoOrig); safe_str(p, buff1, &bp); p = tprintf("%s(#%d).", Name(nDroptoNew), nDroptoNew); safe_str(p, buff1, &bp); *bp = '\0'; notify_quiet(executor, buff1); free_lbuf(buff1); } } break; case TYPE_GARBAGE: notify_quiet(executor, NOPERM_MESSAGE); break; default: STARTLOG(LOG_BUGS, "BUG", "OTYPE"); buff = alloc_mbuf("do_link.LOG.badtype"); mux_sprintf(buff, MBUF_SIZE, "Strange object type: object #%d = %d", thing, Typeof(thing)); log_text(buff); free_mbuf(buff); ENDLOG; } } // --------------------------------------------------------------------------- // do_parent: Set an object's parent field. // void do_parent ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *tname, char *pname ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nargs); dbref thing, parent, curr; int lev; // Get victim. // init_match(executor, tname, NOTYPE); match_everything(0); thing = noisy_match_result(); if (!Good_obj(thing)) { return; } // Make sure we can do it. // if ( Going(thing) || !Controls(executor, thing)) { notify_quiet(executor, NOPERM_MESSAGE); return; } // Find out what the new parent is. // if (*pname) { init_match(executor, pname, Typeof(thing)); match_everything(0); parent = noisy_match_result(); if (!Good_obj(parent)) { return; } // Make sure we have rights to set parent. // if (!Parentable(executor, parent)) { notify_quiet(executor, NOPERM_MESSAGE); return; } // Verify no recursive reference // ITER_PARENTS(parent, curr, lev) { if (curr == thing) { notify_quiet(executor, "You can't have yourself as a parent!"); return; } } } else { parent = NOTHING; } s_Parent(thing, parent); if (!Quiet(thing) && !Quiet(executor)) { if (parent == NOTHING) notify_quiet(executor, "Parent cleared."); else notify_quiet(executor, "Parent set."); } } // --------------------------------------------------------------------------- // do_dig: Create a new room. // void do_dig(dbref executor, dbref caller, dbref enactor, int eval, int key, char *name, char *args[], int nargs) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(caller); // we don't need to know player's location! hooray! // if (!name || !*name) { notify_quiet(executor, "Dig what?"); return; } dbref room = create_obj(executor, TYPE_ROOM, name, 0); if (room == NOTHING) { return; } local_data_create(room); notify(executor, tprintf("%s created as room #%d.", name, room)); char *buff = alloc_sbuf("do_dig"); if ( nargs >= 1 && args[0] && *args[0]) { mux_ltoa(room, buff); open_exit(executor, Location(executor), args[0], buff); } if ( nargs >= 2 && args[1] && *args[1]) { mux_ltoa(Location(executor), buff); open_exit(executor, room, args[1], buff); } free_sbuf(buff); if (key == DIG_TELEPORT) { (void)move_via_teleport(executor, room, enactor, 0); } } // --------------------------------------------------------------------------- // do_create: Make a new object. // void do_create ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *coststr ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); int cost = 0; if (!name || !*name) { notify_quiet(executor, "Create what?"); return; } else if ( nargs == 2 && (cost = mux_atol(coststr)) < 0) { notify_quiet(executor, "You can't create an object for less than nothing!"); return; } dbref thing = create_obj(executor, TYPE_THING, name, cost); if (thing == NOTHING) { return; } move_via_generic(thing, executor, NOTHING, 0); s_Home(thing, new_home(executor)); if (!Quiet(executor)) { notify(executor, tprintf("%s created as object #%d", Name(thing), thing)); } local_data_create(thing); } // --------------------------------------------------------------------------- // do_clone: Create a copy of an object. // void do_clone ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *arg2 ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); dbref clone, thing, new_owner, loc; int cost; if ( (key & CLONE_INVENTORY) || !Has_location(executor)) { loc = executor; } else { loc = Location(executor); } if (!Good_obj(loc)) { return; } init_match(executor, name, NOTYPE); match_everything(0); thing = noisy_match_result(); if ( NOTHING == thing || AMBIGUOUS == thing) { return; } // Let players clone things set VISUAL. It's easier than retyping // in all that data. // if (!Examinable(executor, thing)) { notify_quiet(executor, NOPERM_MESSAGE); return; } if (isPlayer(thing)) { notify_quiet(executor, "You cannot clone players!"); return; } // You can only make a parent link to what you control. // if ( !Controls(executor, thing) && !Parent_ok(thing) && (key & CLONE_FROM_PARENT)) { notify_quiet(executor, tprintf("You don't control %s, ignoring /parent.", Name(thing))); key &= ~CLONE_FROM_PARENT; } // Determine the cost of cloning // new_owner = (key & CLONE_PRESERVE) ? Owner(thing) : Owner(executor); if (key & CLONE_SET_COST) { cost = mux_atol(arg2); if (cost < mudconf.createmin) cost = mudconf.createmin; if (cost > mudconf.createmax) cost = mudconf.createmax; arg2 = NULL; } else { cost = 1; switch (Typeof(thing)) { case TYPE_THING: cost = OBJECT_DEPOSIT((mudconf.clone_copy_cost) ? Pennies(thing) : 1); break; case TYPE_ROOM: cost = mudconf.digcost; break; case TYPE_EXIT: if (!Controls(executor, loc)) { notify_quiet(executor, NOPERM_MESSAGE); return; } cost = mudconf.digcost; break; } } // Go make the clone object. // bool bValid; size_t nValidName; char *pValidName = MakeCanonicalObjectName(arg2, &nValidName, &bValid); const char *clone_name; if (bValid) { clone_name = pValidName; } else { clone_name = Name(thing); } clone = create_obj(new_owner, Typeof(thing), clone_name, cost); if (clone == NOTHING) { return; } // Copy in the new data. // if (key & CLONE_FROM_PARENT) { s_Parent(clone, thing); } else { atr_cpy(clone, thing, false); } // Reset the name, since we cleared the attributes. // s_Name(clone, clone_name); // Reset the pennies, since it looks like we stamped on that, too. // s_Pennies(clone, OBJECT_ENDOWMENT(cost)); FLAGSET clearflags; TranslateFlags_Clone(clearflags.word, executor, key); SetClearFlags(clone, clearflags.word, NULL); // Tell creator about it // if (!Quiet(executor)) { if (arg2 && *arg2) { notify(executor, tprintf("%s cloned as %s, new copy is object #%d.", Name(thing), arg2, clone)); } else { notify(executor, tprintf("%s cloned, new copy is object #%d.", Name(thing), clone)); } } // Put the new thing in its new home. Break any dropto or link, then // try to re-establish it. // switch (Typeof(thing)) { case TYPE_THING: s_Home(clone, clone_home(executor, thing)); move_via_generic(clone, loc, executor, 0); break; case TYPE_ROOM: s_Dropto(clone, NOTHING); if (Dropto(thing) != NOTHING) { link_exit(executor, clone, Dropto(thing)); } break; case TYPE_EXIT: s_Exits(loc, insert_first(Exits(loc), clone)); s_Exits(clone, loc); s_Location(clone, NOTHING); if (Location(thing) != NOTHING) { link_exit(executor, clone, Location(thing)); } break; } // If same owner run ACLONE, else halt it. Also copy parent if we can. // if (new_owner == Owner(thing)) { if (!(key & CLONE_FROM_PARENT)) { s_Parent(clone, Parent(thing)); } did_it(executor, clone, 0, NULL, 0, NULL, A_ACLONE, 0, NULL, 0); } else { if ( !(key & CLONE_FROM_PARENT) && (Controls(executor, thing) || Parent_ok(thing))) { s_Parent(clone, Parent(thing)); } s_Halted(clone); } local_data_clone(clone, thing); } // --------------------------------------------------------------------------- // do_pcreate: Create new players and robots. // void do_pcreate ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *name, char *pass ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); const char *pmsg; bool isrobot = (key == PCRE_ROBOT); dbref newplayer = create_player(name, pass, executor, isrobot, &pmsg); if (newplayer == NOTHING) { notify_quiet(executor, tprintf("Failure creating '%s'. %s", name, pmsg)); return; } AddToPublicChannel(newplayer); if (isrobot) { move_object(newplayer, Location(executor)); notify_quiet(executor, tprintf("New robot '%s' (#%d) created with password '%s'", name, newplayer, pass)); notify_quiet(executor, "Your robot has arrived."); STARTLOG(LOG_PCREATES, "CRE", "ROBOT"); log_name(newplayer); log_text(" created by "); log_name(executor); ENDLOG; } else { move_object(newplayer, mudconf.start_room); notify_quiet(executor, tprintf("New player '%s' (#%d) created with password '%s'", name, newplayer, pass)); STARTLOG(LOG_PCREATES | LOG_WIZARD, "WIZ", "PCREA"); log_name(newplayer); log_text(" created by "); log_name(executor); ENDLOG; #ifdef GAME_DOOFERMUX // Added by D.Piper (del@doofer.org) 2000-APR // atr_add_raw(newplayer, A_REGINFO, "*Requires Registration*"); #endif } } // --------------------------------------------------------------------------- // destroyable: Indicates if target of a @destroy is a 'special' object in // the database. // static bool destroyable(dbref victim) { if ( (victim == mudconf.default_home) || (victim == mudconf.start_home) || (victim == mudconf.start_room) || (victim == mudconf.master_room) || (victim == (dbref) 0) || (God(victim))) { return false; } return true; } // --------------------------------------------------------------------------- // can_destroy_player, do_destroy: Destroy things. // static bool can_destroy_player(dbref player, dbref victim) { if (!Wizard(player)) { notify_quiet(player, "Sorry, no suicide allowed."); return false; } if (RealWizard(victim)) { notify_quiet(player, "Even you can't do that!"); return false; } return true; } void do_destroy(dbref executor, dbref caller, dbref enactor, int eval, int key, char *what) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); // You can destroy anything you control. // dbref thing = match_controlled_quiet(executor, what); // If you own a location, you can destroy its exits. // if ( thing == NOTHING && Controls(executor, Location(executor))) { init_match(executor, what, TYPE_EXIT); match_exit(); thing = last_match_result(); } // You may destroy DESTROY_OK things in your inventory. // if (thing == NOTHING) { init_match(executor, what, TYPE_THING); match_possession(); thing = last_match_result(); if ( thing != NOTHING && !(isThing(thing) && Destroy_ok(thing))) { thing = NOPERM; } } // Return an error if we didn't find anything to destroy. // if (match_status(executor, thing) == NOTHING) { return; } // Check SAFE and DESTROY_OK flags. // if ( Safe(thing, executor) && !(key & DEST_OVERRIDE) && !(isThing(thing) && Destroy_ok(thing))) { notify_quiet(executor, "Sorry, that object is protected. Use @destroy/override to destroy it."); return; } // Make sure we're not trying to destroy a special object. // if (!destroyable(thing)) { notify_quiet(executor, "You can't destroy that!"); return; } // Make sure we can do it, on a type-specific basis. // if( isPlayer(thing) && !can_destroy_player(executor, thing)) { return; } char *NameOfType = alloc_sbuf("do_destroy.NameOfType"); mux_strncpy(NameOfType, object_types[Typeof(thing)].name, SBUF_SIZE-1); mux_strlwr(NameOfType); if (Going(thing)) { if (!mudconf.destroy_going_now) { notify_quiet(executor, tprintf("No sense beating a dead %s.", NameOfType)); free_sbuf(NameOfType); return; } key |= DEST_INSTANT; } // Check whether we should perform instant destruction. // dbref ThingOwner = Owner(thing); bool bInstant = (key & DEST_INSTANT) || Destroy_ok(thing) || Destroy_ok(ThingOwner); if (!bInstant) { // Pre-destruction 'crumble' emits and one last possible showstopper. // switch (Typeof(thing)) { case TYPE_ROOM: notify_all(thing, executor, "The room shakes and begins to crumble."); break; case TYPE_PLAYER: atr_add_raw(thing, A_DESTROYER, mux_ltoa_t(executor)); if (!atr_get_raw(thing, A_DESTROYER)) { // Not a likely situation, but the player has too many // attributes to remember it's destroyer, so we we need to // take care of this more immediately. // bInstant = true; notify(executor, "Player has a lot of attributes. Performing destruction immediately."); break; } // FALL THROUGH case TYPE_EXIT: case TYPE_THING: notify(executor, tprintf("The %s shakes and begins to crumble.", NameOfType)); break; default: notify(executor, "Weird object type cannot be destroyed."); free_sbuf(NameOfType); return; } if ( !bInstant && !Quiet(thing) && !Quiet(ThingOwner)) { notify_quiet(ThingOwner, tprintf("You will be rewarded shortly for %s(#%d).", Moniker(thing), thing)); } } free_sbuf(NameOfType); // Imperative Destruction emits. // if (!Quiet(executor)) { if (Good_owner(ThingOwner)) { if (ThingOwner == Owner(executor)) { if (!Quiet(thing)) { notify(executor, tprintf("Destroyed %s(#%d).", Moniker(thing), thing)); } } else if (ThingOwner == thing) { notify(executor, tprintf("Destroyed %s(#%d).", Moniker(thing), thing)); } else { char *tname = alloc_lbuf("destroy_obj"); mux_strncpy(tname, Moniker(ThingOwner), LBUF_SIZE-1); notify(executor, tprintf("Destroyed %s's %s(#%d).", tname, Moniker(thing), thing)); free_lbuf(tname); } } } if (bInstant) { // Instant destruction by type. // switch (Typeof(thing)) { case TYPE_EXIT: destroy_exit(thing); break; case TYPE_PLAYER: destroy_player(executor, thing); break; case TYPE_ROOM: empty_obj(thing); destroy_obj(thing); break; case TYPE_THING: destroy_thing(thing); break; default: notify(executor, "Weird object type cannot be destroyed."); return; } } s_Going(thing); } mux2.6/src/boolexp.cpp0000600000175000017500000004077311025753746014765 0ustar sdennissdennis/*! \file boolexp.cpp * Boolean Expressions for @locks * * $Id: boolexp.cpp 3182 2008-01-18 08:01:21Z brazilofmux $ * * The functions here evaluate and organize boolean expressions used in * locks. Lock evaluation contains one of server's the three parsers. The * other two parsers are for functions (see eval.cpp) and commands (see * command.cpp). */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" static bool parsing_internal = false; /* --------------------------------------------------------------------------- * check_attr: indicate if attribute ATTR on player passes key when checked by * the object lockobj */ static bool check_attr(dbref player, dbref lockobj, ATTR *attr, char *key) { dbref aowner; int aflags; bool bCheck = false; char *buff = atr_pget(player, attr->number, &aowner, &aflags); if (attr->number == A_LENTER) { // We can see enterlocks... else we'd break zones. // bCheck = true; } else if (See_attr(lockobj, player, attr)) { bCheck = true; } else if (attr->number == A_NAME) { bCheck = true; } if ( bCheck && !wild_match(key, buff)) { bCheck = false; } free_lbuf(buff); return bCheck; } bool eval_boolexp(dbref player, dbref thing, dbref from, BOOLEXP *b) { if (b == TRUE_BOOLEXP) { return true; } dbref aowner, obj, source; int aflags; char *key, *buff, *buff2, *bp, *str; ATTR *a; bool bCheck, c; switch (b->type) { case BOOLEXP_AND: return eval_boolexp(player, thing, from, b->sub1) && eval_boolexp(player, thing, from, b->sub2); case BOOLEXP_OR: return eval_boolexp(player, thing, from, b->sub1) || eval_boolexp(player, thing, from, b->sub2); case BOOLEXP_NOT: return !eval_boolexp(player, thing, from, b->sub1); case BOOLEXP_INDIR: // BOOLEXP_INDIR (i.e. @) is a unary operation which is replaced at // evaluation time by the lock of the object whose number is the // argument of the operation. // mudstate.lock_nest_lev++; if (mudstate.lock_nest_lev >= mudconf.lock_nest_lim) { if (mudstate.bStandAlone) { Log.WriteString("Lock exceeded recursion limit." ENDLINE); } else { STARTLOG(LOG_BUGS, "BUG", "LOCK"); log_name_and_loc(player); log_text(": Lock exceeded recursion limit."); ENDLOG; notify(player, "Sorry, broken lock!"); } mudstate.lock_nest_lev--; return false; } if ( b->sub1->type != BOOLEXP_CONST || b->sub1->thing < 0) { if (mudstate.bStandAlone) { Log.WriteString("Broken lock." ENDLINE); } else { STARTLOG(LOG_BUGS, "BUG", "LOCK"); log_name_and_loc(player); buff = alloc_mbuf("eval_boolexp.LOG.indir"); mux_sprintf(buff, MBUF_SIZE, ": Lock had bad indirection (%c, type %d)", INDIR_TOKEN, b->sub1->type); log_text(buff); free_mbuf(buff); ENDLOG; notify(player, "Sorry, broken lock!"); } mudstate.lock_nest_lev--; return false; } key = atr_get(b->sub1->thing, A_LOCK, &aowner, &aflags); c = eval_boolexp_atr(player, b->sub1->thing, from, key); free_lbuf(key); mudstate.lock_nest_lev--; return c; case BOOLEXP_CONST: return b->thing == player || member(b->thing, Contents(player)); case BOOLEXP_ATR: a = atr_num(b->thing); if (!a) { // No such attribute. // return false; } // First check the object itself, then its contents. // if (check_attr(player, from, a, (char *)b->sub1)) { return true; } DOLIST(obj, Contents(player)) { if (check_attr(obj, from, a, (char *)b->sub1)) { return true; } } return false; case BOOLEXP_EVAL: a = atr_num(b->thing); if ( !a || MuxAlarm.bAlarmed) { // No such attribute. // return false; } source = from; buff = atr_pget(from, a->number, &aowner, &aflags); if (!buff || !*buff) { free_lbuf(buff); buff = atr_pget(thing, a->number, &aowner, &aflags); source = thing; } bCheck = false; if ( a->number == A_NAME || a->number == A_LENTER) { bCheck = true; } else if (bCanReadAttr(source, source, a, false)) { bCheck = true; } if (bCheck) { reg_ref **preserve = NULL; preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); buff2 = bp = alloc_lbuf("eval_boolexp"); str = buff; mux_exec(buff2, &bp, source, player, player, AttrTrace(aflags, EV_FIGNORE|EV_EVAL|EV_FCHECK|EV_TOP), &str, NULL, 0); *bp = '\0'; restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); bCheck = !string_compare(buff2, (char *)b->sub1); free_lbuf(buff2); } free_lbuf(buff); return bCheck; case BOOLEXP_IS: // If an object check, do that. // if (b->sub1->type == BOOLEXP_CONST) { return (b->sub1->thing == player); } // Nope, do an attribute check // a = atr_num(b->sub1->thing); if (!a) { return false; } return check_attr(player, from, a, (char *)(b->sub1)->sub1); case BOOLEXP_CARRY: // If an object check, do that // if (b->sub1->type == BOOLEXP_CONST) { return member(b->sub1->thing, Contents(player)); } // Nope, do an attribute check // a = atr_num(b->sub1->thing); if (!a) { return false; } DOLIST(obj, Contents(player)) { if (check_attr(obj, from, a, (char *)(b->sub1)->sub1)) { return true; } } return false; case BOOLEXP_OWNER: return (Owner(b->sub1->thing) == Owner(player)); default: // Bad type // mux_assert(0); return false; } } bool eval_boolexp_atr(dbref player, dbref thing, dbref from, char *key) { bool ret_value; BOOLEXP *b = parse_boolexp(player, key, true); if (b == NULL) { ret_value = true; } else { ret_value = eval_boolexp(player, thing, from, b); free_boolexp(b); } return ret_value; } // If the parser returns TRUE_BOOLEXP, you lose // TRUE_BOOLEXP cannot be typed in by the user; use @unlock instead // static const char *parsebuf; static char parsestore[LBUF_SIZE]; static dbref parse_player; static void skip_whitespace(void) { while (mux_isspace(*parsebuf)) { parsebuf++; } } // Defined below. // static BOOLEXP *parse_boolexp_E(void); static BOOLEXP *test_atr(char *s) { char *s1; int anum; boolexp_type locktype; char *buff = alloc_lbuf("test_atr"); mux_strncpy(buff, s, LBUF_SIZE-1); for (s = buff; *s && (*s != ':') && (*s != '/'); s++) { ; // Nothing. } if (!*s) { free_lbuf(buff); return TRUE_BOOLEXP; } if (*s == '/') { locktype = BOOLEXP_EVAL; } else { locktype = BOOLEXP_ATR; } *s++ = '\0'; // See if left side is valid attribute. Access to attr is checked on eval // Also allow numeric references to attributes. It can't hurt us, and lets // us import stuff that stores attr locks by number instead of by name. // ATTR *attrib = atr_str(buff); if (!attrib) { // Only #1 can lock on numbers // if (!God(parse_player)) { free_lbuf(buff); return TRUE_BOOLEXP; } for (s1 = buff; mux_isdigit(*s1); s1++) { ; // Nothing. } if (*s1) { free_lbuf(buff); return TRUE_BOOLEXP; } anum = mux_atol(buff); if (anum <= 0) { free_lbuf(buff); return TRUE_BOOLEXP; } } else { anum = attrib->number; } // made it now make the parse tree node // BOOLEXP *b = alloc_bool("test_str"); b->type = locktype; b->thing = (dbref) anum; b->sub1 = (BOOLEXP *) StringClone(s); free_lbuf(buff); return b; } // L -> (E); L -> object identifier // static BOOLEXP *parse_boolexp_L(void) { BOOLEXP *b; char *p; char *buf; MSTATE mstate; buf = NULL; skip_whitespace(); switch (*parsebuf) { case '(': parsebuf++; b = parse_boolexp_E(); skip_whitespace(); if ( b == TRUE_BOOLEXP || *parsebuf++ != ')') { free_boolexp(b); return TRUE_BOOLEXP; } break; default: // Must have hit an object ref. Load the name into our buffer. // buf = alloc_lbuf("parse_boolexp_L"); p = buf; while ( *parsebuf && *parsebuf != AND_TOKEN && *parsebuf != OR_TOKEN && *parsebuf != ')' && p < buf + LBUF_SIZE) { *p++ = *parsebuf++; } // Strip trailing whitespace. // *p-- = '\0'; while (mux_isspace(*p)) { *p-- = '\0'; } // Check for an attribute. // if ((b = test_atr(buf)) != NULL) { free_lbuf(buf); return (b); } b = alloc_bool("parse_boolexp_L"); b->type = BOOLEXP_CONST; // do the match. // if (!mudstate.bStandAlone) { // If we are parsing a boolexp that was a stored lock then we // know that object refs are all dbrefs, so we skip the // expensive match code. // if (parsing_internal) { if (buf[0] != '#') { free_lbuf(buf); free_bool(b); return TRUE_BOOLEXP; } b->thing = mux_atol(&buf[1]); if (!Good_dbref(b->thing)) { free_lbuf(buf); free_bool(b); return TRUE_BOOLEXP; } } else { save_match_state(&mstate); init_match(parse_player, buf, TYPE_THING); match_everything(MAT_EXIT_PARENTS); b->thing = match_result(); restore_match_state(&mstate); } if (b->thing == NOTHING) { notify(parse_player, tprintf("I don't see %s here.", buf)); free_lbuf(buf); free_bool(b); return TRUE_BOOLEXP; } if (b->thing == AMBIGUOUS) { notify(parse_player, tprintf("I don't know which %s you mean!", buf)); free_lbuf(buf); free_bool(b); return TRUE_BOOLEXP; } } else { // Had better be # or we're hosed. // if (buf[0] != '#') { free_lbuf(buf); free_bool(b); return TRUE_BOOLEXP; } b->thing = mux_atol(&buf[1]); if (b->thing < 0) { free_lbuf(buf); free_bool(b); return TRUE_BOOLEXP; } } free_lbuf(buf); } return b; } // F -> !F; F -> @L; F -> =L; F -> +L; F -> $L // The argument L must be type BOOLEXP_CONST // static BOOLEXP *parse_boolexp_F(void) { BOOLEXP *b2; skip_whitespace(); switch (*parsebuf) { case NOT_TOKEN: parsebuf++; b2 = alloc_bool("parse_boolexp_F.not"); b2->type = BOOLEXP_NOT; if ((b2->sub1 = parse_boolexp_F()) == TRUE_BOOLEXP) { free_boolexp(b2); return (TRUE_BOOLEXP); } else { return (b2); } // NOTREACHED // case INDIR_TOKEN: parsebuf++; b2 = alloc_bool("parse_boolexp_F.indir"); b2->type = BOOLEXP_INDIR; b2->sub1 = parse_boolexp_L(); if ((b2->sub1) == TRUE_BOOLEXP) { free_boolexp(b2); return (TRUE_BOOLEXP); } else if ((b2->sub1->type) != BOOLEXP_CONST) { free_boolexp(b2); return (TRUE_BOOLEXP); } else { return (b2); } // NOTREACHED // case IS_TOKEN: parsebuf++; b2 = alloc_bool("parse_boolexp_F.is"); b2->type = BOOLEXP_IS; b2->sub1 = parse_boolexp_L(); if (b2->sub1 == TRUE_BOOLEXP) { free_boolexp(b2); return (TRUE_BOOLEXP); } else if ( b2->sub1->type != BOOLEXP_CONST && b2->sub1->type != BOOLEXP_ATR) { free_boolexp(b2); return TRUE_BOOLEXP; } else { return (b2); } // NOTREACHED // case CARRY_TOKEN: parsebuf++; b2 = alloc_bool("parse_boolexp_F.carry"); b2->type = BOOLEXP_CARRY; b2->sub1 = parse_boolexp_L(); if (b2->sub1 == TRUE_BOOLEXP) { free_boolexp(b2); return TRUE_BOOLEXP; } else if ( b2->sub1->type != BOOLEXP_CONST && b2->sub1->type != BOOLEXP_ATR) { free_boolexp(b2); return TRUE_BOOLEXP; } else { return b2; } // NOTREACHED // case OWNER_TOKEN: parsebuf++; b2 = alloc_bool("parse_boolexp_F.owner"); b2->type = BOOLEXP_OWNER; b2->sub1 = parse_boolexp_L(); if (b2->sub1 == TRUE_BOOLEXP) { free_boolexp(b2); return TRUE_BOOLEXP; } else if (b2->sub1->type != BOOLEXP_CONST) { free_boolexp(b2); return TRUE_BOOLEXP; } else { return b2; } // NOTREACHED // default: return parse_boolexp_L(); } } // T -> F; T -> F & T // static BOOLEXP *parse_boolexp_T(void) { BOOLEXP *b, *b2; if ((b = parse_boolexp_F()) != TRUE_BOOLEXP) { skip_whitespace(); if (*parsebuf == AND_TOKEN) { parsebuf++; b2 = alloc_bool("parse_boolexp_T"); b2->type = BOOLEXP_AND; b2->sub1 = b; if ((b2->sub2 = parse_boolexp_T()) == TRUE_BOOLEXP) { free_boolexp(b2); return TRUE_BOOLEXP; } b = b2; } } return b; } // E -> T; E -> T | E // static BOOLEXP *parse_boolexp_E(void) { BOOLEXP *b, *b2; if ((b = parse_boolexp_T()) != TRUE_BOOLEXP) { skip_whitespace(); if (*parsebuf == OR_TOKEN) { parsebuf++; b2 = alloc_bool("parse_boolexp_E"); b2->type = BOOLEXP_OR; b2->sub1 = b; if ((b2->sub2 = parse_boolexp_E()) == TRUE_BOOLEXP) { free_boolexp(b2); return TRUE_BOOLEXP; } b = b2; } } return b; } BOOLEXP *parse_boolexp(dbref player, const char *buf, bool internal) { if ( NULL == buf || '\0' == buf[0]) { return TRUE_BOOLEXP; } size_t n = strlen(buf); if (n > sizeof(parsestore)-1) { n = sizeof(parsestore)-1; } memcpy(parsestore, buf, n+1); parsebuf = parsestore; parse_player = player; if (!mudstate.bStandAlone) { parsing_internal = internal; } return parse_boolexp_E(); } mux2.6/src/misc.h0000600000175000017500000000175111025753746013706 0ustar sdennissdennis// misc.h -- miscellaneous structures that are needed in more than one file. // // $Id: misc.h 8 2006-09-05 01:55:58Z brazilofmux $ // #include "copyright.h" #ifndef _MISC_H #define _MISC_H #include "powers.h" /* Search structure, used by @search and search(). */ typedef struct search_type SEARCH; struct search_type { int s_wizard; dbref s_owner; dbref s_rst_owner; int s_rst_type; FLAGSET s_fset; POWERSET s_pset; dbref s_parent; dbref s_zone; char *s_rst_name; char *s_rst_eval; int low_bound; int high_bound; }; /* Stats structure, used by @stats and stats(). */ typedef struct stats_type STATS; struct stats_type { int s_total; int s_rooms; int s_exits; int s_things; int s_players; int s_garbage; }; extern bool search_setup(dbref, char *, SEARCH *); extern void search_perform(dbref executor, dbref caller, dbref enactor, SEARCH *); extern bool get_stats(dbref, dbref, STATS *); #endif // !_MISC_H mux2.6/src/funmath.cpp0000600000175000017500000017215211025753746014754 0ustar sdennissdennis// funmath.cpp -- MUX math function handlers. // // $Id: funmath.cpp 1862 2007-04-07 17:17:16Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include #include #include #include "functions.h" #include "funmath.h" #include "sha1.h" #ifdef HAVE_IEEE_FP_FORMAT static const char *mux_FPStrings[] = { "+Inf", "-Inf", "Ind", "NaN", "0", "0", "0", "0" }; #define MUX_FPGROUP_PASS 0x00 // Pass-through to printf #define MUX_FPGROUP_ZERO 0x10 // Force to be zero. #define MUX_FPGROUP_PINF 0x20 // "+Inf" #define MUX_FPGROUP_NINF 0x30 // "-Inf" #define MUX_FPGROUP_IND 0x40 // "Ind" #define MUX_FPGROUP_NAN 0x50 // "NaN" #define MUX_FPGROUP(x) ((x) & 0xF0) // mux_fpclass returns an integer that is one of the following: // #define MUX_FPCLASS_PINF (MUX_FPGROUP_PINF|0) // Positive infinity (+INF) #define MUX_FPCLASS_NINF (MUX_FPGROUP_NINF|1) // Negative infinity (-INF) #define MUX_FPCLASS_QNAN (MUX_FPGROUP_IND |2) // Quiet NAN (Indefinite) #define MUX_FPCLASS_SNAN (MUX_FPGROUP_NAN |3) // Signaling NAN #define MUX_FPCLASS_ND (MUX_FPGROUP_ZERO|4) // Negative denormalized #define MUX_FPCLASS_NZ (MUX_FPGROUP_ZERO|5) // Negative zero (-0) #define MUX_FPCLASS_PZ (MUX_FPGROUP_ZERO|6) // Positive zero (+0) #define MUX_FPCLASS_PD (MUX_FPGROUP_ZERO|7) // Positive denormalized #define MUX_FPCLASS_PN (MUX_FPGROUP_PASS|8) // Positive normalized non-zero #define MUX_FPCLASS_NN (MUX_FPGROUP_PASS|9) // Negative normalized non-zero #define MUX_FPCLASS(x) ((x) & 0x0F) #ifdef WIN32 #define IEEE_MASK_SIGN 0x8000000000000000ui64 #define IEEE_MASK_EXPONENT 0x7FF0000000000000ui64 #define IEEE_MASK_MANTISSA 0x000FFFFFFFFFFFFFui64 #define IEEE_MASK_QNAN 0x0008000000000000ui64 #else #define IEEE_MASK_SIGN 0x8000000000000000ull #define IEEE_MASK_EXPONENT 0x7FF0000000000000ull #define IEEE_MASK_MANTISSA 0x000FFFFFFFFFFFFFull #define IEEE_MASK_QNAN 0x0008000000000000ull #endif #define ARBITRARY_NUMBER 1 #define IEEE_MAKE_TABLESIZE 5 typedef union { INT64 i64; double d; } SpecialFloatUnion; // We return a Quiet NAN when a Signalling NAN is requested because // any operation on a Signalling NAN will result in a Quiet NAN anyway. // MUX doesn't catch SIGFPE, but if it did, a Signalling NAN would // generate a SIGFPE. // static SpecialFloatUnion SpecialFloatTable[IEEE_MAKE_TABLESIZE] = { { 0 }, // Unused. { IEEE_MASK_EXPONENT | IEEE_MASK_QNAN | ARBITRARY_NUMBER }, { IEEE_MASK_EXPONENT | IEEE_MASK_QNAN | ARBITRARY_NUMBER }, { IEEE_MASK_EXPONENT }, { IEEE_MASK_EXPONENT | IEEE_MASK_SIGN } }; double MakeSpecialFloat(int iWhich) { return SpecialFloatTable[iWhich].d; } static int mux_fpclass(double result) { union { UINT64 i64; double d; } u; u.d = result; if ((u.i64 & IEEE_MASK_EXPONENT) == 0) { if (u.i64 & IEEE_MASK_MANTISSA) { if (u.i64 & IEEE_MASK_SIGN) return MUX_FPCLASS_ND; else return MUX_FPCLASS_PD; } else { if (u.i64 & IEEE_MASK_SIGN) return MUX_FPCLASS_NZ; else return MUX_FPCLASS_PZ; } } else if ((u.i64 & IEEE_MASK_EXPONENT) == IEEE_MASK_EXPONENT) { if (u.i64 & IEEE_MASK_MANTISSA) { if (u.i64 & IEEE_MASK_QNAN) return MUX_FPCLASS_QNAN; else return MUX_FPCLASS_SNAN; } else { if (u.i64 & IEEE_MASK_SIGN) return MUX_FPCLASS_NINF; else return MUX_FPCLASS_PINF; } } else { if (u.i64 & IEEE_MASK_SIGN) return MUX_FPCLASS_NN; else return MUX_FPCLASS_PN; } } #endif // HAVE_IEEE_FP_FORMAT static double AddWithError(double& err, double a, double b) { double sum = a+b; err = b-(sum-a); return sum; } // Typically, we are within 1ulp of an exact answer, find the shortest answer // within that 1 ulp (that is, within 0, +ulp, and -ulp). // static double NearestPretty(double R) { char *rve = NULL; int decpt; int bNegative; const int mode = 0; double ulpR = ulp(R); double R0 = R-ulpR; double R1 = R+ulpR; // R. // char *p = mux_dtoa(R, mode, 50, &decpt, &bNegative, &rve); size_t nDigits = rve - p; // R-ulp(R) // p = mux_dtoa(R0, mode, 50, &decpt, &bNegative, &rve); size_t nDigitsR0 = rve - p; if (nDigitsR0 < nDigits) { nDigits = rve - p; R = R0; } // R+ulp(R) // p = mux_dtoa(R1, mode, 50, &decpt, &bNegative, &rve); size_t nDigitsR1 = rve - p; if (nDigitsR1 < nDigits) { nDigits = rve - p; R = R1; } return R; } // Compare for decreasing order by absolute value. // static int DCL_CDECL f_comp_abs(const void *s1, const void *s2) { double a = fabs(*(double *)s1); double b = fabs(*(double *)s2); if (a > b) { return -1; } else if (a < b) { return 1; } return 0; } // Double compensation method. Extended by Priest from Knuth and Kahan. // // Error of sum is less than 2*epsilon or 1 ulp except for very large n. // Return the result that yields the shortest number of base-10 digits. // static double AddDoubles(int n, double pd[]) { qsort(pd, n, sizeof(double), f_comp_abs); double sum = 0.0; if (0 < n) { sum = pd[0]; double sum_err = 0.0; int i; for (i = 1; i < n; i++) { double addend_err; double addend = AddWithError(addend_err, sum_err, pd[i]); double sum1_err; double sum1 = AddWithError(sum1_err, sum, addend); sum = AddWithError(sum_err, sum1, addend_err + sum1_err); } } return NearestPretty(sum); } /* --------------------------------------------------------------------------- * fval: copy the floating point value into a buffer and make it presentable */ static void fval(char *buff, char **bufc, double result) { // Get double val into buffer. // #ifdef HAVE_IEEE_FP_FORMAT int fpc = mux_fpclass(result); if (MUX_FPGROUP(fpc) == MUX_FPGROUP_PASS) { #endif // HAVE_IEEE_FP_FORMAT double rIntegerPart; double rFractionalPart = modf(result, &rIntegerPart); if ( 0.0 == rFractionalPart && LONG_MIN <= rIntegerPart && rIntegerPart <= LONG_MAX) { long i = (long)rIntegerPart; safe_ltoa(i, buff, bufc); } else { safe_str(mux_ftoa(result, false, 0), buff, bufc); } #ifdef HAVE_IEEE_FP_FORMAT } else { safe_str(mux_FPStrings[MUX_FPCLASS(fpc)], buff, bufc); } #endif // HAVE_IEEE_FP_FORMAT } static const long nMaximums[10] = { 0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999 }; static double g_aDoubles[LBUF_SIZE]; int const g_nDoubles = sizeof(g_aDoubles)/sizeof(double); FUNCTION(fun_add) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int nArgs = nfargs; if (g_nDoubles < nArgs) { nArgs = g_nDoubles; } int i; for (i = 0; i < nArgs; i++) { int nDigits; long nMaxValue = 0; if ( !is_integer(fargs[i], &nDigits) || nDigits > 9 || (nMaxValue += nMaximums[nDigits]) > 999999999L) { // Do it the slow way. // for (int j = 0; j < nArgs; j++) { g_aDoubles[j] = mux_atof(fargs[j]); } fval(buff, bufc, AddDoubles(nArgs, g_aDoubles)); return; } } // We can do it the fast way. // long sum = 0; for (i = 0; i < nArgs; i++) { sum += mux_atol(fargs[i]); } safe_ltoa(sum, buff, bufc); } FUNCTION(fun_ladd) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int n = 0; if (0 < nfargs) { SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } char *cp = trim_space_sep(fargs[0], &sep); while ( cp && n < g_nDoubles) { char *curr = split_token(&cp, &sep); g_aDoubles[n++] = mux_atof(curr); } } fval(buff, bufc, AddDoubles(n, g_aDoubles)); } ///////////////////////////////////////////////////////////////// // Function : iadd(Arg[0], Arg[1],..,Arg[n]) // // Written by : Chris Rouse (Seraphim) 04/04/2000 ///////////////////////////////////////////////////////////////// FUNCTION(fun_iadd) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); INT64 sum = 0; for (int i = 0; i < nfargs; i++) { sum += mux_atoi64(fargs[i]); } safe_i64toa(sum, buff, bufc); } FUNCTION(fun_sub) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int nDigits; if ( is_integer(fargs[0], &nDigits) && nDigits <= 9 && is_integer(fargs[1], &nDigits) && nDigits <= 9) { int iResult; long a = mux_atol(fargs[0]); long b = mux_atol(fargs[1]); iResult = a - b; safe_ltoa(iResult, buff, bufc); } else { g_aDoubles[0] = mux_atof(fargs[0]); g_aDoubles[1] = -mux_atof(fargs[1]); fval(buff, bufc, AddDoubles(2, g_aDoubles)); } } ///////////////////////////////////////////////////////////////// // Function : isub(Arg[0], Arg[1]) // // Written by : Chris Rouse (Seraphim) 04/04/2000 ///////////////////////////////////////////////////////////////// FUNCTION(fun_isub) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); INT64 a = mux_atoi64(fargs[0]); INT64 b = mux_atoi64(fargs[1]); INT64 diff = a - b; safe_i64toa(diff, buff, bufc); } FUNCTION(fun_mul) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double prod = 1.0; for (int i = 0; i < nfargs; i++) { prod *= mux_atof(fargs[i]); } fval(buff, bufc, NearestPretty(prod)); } ///////////////////////////////////////////////////////////////// // Function : imul(Arg[0], Arg[1], ... , Arg[n]) // // Written by : Chris Rouse (Seraphim) 04/04/2000 ///////////////////////////////////////////////////////////////// FUNCTION(fun_imul) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); INT64 prod = 1; for (int i = 0; i < nfargs; i++) { prod *= mux_atoi64(fargs[i]); } safe_i64toa(prod, buff, bufc); } FUNCTION(fun_gt) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool bResult = false; int nDigits; if ( is_integer(fargs[0], &nDigits) && nDigits <= 9 && is_integer(fargs[1], &nDigits) && nDigits <= 9) { long a = mux_atol(fargs[0]); long b = mux_atol(fargs[1]); bResult = (a > b); } else { double a = mux_atof(fargs[0]); double b = mux_atof(fargs[1]); bResult = (a > b); } safe_bool(bResult, buff, bufc); } FUNCTION(fun_gte) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool bResult = false; int nDigits; if ( is_integer(fargs[0], &nDigits) && nDigits <= 9 && is_integer(fargs[1], &nDigits) && nDigits <= 9) { long a = mux_atol(fargs[0]); long b = mux_atol(fargs[1]); bResult = (a >= b); } else { double a = mux_atof(fargs[0]); double b = mux_atof(fargs[1]); bResult = (a >= b); } safe_bool(bResult, buff, bufc); } FUNCTION(fun_lt) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool bResult = false; int nDigits; if ( is_integer(fargs[0], &nDigits) && nDigits <= 9 && is_integer(fargs[1], &nDigits) && nDigits <= 9) { long a = mux_atol(fargs[0]); long b = mux_atol(fargs[1]); bResult = (a < b); } else { double a = mux_atof(fargs[0]); double b = mux_atof(fargs[1]); bResult = (a < b); } safe_bool(bResult, buff, bufc); } FUNCTION(fun_lte) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool bResult = false; int nDigits; if ( is_integer(fargs[0], &nDigits) && nDigits <= 9 && is_integer(fargs[1], &nDigits) && nDigits <= 9) { long a = mux_atol(fargs[0]); long b = mux_atol(fargs[1]); bResult = (a <= b); } else { double a = mux_atof(fargs[0]); double b = mux_atof(fargs[1]); bResult = (a <= b); } safe_bool(bResult, buff, bufc); } FUNCTION(fun_eq) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool bResult = true; int nDigits; if ( is_integer(fargs[0], &nDigits) && nDigits <= 9 && is_integer(fargs[1], &nDigits) && nDigits <= 9) { long a = mux_atol(fargs[0]); long b = mux_atol(fargs[1]); bResult = (a == b); } else { if (strcmp(fargs[0], fargs[1]) != 0) { double a = mux_atof(fargs[0]); double b = mux_atof(fargs[1]); bResult = (a == b); } } safe_bool(bResult, buff, bufc); } FUNCTION(fun_neq) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool bResult = false; int nDigits; if ( is_integer(fargs[0], &nDigits) && nDigits <= 9 && is_integer(fargs[1], &nDigits) && nDigits <= 9) { long a = mux_atol(fargs[0]); long b = mux_atol(fargs[1]); bResult = (a != b); } else { if (strcmp(fargs[0], fargs[1]) != 0) { double a = mux_atof(fargs[0]); double b = mux_atof(fargs[1]); bResult = (a != b); } } safe_bool(bResult, buff, bufc); } /* * --------------------------------------------------------------------------- * * fun_max, fun_min: Return maximum (minimum) value. */ FUNCTION(fun_max) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double maximum = 0.0; for (int i = 0; i < nfargs; i++) { double tval = mux_atof(fargs[i]); if ( i == 0 || tval > maximum) { maximum = tval; } } fval(buff, bufc, maximum); } FUNCTION(fun_min) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double minimum = 0.0; for (int i = 0; i < nfargs; i++) { double tval = mux_atof(fargs[i]); if ( i == 0 || tval < minimum) { minimum = tval; } } fval(buff, bufc, minimum); } /* --------------------------------------------------------------------------- * fun_sign: Returns -1, 0, or 1 based on the the sign of its argument. */ FUNCTION(fun_sign) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double num = mux_atof(fargs[0]); if (num < 0) { safe_str("-1", buff, bufc); } else { safe_bool(num > 0, buff, bufc); } } // fun_isign: Returns -1, 0, or 1 based on the the sign of its argument. // FUNCTION(fun_isign) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); INT64 num = mux_atoi64(fargs[0]); if (num < 0) { safe_str("-1", buff, bufc); } else { safe_bool(num > 0, buff, bufc); } } // shl() and shr() borrowed from PennMUSH 1.50 // FUNCTION(fun_shl) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if ( is_integer(fargs[0], NULL) && is_integer(fargs[1], NULL)) { INT64 a = mux_atoi64(fargs[0]); long b = mux_atol(fargs[1]); safe_i64toa(a << b, buff, bufc); } else { safe_str("#-1 ARGUMENTS MUST BE INTEGERS", buff, bufc); } } FUNCTION(fun_shr) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if ( is_integer(fargs[0], NULL) && is_integer(fargs[1], NULL)) { INT64 a = mux_atoi64(fargs[0]); long b = mux_atol(fargs[1]); safe_i64toa(a >> b, buff, bufc); } else { safe_str("#-1 ARGUMENTS MUST BE INTEGERS", buff, bufc); } } FUNCTION(fun_inc) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (nfargs == 1) { safe_i64toa(mux_atoi64(fargs[0]) + 1, buff, bufc); } else { safe_chr('1', buff, bufc); } } FUNCTION(fun_dec) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (nfargs == 1) { safe_i64toa(mux_atoi64(fargs[0]) - 1, buff, bufc); } else { safe_str("-1", buff, bufc); } } FUNCTION(fun_trunc) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double rArg = mux_atof(fargs[0]); double rIntegerPart; mux_FPRestore(); (void)modf(rArg, &rIntegerPart); mux_FPSet(); #ifdef HAVE_IEEE_FP_FORMAT int fpc = mux_fpclass(rIntegerPart); if (MUX_FPGROUP(fpc) == MUX_FPGROUP_PASS) { #endif // HAVE_IEEE_FP_FORMAT safe_tprintf_str(buff, bufc, "%.0f", rIntegerPart); #ifdef HAVE_IEEE_FP_FORMAT } else { safe_str(mux_FPStrings[MUX_FPCLASS(fpc)], buff, bufc); } #endif // HAVE_IEEE_FP_FORMAT } FUNCTION(fun_fdiv) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double bot = mux_atof(fargs[1]); double top = mux_atof(fargs[0]); #ifndef HAVE_IEEE_FP_SNAN if (bot == 0.0) { if (top > 0.0) { safe_str("+Inf", buff, bufc); } else if (top < 0.0) { safe_str("-Inf", buff, bufc); } else { safe_str("Ind", buff, bufc); } } else { fval(buff, bufc, top/bot); } #else fval(buff, bufc, top/bot); #endif } FUNCTION(fun_idiv) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); INT64 bot, top; bot = mux_atoi64(fargs[1]); if (bot == 0) { safe_str("#-1 DIVIDE BY ZERO", buff, bufc); } else { top = mux_atoi64(fargs[0]); top = i64Division(top, bot); safe_i64toa(top, buff, bufc); } } FUNCTION(fun_floordiv) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); INT64 bot, top; bot = mux_atoi64(fargs[1]); if (bot == 0) { safe_str("#-1 DIVIDE BY ZERO", buff, bufc); } else { top = mux_atoi64(fargs[0]); top = i64FloorDivision(top, bot); safe_i64toa(top, buff, bufc); } } FUNCTION(fun_mod) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); INT64 bot, top; bot = mux_atoi64(fargs[1]); if (bot == 0) { bot = 1; } top = mux_atoi64(fargs[0]); top = i64Mod(top, bot); safe_i64toa(top, buff, bufc); } FUNCTION(fun_remainder) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); INT64 bot, top; bot = mux_atoi64(fargs[1]); if (bot == 0) { bot = 1; } top = mux_atoi64(fargs[0]); top = i64Remainder(top, bot); safe_i64toa(top, buff, bufc); } /* --------------------------------------------------------------------------- * fun_abs: Returns the absolute value of its argument. */ FUNCTION(fun_abs) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double num = mux_atof(fargs[0]); if (0.0 == num) { safe_chr('0', buff, bufc); } else if (num < 0.0) { fval(buff, bufc, -num); } else { fval(buff, bufc, num); } } // fun_iabs: Returns the absolute value of its argument. // FUNCTION(fun_iabs) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); INT64 num = mux_atoi64(fargs[0]); if (num == 0) { safe_chr('0', buff, bufc); } else if (num < 0) { safe_i64toa(-num, buff, bufc); } else { safe_i64toa(num, buff, bufc); } } FUNCTION(fun_dist2d) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double a, b, d; double sum; a = mux_atof(fargs[0]); b = mux_atof(fargs[2]); d = a - b; sum = d * d; a = mux_atof(fargs[1]); b = mux_atof(fargs[3]); d = a - b; sum += d * d; mux_FPRestore(); double result = sqrt(sum); mux_FPSet(); fval(buff, bufc, result); } FUNCTION(fun_dist3d) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double a, b, d; double sum; a = mux_atof(fargs[0]); b = mux_atof(fargs[3]); d = a - b; sum = d * d; a = mux_atof(fargs[1]); b = mux_atof(fargs[4]); d = a - b; sum += d * d; a = mux_atof(fargs[2]); b = mux_atof(fargs[5]); d = a - b; sum += d * d; mux_FPRestore(); double result = sqrt(sum); mux_FPSet(); fval(buff, bufc, result); } //------------------------------------------------------------------------ // Vector functions: VADD, VSUB, VMUL, VCROSS, VMAG, VUNIT, VDIM // Vectors are space-separated numbers. // #define VADD_F 0 #define VSUB_F 1 #define VMUL_F 2 #define VDOT_F 3 #define VCROSS_F 4 static void handle_vectors ( char *vecarg1, char *vecarg2, char *buff, char **bufc, SEP *psep, SEP *posep, int flag ) { // Return if the list is empty. // if (!vecarg1 || !*vecarg1 || !vecarg2 || !*vecarg2) { return; } char **v1 = new char *[(LBUF_SIZE+1)/2]; ISOUTOFMEMORY(v1); char **v2 = new char *[(LBUF_SIZE+1)/2]; ISOUTOFMEMORY(v2); // Split the list up, or return if the list is empty. // int n = list2arr(v1, (LBUF_SIZE+1)/2, vecarg1, psep); int m = list2arr(v2, (LBUF_SIZE+1)/2, vecarg2, psep); // vmul() and vadd() accepts a scalar in the first or second arg, // but everything else has to be same-dimensional. // if ( n != m && !( ( flag == VMUL_F || flag == VADD_F || flag == VSUB_F) && ( n == 1 || m == 1))) { safe_str("#-1 VECTORS MUST BE SAME DIMENSIONS", buff, bufc); delete [] v1; delete [] v2; return; } double scalar; int i; switch (flag) { case VADD_F: // If n or m is 1, this is scalar addition. // otherwise, add element-wise. // if (n == 1) { scalar = mux_atof(v1[0]); for (i = 0; i < m; i++) { if (i != 0) { print_sep(posep, buff, bufc); } fval(buff, bufc, mux_atof(v2[i]) + scalar); } n = m; } else if (m == 1) { scalar = mux_atof(v2[0]); for (i = 0; i < n; i++) { if (i != 0) { print_sep(posep, buff, bufc); } fval(buff, bufc, mux_atof(v1[i]) + scalar); } } else { for (i = 0; i < n; i++) { if (i != 0) { print_sep(posep, buff, bufc); } double a = mux_atof(v1[i]); double b = mux_atof(v2[i]); fval(buff, bufc, a + b); } } break; case VSUB_F: if (n == 1) { // This is a scalar minus a vector. // scalar = mux_atof(v1[0]); for (i = 0; i < m; i++) { if (i != 0) { print_sep(posep, buff, bufc); } fval(buff, bufc, scalar - mux_atof(v2[i])); } } else if (m == 1) { // This is a vector minus a scalar. // scalar = mux_atof(v2[0]); for (i = 0; i < n; i++) { if (i != 0) { print_sep(posep, buff, bufc); } fval(buff, bufc, mux_atof(v1[i]) - scalar); } } else { // This is a vector minus a vector. // for (i = 0; i < n; i++) { if (i != 0) { print_sep(posep, buff, bufc); } double a = mux_atof(v1[i]); double b = mux_atof(v2[i]); fval(buff, bufc, a - b); } } break; case VMUL_F: // If n or m is 1, this is scalar multiplication. // otherwise, multiply elementwise. // if (n == 1) { scalar = mux_atof(v1[0]); for (i = 0; i < m; i++) { if (i != 0) { print_sep(posep, buff, bufc); } fval(buff, bufc, mux_atof(v2[i]) * scalar); } } else if (m == 1) { scalar = mux_atof(v2[0]); for (i = 0; i < n; i++) { if (i != 0) { print_sep(posep, buff, bufc); } fval(buff, bufc, mux_atof(v1[i]) * scalar); } } else { // Vector element-wise product. // for (i = 0; i < n; i++) { if (i != 0) { print_sep(posep, buff, bufc); } double a = mux_atof(v1[i]); double b = mux_atof(v2[i]); fval(buff, bufc, a * b); } } break; case VDOT_F: scalar = 0.0; for (i = 0; i < n; i++) { double a = mux_atof(v1[i]); double b = mux_atof(v2[i]); scalar += a * b; } fval(buff, bufc, scalar); break; case VCROSS_F: // cross product: (a,b,c) x (d,e,f) = (bf - ce, cd - af, ae - bd) // // Or in other words: // // | a b c | // det | d e f | = i(bf-ce) + j(cd-af) + k(ae-bd) // | i j k | // // where i, j, and k are unit vectors in the x, y, and z // cartisian coordinate space and are understood when expressed // in vector form. // if (n != 3) { safe_str("#-1 VECTORS MUST BE DIMENSION OF 3", buff, bufc); } else { double a[2][3]; for (i = 0; i < 3; i++) { a[0][i] = mux_atof(v1[i]); a[1][i] = mux_atof(v2[i]); } fval(buff, bufc, (a[0][1] * a[1][2]) - (a[0][2] * a[1][1])); print_sep(posep, buff, bufc); fval(buff, bufc, (a[0][2] * a[1][0]) - (a[0][0] * a[1][2])); print_sep(posep, buff, bufc); fval(buff, bufc, (a[0][0] * a[1][1]) - (a[0][1] * a[1][0])); } break; default: // If we reached this, we're in trouble. // safe_str("#-1 UNIMPLEMENTED", buff, bufc); } delete [] v1; delete [] v2; } FUNCTION(fun_vadd) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT)) { return; } handle_vectors(fargs[0], fargs[1], buff, bufc, &sep, &osep, VADD_F); } FUNCTION(fun_vsub) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT)) { return; } handle_vectors(fargs[0], fargs[1], buff, bufc, &sep, &osep, VSUB_F); } FUNCTION(fun_vmul) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT)) { return; } handle_vectors(fargs[0], fargs[1], buff, bufc, &sep, &osep, VMUL_F); } FUNCTION(fun_vdot) { // dot product: (a,b,c) . (d,e,f) = ad + be + cf // SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT)) { return; } handle_vectors(fargs[0], fargs[1], buff, bufc, &sep, &osep, VDOT_F); } FUNCTION(fun_vcross) { // cross product: (a,b,c) x (d,e,f) = (bf - ce, cd - af, ae - bd) // SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT)) { return; } handle_vectors(fargs[0], fargs[1], buff, bufc, &sep, &osep, VCROSS_F); } FUNCTION(fun_vmag) { SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } int n, i; double tmp, res = 0.0; // Split the list up, or return if the list is empty. // if (!fargs[0] || !*fargs[0]) { return; } char **v1 = new char *[LBUF_SIZE]; ISOUTOFMEMORY(v1); n = list2arr(v1, LBUF_SIZE, fargs[0], &sep); // Calculate the magnitude. // for (i = 0; i < n; i++) { tmp = mux_atof(v1[i]); res += tmp * tmp; } if (res > 0) { mux_FPRestore(); double result = sqrt(res); mux_FPSet(); fval(buff, bufc, result); } else { safe_chr('0', buff, bufc); } delete [] v1; } FUNCTION(fun_vunit) { SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } int n, i; double tmp, res = 0.0; // Split the list up, or return if the list is empty. // if (!fargs[0] || !*fargs[0]) { return; } char **v1 = new char *[LBUF_SIZE]; ISOUTOFMEMORY(v1); n = list2arr(v1, LBUF_SIZE, fargs[0], &sep); // Calculate the magnitude. // for (i = 0; i < n; i++) { tmp = mux_atof(v1[i]); res += tmp * tmp; } if (res <= 0) { safe_str("#-1 CAN'T MAKE UNIT VECTOR FROM ZERO-LENGTH VECTOR", buff, bufc); delete [] v1; return; } for (i = 0; i < n; i++) { if (i != 0) { print_sep(&sep, buff, bufc); } mux_FPRestore(); double result = sqrt(res); mux_FPSet(); fval(buff, bufc, mux_atof(v1[i]) / result); } delete [] v1; } FUNCTION(fun_floor) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); mux_FPRestore(); double r = floor(mux_atof(fargs[0])); mux_FPSet(); #ifdef HAVE_IEEE_FP_FORMAT int fpc = mux_fpclass(r); if (MUX_FPGROUP(fpc) == MUX_FPGROUP_PASS) { #endif // HAVE_IEEE_FP_FORMAT safe_tprintf_str(buff, bufc, "%.0f", r); #ifdef HAVE_IEEE_FP_FORMAT } else { safe_str(mux_FPStrings[MUX_FPCLASS(fpc)], buff, bufc); } #endif // HAVE_IEEE_FP_FORMAT } FUNCTION(fun_ceil) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); mux_FPRestore(); double r = ceil(mux_atof(fargs[0])); mux_FPSet(); #ifdef HAVE_IEEE_FP_FORMAT int fpc = mux_fpclass(r); if (MUX_FPGROUP(fpc) == MUX_FPGROUP_PASS) { #endif // HAVE_IEEE_FP_FORMAT safe_tprintf_str(buff, bufc, "%.0f", r); #ifdef HAVE_IEEE_FP_FORMAT } else { safe_str(mux_FPStrings[MUX_FPCLASS(fpc)], buff, bufc); } #endif // HAVE_IEEE_FP_FORMAT } FUNCTION(fun_round) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double r = mux_atof(fargs[0]); #ifdef HAVE_IEEE_FP_FORMAT int fpc = mux_fpclass(r); if ( MUX_FPGROUP(fpc) == MUX_FPGROUP_PASS || MUX_FPGROUP(fpc) == MUX_FPGROUP_ZERO) { if (MUX_FPGROUP(fpc) == MUX_FPGROUP_ZERO) { r = 0.0; } #endif // HAVE_IEEE_FP_FORMAT int frac = mux_atol(fargs[1]); safe_str(mux_ftoa(r, true, frac), buff, bufc); #ifdef HAVE_IEEE_FP_FORMAT } else { safe_str(mux_FPStrings[MUX_FPCLASS(fpc)], buff, bufc); } #endif // HAVE_IEEE_FP_FORMAT } FUNCTION(fun_pi) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_str("3.141592653589793", buff, bufc); } FUNCTION(fun_e) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_str("2.718281828459045", buff, bufc); } static double ConvertRDG2R(double d, const char *szUnits) { switch (mux_tolower(szUnits[0])) { case 'd': // Degrees to Radians. // d *= 0.017453292519943295; break; case 'g': // Gradians to Radians. // d *= 0.015707963267948967; break; } return d; } static double ConvertR2RDG(double d, const char *szUnits) { switch (mux_tolower(szUnits[0])) { case 'd': // Radians to Degrees. // d *= 57.29577951308232; break; case 'g': // Radians to Gradians. // d *= 63.66197723675813; break; } return d; } FUNCTION(fun_ctu) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double val = mux_atof(fargs[0]); val = ConvertRDG2R(val, fargs[1]); val = ConvertR2RDG(val, fargs[2]); fval(buff, bufc, val); } FUNCTION(fun_sin) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double d = mux_atof(fargs[0]); if (nfargs == 2) { d = ConvertRDG2R(d, fargs[1]); } mux_FPRestore(); d = sin(d); mux_FPSet(); fval(buff, bufc, d); } FUNCTION(fun_cos) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double d = mux_atof(fargs[0]); if (nfargs == 2) { d = ConvertRDG2R(d, fargs[1]); } mux_FPRestore(); d = cos(d); mux_FPSet(); fval(buff, bufc, d); } FUNCTION(fun_tan) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double d = mux_atof(fargs[0]); if (nfargs == 2) { d = ConvertRDG2R(d, fargs[1]); } mux_FPRestore(); d = tan(d); mux_FPSet(); fval(buff, bufc, d); } FUNCTION(fun_asin) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double val = mux_atof(fargs[0]); #ifndef HAVE_IEEE_FP_SNAN if ((val < -1.0) || (val > 1.0)) { safe_str("Ind", buff, bufc); return; } #endif mux_FPRestore(); val = asin(val); mux_FPSet(); if (nfargs == 2) { val = ConvertR2RDG(val, fargs[1]); } fval(buff, bufc, val); } FUNCTION(fun_acos) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double val = mux_atof(fargs[0]); #ifndef HAVE_IEEE_FP_SNAN if ((val < -1.0) || (val > 1.0)) { safe_str("Ind", buff, bufc); return; } #endif mux_FPRestore(); val = acos(val); mux_FPSet(); if (nfargs == 2) { val = ConvertR2RDG(val, fargs[1]); } fval(buff, bufc, val); } FUNCTION(fun_atan) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double val = mux_atof(fargs[0]); mux_FPRestore(); val = atan(val); mux_FPSet(); if (nfargs == 2) { val = ConvertR2RDG(val, fargs[1]); } fval(buff, bufc, val); } FUNCTION(fun_exp) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double val = mux_atof(fargs[0]); mux_FPRestore(); val = exp(val); mux_FPSet(); fval(buff, bufc, val); } FUNCTION(fun_power) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double val, val1, val2; val1 = mux_atof(fargs[0]); val2 = mux_atof(fargs[1]); #ifndef HAVE_IEEE_FP_SNAN if (val1 < 0.0) { safe_str("Ind", buff, bufc); } else { mux_FPRestore(); val = pow(val1, val2); mux_FPSet(); fval(buff, bufc, val); } #else mux_FPRestore(); val = pow(val1, val2); mux_FPSet(); fval(buff, bufc, val); #endif } FUNCTION(fun_fmod) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double val, val1, val2; val1 = mux_atof(fargs[0]); val2 = mux_atof(fargs[1]); #ifndef HAVE_IEEE_FP_SNAN if (val1 == 0.0) { safe_str("Ind", buff, bufc); } else { mux_FPRestore(); val = fmod(val1, val2); mux_FPSet(); fval(buff, bufc, val); } #else mux_FPRestore(); val = fmod(val1, val2); mux_FPSet(); fval(buff, bufc, val); #endif } FUNCTION(fun_ln) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double val; val = mux_atof(fargs[0]); #ifndef HAVE_IEEE_FP_SNAN if (val < 0.0) { safe_str("Ind", buff, bufc); } else if (val == 0.0) { safe_str("-Inf", buff, bufc); } else { mux_FPRestore(); val = log(val); mux_FPSet(); } #else mux_FPRestore(); val = log(val); mux_FPSet(); #endif fval(buff, bufc, val); } FUNCTION(fun_log) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double val; val = mux_atof(fargs[0]); #ifndef HAVE_IEEE_FP_SNAN if (val < 0.0) { safe_str("Ind", buff, bufc); } else if (val == 0.0) { safe_str("-Inf", buff, bufc); } else { mux_FPRestore(); val = log10(val); mux_FPSet(); } #else mux_FPRestore(); val = log10(val); mux_FPSet(); #endif fval(buff, bufc, val); } FUNCTION(fun_sqrt) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); double val; val = mux_atof(fargs[0]); #ifndef HAVE_IEEE_FP_SNAN if (val < 0.0) { safe_str("Ind", buff, bufc); } else if (val == 0.0) { safe_chr('0', buff, bufc); } else { mux_FPRestore(); val = sqrt(val); mux_FPSet(); } #else mux_FPRestore(); val = sqrt(val); mux_FPSet(); #endif fval(buff, bufc, val); } /* --------------------------------------------------------------------------- * isnum: is the argument a number? */ FUNCTION(fun_isnum) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_bool(is_real(fargs[0]), buff, bufc); } /* --------------------------------------------------------------------------- * israt: is the argument an rational? */ FUNCTION(fun_israt) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_bool(is_rational(fargs[0]), buff, bufc); } /* --------------------------------------------------------------------------- * isint: is the argument an integer? */ FUNCTION(fun_isint) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_bool(is_integer(fargs[0], NULL), buff, bufc); } FUNCTION(fun_and) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool val = true; for (int i = 0; i < nfargs && val; i++) { val = isTRUE(mux_atol(fargs[i])); } safe_bool(val, buff, bufc); } FUNCTION(fun_or) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool val = false; for (int i = 0; i < nfargs && !val; i++) { val = isTRUE(mux_atol(fargs[i])); } safe_bool(val, buff, bufc); } FUNCTION(fun_andbool) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool val = true; for (int i = 0; i < nfargs && val; i++) { val = xlate(fargs[i]); } safe_bool(val, buff, bufc); } FUNCTION(fun_orbool) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool val = false; for (int i = 0; i < nfargs && !val; i++) { val = xlate(fargs[i]); } safe_bool(val, buff, bufc); } FUNCTION(fun_cand) { bool val = true; char *temp = alloc_lbuf("fun_cand"); for (int i = 0; i < nfargs && val && !MuxAlarm.bAlarmed; i++) { char *bp = temp; char *str = fargs[i]; mux_exec(temp, &bp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *bp = '\0'; val = isTRUE(mux_atol(temp)); } free_lbuf(temp); safe_bool(val, buff, bufc); } FUNCTION(fun_cor) { bool val = false; char *temp = alloc_lbuf("fun_cor"); for (int i = 0; i < nfargs && !val && !MuxAlarm.bAlarmed; i++) { char *bp = temp; char *str = fargs[i]; mux_exec(temp, &bp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *bp = '\0'; val = isTRUE(mux_atol(temp)); } free_lbuf(temp); safe_bool(val, buff, bufc); } FUNCTION(fun_candbool) { bool val = true; char *temp = alloc_lbuf("fun_candbool"); for (int i = 0; i < nfargs && val && !MuxAlarm.bAlarmed; i++) { char *bp = temp; char *str = fargs[i]; mux_exec(temp, &bp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *bp = '\0'; val = xlate(temp); } free_lbuf(temp); safe_bool(val, buff, bufc); } FUNCTION(fun_corbool) { bool val = false; char *temp = alloc_lbuf("fun_corbool"); for (int i = 0; i < nfargs && !val && !MuxAlarm.bAlarmed; i++) { char *bp = temp; char *str = fargs[i]; mux_exec(temp, &bp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *bp = '\0'; val = xlate(temp); } free_lbuf(temp); safe_bool(val, buff, bufc); } FUNCTION(fun_xor) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool val = false; for (int i = 0; i < nfargs; i++) { int tval = mux_atol(fargs[i]); val = (val && !tval) || (!val && tval); } safe_bool(val, buff, bufc); } FUNCTION(fun_not) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_bool(!xlate(fargs[0]), buff, bufc); } FUNCTION(fun_t) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if ( nfargs <= 0 || fargs[0][0] == '\0') { safe_chr('0', buff, bufc); } else { safe_bool(xlate(fargs[0]), buff, bufc); } } static const char *bigones[] = { "", "thousand", "million", "billion", "trillion" }; static const char *singles[] = { "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; static const char *teens[] = { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" }; static const char *tens[] = { "", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" }; static const char *th_prefix[] = { "", "ten", "hundred" }; class CSpellNum { public: void SpellNum(const char *p, char *buff_arg, char **bufc_arg); private: void TwoDigits(const char *p); void ThreeDigits(const char *p, size_t iBigOne); void ManyDigits(size_t n, const char *p, bool bHundreds); void FractionalDigits(size_t n, const char *p); void StartWord(void); void AddWord(const char *p); char *buff; char **bufc; bool bNeedSpace; }; void CSpellNum::StartWord(void) { if (bNeedSpace) { safe_chr(' ', buff, bufc); } bNeedSpace = true; } void CSpellNum::AddWord(const char *p) { safe_str(p, buff, bufc); } // Handle two-character sequences. // void CSpellNum::TwoDigits(const char *p) { int n0 = p[0] - '0'; int n1 = p[1] - '0'; if (n0 == 0) { if (n1 != 0) { StartWord(); AddWord(singles[n1]); } return; } else if (n0 == 1) { StartWord(); AddWord(teens[n1]); return; } if (n1 == 0) { StartWord(); AddWord(tens[n0]); } else { StartWord(); AddWord(tens[n0]); AddWord("-"); AddWord(singles[n1]); } } // Handle three-character sequences. // void CSpellNum::ThreeDigits(const char *p, size_t iBigOne) { if ( p[0] == '0' && p[1] == '0' && p[2] == '0') { return; } // Handle hundreds. // if (p[0] != '0') { StartWord(); AddWord(singles[p[0]-'0']); StartWord(); AddWord("hundred"); } TwoDigits(p+1); if (iBigOne > 0) { StartWord(); AddWord(bigones[iBigOne]); } } // Handle a series of patterns of three. // void CSpellNum::ManyDigits(size_t n, const char *p, bool bHundreds) { // Handle special Hundreds cases. // if ( bHundreds && n == 4 && p[1] != '0') { TwoDigits(p); StartWord(); AddWord("hundred"); TwoDigits(p+2); return; } // Handle normal cases. // size_t ndiv = ((n + 2) / 3) - 1; size_t nrem = n % 3; char buf[3]; if (nrem == 0) { nrem = 3; } size_t j = nrem; for (int i = 2; 0 <= i; i--) { if (j) { j--; buf[i] = p[j]; } else { buf[i] = '0'; } } ThreeDigits(buf, ndiv); p += nrem; while (ndiv-- > 0) { ThreeDigits(p, ndiv); p += 3; } } // Handle precision ending for part to the right of the decimal place. // void CSpellNum::FractionalDigits(size_t n, const char *p) { ManyDigits(n, p, false); if ( 0 < n && n < 15) { size_t d = n / 3; size_t r = n % 3; StartWord(); if (r != 0) { AddWord(th_prefix[r]); if (d != 0) { AddWord("-"); } } AddWord(bigones[d]); AddWord("th"); INT64 i64 = mux_atoi64(p); if (i64 != 1) { AddWord("s"); } } } void CSpellNum::SpellNum(const char *number, char *buff_arg, char **bufc_arg) { buff = buff_arg; bufc = bufc_arg; bNeedSpace = false; // Trim Spaces from beginning. // while (mux_isspace(*number)) { number++; } if (*number == '-') { StartWord(); AddWord("negative"); number++; } // Trim Zeroes from Beginning. // while (*number == '0') { number++; } const char *pA = number; while (mux_isdigit(*number)) { number++; } size_t nA = number - pA; const char *pB = NULL; size_t nB = 0; if (*number == '.') { number++; pB = number; while (mux_isdigit(*number)) { number++; } nB = number - pB; } // Skip trailing spaces. // while (mux_isspace(*number)) { number++; } if ( *number || nA >= 16 || nB >= 15) { safe_str("#-1 ARGUMENT MUST BE A NUMBER", buff, bufc); return; } if (nA == 0) { if (nB == 0) { StartWord(); AddWord("zero"); } } else { ManyDigits(nA, pA, true); if (nB) { StartWord(); AddWord("and"); } } if (nB) { FractionalDigits(nB, pB); } } FUNCTION(fun_spellnum) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); CSpellNum sn; sn.SpellNum(fargs[0], buff, bufc); } FUNCTION(fun_roman) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); const char *number = fargs[0]; // Trim Spaces from beginning. // while (mux_isspace(*number)) { number++; } // Trim Zeroes from Beginning. // while (*number == '0') { number++; } const char *pA = number; while (mux_isdigit(*number)) { number++; } size_t nA = number - pA; // Skip trailing spaces. // while (mux_isspace(*number)) { number++; } // Validate that argument is numeric with a value between 1 and 3999. // if (*number || nA < 1) { safe_str("#-1 ARGUMENT MUST BE A POSITIVE NUMBER", buff, bufc); return; } else if ( nA > 4 || ( nA == 1 && pA[0] == '0') || ( nA == 4 && '3' < pA[0])) { safe_range(buff, bufc); return; } // I:1, V:5, X:10, L:50, C:100, D:500, M:1000 // // Ones: _ I II III IV V VI VII VIII IX // Tens: _ X XX XXX XL L LX LXX LXXX XC // Hundreds: _ C CC CCC CD D DC DCC DCCC CM // Thousands: _ M MM MMM // static const char aLetters[4][3] = { { 'I', 'V', 'X' }, { 'X', 'L', 'C' }, { 'C', 'D', 'M' }, { 'M', ' ', ' ' } }; static const char *aCode[10] = { "", "1", "11", "111", "12", "2", "21", "211", "2111", "13" }; while (nA--) { const char *pCode = aCode[*pA - '0']; const char *pLetters = aLetters[nA]; while (*pCode) { safe_chr(pLetters[*pCode - '1'], buff, bufc); pCode++; } pA++; } } /*------------------------------------------------------------------------- * List-based numeric functions. */ FUNCTION(fun_land) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool bValue = true; if (0 < nfargs) { SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } char *cp = trim_space_sep(fargs[0], &sep); while (cp && bValue) { char *curr = split_token(&cp, &sep); bValue = isTRUE(mux_atol(curr)); } } safe_bool(bValue, buff, bufc); } FUNCTION(fun_lor) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool bValue = false; if (0 < nfargs) { SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } char *cp = trim_space_sep(fargs[0], &sep); while (cp && !bValue) { char *curr = split_token(&cp, &sep); bValue = isTRUE(mux_atol(curr)); } } safe_bool(bValue, buff, bufc); } FUNCTION(fun_band) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); UINT64 val = UINT64_MAX_VALUE; for (int i = 0; i < nfargs; i++) { if (is_integer(fargs[i], NULL)) { val &= mux_atoi64(fargs[i]); } else { safe_str("#-1 ARGUMENTS MUST BE INTEGERS", buff, bufc); return; } } safe_i64toa(val, buff, bufc); } FUNCTION(fun_bor) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); UINT64 val = 0; for (int i = 0; i < nfargs; i++) { if (is_integer(fargs[i], NULL)) { val |= mux_atoi64(fargs[i]); } else { safe_str("#-1 ARGUMENTS MUST BE INTEGERS", buff, bufc); return; } } safe_i64toa(val, buff, bufc); } FUNCTION(fun_bnand) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if ( is_integer(fargs[0], NULL) && is_integer(fargs[1], NULL)) { INT64 a = mux_atoi64(fargs[0]); INT64 b = mux_atoi64(fargs[1]); safe_i64toa(a & ~(b), buff, bufc); } else { safe_str("#-1 ARGUMENTS MUST BE INTEGERS", buff, bufc); } } FUNCTION(fun_bxor) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); UINT64 val = 0; for (int i = 0; i < nfargs; i++) { if (is_integer(fargs[i], NULL)) { val ^= mux_atoi64(fargs[i]); } else { safe_str("#-1 ARGUMENTS MUST BE INTEGERS", buff, bufc); return; } } safe_i64toa(val, buff, bufc); } FUNCTION(fun_crc32) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); UINT32 ulCRC32 = 0; for (int i = 0; i < nfargs; i++) { size_t n = strlen(fargs[i]); ulCRC32 = CRC32_ProcessBuffer(ulCRC32, fargs[i], n); } safe_i64toa(ulCRC32, buff, bufc); } FUNCTION(fun_sha1) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int i; SHA1_CONTEXT shac; SHA1_Init(&shac); for (i = 0; i < nfargs; i++) { SHA1_Compute(&shac, strlen(fargs[i]), fargs[i]); } SHA1_Final(&shac); for (i = 0; i <= 4; i++) { char buf[9]; mux_sprintf(buf, sizeof(buf), "%08X", shac.H[i]); safe_str(buf, buff, bufc); } } mux2.6/src/timeutil.cpp0000600000175000017500000030337011025753746015144 0ustar sdennissdennis/*! \file timeutil.cpp * CLinearTimeAbsolute and CLinearTimeDelta modules. * * $Id: timeutil.cpp 2734 2007-10-28 23:02:55Z brazilofmux $ * * Date/Time code based on algorithms presented in "Calendrical Calculations", * Cambridge Press, 1998. * * The two primary classes are CLinearTimeAbsolute and CLinearTimeDelta deal * with civil time from a fixed Epoch and time differences generally, * respectively. * * This file also contains code related to parsing date strings and glossing * over time-related platform differences. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" // for tzset() and localtime() // #include #include "timeutil.h" #include "stringutil.h" CMuxAlarm MuxAlarm; #ifdef SMALLEST_INT_GTE_NEG_QUOTIENT // The following functions provide a consistent division/modulus function // regardless of how the platform chooses to provide this function. // // Confused yet? Here's an example: // // SMALLEST_INT_GTE_NEG_QUOTIENT indicates that this platform computes // division and modulus like so: // // -9/5 ==> -1 and -9%5 ==> -4 // and (-9/5)*5 + (-9%5) ==> -1*5 + -4 ==> -5 + -4 ==> -9 // // The iMod() function uses this to provide LARGEST_INT_LTE_NEG_QUOTIENT // behavior (required by much math). This behavior computes division and // modulus like so: // // -9/5 ==> -2 and -9%5 ==> 1 // and (-9/5)*5 + (-9%5) ==> -2*5 + 1 ==> -10 + 1 ==> -9 // // Provide LLEQ modulus on a SGEQ platform. // int iMod(int x, int y) { if (y < 0) { if (x <= 0) { return x % y; } else { return ((x-1) % y) + y + 1; } } else { if (x < 0) { return ((x+1) % y) + y - 1; } else { return x % y; } } } INT64 i64Mod(INT64 x, INT64 y) { if (y < 0) { if (x <= 0) { return x % y; } else { return ((x-1) % y) + y + 1; } } else { if (x < 0) { return ((x+1) % y) + y - 1; } else { return x % y; } } } // Provide SGEQ modulus on a SGEQ platform. // DCL_INLINE int iRemainder(int x, int y) { return x % y; } // Provide SGEQ division on a SGEQ platform. // DCL_INLINE int iDivision(int x, int y) { return x / y; } // Provide LLEQ division on a SGEQ platform. // static int iFloorDivision(int x, int y) { if (y < 0) { if (x <= 0) { return x / y; } else { return (x - y - 1) / y; } } else { if (x < 0) { return (x - y + 1) / y; } else { return x / y; } } } INT64 i64FloorDivision(INT64 x, INT64 y) { if (y < 0) { if (x <= 0) { return x / y; } else { return (x - y - 1) / y; } } else { if (x < 0) { return (x - y + 1) / y; } else { return x / y; } } } int iFloorDivisionMod(int x, int y, int *piMod) { if (y < 0) { if (x <= 0) { *piMod = x % y; return x / y; } else { *piMod = ((x-1) % y) + y + 1; return (x - y - 1) / y; } } else { if (x < 0) { *piMod = ((x+1) % y) + y - 1; return (x - y + 1) / y; } else { *piMod = x % y; return x / y; } } } static INT64 i64FloorDivisionMod(INT64 x, INT64 y, INT64 *piMod) { if (y < 0) { if (x <= 0) { *piMod = x % y; return x / y; } else { *piMod = ((x-1) % y) + y + 1; return (x - y - 1) / y; } } else { if (x < 0) { *piMod = ((x+1) % y) + y - 1; return (x - y + 1) / y; } else { *piMod = x % y; return x / y; } } } #if 0 int iCeilingDivision(int x, int y) { if (x < 0) { return x / y; } else { return (x + y - 1) / y; } } INT64 i64CeilingDivision(INT64 x, INT64 y) { if (x < 0) { return x / y; } else { return (x + y - 1) / y; } } #endif // 0 #else // LARGEST_INT_LTE_NEG_QUOTIENT // Provide LLEQ modulus on a LLEQ platform. // int DCL_INLINE iMod(int x, int y) { return x % y; } // Provide a SGEQ modulus on a LLEQ platform. // int iRemainder(int x, int y) { if (y < 0) { if (x <= 0) { return x % y; } else { return ((x+1) % y) - y - 1; } } else { if (x < 0) { return ((x-1) % y) - y + 1; } else { return x % y; } } } INT64 i64Remainder(INT64 x, INT64 y) { if (y < 0) { if (x <= 0) { return x % y; } else { return ((x+1) % y) - y - 1; } } else { if (x < 0) { return ((x-1) % y) - y + 1; } else { return x % y; } } } // Provide SGEQ division on a LLEQ platform. // int iDivision(int x, int y) { if (y < 0) { if (x <= 0) { return x / y; } else { return (x + y + 1) / y; } } else { if (x < 0) { return (x + y - 1) / y; } else { return x / y; } } } INT64 i64Division(INT64 x, INT64 y) { if (y < 0) { if (x <= 0) { return x / y; } else { return (x + y + 1) / y; } } else { if (x < 0) { return (x + y - 1) / y; } else { return x / y; } } } // Provide a LLEQ division on a LLEQ platform. // int DCL_INLINE iFloorDivision(int x, int y) { return x / y; } INT64 DCL_INLINE i64FloorDivisionMod(INT64 x, INT64 y, INT64 *piMod) { *piMod = x % y; return x / y; } #endif // LARGEST_INT_LTE_NEG_QUOTIENT #if 0 static int iModAdjusted(int x, int y) { return iMod(x - 1, y) + 1; } static INT64 i64ModAdjusted(INT64 x, INT64 y) { return i64Mod(x - 1, y) + 1; } #endif // 0 #ifdef WIN32 const INT64 FACTOR_100NS_PER_SECOND = 10000000i64; #else // WIN32 const INT64 FACTOR_100NS_PER_SECOND = 10000000ull; #endif // WIN32 const INT64 FACTOR_100NS_PER_MINUTE = FACTOR_100NS_PER_SECOND*60; const INT64 FACTOR_100NS_PER_HOUR = FACTOR_100NS_PER_MINUTE*60; const INT64 FACTOR_100NS_PER_DAY = FACTOR_100NS_PER_HOUR*24; const INT64 FACTOR_100NS_PER_WEEK = FACTOR_100NS_PER_DAY*7; int CLinearTimeAbsolute::m_nCount = 0; char CLinearTimeAbsolute::m_Buffer[204]; char CLinearTimeDelta::m_Buffer[204]; static void GetUTCLinearTime(INT64 *plt); bool operator<(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb) { return lta.m_tAbsolute < ltb.m_tAbsolute; } bool operator>(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb) { return lta.m_tAbsolute > ltb.m_tAbsolute; } bool operator==(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb) { return lta.m_tAbsolute == ltb.m_tAbsolute; } bool operator==(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb) { return lta.m_tDelta == ltb.m_tDelta; } bool operator!=(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb) { return lta.m_tDelta != ltb.m_tDelta; } bool operator<=(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb) { return lta.m_tDelta <= ltb.m_tDelta; } bool operator<=(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb) { return lta.m_tAbsolute <= ltb.m_tAbsolute; } CLinearTimeAbsolute operator-(const CLinearTimeAbsolute& lta, const CLinearTimeDelta& ltd) { CLinearTimeAbsolute t; t.m_tAbsolute = lta.m_tAbsolute - ltd.m_tDelta; return t; } CLinearTimeAbsolute::CLinearTimeAbsolute(const CLinearTimeAbsolute& ltaOrigin, const CLinearTimeDelta& ltdOffset) { m_tAbsolute = ltaOrigin.m_tAbsolute + ltdOffset.m_tDelta; } static bool ParseFractionalSecondsString(INT64 &i64, char *str) { bool bMinus = false; i64 = 0; bool bGotOne; // Leading spaces. // while (mux_isspace(*str)) { str++; } // Leading minus // if (*str == '-') { bMinus = true; str++; // But not if just a minus // if (!*str) { return false; } } // Need at least one digit. // bGotOne = false; char *pIntegerStart = str; if (mux_isdigit(*str)) { bGotOne = true; str++; } // The number (int) // while (mux_isdigit(*str)) { str++; } char *pIntegerEnd = str; // Decimal point. // if (*str == '.') { str++; } // Need at least one digit // char *pFractionalStart = str; if (mux_isdigit(*str)) { bGotOne = true; str++; } // The number (fract) // while (mux_isdigit(*str)) { str++; } char *pFractionalEnd = str; // Trailing spaces. // while (mux_isspace(*str)) { str++; } if (*str || !bGotOne) { return false; } #define PFSS_PRECISION 7 char aBuffer[64]; size_t nBufferAvailable = sizeof(aBuffer) - PFSS_PRECISION - 1; char *p = aBuffer; // Sign. // if (bMinus) { *p++ = '-'; nBufferAvailable--; } // Integer part. // bool bOverUnderflow = false; size_t n = pIntegerEnd - pIntegerStart; if (n > 0) { if (n > nBufferAvailable) { bOverUnderflow = true; n = nBufferAvailable; } memcpy(p, pIntegerStart, n); p += n; nBufferAvailable -= n; } // Fractional part. // n = pFractionalEnd - pFractionalStart; if (n > 0) { if (n > PFSS_PRECISION) { n = PFSS_PRECISION; } memcpy(p, pFractionalStart, n); p += n; nBufferAvailable -= n; } // Handle trailing zeroes. // n = PFSS_PRECISION - n; if (n > 0) { memset(p, '0', n); p += n; } *p++ = '\0'; if (bOverUnderflow) { if (bMinus) { i64 = INT64_MIN_VALUE; } else { i64 = INT64_MAX_VALUE; } } else { i64 = mux_atoi64(aBuffer); } return true; } static void ConvertToSecondsString(char *buffer, INT64 n64, int nFracDigits) { INT64 Leftover; INT64 lt = i64FloorDivisionMod(n64, FACTOR_100NS_PER_SECOND, &Leftover); size_t n = mux_i64toa(lt, buffer); if (Leftover == 0) { return; } // Sanitize Precision Request. // const int maxFracDigits = 7; const int minFracDigits = 0; if (nFracDigits < minFracDigits) { nFracDigits = minFracDigits; } else if (maxFracDigits < nFracDigits) { nFracDigits = maxFracDigits; } if (0 < nFracDigits) { char *p = buffer + n; *p++ = '.'; char *q = p; char buf[maxFracDigits+1]; size_t m = mux_i64toa(Leftover, buf); memset(p, '0', maxFracDigits - m); p += maxFracDigits - m; memcpy(p, buf, m); p = q + nFracDigits - 1; while (*p == '0') { p--; } p++; *p = '\0'; } } char *CLinearTimeDelta::ReturnSecondsString(int nFracDigits) { ConvertToSecondsString(m_Buffer, m_tDelta, nFracDigits); return m_Buffer; } char *CLinearTimeAbsolute::ReturnSecondsString(int nFracDigits) { ConvertToSecondsString(m_Buffer, m_tAbsolute - EPOCH_OFFSET, nFracDigits); return m_Buffer; } CLinearTimeAbsolute::CLinearTimeAbsolute(const CLinearTimeAbsolute <a) { m_tAbsolute = lta.m_tAbsolute; } CLinearTimeAbsolute::CLinearTimeAbsolute(void) { m_tAbsolute = 0; } CLinearTimeDelta::CLinearTimeDelta(void) { m_tDelta = 0; } CLinearTimeDelta::CLinearTimeDelta(INT64 arg_t100ns) { m_tDelta = arg_t100ns; } void CLinearTimeDelta::ReturnTimeValueStruct(struct timeval *tv) { INT64 Leftover; tv->tv_sec = static_cast(i64FloorDivisionMod(m_tDelta, FACTOR_100NS_PER_SECOND, &Leftover)); tv->tv_usec = static_cast(i64FloorDivision(Leftover, FACTOR_100NS_PER_MICROSECOND)); } #ifdef HAVE_NANOSLEEP void CLinearTimeDelta::ReturnTimeSpecStruct(struct timespec *ts) { INT64 Leftover; ts->tv_sec = static_cast(i64FloorDivisionMod(m_tDelta, FACTOR_100NS_PER_SECOND, &Leftover)); ts->tv_nsec = static_cast(Leftover*FACTOR_NANOSECONDS_PER_100NS); } #endif // HAVE_NANOSLEEP void CLinearTimeDelta::SetTimeValueStruct(struct timeval *tv) { m_tDelta = FACTOR_100NS_PER_SECOND * tv->tv_sec + FACTOR_100NS_PER_MICROSECOND * tv->tv_usec; } // Time string format is usually 24 characters long, in format // Ddd Mmm DD HH:MM:SS YYYY // // However, the year may be larger than 4 characters. // const char *DayOfWeekString[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static const char daystab[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; const char *monthtab[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; void CLinearTimeDelta::SetMilliseconds(unsigned long arg_dwMilliseconds) { m_tDelta = arg_dwMilliseconds * FACTOR_100NS_PER_MILLISECOND; } long CLinearTimeDelta::ReturnMilliseconds(void) { return static_cast(m_tDelta/FACTOR_100NS_PER_MILLISECOND); } INT64 CLinearTimeDelta::ReturnMicroseconds(void) { return m_tDelta/FACTOR_100NS_PER_MICROSECOND; } void CLinearTimeDelta::SetSecondsString(char *arg_szSeconds) { ParseFractionalSecondsString(m_tDelta, arg_szSeconds); } void CLinearTimeDelta::SetSeconds(INT64 arg_tSeconds) { m_tDelta = arg_tSeconds * FACTOR_100NS_PER_SECOND; } void CLinearTimeDelta::Set100ns(INT64 arg_t100ns) { m_tDelta = arg_t100ns; } INT64 CLinearTimeDelta::Return100ns(void) { return m_tDelta; } void CLinearTimeAbsolute::Set100ns(INT64 arg_t100ns) { m_tAbsolute = arg_t100ns; } INT64 CLinearTimeAbsolute::Return100ns(void) { return m_tAbsolute; } void CLinearTimeAbsolute::SetSeconds(INT64 arg_tSeconds) { m_tAbsolute = arg_tSeconds; m_tAbsolute *= FACTOR_100NS_PER_SECOND; // Epoch difference between (00:00:00 UTC, January 1, 1970) and // (00:00:00 UTC, January 1, 1601). // m_tAbsolute += EPOCH_OFFSET; } INT64 CLinearTimeAbsolute::ReturnSeconds(void) { // INT64 is in hundreds of nanoseconds. // And the Epoch is 0:00 1/1/1601 instead of 0:00 1/1/1970 // return i64FloorDivision(m_tAbsolute - EPOCH_OFFSET, FACTOR_100NS_PER_SECOND); } bool isLeapYear(long iYear) { if (iMod(iYear, 4) != 0) { // Not a leap year. // return false; } unsigned long wMod = iMod(iYear, 400); if ((wMod == 100) || (wMod == 200) || (wMod == 300)) { // Not a leap year. // return false; } return true; } static bool isValidDate(int iYear, int iMonth, int iDay) { if (iYear < -27256 || 30826 < iYear) { return false; } if (iMonth < 1 || 12 < iMonth) { return false; } if (iDay < 1 || daystab[iMonth-1] < iDay) { return false; } if (iMonth == 2 && iDay == 29 && !isLeapYear(iYear)) { return false; } return true; } static int FixedFromGregorian(int iYear, int iMonth, int iDay) { iYear = iYear - 1; int iFixedDay = 365 * iYear; iFixedDay += iFloorDivision(iYear, 4); iFixedDay -= iFloorDivision(iYear, 100); iFixedDay += iFloorDivision(iYear, 400); iFixedDay += iFloorDivision(367 * iMonth - 362, 12); iFixedDay += iDay; if (iMonth > 2) { if (isLeapYear(iYear+1)) { iFixedDay -= 1; } else { iFixedDay -= 2; } } // At this point, iFixedDay has an epoch of 1 R.D. // return iFixedDay; } static int FixedFromGregorian_Adjusted(int iYear, int iMonth, int iDay) { int iFixedDay = FixedFromGregorian(iYear, iMonth, iDay); // At this point, iFixedDay has an epoch of 1 R.D. // We need an Epoch of (00:00:00 UTC, January 1, 1601) // return iFixedDay - 584389; } // Epoch of iFixedDay should be 1 R.D. // static void GregorianFromFixed(int iFixedDay, int &iYear, int &iMonth, int &iDayOfYear, int &iDayOfMonth, int &iDayOfWeek) { int d0 = iFixedDay - 1; int d1, n400 = iFloorDivisionMod(d0, 146097, &d1); int d2, n100 = iFloorDivisionMod(d1, 36524, &d2); int d3, n4 = iFloorDivisionMod(d2, 1461, &d3); int d4, n1 = iFloorDivisionMod(d3, 365, &d4); d4 = d4 + 1; iYear = 400*n400 + 100*n100 + 4*n4 + n1; if (n100 != 4 && n1 != 4) { iYear = iYear + 1; } static int cache_iYear = 99999; static int cache_iJan1st = 0; static int cache_iMar1st = 0; int iFixedDayOfJanuary1st; int iFixedDayOfMarch1st; if (iYear == cache_iYear) { iFixedDayOfJanuary1st = cache_iJan1st; iFixedDayOfMarch1st = cache_iMar1st; } else { cache_iYear = iYear; cache_iJan1st = iFixedDayOfJanuary1st = FixedFromGregorian(iYear, 1, 1); cache_iMar1st = iFixedDayOfMarch1st = FixedFromGregorian(iYear, 3, 1); } int iPriorDays = iFixedDay - iFixedDayOfJanuary1st; int iCorrection; if (iFixedDay < iFixedDayOfMarch1st) { iCorrection = 0; } else if (isLeapYear(iYear)) { iCorrection = 1; } else { iCorrection = 2; } iMonth = (12*(iPriorDays+iCorrection)+373)/367; iDayOfMonth = iFixedDay - FixedFromGregorian(iYear, iMonth, 1) + 1; iDayOfYear = iPriorDays + 1; // Calculate the Day of week using the linear progression of days. // iDayOfWeek = iMod(iFixedDay, 7); } static void GregorianFromFixed_Adjusted(int iFixedDay, int &iYear, int &iMonth, int &iDayOfYear, int &iDayOfMonth, int &iDayOfWeek) { // We need to convert the Epoch to 1 R.D. from // (00:00:00 UTC, January 1, 1601) // GregorianFromFixed(iFixedDay + 584389, iYear, iMonth, iDayOfYear, iDayOfMonth, iDayOfWeek); } // do_convtime() // // converts time string to time structure (fielded time). Returns 1 on // success, 0 on fail. Time string format is: // // [Ddd] Mmm DD HH:MM:SS YYYY // // The initial Day-of-week token is optional. // static int MonthTabHash[12] = { 0x004a414e, 0x00464542, 0x004d4152, 0x00415052, 0x004d4159, 0x004a554e, 0x004a554c, 0x00415547, 0x00534550, 0x004f4354, 0x004e4f56, 0x00444543 }; static bool ParseThreeLetters(const char **pp, int *piHash) { *piHash = 0; // Skip Initial spaces // const char *p = *pp; while (*p == ' ') { p++; } // Parse space-separate token. // const char *q = p; int iHash = 0; while (*q && *q != ' ') { if (!mux_isalpha(*q)) { return false; } iHash = (iHash << 8) | mux_toupper(*q); q++; } // Must be exactly 3 letters long. // if (q - p != 3) { return false; } p = q; // Skip final spaces // while (*p == ' ') { p++; } *pp = p; *piHash = iHash; return true; } static void ParseDecimalSeconds(size_t n, const char *p, unsigned short *iMilli, unsigned short *iMicro, unsigned short *iNano) { char aBuffer[10]; if (n > sizeof(aBuffer) - 1) { n = sizeof(aBuffer) - 1; } memcpy(aBuffer, p, n); memset(aBuffer + n, '0', sizeof(aBuffer) - n - 1); aBuffer[sizeof(aBuffer) - 1] = '\0'; long ns = mux_atol(aBuffer); *iNano = static_cast(ns % 1000); ns /= 1000; *iMicro = static_cast(ns % 1000); *iMilli = static_cast(ns / 1000); } static bool do_convtime(const char *str, FIELDEDTIME *ft) { memset(ft, 0, sizeof(FIELDEDTIME)); if (!str || !ft) { return false; } // Day-of-week OR month. // const char *p = str; int i, iHash; if (!ParseThreeLetters(&p, &iHash)) { return false; } for (i = 0; (i < 12) && iHash != MonthTabHash[i]; i++) { ; // Nothing. } if (i == 12) { // The above three letters were probably the Day-Of-Week, the // next three letters are required to be the month name. // if (!ParseThreeLetters(&p, &iHash)) { return false; } for (i = 0; (i < 12) && iHash != MonthTabHash[i]; i++) { ; // Nothing. } if (i == 12) { return false; } } // January = 1, February = 2, etc. // ft->iMonth = static_cast(i + 1); // Day of month. // ft->iDayOfMonth = (unsigned short)mux_atol(p); if (ft->iDayOfMonth < 1 || daystab[i] < ft->iDayOfMonth) { return false; } while (*p && *p != ' ') p++; while (*p == ' ') p++; // Hours // ft->iHour = (unsigned short)mux_atol(p); if (ft->iHour > 23 || (ft->iHour == 0 && *p != '0')) { return false; } while (*p && *p != ':') p++; if (*p == ':') p++; while (*p == ' ') p++; // Minutes // ft->iMinute = (unsigned short)mux_atol(p); if (ft->iMinute > 59 || (ft->iMinute == 0 && *p != '0')) { return false; } while (*p && *p != ':') p++; if (*p == ':') p++; while (*p == ' ') p++; // Seconds // ft->iSecond = (unsigned short)mux_atol(p); if (ft->iSecond > 59 || (ft->iSecond == 0 && *p != '0')) { return false; } while (mux_isdigit(*p)) { p++; } // Milliseconds, Microseconds, and Nanoseconds // if (*p == '.') { p++; size_t n; const char *q = strchr(p, ' '); if (q) { n = q - p; } else { n = strlen(p); } ParseDecimalSeconds(n, p, &ft->iMillisecond, &ft->iMicrosecond, &ft->iNanosecond); } while (*p && *p != ' ') p++; while (*p == ' ') p++; // Year // ft->iYear = (short)mux_atol(p); while (mux_isdigit(*p)) { p++; } while (*p == ' ') p++; if (*p != '\0') { return false; } // DayOfYear and DayOfWeek // ft->iDayOfYear = 0; ft->iDayOfWeek = 0; return isValidDate(ft->iYear, ft->iMonth, ft->iDayOfMonth); } CLinearTimeDelta::CLinearTimeDelta(CLinearTimeAbsolute t0, CLinearTimeAbsolute t1) { m_tDelta = t1.m_tAbsolute - t0.m_tAbsolute; } long CLinearTimeDelta::ReturnDays(void) { return static_cast(m_tDelta/FACTOR_100NS_PER_DAY); } long CLinearTimeDelta::ReturnSeconds(void) { return static_cast(m_tDelta/FACTOR_100NS_PER_SECOND); } bool CLinearTimeAbsolute::ReturnFields(FIELDEDTIME *arg_tStruct) { return LinearTimeToFieldedTime(m_tAbsolute, arg_tStruct); } bool CLinearTimeAbsolute::SetString(const char *arg_tBuffer) { FIELDEDTIME ft; if (do_convtime(arg_tBuffer, &ft)) { if (FieldedTimeToLinearTime(&ft, &m_tAbsolute)) { return true; } } m_tAbsolute = 0; return false; } void CLinearTimeDelta::operator+=(const CLinearTimeDelta& ltd) { m_tDelta += ltd.m_tDelta; } CLinearTimeDelta operator-(const CLinearTimeAbsolute& ltaA, const CLinearTimeAbsolute& ltaB) { CLinearTimeDelta ltd; ltd.m_tDelta = ltaA.m_tAbsolute - ltaB.m_tAbsolute; return ltd; } CLinearTimeDelta operator-(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb) { CLinearTimeDelta ltd; ltd.m_tDelta = lta.m_tDelta - ltb.m_tDelta; return ltd; } CLinearTimeAbsolute operator+(const CLinearTimeAbsolute& ltaA, const CLinearTimeDelta& ltdB) { CLinearTimeAbsolute lta; lta.m_tAbsolute = ltaA.m_tAbsolute + ltdB.m_tDelta; return lta; } void CLinearTimeAbsolute::operator=(const CLinearTimeAbsolute& lta) { m_tAbsolute = lta.m_tAbsolute; } CLinearTimeDelta operator*(const CLinearTimeDelta& ltd, int Scale) { CLinearTimeDelta ltdResult; ltdResult.m_tDelta = ltd.m_tDelta * Scale; return ltdResult; } int operator/(const CLinearTimeDelta& ltdA, const CLinearTimeDelta& ltdB) { int iResult = static_cast(ltdA.m_tDelta / ltdB.m_tDelta); return iResult; } bool operator<(const CLinearTimeDelta& ltdA, const CLinearTimeDelta& ltdB) { return ltdA.m_tDelta < ltdB.m_tDelta; } bool operator>(const CLinearTimeDelta& ltdA, const CLinearTimeDelta& ltdB) { return ltdA.m_tDelta > ltdB.m_tDelta; } void CLinearTimeAbsolute::operator-=(const CLinearTimeDelta& ltd) { m_tAbsolute -= ltd.m_tDelta; } void CLinearTimeAbsolute::operator+=(const CLinearTimeDelta& ltd) { m_tAbsolute += ltd.m_tDelta; } bool CLinearTimeAbsolute::SetFields(FIELDEDTIME *arg_tStruct) { m_tAbsolute = 0; return FieldedTimeToLinearTime(arg_tStruct, &m_tAbsolute); } static void SetStructTm(FIELDEDTIME *ft, struct tm *ptm) { ft->iYear = static_cast(ptm->tm_year + 1900); ft->iMonth = static_cast(ptm->tm_mon + 1); ft->iDayOfMonth = static_cast(ptm->tm_mday); ft->iDayOfWeek = static_cast(ptm->tm_wday); ft->iDayOfYear = 0; ft->iHour = static_cast(ptm->tm_hour); ft->iMinute = static_cast(ptm->tm_min); ft->iSecond = static_cast(ptm->tm_sec); } void CLinearTimeAbsolute::ReturnUniqueString(char *buffer, size_t nBuffer) { FIELDEDTIME ft; if (LinearTimeToFieldedTime(m_tAbsolute, &ft)) { mux_sprintf(buffer, nBuffer, "%04d%02d%02d-%02d%02d%02d", ft.iYear, ft.iMonth, ft.iDayOfMonth, ft.iHour, ft.iMinute, ft.iSecond); } else { mux_sprintf(buffer, nBuffer, "%03d", m_nCount++); } } char *CLinearTimeAbsolute::ReturnDateString(int nFracDigits) { FIELDEDTIME ft; if (LinearTimeToFieldedTime(m_tAbsolute, &ft)) { // Sanitize Precision Request. // const int maxFracDigits = 7; const int minFracDigits = 0; if (nFracDigits < minFracDigits) { nFracDigits = minFracDigits; } else if (maxFracDigits < nFracDigits) { nFracDigits = maxFracDigits; } char buffer[11]; buffer[0] = '\0'; if ( 0 < nFracDigits && ( ft.iMillisecond != 0 || ft.iMicrosecond != 0 || ft.iNanosecond != 0)) { mux_sprintf(buffer, sizeof(buffer), ".%03d%03d%03d", ft.iMillisecond, ft.iMicrosecond, ft.iNanosecond); // Remove trailing zeros. // char *p = (buffer + 1) + (nFracDigits - 1); while (*p == '0') { p--; } p++; *p = '\0'; } mux_sprintf(m_Buffer, sizeof(m_Buffer), "%s %s %02d %02d:%02d:%02d%s %04d", DayOfWeekString[ft.iDayOfWeek], monthtab[ft.iMonth-1], ft.iDayOfMonth, ft.iHour, ft.iMinute, ft.iSecond, buffer, ft.iYear); } else { m_Buffer[0] = '\0'; } return m_Buffer; } void CLinearTimeAbsolute::GetUTC(void) { GetUTCLinearTime(&m_tAbsolute); } void CLinearTimeAbsolute::GetLocal(void) { GetUTCLinearTime(&m_tAbsolute); UTC2Local(); } bool FieldedTimeToLinearTime(FIELDEDTIME *ft, INT64 *plt) { if (!isValidDate(ft->iYear, ft->iMonth, ft->iDayOfMonth)) { *plt = 0; return false; } int iFixedDay = FixedFromGregorian_Adjusted(ft->iYear, ft->iMonth, ft->iDayOfMonth); ft->iDayOfWeek = static_cast(iMod(iFixedDay+1, 7)); INT64 lt; lt = iFixedDay * FACTOR_100NS_PER_DAY; lt += ft->iHour * FACTOR_100NS_PER_HOUR; lt += ft->iMinute * FACTOR_100NS_PER_MINUTE; lt += ft->iSecond * FACTOR_100NS_PER_SECOND; lt += ft->iMicrosecond * FACTOR_100NS_PER_MICROSECOND; lt += ft->iMillisecond * FACTOR_100NS_PER_MILLISECOND; lt += ft->iNanosecond / FACTOR_NANOSECONDS_PER_100NS; *plt = lt; return true; } bool LinearTimeToFieldedTime(INT64 lt, FIELDEDTIME *ft) { INT64 ns100; int iYear, iMonth, iDayOfYear, iDayOfMonth, iDayOfWeek; memset(ft, 0, sizeof(FIELDEDTIME)); int d0 = static_cast(i64FloorDivisionMod(lt, FACTOR_100NS_PER_DAY, &ns100)); GregorianFromFixed_Adjusted(d0, iYear, iMonth, iDayOfYear, iDayOfMonth, iDayOfWeek); if (!isValidDate(iYear, iMonth, iDayOfMonth)) { return false; } ft->iYear = static_cast(iYear); ft->iMonth = static_cast(iMonth); ft->iDayOfYear = static_cast(iDayOfYear); ft->iDayOfMonth = static_cast(iDayOfMonth); ft->iDayOfWeek = static_cast(iDayOfWeek); ft->iHour = static_cast(ns100 / FACTOR_100NS_PER_HOUR); ns100 = ns100 % FACTOR_100NS_PER_HOUR; ft->iMinute = static_cast(ns100 / FACTOR_100NS_PER_MINUTE); ns100 = ns100 % FACTOR_100NS_PER_MINUTE; ft->iSecond = static_cast(ns100 / FACTOR_100NS_PER_SECOND); ns100 = ns100 % FACTOR_100NS_PER_SECOND; ft->iMillisecond = static_cast(ns100 / FACTOR_100NS_PER_MILLISECOND); ns100 = ns100 % FACTOR_100NS_PER_MILLISECOND; ft->iMicrosecond = static_cast(ns100 / FACTOR_100NS_PER_MICROSECOND); ns100 = ns100 % FACTOR_100NS_PER_MICROSECOND; ft->iNanosecond = static_cast(ns100 * FACTOR_NANOSECONDS_PER_100NS); return true; } bool CLinearTimeAbsolute::SetSecondsString(char *arg_szSeconds) { INT64 t; const INT64 tEarliest = EARLIEST_VALID_DATE; const INT64 tLatest = LATEST_VALID_DATE; ParseFractionalSecondsString(t, arg_szSeconds); t += EPOCH_OFFSET; if ( tEarliest <= t && t <= tLatest) { m_tAbsolute = t; return true; } return false; } // OS Dependent Routines: // #ifdef WIN32 void GetUTCLinearTime(INT64 *plt) { GetSystemTimeAsFileTime((struct _FILETIME *)plt); } static DWORD WINAPI AlarmProc(LPVOID lpParameter) { CMuxAlarm *pthis = (CMuxAlarm *)lpParameter; DWORD dwWait = pthis->dwWait; for (;;) { HANDLE hSemAlarm = pthis->hSemAlarm; if (hSemAlarm == INVALID_HANDLE_VALUE) { break; } DWORD dwReason = WaitForSingleObject(hSemAlarm, dwWait); if (dwReason == WAIT_TIMEOUT) { pthis->bAlarmed = true; dwWait = INFINITE; } else { dwWait = pthis->dwWait; } } return 1; } CMuxAlarm::CMuxAlarm(void) { hSemAlarm = CreateSemaphore(NULL, 0, 1, NULL); Clear(); hThread = CreateThread(NULL, 0, AlarmProc, (LPVOID)this, 0, NULL); } CMuxAlarm::~CMuxAlarm() { HANDLE hSave = hSemAlarm; hSemAlarm = INVALID_HANDLE_VALUE; ReleaseSemaphore(hSave, 1, NULL); WaitForSingleObject(hThread, 15*FACTOR_100NS_PER_SECOND); CloseHandle(hSave); } void CMuxAlarm::Sleep(CLinearTimeDelta ltd) { ::Sleep(ltd.ReturnMilliseconds()); } void CMuxAlarm::SurrenderSlice(void) { ::Sleep(0); } void CMuxAlarm::Set(CLinearTimeDelta ltd) { dwWait = ltd.ReturnMilliseconds(); ReleaseSemaphore(hSemAlarm, 1, NULL); bAlarmed = false; bAlarmSet = true; } void CMuxAlarm::Clear(void) { dwWait = INFINITE; ReleaseSemaphore(hSemAlarm, 1, NULL); bAlarmed = false; bAlarmSet = false; } #else // !WIN32 void GetUTCLinearTime(INT64 *plt) { #ifdef HAVE_GETTIMEOFDAY struct timeval tv; struct timezone tz; tz.tz_minuteswest = 0; tz.tz_dsttime = 0; gettimeofday(&tv, &tz); *plt = (((INT64)tv.tv_sec) * FACTOR_100NS_PER_SECOND) + (tv.tv_usec * FACTOR_100NS_PER_MICROSECOND) + EPOCH_OFFSET; #else time_t t; time(&t); *plt = t*FACTOR_100NS_PER_SECOND; #endif } CMuxAlarm::CMuxAlarm(void) { bAlarmed = false; bAlarmSet = false; } void CMuxAlarm::Sleep(CLinearTimeDelta ltd) { #if defined(HAVE_NANOSLEEP) struct timespec req; ltd.ReturnTimeSpecStruct(&req); while (!mudstate.shutdown_flag) { struct timespec rem; if ( nanosleep(&req, &rem) == -1 && errno == EINTR) { req = rem; } else { break; } } #else #ifdef HAVE_SETITIMER struct itimerval oit; bool bSaved = false; if (bAlarmSet) { // Save existing timer and disable. // struct itimerval it; it.it_value.tv_sec = 0; it.it_value.tv_usec = 0; it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 0; setitimer(ITIMER_PROF, &it, &oit); bSaved = true; bAlarmSet = false; } #endif #if defined(HAVE_USLEEP) #define TIME_1S 1000000 unsigned long usec; INT64 usecTotal = ltd.ReturnMicroseconds(); while ( usecTotal && mudstate.shutdown_flag) { usec = usecTotal; if (usecTotal < TIME_1S) { usec = usecTotal; } else { usec = TIME_1S-1; } usleep(usec); usecTotal -= usec; } #else ::sleep(ltd.ReturnSeconds()); #endif #ifdef HAVE_SETITIMER if (bSaved) { // Restore and re-enabled timer. // setitimer(ITIMER_PROF, &oit, NULL); bAlarmSet = true; } #endif #endif } void CMuxAlarm::SurrenderSlice(void) { ::sleep(0); } void CMuxAlarm::Set(CLinearTimeDelta ltd) { #ifdef HAVE_SETITIMER struct itimerval it; ltd.ReturnTimeValueStruct(&it.it_value); it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 0; setitimer(ITIMER_PROF, &it, NULL); bAlarmSet = true; bAlarmed = false; #endif } void CMuxAlarm::Clear(void) { #ifdef HAVE_SETITIMER // Turn off the timer. // struct itimerval it; it.it_value.tv_sec = 0; it.it_value.tv_usec = 0; it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 0; setitimer(ITIMER_PROF, &it, NULL); bAlarmSet = false; bAlarmed = false; #endif } void CMuxAlarm::Signal(void) { bAlarmSet = false; bAlarmed = true; } #endif // !WIN32 static int YearType(int iYear) { FIELDEDTIME ft; memset(&ft, 0, sizeof(FIELDEDTIME)); ft.iYear = static_cast(iYear); ft.iMonth = 1; ft.iDayOfMonth = 1; CLinearTimeAbsolute ltaLocal; ltaLocal.SetFields(&ft); if (isLeapYear(iYear)) { return ft.iDayOfWeek + 8; } else { return ft.iDayOfWeek + 1; } } static CLinearTimeAbsolute ltaLowerBound; static CLinearTimeAbsolute ltaUpperBound; static CLinearTimeDelta ltdTimeZoneStandard; // Because of signed-ness and -LONG_MAX overflowing, we need to be // particularly careful with finding the mid-point. // static time_t time_t_midpoint(time_t tLower, time_t tUpper) { time_t tDiff = (tUpper-2) - tLower; return tLower+tDiff/2+1; } static time_t time_t_largest(void) { time_t t; if (sizeof(INT64) <= sizeof(time_t)) { t = static_cast(INT64_MAX_VALUE); } else { t = static_cast(INT32_MAX_VALUE); } #if defined(TIMEUTIL_TIME_T_MAX_VALUE) INT64 t64 = static_cast(t); if (TIMEUTIL_TIME_T_MAX_VALUE < t64) { t = static_cast(TIMEUTIL_TIME_T_MAX_VALUE); } #endif #if defined(LOCALTIME_TIME_T_MAX_VALUE) // Windows cannot handle negative time_t values, and some versions have // an upper limit as well. Values which are too large cause an assert. // // In VS 2003, the limit is 0x100000000000i64 (beyond the size of a // time_t). In VS 2005, the limit is December 31, 2999, 23:59:59 UTC // (or 32535215999). // if (LOCALTIME_TIME_T_MAX_VALUE < t) { t = static_cast(LOCALTIME_TIME_T_MAX_VALUE); } #endif return t; } static time_t time_t_smallest(void) { time_t t; if (sizeof(INT64) <= sizeof(time_t)) { t = static_cast(INT64_MIN_VALUE); } else { t = static_cast(INT32_MIN_VALUE); } #if defined(TIMEUTIL_TIME_T_MIN_VALUE) INT64 t64 = static_cast(t); if (t64 < TIMEUTIL_TIME_T_MIN_VALUE) { t = static_cast(TIMEUTIL_TIME_T_MIN_VALUE); } #endif #if defined(LOCALTIME_TIME_T_MIN_VALUE) if (t < LOCALTIME_TIME_T_MIN_VALUE) { t = static_cast(LOCALTIME_TIME_T_MIN_VALUE); } #endif return t; } static bool mux_localtime(struct tm *ptm_arg, const time_t *pt_arg) { #if defined(WIN32) && !defined(__INTEL_COMPILER) && (_MSC_VER >= 1400) // 1400 is Visual C++ 2005 // return (_localtime64_s(ptm_arg, pt_arg) == 0); #elif defined(HAVE_LOCALTIME_R) return (localtime_r(pt_arg, ptm_arg) != NULL); #else struct tm *ptm = localtime(pt_arg); if (ptm) { *ptm_arg = *ptm; return true; } else { return false; } #endif // WIN32 } // This determines the valid range of localtime() and finds a 'standard' // time zone near the earliest supported time_t. // static void test_time_t(void) { struct tm _tm; // Search for the highest supported value of time_t. // time_t tUpper = time_t_largest(); time_t tLower = 0; time_t tMid; while (tLower < tUpper) { tMid = time_t_midpoint(tLower+1, tUpper); if (mux_localtime(&_tm, &tMid)) { tLower = tMid; } else { tUpper = tMid-1; } } ltaUpperBound.SetSeconds(tLower); // Search for the lowest supported value of time_t. // tUpper = 0; tLower = time_t_smallest(); while (tLower < tUpper) { tMid = time_t_midpoint(tLower, tUpper-1); if (mux_localtime(&_tm, &tMid)) { tUpper = tMid; } else { tLower = tMid+1; } } ltaLowerBound.SetSeconds(tUpper); // Find a time near tLower for which DST is not in affect. // for (;;) { mux_localtime(&_tm, &tLower); if (_tm.tm_isdst <= 0) { // Daylight savings time is either not in effect or // we have no way of knowing whether it is in effect // or not. // FIELDEDTIME ft; SetStructTm(&ft, &_tm); ft.iMillisecond = 0; ft.iMicrosecond = 0; ft.iNanosecond = 0; CLinearTimeAbsolute ltaLocal; CLinearTimeAbsolute ltaUTC; ltaLocal.SetFields(&ft); ltaUTC.SetSeconds(tLower); ltdTimeZoneStandard = ltaLocal - ltaUTC; break; } // Advance the time by 1 month (expressed as seconds). // tLower += 30*24*60*60; } } static short NearestYearOfType[15]; static CLinearTimeDelta ltdIntervalMinimum; static bool bTimeInitialized = false; void TIME_Initialize(void) { if (bTimeInitialized) { return; } bTimeInitialized = true; mux_tzset(); test_time_t(); ltdIntervalMinimum = time_1w; int i; for (i = 0; i < 15; i++) { NearestYearOfType[i] = -1; } int cnt = 14; FIELDEDTIME ft; ltaUpperBound.ReturnFields(&ft); for (i = ft.iYear-1; cnt; i--) { int iYearType = YearType(i); if (NearestYearOfType[iYearType] < 0) { NearestYearOfType[iYearType] = static_cast(i); cnt--; } } } // Explanation of the table. // // The table contains intervals of time for which (ltdOffset, isDST) // tuples are known. // // Two intervals may be combined when they share the same tuple // value and the time between them is less than ltdIntervalMinimum. // // Intervals are thrown away in a least-recently-used (LRU) fashion. // typedef struct { CLinearTimeAbsolute ltaStart; CLinearTimeAbsolute ltaEnd; CLinearTimeDelta ltdOffset; int nTouched; bool isDST; } OffsetEntry; #define MAX_OFFSETS 50 static int nOffsetTable = 0; static int nTouched0 = 0; static OffsetEntry OffsetTable[MAX_OFFSETS]; // This function finds the entry in the table (0...nOffsetTable-1) // whose ltaStart is less than or equal to the search key. // If no entry satisfies this search, -1 is returned. // static int FindOffsetEntry(const CLinearTimeAbsolute& lta) { int lo = 0; int hi = nOffsetTable - 1; int mid = 0; while (lo <= hi) { mid = ((hi - lo) >> 1) + lo; if (OffsetTable[mid].ltaStart <= lta) { lo = mid + 1; } else { hi = mid - 1; } } return lo-1; } static bool QueryOffsetTable ( CLinearTimeAbsolute lta, CLinearTimeDelta *pltdOffset, bool *pisDST, int *piEntry ) { nTouched0++; int i = FindOffsetEntry(lta); *piEntry = i; // Is the interval defined? // if ( 0 <= i && lta <= OffsetTable[i].ltaEnd) { *pltdOffset = OffsetTable[i].ltdOffset; *pisDST = OffsetTable[i].isDST; OffsetTable[i].nTouched = nTouched0; return true; } return false; } static void UpdateOffsetTable ( CLinearTimeAbsolute <a, CLinearTimeDelta ltdOffset, bool isDST, int i ) { Again: nTouched0++; // Is the interval defined? // if ( 0 <= i && lta <= OffsetTable[i].ltaEnd) { OffsetTable[i].nTouched = nTouched0; return; } bool bTryMerge = false; // Coalesce new data point into this interval if: // // 1. Tuple for this interval matches the new tuple value. // 2. It's close enough that we can assume all intervening // values are the same. // if ( 0 <= i && OffsetTable[i].ltdOffset == ltdOffset && OffsetTable[i].isDST == isDST && lta <= OffsetTable[i].ltaEnd + ltdIntervalMinimum) { // Cool. We can just extend this interval to include our new // data point. // OffsetTable[i].ltaEnd = lta; OffsetTable[i].nTouched = nTouched0; // Since we have changed this interval, we may be able to // coalesce it with the next interval. // bTryMerge = true; } // Coalesce new data point into next interval if: // // 1. Next interval exists. // 2. Tuple in next interval matches the new tuple value. // 3. It's close enough that we can assume all intervening // values are the same. // int iNext = i+1; if ( 0 <= iNext && iNext < nOffsetTable && OffsetTable[iNext].ltdOffset == ltdOffset && OffsetTable[iNext].isDST == isDST && OffsetTable[iNext].ltaStart - ltdIntervalMinimum <= lta) { // Cool. We can just extend the next interval to include our // new data point. // OffsetTable[iNext].ltaStart = lta; OffsetTable[iNext].nTouched = nTouched0; // Since we have changed the next interval, we may be able // to coalesce it with the previous interval. // bTryMerge = true; } if (bTryMerge) { // We should combine the current and next intervals if we can. // if ( 0 <= i && iNext < nOffsetTable && OffsetTable[i].ltdOffset == OffsetTable[iNext].ltdOffset && OffsetTable[i].isDST == OffsetTable[iNext].isDST && OffsetTable[iNext].ltaStart - ltdIntervalMinimum <= OffsetTable[i].ltaEnd) { if (0 <= i && 0 <= iNext) { OffsetTable[i].ltaEnd = OffsetTable[iNext].ltaEnd; } int nSize = sizeof(OffsetEntry)*(nOffsetTable-i-2); memmove(OffsetTable+i+1, OffsetTable+i+2, nSize); nOffsetTable--; } } else { // We'll have'ta create a new interval. // if (nOffsetTable < MAX_OFFSETS) { size_t nSize = sizeof(OffsetEntry)*(nOffsetTable-i-1); memmove(OffsetTable+i+2, OffsetTable+i+1, nSize); nOffsetTable++; i++; OffsetTable[i].isDST = isDST; OffsetTable[i].ltdOffset = ltdOffset; OffsetTable[i].ltaStart= lta; OffsetTable[i].ltaEnd= lta; OffsetTable[i].nTouched = nTouched0; } else { // We ran out of room. Throw away the least used // interval and try again. // int nMinTouched = OffsetTable[0].nTouched; int iMinTouched = 0; for (int j = 1; j < nOffsetTable; j++) { if (OffsetTable[j].nTouched - nMinTouched < 0) { nMinTouched = OffsetTable[j].nTouched; iMinTouched = j; } } int nSize = sizeof(OffsetEntry)*(nOffsetTable-iMinTouched-1); memmove(OffsetTable+iMinTouched, OffsetTable+iMinTouched+1, nSize); nOffsetTable--; if (iMinTouched <= i) { i--; } goto Again; } } } static CLinearTimeDelta QueryLocalOffsetAt_Internal ( CLinearTimeAbsolute lta, bool *pisDST, int iEntry ) { if (!bTimeInitialized) { TIME_Initialize(); } // At this point, we must use localtime() to discover what the // UTC to local time offset is for the requested UTC time. // // However, localtime() does not support times beyond around // the 2038 year on machines with 32-bit integers, so to // compensant for this, and knowing that we are already dealing // with fictionalized adjustments, we associate a future year // that is outside the supported range with one that is inside // the support range of the same type (there are 14 different // year types depending on leap-year-ness and which day of the // week that January 1st falls on. // // Note: Laws beyond the current year have not been written yet // and are subject to change at any time. For example, Israel // doesn't have regular rules for DST but makes a directive each // year...sometimes to avoid conflicts with Jewish holidays. // if (lta > ltaUpperBound) { // Map the specified year to the closest year with the same // pattern of weeks. // FIELDEDTIME ft; lta.ReturnFields(&ft); ft.iYear = NearestYearOfType[YearType(ft.iYear)]; lta.SetFields(&ft); } // Rely on localtime() to take a UTC count of seconds and convert // to a fielded local time complete with known timezone and DST // adjustments. // struct tm _tm; time_t lt = static_cast(lta.ReturnSeconds()); if (!mux_localtime(&_tm, <)) { // This should never happen as we have already taken pains // to restrict the range of UTC seconds gives to localtime(). // return ltdTimeZoneStandard; } // With the fielded (or broken down) time from localtime(), we // can convert to a linear time in the same time zone. // FIELDEDTIME ft; SetStructTm(&ft, &_tm); ft.iMillisecond = 0; ft.iMicrosecond = 0; ft.iNanosecond = 0; CLinearTimeAbsolute ltaLocal; CLinearTimeDelta ltdOffset; ltaLocal.SetFields(&ft); lta.SetSeconds(lt); ltdOffset = ltaLocal - lta; *pisDST = (_tm.tm_isdst > 0); // We now have a mapping from UTC lta to a (ltdOffset, *pisDST) // tuple which will will use to update the cache. // UpdateOffsetTable(lta, ltdOffset, *pisDST, iEntry); return ltdOffset; } static CLinearTimeDelta QueryLocalOffsetAtUTC ( const CLinearTimeAbsolute <a, bool *pisDST ) { *pisDST = false; // DST started in Britain in May 1916 and in the US in 1918. // Germany used it a little before May 1916, but I'm not sure // of exactly when. // // So, there is locale specific information about DST adjustments // that could reasonable be made between 1916 and 1970. // Because Unix supports negative time_t values while Win32 does // not, it can also support that 1916 to 1970 interval with // timezone information. // // Win32 only supports one timezone rule at a time, or rather // it doesn't have any historical timezone information, but you // can/must provide it yourself. So, in the Win32 case, unless we // are willing to provide historical information (from a tzfile // perhaps), it will only give us the current timezone rule // (the one selected by the control panel or by a TZ environment // variable). It projects this rule forwards and backwards. // // Feel free to fill that gap in yourself with a tzfile file // reader for Win32. // if (lta < ltaLowerBound) { return ltdTimeZoneStandard; } // Next, we check our table for whether this time falls into a // previously discovered interval. You could view this as a // cache, or you could also view it as a way of reading in the // tzfile without becoming system-dependent enough to actually // read the tzfile. // CLinearTimeDelta ltdOffset; int iEntry; if (QueryOffsetTable(lta, <dOffset, pisDST, &iEntry)) { return ltdOffset; } ltdOffset = QueryLocalOffsetAt_Internal(lta, pisDST, iEntry); // Since the cache failed, let's make sure we have a useful // interval surrounding this last request so that future queries // nearby will be serviced by the cache. // CLinearTimeAbsolute ltaProbe; CLinearTimeDelta ltdDontCare; bool bDontCare; ltaProbe = lta - ltdIntervalMinimum; if (!QueryOffsetTable(ltaProbe, <dDontCare, &bDontCare, &iEntry)) { QueryLocalOffsetAt_Internal(ltaProbe, &bDontCare, iEntry); } ltaProbe = lta + ltdIntervalMinimum; if (!QueryOffsetTable(ltaProbe, <dDontCare, &bDontCare, &iEntry)) { QueryLocalOffsetAt_Internal(ltaProbe, &bDontCare, iEntry); } return ltdOffset; } void CLinearTimeAbsolute::UTC2Local(void) { bool bDST; CLinearTimeDelta ltd = QueryLocalOffsetAtUTC(*this, &bDST); m_tAbsolute += ltd.m_tDelta; } void CLinearTimeAbsolute::Local2UTC(void) { bool bDST1, bDST2; CLinearTimeDelta ltdOffset1 = QueryLocalOffsetAtUTC(*this, &bDST1); CLinearTimeAbsolute ltaUTC2 = *this - ltdOffset1; CLinearTimeDelta ltdOffset2 = QueryLocalOffsetAtUTC(ltaUTC2, &bDST2); CLinearTimeAbsolute ltaLocalGuess = ltaUTC2 + ltdOffset2; if (ltaLocalGuess == *this) { // We found an offset, UTC, local time combination that // works. // m_tAbsolute = ltaUTC2.m_tAbsolute; } else { CLinearTimeAbsolute ltaUTC1 = *this - ltdOffset2; m_tAbsolute = ltaUTC1.m_tAbsolute; } } // AUTOMAGIC DATE PARSING. // We must deal with several levels at once. That is, a single // character is overlapped by layers and layers of meaning from 'digit' // to 'the second digit of the hours field of the timezone'. // typedef struct tag_pd_node { // The following is a bitfield which contains a '1' bit for every // possible meaning associated with this token. This bitfield is // initially determined by looking at the token, and then we use // the following logic to refine this set further: // // 1. Suffix and Prefix hints. e.g., '1st', '2nd', etc. ':' with // time fields, 'am'/'pm', timezone field must follow time // field, 'Wn' is a week-of-year indicator, 'nTn' is an ISO // date/time seperator, 'Z' shows that 'Z' is a // military timezone letter, '-n' indicates that the field is // either a year or a numeric timezone, '+n' indicates that the // field can only be a timezone. // // 2. Single Field Exclusiveness. We only allow -one- timezone // indicator in the field. Likewise, there can't be two months, // two day-of-month fields, two years, etc. // // 3. Semantic exclusions. day-of-year, month/day-of-month, and // and week-of-year/day-of-year(numeric) are mutually exclusive. // // If successful, this bitfield will ultimately only contain a single // '1' bit which tells us what it is. // unsigned uCouldBe; // These fields deal with token things and we avoid mixing // them up in higher meanings. This is the lowest level. // // Further Notes: // // PDTT_SYMBOL is always a -single- (nToken==1) character. // // uTokenType must be one of the PDTT_* values. // // PDTT_NUMERIC_* and PDTT_TEXT types may have an // iToken value associated with them. // #define PDTT_SYMBOL 1 // e.g., :/.-+ #define PDTT_NUMERIC_UNSIGNED 2 // [0-9]+ #define PDTT_SPACES 3 // One or more space/tab characters #define PDTT_TEXT 4 // 'January' 'Jan' 'T' 'W' #define PDTT_NUMERIC_SIGNED 5 // [+-][0-9]+ unsigned uTokenType; char *pToken; size_t nToken; int iToken; // Link to previous and next node. // struct tag_pd_node *pNextNode; struct tag_pd_node *pPrevNode; } PD_Node; #define PDCB_NOTHING 0x00000000 #define PDCB_TIME_FIELD_SEPARATOR 0x00000001 #define PDCB_DATE_FIELD_SEPARATOR 0x00000002 #define PDCB_WHITESPACE 0x00000004 #define PDCB_DAY_OF_MONTH_SUFFIX 0x00000008 #define PDCB_SIGN 0x00000010 #define PDCB_SECONDS_DECIMAL 0x00000020 #define PDCB_REMOVEABLE 0x00000040 #define PDCB_YEAR 0x00000080 #define PDCB_MONTH 0x00000100 #define PDCB_DAY_OF_MONTH 0x00000200 #define PDCB_DAY_OF_WEEK 0x00000400 #define PDCB_WEEK_OF_YEAR 0x00000800 #define PDCB_DAY_OF_YEAR 0x00001000 #define PDCB_YD 0x00002000 #define PDCB_YMD 0x00004000 #define PDCB_MDY 0x00008000 #define PDCB_DMY 0x00010000 #define PDCB_DATE_TIME_SEPARATOR 0x00020000 #define PDCB_TIMEZONE 0x00040000 #define PDCB_WEEK_OF_YEAR_PREFIX 0x00080000 #define PDCB_MERIDIAN 0x00100000 #define PDCB_MINUTE 0x00200000 #define PDCB_SECOND 0x00400000 #define PDCB_SUBSECOND 0x00800000 #define PDCB_HOUR_TIME 0x01000000 #define PDCB_HMS_TIME 0x02000000 #define PDCB_HOUR_TIMEZONE 0x04000000 #define PDCB_HMS_TIMEZONE 0x08000000 static PD_Node *PD_NewNode(void); static void PD_AppendNode(PD_Node *pNode); static void PD_InsertAfter(PD_Node *pWhere, PD_Node *pNode); typedef void BREAK_DOWN_FUNC(PD_Node *pNode); typedef struct tag_pd_breakdown { unsigned int mask; BREAK_DOWN_FUNC *fpBreakDown; } PD_BREAKDOWN; #define NOT_PRESENT -9999999 typedef struct tag_AllFields { int iYear; int iDayOfYear; int iMonthOfYear; int iDayOfMonth; int iWeekOfYear; int iDayOfWeek; int iHourTime; int iMinuteTime; int iSecondTime; int iMillisecondTime; int iMicrosecondTime; int iNanosecondTime; int iMinuteTimeZone; } ALLFIELDS; // isValidYear assumes numeric string. // static bool isValidYear(size_t nStr, char *pStr, int iValue) { UNUSED_PARAMETER(pStr); UNUSED_PARAMETER(iValue); // Year may be Y, YY, YYY, YYYY, or YYYYY. // Negative and zero years are permitted in general, but we aren't // give the leading sign. // if (1 <= nStr && nStr <= 5) { return true; } return false; } static bool isValidMonth(size_t nStr, char *pStr, int iValue) { UNUSED_PARAMETER(pStr); // Month may be 1 through 9, 01 through 09, 10, 11, or 12. // if ( 1 <= nStr && nStr <= 2 && 1 <= iValue && iValue <= 12) { return true; } return false; } static bool isValidDayOfMonth(size_t nStr, char *pStr, int iValue) { UNUSED_PARAMETER(pStr); // Day Of Month may be 1 through 9, 01 through 09, 10 through 19, // 20 through 29, 30, and 31. // if ( 1 <= nStr && nStr <= 2 && 1 <= iValue && iValue <= 31) { return true; } return false; } static bool isValidDayOfWeek(size_t nStr, char *pStr, int iValue) { UNUSED_PARAMETER(pStr); // Day Of Week may be 1 through 7. // if ( 1 == nStr && 1 <= iValue && iValue <= 7) { return true; } return false; } static bool isValidDayOfYear(size_t nStr, char *pStr, int iValue) { UNUSED_PARAMETER(pStr); // Day Of Year 001 through 366 // if ( 3 == nStr && 1 <= iValue && iValue <= 366) { return true; } return false; } static bool isValidWeekOfYear(size_t nStr, char *pStr, int iValue) { UNUSED_PARAMETER(pStr); // Week Of Year may be 01 through 53. // if ( 2 == nStr && 1 <= iValue && iValue <= 53) { return true; } return false; } static bool isValidHour(size_t nStr, char *pStr, int iValue) { UNUSED_PARAMETER(pStr); // Hour may be 0 through 9, 00 through 09, 10 through 19, 20 through 24. // if ( 1 <= nStr && nStr <= 2 && 0 <= iValue && iValue <= 24) { return true; } return false; } static bool isValidMinute(size_t nStr, char *pStr, int iValue) { UNUSED_PARAMETER(pStr); // Minute may be 00 through 59. // if ( 2 == nStr && 0 <= iValue && iValue <= 59) { return true; } return false; } static bool isValidSecond(size_t nStr, char *pStr, int iValue) { UNUSED_PARAMETER(pStr); // Second may be 00 through 59. Leap seconds represented // by '60' are not dealt with. // if ( 2 == nStr && 0 <= iValue && iValue <= 59) { return true; } return false; } static bool isValidSubSecond(size_t nStr, char *pStr, int iValue) { UNUSED_PARAMETER(pStr); UNUSED_PARAMETER(iValue); // Sub seconds can really be anything, but we limit // it's precision to 100 ns. // if (nStr <= 7) { return true; } return false; } // This function handles H, HH, HMM, HHMM, HMMSS, HHMMSS // static bool isValidHMS(size_t nStr, char *pStr, int iValue) { int iHour, iMinutes, iSeconds; switch (nStr) { case 1: case 2: return isValidHour(nStr, pStr, iValue); case 3: case 4: iHour = iValue/100; iValue -= iHour*100; iMinutes = iValue; if ( isValidHour(nStr-2, pStr, iHour) && isValidMinute(2, pStr+nStr-2, iMinutes)) { return true; } break; case 5: case 6: iHour = iValue/10000; iValue -= iHour*10000; iMinutes = iValue/100; iValue -= iMinutes*100; iSeconds = iValue; if ( isValidHour(nStr-4, pStr, iHour) && isValidMinute(2, pStr+nStr-4, iMinutes) && isValidSecond(2, pStr+nStr-2, iSeconds)) { return true; } break; } return false; } static void SplitLastTwoDigits(PD_Node *pNode, unsigned mask) { PD_Node *p = PD_NewNode(); if (p) { *p = *pNode; p->uCouldBe = mask; p->nToken = 2; p->pToken += pNode->nToken - 2; p->iToken = pNode->iToken % 100; pNode->nToken -= 2; pNode->iToken /= 100; PD_InsertAfter(pNode, p); } } static void SplitLastThreeDigits(PD_Node *pNode, unsigned mask) { PD_Node *p = PD_NewNode(); if (p) { *p = *pNode; p->uCouldBe = mask; p->nToken = 3; p->pToken += pNode->nToken - 3; p->iToken = pNode->iToken % 1000; pNode->nToken -= 3; pNode->iToken /= 1000; PD_InsertAfter(pNode, p); } } // This function breaks down H, HH, HMM, HHMM, HMMSS, HHMMSS // static void BreakDownHMS(PD_Node *pNode) { if (pNode->uCouldBe & PDCB_HMS_TIME) { pNode->uCouldBe = PDCB_HOUR_TIME; } else { pNode->uCouldBe = PDCB_HOUR_TIMEZONE; } switch (pNode->nToken) { case 5: case 6: SplitLastTwoDigits(pNode, PDCB_SECOND); case 3: case 4: SplitLastTwoDigits(pNode, PDCB_MINUTE); } } // This function handles YYMMDD, YYYMMDD, YYYYMMDD, YYYYYMMDD // static bool isValidYMD(size_t nStr, char *pStr, int iValue) { int iYear = iValue / 10000; iValue -= 10000 * iYear; int iMonth = iValue / 100; iValue -= 100 * iMonth; int iDay = iValue; if ( isValidMonth(2, pStr+nStr-4, iMonth) && isValidDayOfMonth(2, pStr+nStr-2, iDay) && isValidYear(nStr-4, pStr, iYear)) { return true; } return false; } // This function breaks down YYMMDD, YYYMMDD, YYYYMMDD, YYYYYMMDD // static void BreakDownYMD(PD_Node *pNode) { pNode->uCouldBe = PDCB_YEAR; SplitLastTwoDigits(pNode, PDCB_DAY_OF_MONTH); SplitLastTwoDigits(pNode, PDCB_MONTH); } // This function handles MMDDYY // static bool isValidMDY(size_t nStr, char *pStr, int iValue) { int iMonth = iValue / 10000; iValue -= 10000 * iMonth; int iDay = iValue / 100; iValue -= 100 * iDay; int iYear = iValue; if ( 6 == nStr && isValidMonth(2, pStr, iMonth) && isValidDayOfMonth(2, pStr+2, iDay) && isValidYear(2, pStr+4, iYear)) { return true; } return false; } // This function breaks down MMDDYY // static void BreakDownMDY(PD_Node *pNode) { pNode->uCouldBe = PDCB_MONTH; SplitLastTwoDigits(pNode, PDCB_YEAR); SplitLastTwoDigits(pNode, PDCB_DAY_OF_MONTH); } // This function handles DDMMYY // static bool isValidDMY(size_t nStr, char *pStr, int iValue) { int iDay = iValue / 10000; iValue -= 10000 * iDay; int iMonth = iValue / 100; iValue -= 100 * iMonth; int iYear = iValue; if ( 6 == nStr && isValidMonth(2, pStr+2, iMonth) && isValidDayOfMonth(2, pStr, iDay) && isValidYear(2, pStr+4, iYear)) { return true; } return false; } // This function breaks down DDMMYY // static void BreakDownDMY(PD_Node *pNode) { pNode->uCouldBe = PDCB_DAY_OF_MONTH; SplitLastTwoDigits(pNode, PDCB_YEAR); SplitLastTwoDigits(pNode, PDCB_MONTH); } // This function handles YDDD, YYDDD, YYYDDD, YYYYDDD, YYYYYDDD // static bool isValidYD(size_t nStr, char *pStr, int iValue) { int iYear = iValue / 1000; iValue -= 1000*iYear; int iDay = iValue; if ( 4 <= nStr && nStr <= 8 && isValidDayOfYear(3, pStr+nStr-3, iDay) && isValidYear(nStr-3, pStr, iYear)) { return true; } return false; } // This function breaks down YDDD, YYDDD, YYYDDD, YYYYDDD, YYYYYDDD // static void BreakDownYD(PD_Node *pNode) { pNode->uCouldBe = PDCB_YEAR; SplitLastThreeDigits(pNode, PDCB_DAY_OF_YEAR); } static const int InitialCouldBe[9] = { PDCB_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_DAY_OF_WEEK|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE|PDCB_SUBSECOND, // 1 PDCB_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE|PDCB_MINUTE|PDCB_SECOND|PDCB_SUBSECOND, // 2 PDCB_YEAR|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_DAY_OF_YEAR|PDCB_SUBSECOND, // 3 PDCB_YEAR|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_YD|PDCB_SUBSECOND, // 4 PDCB_YEAR|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_YD|PDCB_SUBSECOND, // 5 PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_YD|PDCB_SUBSECOND, // 6 PDCB_YMD|PDCB_YD|PDCB_SUBSECOND, // 7 PDCB_YMD|PDCB_YD, // 8 PDCB_YMD // 9 }; typedef bool PVALIDFUNC(size_t nStr, char *pStr, int iValue); typedef struct tag_pd_numeric_valid { unsigned mask; PVALIDFUNC *fnValid; } NUMERIC_VALID_RECORD; const NUMERIC_VALID_RECORD NumericSet[] = { { PDCB_YEAR, isValidYear }, { PDCB_MONTH, isValidMonth }, { PDCB_DAY_OF_MONTH, isValidDayOfMonth }, { PDCB_DAY_OF_YEAR, isValidDayOfYear }, { PDCB_WEEK_OF_YEAR, isValidWeekOfYear }, { PDCB_DAY_OF_WEEK, isValidDayOfWeek }, { PDCB_HMS_TIME|PDCB_HMS_TIMEZONE, isValidHMS }, { PDCB_YMD, isValidYMD }, { PDCB_MDY, isValidMDY }, { PDCB_DMY, isValidDMY }, { PDCB_YD, isValidYD }, { PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE, isValidHour }, { PDCB_MINUTE, isValidMinute }, { PDCB_SECOND, isValidSecond }, { PDCB_SUBSECOND, isValidSubSecond }, { 0, 0}, }; // This function looks at the numeric token and assigns the initial set // of possibilities. // static void ClassifyNumericToken(PD_Node *pNode) { size_t nToken = pNode->nToken; char *pToken = pNode->pToken; int iToken = pNode->iToken; unsigned int uCouldBe = InitialCouldBe[nToken-1]; int i = 0; int mask = 0; while ((mask = NumericSet[i].mask) != 0) { if ( (mask & uCouldBe) && !(NumericSet[i].fnValid(nToken, pToken, iToken))) { uCouldBe &= ~mask; } i++; } pNode->uCouldBe = uCouldBe; } typedef struct { const char *szText; unsigned int uCouldBe; int iValue; } PD_TEXT_ENTRY; const PD_TEXT_ENTRY PD_TextTable[] = { {"sun", PDCB_DAY_OF_WEEK, 7 }, {"mon", PDCB_DAY_OF_WEEK, 1 }, {"tue", PDCB_DAY_OF_WEEK, 2 }, {"wed", PDCB_DAY_OF_WEEK, 3 }, {"thu", PDCB_DAY_OF_WEEK, 4 }, {"fri", PDCB_DAY_OF_WEEK, 5 }, {"sat", PDCB_DAY_OF_WEEK, 6 }, {"jan", PDCB_MONTH, 1 }, {"feb", PDCB_MONTH, 2 }, {"mar", PDCB_MONTH, 3 }, {"apr", PDCB_MONTH, 4 }, {"may", PDCB_MONTH, 5 }, {"jun", PDCB_MONTH, 6 }, {"jul", PDCB_MONTH, 7 }, {"aug", PDCB_MONTH, 8 }, {"sep", PDCB_MONTH, 9 }, {"oct", PDCB_MONTH, 10 }, {"nov", PDCB_MONTH, 11 }, {"dec", PDCB_MONTH, 12 }, {"january", PDCB_MONTH, 1 }, {"february", PDCB_MONTH, 2 }, {"march", PDCB_MONTH, 3 }, {"april", PDCB_MONTH, 4 }, {"may", PDCB_MONTH, 5 }, {"june", PDCB_MONTH, 6 }, {"july", PDCB_MONTH, 7 }, {"august", PDCB_MONTH, 8 }, {"september", PDCB_MONTH, 9 }, {"october", PDCB_MONTH, 10 }, {"november", PDCB_MONTH, 11 }, {"december", PDCB_MONTH, 12 }, {"sunday", PDCB_DAY_OF_WEEK, 7 }, {"monday", PDCB_DAY_OF_WEEK, 1 }, {"tuesday", PDCB_DAY_OF_WEEK, 2 }, {"wednesday", PDCB_DAY_OF_WEEK, 3 }, {"thursday", PDCB_DAY_OF_WEEK, 4 }, {"friday", PDCB_DAY_OF_WEEK, 5 }, {"saturday", PDCB_DAY_OF_WEEK, 6 }, {"a", PDCB_TIMEZONE, 100 }, {"b", PDCB_TIMEZONE, 200 }, {"c", PDCB_TIMEZONE, 300 }, {"d", PDCB_TIMEZONE, 400 }, {"e", PDCB_TIMEZONE, 500 }, {"f", PDCB_TIMEZONE, 600 }, {"g", PDCB_TIMEZONE, 700 }, {"h", PDCB_TIMEZONE, 800 }, {"i", PDCB_TIMEZONE, 900 }, {"k", PDCB_TIMEZONE, 1000 }, {"l", PDCB_TIMEZONE, 1100 }, {"m", PDCB_TIMEZONE, 1200 }, {"n", PDCB_TIMEZONE, -100 }, {"o", PDCB_TIMEZONE, -200 }, {"p", PDCB_TIMEZONE, -300 }, {"q", PDCB_TIMEZONE, -400 }, {"r", PDCB_TIMEZONE, -500 }, {"s", PDCB_TIMEZONE, -600 }, {"t", PDCB_DATE_TIME_SEPARATOR|PDCB_TIMEZONE, -700}, {"u", PDCB_TIMEZONE, -800 }, {"v", PDCB_TIMEZONE, -900 }, {"w", PDCB_WEEK_OF_YEAR_PREFIX|PDCB_TIMEZONE, -1000 }, {"x", PDCB_TIMEZONE, -1100 }, {"y", PDCB_TIMEZONE, -1200 }, {"z", PDCB_TIMEZONE, 0 }, {"hst", PDCB_TIMEZONE, -1000 }, {"akst", PDCB_TIMEZONE, -900 }, {"pst", PDCB_TIMEZONE, -800 }, {"mst", PDCB_TIMEZONE, -700 }, {"cst", PDCB_TIMEZONE, -600 }, {"est", PDCB_TIMEZONE, -500 }, {"ast", PDCB_TIMEZONE, -400 }, {"akdt", PDCB_TIMEZONE, -800 }, {"pdt", PDCB_TIMEZONE, -700 }, {"mdt", PDCB_TIMEZONE, -600 }, {"cdt", PDCB_TIMEZONE, -500 }, {"edt", PDCB_TIMEZONE, -400 }, {"adt", PDCB_TIMEZONE, -300 }, {"bst", PDCB_TIMEZONE, 100 }, {"ist", PDCB_TIMEZONE, 100 }, {"cet", PDCB_TIMEZONE, 100 }, {"cest", PDCB_TIMEZONE, 200 }, {"eet", PDCB_TIMEZONE, 200 }, {"eest", PDCB_TIMEZONE, 300 }, {"aest", PDCB_TIMEZONE, 1000 }, {"gmt", PDCB_TIMEZONE, 0 }, {"ut", PDCB_TIMEZONE, 0 }, {"utc", PDCB_TIMEZONE, 0 }, {"st", PDCB_DAY_OF_MONTH_SUFFIX, 0 }, {"nd", PDCB_DAY_OF_MONTH_SUFFIX, 0 }, {"rd", PDCB_DAY_OF_MONTH_SUFFIX, 0 }, {"th", PDCB_DAY_OF_MONTH_SUFFIX, 0 }, {"am", PDCB_MERIDIAN, 0 }, {"pm", PDCB_MERIDIAN, 12 }, { 0, 0, 0} }; #define PD_LEX_INVALID 0 #define PD_LEX_SYMBOL 1 #define PD_LEX_DIGIT 2 #define PD_LEX_SPACE 3 #define PD_LEX_ALPHA 4 #define PD_LEX_EOS 5 const char LexTable[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 5, 0, 0, 0, 0, 0, 0, 0, 0, 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 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, // 2 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, // 3 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 4 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 5 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 6 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; static int nNodes = 0; #define MAX_NODES 200 static PD_Node Nodes[MAX_NODES]; static PD_Node *PD_Head = 0; static PD_Node *PD_Tail = 0; static void PD_Reset(void) { nNodes = 0; PD_Head = 0; PD_Tail = 0; } PD_Node *PD_NewNode(void) { if (nNodes < MAX_NODES) { return Nodes+(nNodes++); } return NULL; } static PD_Node *PD_FirstNode(void) { return PD_Head; } #if 0 static PD_Node *PD_LastNode(void) { return PD_Tail; } #endif static PD_Node *PD_NextNode(PD_Node *pNode) { return pNode->pNextNode; } static PD_Node *PD_PrevNode(PD_Node *pNode) { return pNode->pPrevNode; } // PD_AppendNode - Appends a node onto the end of the list. It's used during // the first pass over the date string; these nodes are therefore always // elemental nodes. It might be possible to append a group node. However, // usually group nodes a created at a later from recognizing a deeper semantic // meaning of an elemental node and this promotion event could happen anywhere // in the sequence. The order of promotion isn't clear during the first pass // over the date string. // void PD_AppendNode(PD_Node *pNode) { if (!PD_Head) { PD_Head = PD_Tail = pNode; return; } pNode->pNextNode = 0; PD_Tail->pNextNode = pNode; pNode->pPrevNode = PD_Tail; PD_Tail = pNode; } void PD_InsertAfter(PD_Node *pWhere, PD_Node *pNode) { pNode->pPrevNode = pWhere; pNode->pNextNode = pWhere->pNextNode; pWhere->pNextNode = pNode; if (pNode->pNextNode) { pNode->pNextNode->pPrevNode = pNode; } else { PD_Tail = pNode; } } static void PD_RemoveNode(PD_Node *pNode) { if (pNode == PD_Head) { if (pNode == PD_Tail) { PD_Head = PD_Tail = 0; } else { PD_Head = pNode->pNextNode; PD_Head->pPrevNode = 0; pNode->pNextNode = 0; } } else if (pNode == PD_Tail) { PD_Tail = pNode->pPrevNode; PD_Tail->pNextNode = 0; pNode->pPrevNode = 0; } else { pNode->pNextNode->pPrevNode = pNode->pPrevNode; pNode->pPrevNode->pNextNode = pNode->pNextNode; pNode->pNextNode = 0; pNode->pPrevNode = 0; } } static PD_Node *PD_ScanNextToken(char **ppString) { char *p = *ppString; int ch = *p; if (ch == 0) { return NULL; } PD_Node *pNode; int iType = LexTable[ch]; if (iType == PD_LEX_EOS || iType == PD_LEX_INVALID) { return NULL; } else if (iType == PD_LEX_SYMBOL) { pNode = PD_NewNode(); if (!pNode) { return NULL; } pNode->pNextNode = 0; pNode->pPrevNode = 0; pNode->iToken = 0; pNode->nToken = 1; pNode->pToken = p; pNode->uTokenType = PDTT_SYMBOL; if (ch == ':') { pNode->uCouldBe = PDCB_TIME_FIELD_SEPARATOR; } else if (ch == '-') { pNode->uCouldBe = PDCB_DATE_FIELD_SEPARATOR|PDCB_SIGN; } else if (ch == '+') { pNode->uCouldBe = PDCB_SIGN; } else if (ch == '/') { pNode->uCouldBe = PDCB_DATE_FIELD_SEPARATOR; } else if (ch == '.') { pNode->uCouldBe = PDCB_DATE_FIELD_SEPARATOR|PDCB_SECONDS_DECIMAL; } else if (ch == ',') { pNode->uCouldBe = PDCB_REMOVEABLE|PDCB_SECONDS_DECIMAL|PDCB_DAY_OF_MONTH_SUFFIX; } p++; } else { char *pSave = p; do { p++; ch = *p; } while (iType == LexTable[ch]); pNode = PD_NewNode(); if (!pNode) { return NULL; } pNode->pNextNode = 0; pNode->pPrevNode = 0; size_t nLen = p - pSave; pNode->nToken = nLen; pNode->pToken = pSave; pNode->iToken = 0; pNode->uCouldBe = PDCB_NOTHING; if (iType == PD_LEX_DIGIT) { pNode->uTokenType = PDTT_NUMERIC_UNSIGNED; if (1 <= nLen && nLen <= 9) { char buff[10]; memcpy(buff, pSave, nLen); buff[nLen] = '\0'; pNode->iToken = mux_atol(buff); ClassifyNumericToken(pNode); } } else if (iType == PD_LEX_SPACE) { pNode->uTokenType = PDTT_SPACES; pNode->uCouldBe = PDCB_WHITESPACE; } else if (iType == PD_LEX_ALPHA) { pNode->uTokenType = PDTT_TEXT; // Match Text. // int j = 0; bool bFound = false; while (PD_TextTable[j].szText) { if ( strlen(PD_TextTable[j].szText) == nLen && mux_memicmp(PD_TextTable[j].szText, pSave, nLen) == 0) { pNode->uCouldBe = PD_TextTable[j].uCouldBe; pNode->iToken = PD_TextTable[j].iValue; bFound = true; break; } j++; } if (!bFound) { return NULL; } } } *ppString = p; return pNode; } static const PD_BREAKDOWN BreakDownTable[] = { { PDCB_HMS_TIME, BreakDownHMS }, { PDCB_HMS_TIMEZONE, BreakDownHMS }, { PDCB_YD, BreakDownYD }, { PDCB_YMD, BreakDownYMD }, { PDCB_MDY, BreakDownMDY }, { PDCB_DMY, BreakDownDMY }, { 0, 0 } }; static void PD_Pass2(void) { PD_Node *pNode = PD_FirstNode(); while (pNode) { PD_Node *pPrev = PD_PrevNode(pNode); PD_Node *pNext = PD_NextNode(pNode); // Absorb information from PDCB_TIME_FIELD_SEPARATOR. // if (pNode->uCouldBe & PDCB_TIME_FIELD_SEPARATOR) { if (pPrev && pNext) { if ( (pPrev->uCouldBe & (PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE)) && (pNext->uCouldBe & PDCB_MINUTE)) { pPrev->uCouldBe &= (PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE); pNext->uCouldBe = PDCB_MINUTE; } else if ( (pPrev->uCouldBe & PDCB_MINUTE) && (pNext->uCouldBe & PDCB_SECOND)) { pPrev->uCouldBe = PDCB_MINUTE; pNext->uCouldBe = PDCB_SECOND; } } pNode->uCouldBe = PDCB_REMOVEABLE; } // Absorb information from PDCB_SECONDS_DECIMAL. // if (pNode->uCouldBe & PDCB_SECONDS_DECIMAL) { if ( pPrev && pNext && pPrev->uCouldBe == PDCB_SECOND && (pNext->uCouldBe & PDCB_SUBSECOND)) { pNode->uCouldBe = PDCB_SECONDS_DECIMAL; pNext->uCouldBe = PDCB_SUBSECOND; } else { pNode->uCouldBe &= ~PDCB_SECONDS_DECIMAL; } pNode->uCouldBe = PDCB_REMOVEABLE; } // Absorb information from PDCB_SUBSECOND // if (pNode->uCouldBe != PDCB_SUBSECOND) { pNode->uCouldBe &= ~PDCB_SUBSECOND; } // Absorb information from PDCB_DATE_FIELD_SEPARATOR. // if (pNode->uCouldBe & PDCB_DATE_FIELD_SEPARATOR) { pNode->uCouldBe &= ~PDCB_DATE_FIELD_SEPARATOR; #define PDCB_SEPS (PDCB_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_DAY_OF_YEAR|PDCB_WEEK_OF_YEAR|PDCB_DAY_OF_WEEK) if ( pPrev && pNext && (pPrev->uCouldBe & PDCB_SEPS) && (pNext->uCouldBe & PDCB_SEPS)) { pPrev->uCouldBe &= PDCB_SEPS; pNext->uCouldBe &= PDCB_SEPS; pNode->uCouldBe = PDCB_REMOVEABLE; } } // Process PDCB_DAY_OF_MONTH_SUFFIX // if (pNode->uCouldBe & PDCB_DAY_OF_MONTH_SUFFIX) { pNode->uCouldBe = PDCB_REMOVEABLE; if ( pPrev && (pPrev->uCouldBe & PDCB_DAY_OF_MONTH)) { pPrev->uCouldBe = PDCB_DAY_OF_MONTH; } } // Absorb semantic meaning of PDCB_SIGN. // if (pNode->uCouldBe == PDCB_SIGN) { #define PDCB_SIGNABLES_POS (PDCB_HMS_TIME|PDCB_HMS_TIMEZONE) #define PDCB_SIGNABLES_NEG (PDCB_YEAR|PDCB_YD|PDCB_SIGNABLES_POS|PDCB_YMD) unsigned Signable; if (pNode->pToken[0] == '-') { Signable = PDCB_SIGNABLES_NEG; } else { Signable = PDCB_SIGNABLES_POS; } if ( pNext && (pNext->uCouldBe & Signable)) { pNext->uCouldBe &= Signable; } else { pNode->uCouldBe = PDCB_REMOVEABLE; } } // A timezone HOUR or HMS requires a leading sign. // if (pNode->uCouldBe & (PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE)) { if ( !pPrev || pPrev->uCouldBe != PDCB_SIGN) { pNode->uCouldBe &= ~(PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE); } } // Likewise, a PDCB_HOUR_TIME or PDCB_HMS_TIME cannot have a // leading sign. // if (pNode->uCouldBe & (PDCB_HMS_TIME|PDCB_HOUR_TIME)) { if ( pPrev && pPrev->uCouldBe == PDCB_SIGN) { pNode->uCouldBe &= ~(PDCB_HMS_TIME|PDCB_HOUR_TIME); } } // Remove PDCB_WHITESPACE. // if (pNode->uCouldBe & (PDCB_WHITESPACE|PDCB_REMOVEABLE)) { PD_RemoveNode(pNode); } pNode = pNext; } } typedef struct tag_pd_cantbe { unsigned int mask; unsigned int cantbe; } PD_CANTBE; const PD_CANTBE CantBeTable[] = { { PDCB_YEAR, PDCB_YEAR|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY }, { PDCB_MONTH, PDCB_MONTH|PDCB_WEEK_OF_YEAR|PDCB_DAY_OF_YEAR|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_WEEK_OF_YEAR_PREFIX }, { PDCB_DAY_OF_MONTH, PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR|PDCB_DAY_OF_YEAR|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_WEEK_OF_YEAR_PREFIX }, { PDCB_DAY_OF_WEEK, PDCB_DAY_OF_WEEK }, { PDCB_WEEK_OF_YEAR, PDCB_WEEK_OF_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY }, { PDCB_DAY_OF_YEAR, PDCB_DAY_OF_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_WEEK_OF_YEAR_PREFIX }, { PDCB_YD, PDCB_YEAR|PDCB_YD|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_WEEK_OF_YEAR_PREFIX }, { PDCB_YMD, PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR }, { PDCB_MDY, PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR }, { PDCB_DMY, PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR }, { PDCB_YMD|PDCB_MDY, PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR }, { PDCB_MDY|PDCB_DMY, PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR }, { PDCB_YMD|PDCB_DMY, PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR }, { PDCB_YMD|PDCB_DMY|PDCB_MDY, PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR }, { PDCB_TIMEZONE, PDCB_TIMEZONE|PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE }, { PDCB_HOUR_TIME, PDCB_HMS_TIME|PDCB_HOUR_TIME }, { PDCB_HOUR_TIMEZONE, PDCB_TIMEZONE|PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE }, { PDCB_HMS_TIME, PDCB_HMS_TIME|PDCB_HOUR_TIME }, { PDCB_HMS_TIMEZONE, PDCB_TIMEZONE|PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE }, { 0, 0 } }; static void PD_Deduction(void) { PD_Node *pNode = PD_FirstNode(); while (pNode) { int j =0; while (CantBeTable[j].mask) { if (pNode->uCouldBe == CantBeTable[j].mask) { PD_Node *pNodeInner = PD_FirstNode(); while (pNodeInner) { pNodeInner->uCouldBe &= ~CantBeTable[j].cantbe; pNodeInner = PD_NextNode(pNodeInner); } pNode->uCouldBe = CantBeTable[j].mask; break; } j++; } pNode = PD_NextNode(pNode); } } static void PD_BreakItDown(void) { PD_Node *pNode = PD_FirstNode(); while (pNode) { int j =0; while (BreakDownTable[j].mask) { if (pNode->uCouldBe == BreakDownTable[j].mask) { BreakDownTable[j].fpBreakDown(pNode); break; } j++; } pNode = PD_NextNode(pNode); } } static void PD_Pass5(void) { bool bHaveSeenTimeHour = false; bool bMightHaveSeenTimeHour = false; PD_Node *pNode = PD_FirstNode(); while (pNode) { PD_Node *pPrev = PD_PrevNode(pNode); PD_Node *pNext = PD_NextNode(pNode); // If all that is left is PDCB_HMS_TIME and PDCB_HOUR_TIME, then // it's PDCB_HOUR_TIME. // if (pNode->uCouldBe == (PDCB_HMS_TIME|PDCB_HOUR_TIME)) { pNode->uCouldBe = PDCB_HOUR_TIME; } if (pNode->uCouldBe == (PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE)) { pNode->uCouldBe = PDCB_HOUR_TIMEZONE; } // PDCB_MINUTE must follow an PDCB_HOUR_TIME or PDCB_HOUR_TIMEZONE. // if (pNode->uCouldBe & PDCB_MINUTE) { if ( !pPrev || !(pPrev->uCouldBe & (PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE))) { pNode->uCouldBe &= ~PDCB_MINUTE; } } // PDCB_SECOND must follow an PDCB_MINUTE. // if (pNode->uCouldBe & PDCB_SECOND) { if ( !pPrev || !(pPrev->uCouldBe & PDCB_MINUTE)) { pNode->uCouldBe &= ~PDCB_SECOND; } } // YMD MDY DMY // // PDCB_DAY_OF_MONTH cannot follow PDCB_YEAR. // if ( (pNode->uCouldBe & PDCB_DAY_OF_MONTH) && pPrev && pPrev->uCouldBe == PDCB_YEAR) { pNode->uCouldBe &= ~PDCB_DAY_OF_MONTH; } // Timezone cannot occur before the time. // if ( (pNode->uCouldBe & PDCB_TIMEZONE) && !bMightHaveSeenTimeHour) { pNode->uCouldBe &= ~PDCB_TIMEZONE; } // TimeDateSeparator cannot occur after the time. // if ( (pNode->uCouldBe & PDCB_DATE_TIME_SEPARATOR) && bHaveSeenTimeHour) { pNode->uCouldBe &= ~PDCB_DATE_TIME_SEPARATOR; } if (pNode->uCouldBe == PDCB_DATE_TIME_SEPARATOR) { PD_Node *pNodeInner = PD_FirstNode(); while (pNodeInner && pNodeInner != pNode) { pNodeInner->uCouldBe &= ~(PDCB_TIMEZONE|PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE|PDCB_MINUTE|PDCB_SECOND|PDCB_SUBSECOND|PDCB_MERIDIAN|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE); pNodeInner = PD_NextNode(pNodeInner); } pNodeInner = pNext; while (pNodeInner) { pNodeInner->uCouldBe &= ~(PDCB_WEEK_OF_YEAR_PREFIX|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_DAY_OF_WEEK|PDCB_WEEK_OF_YEAR|PDCB_DAY_OF_YEAR); pNodeInner = PD_NextNode(pNodeInner); } pNode->uCouldBe = PDCB_REMOVEABLE; } if (pNode->uCouldBe & PDCB_WEEK_OF_YEAR_PREFIX) { if ( pNext && (pNext->uCouldBe & PDCB_WEEK_OF_YEAR)) { pNext->uCouldBe = PDCB_WEEK_OF_YEAR; pNode->uCouldBe = PDCB_REMOVEABLE; } else if (pNode->uCouldBe == PDCB_WEEK_OF_YEAR_PREFIX) { pNode->uCouldBe = PDCB_REMOVEABLE; } } if (pNode->uCouldBe & (PDCB_HOUR_TIME|PDCB_HMS_TIME)) { if ((pNode->uCouldBe & ~(PDCB_HOUR_TIME|PDCB_HMS_TIME)) == 0) { bHaveSeenTimeHour = true; } bMightHaveSeenTimeHour = true; } // Remove PDCB_REMOVEABLE. // if (pNode->uCouldBe & PDCB_REMOVEABLE) { PD_RemoveNode(pNode); } pNode = pNext; } } static void PD_Pass6(void) { int cYear = 0; int cMonth = 0; int cDayOfMonth = 0; int cWeekOfYear = 0; int cDayOfYear = 0; int cDayOfWeek = 0; int cTime = 0; PD_Node *pNode = PD_FirstNode(); while (pNode) { if (pNode->uCouldBe & (PDCB_HMS_TIME|PDCB_HOUR_TIME)) { cTime++; } if (pNode->uCouldBe & PDCB_WEEK_OF_YEAR) { cWeekOfYear++; } if (pNode->uCouldBe & (PDCB_YEAR|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY)) { cYear++; } if (pNode->uCouldBe & (PDCB_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY)) { cMonth++; } if (pNode->uCouldBe & (PDCB_DAY_OF_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY)) { cDayOfMonth++; } if (pNode->uCouldBe & PDCB_DAY_OF_WEEK) { cDayOfWeek++; } if (pNode->uCouldBe & (PDCB_DAY_OF_YEAR|PDCB_YD)) { cDayOfYear++; } pNode = PD_NextNode(pNode); } unsigned OnlyOneMask = 0; unsigned CantBeMask = 0; if (cYear == 1) { OnlyOneMask |= PDCB_YEAR|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY; } if (cTime == 1) { OnlyOneMask |= PDCB_HMS_TIME|PDCB_HOUR_TIME; } if (cMonth == 0 || cDayOfMonth == 0) { CantBeMask |= PDCB_MONTH|PDCB_DAY_OF_MONTH; } if (cDayOfWeek == 0) { CantBeMask |= PDCB_WEEK_OF_YEAR; } if ( cMonth == 1 && cDayOfMonth == 1 && (cWeekOfYear != 1 || cDayOfWeek != 1) && cDayOfYear != 1) { OnlyOneMask |= PDCB_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY; OnlyOneMask |= PDCB_DAY_OF_MONTH; CantBeMask |= PDCB_WEEK_OF_YEAR|PDCB_YD; } else if (cDayOfYear == 1 && (cWeekOfYear != 1 || cDayOfWeek != 1)) { OnlyOneMask |= PDCB_DAY_OF_YEAR|PDCB_YD; CantBeMask |= PDCB_WEEK_OF_YEAR|PDCB_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY; CantBeMask |= PDCB_DAY_OF_MONTH; } else if (cWeekOfYear == 1 && cDayOfWeek == 1) { OnlyOneMask |= PDCB_WEEK_OF_YEAR; OnlyOneMask |= PDCB_DAY_OF_WEEK; CantBeMask |= PDCB_YD|PDCB_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY; CantBeMask |= PDCB_DAY_OF_MONTH; } // Also, if we match OnlyOneMask, then force only something in // OnlyOneMask. // pNode = PD_FirstNode(); while (pNode) { if (pNode->uCouldBe & OnlyOneMask) { pNode->uCouldBe &= OnlyOneMask; } if (pNode->uCouldBe & ~CantBeMask) { pNode->uCouldBe &= ~CantBeMask; } pNode = PD_NextNode(pNode); } } static bool PD_GetFields(ALLFIELDS *paf) { paf->iYear = NOT_PRESENT; paf->iDayOfYear = NOT_PRESENT; paf->iMonthOfYear = NOT_PRESENT; paf->iDayOfMonth = NOT_PRESENT; paf->iWeekOfYear = NOT_PRESENT; paf->iDayOfWeek = NOT_PRESENT; paf->iHourTime = NOT_PRESENT; paf->iMinuteTime = NOT_PRESENT; paf->iSecondTime = NOT_PRESENT; paf->iMillisecondTime = NOT_PRESENT; paf->iMicrosecondTime = NOT_PRESENT; paf->iNanosecondTime = NOT_PRESENT; paf->iMinuteTimeZone = NOT_PRESENT; PD_Node *pNode = PD_FirstNode(); while (pNode) { if (pNode->uCouldBe == PDCB_YEAR) { paf->iYear = pNode->iToken; PD_Node *pPrev = PD_PrevNode(pNode); if ( pPrev && pPrev->uCouldBe == PDCB_SIGN && pPrev->pToken[0] == '-') { paf->iYear = -paf->iYear; } } else if (pNode->uCouldBe == PDCB_DAY_OF_YEAR) { paf->iDayOfYear = pNode->iToken; } else if (pNode->uCouldBe == PDCB_MONTH) { paf->iMonthOfYear = pNode->iToken; } else if (pNode->uCouldBe == PDCB_DAY_OF_MONTH) { paf->iDayOfMonth = pNode->iToken; } else if (pNode->uCouldBe == PDCB_WEEK_OF_YEAR) { paf->iWeekOfYear = pNode->iToken; } else if (pNode->uCouldBe == PDCB_DAY_OF_WEEK) { paf->iDayOfWeek = pNode->iToken; } else if (pNode->uCouldBe == PDCB_HOUR_TIME) { paf->iHourTime = pNode->iToken; pNode = PD_NextNode(pNode); if ( pNode && pNode->uCouldBe == PDCB_MINUTE) { paf->iMinuteTime = pNode->iToken; pNode = PD_NextNode(pNode); if ( pNode && pNode->uCouldBe == PDCB_SECOND) { paf->iSecondTime = pNode->iToken; pNode = PD_NextNode(pNode); if ( pNode && pNode->uCouldBe == PDCB_SUBSECOND) { unsigned short ms, us, ns; ParseDecimalSeconds(pNode->nToken, pNode->pToken, &ms, &us, &ns); paf->iMillisecondTime = ms; paf->iMicrosecondTime = us; paf->iNanosecondTime = ns; pNode = PD_NextNode(pNode); } } } if ( pNode && pNode->uCouldBe == PDCB_MERIDIAN) { if (paf->iHourTime == 12) { paf->iHourTime = 0; } paf->iHourTime += pNode->iToken; pNode = PD_NextNode(pNode); } continue; } else if (pNode->uCouldBe == PDCB_HOUR_TIMEZONE) { paf->iMinuteTimeZone = pNode->iToken * 60; PD_Node *pPrev = PD_PrevNode(pNode); if ( pPrev && pPrev->uCouldBe == PDCB_SIGN && pPrev->pToken[0] == '-') { paf->iMinuteTimeZone = -paf->iMinuteTimeZone; } pNode = PD_NextNode(pNode); if ( pNode && pNode->uCouldBe == PDCB_MINUTE) { if (paf->iMinuteTimeZone < 0) { paf->iMinuteTimeZone -= pNode->iToken; } else { paf->iMinuteTimeZone += pNode->iToken; } pNode = PD_NextNode(pNode); } continue; } else if (pNode->uCouldBe == PDCB_TIMEZONE) { if (pNode->iToken < 0) { paf->iMinuteTimeZone = (pNode->iToken / 100) * 60 - ((-pNode->iToken) % 100); } else { paf->iMinuteTimeZone = (pNode->iToken / 100) * 60 + pNode->iToken % 100; } } else if (pNode->uCouldBe & (PDCB_SIGN|PDCB_DATE_TIME_SEPARATOR)) { ; // Nothing } else { return false; } pNode = PD_NextNode(pNode); } return true; } static bool ConvertAllFieldsToLinearTime(CLinearTimeAbsolute <a, ALLFIELDS *paf) { FIELDEDTIME ft; memset(&ft, 0, sizeof(ft)); int iExtraDays = 0; if (paf->iYear == NOT_PRESENT) { return false; } ft.iYear = static_cast(paf->iYear); if (paf->iMonthOfYear != NOT_PRESENT && paf->iDayOfMonth != NOT_PRESENT) { ft.iMonth = static_cast(paf->iMonthOfYear); ft.iDayOfMonth = static_cast(paf->iDayOfMonth); } else if (paf->iDayOfYear != NOT_PRESENT) { iExtraDays = paf->iDayOfYear - 1; ft.iMonth = 1; ft.iDayOfMonth = 1; } else if (paf->iWeekOfYear != NOT_PRESENT && paf->iDayOfWeek != NOT_PRESENT) { // Remember that iYear in this case represents an ISO year, which // is not exactly the same thing as a Gregorian year. // FIELDEDTIME ftWD; memset(&ftWD, 0, sizeof(ftWD)); ftWD.iYear = static_cast(paf->iYear - 1); ftWD.iMonth = 12; ftWD.iDayOfMonth = 27; if (!lta.SetFields(&ftWD)) { return false; } INT64 i64 = lta.Return100ns(); INT64 j64; i64FloorDivisionMod(i64+FACTOR_100NS_PER_DAY, FACTOR_100NS_PER_WEEK, &j64); i64 -= j64; // i64 now corresponds to the Sunday that strickly preceeds before // December 28th, and the 28th is guaranteed to be in the previous // year so that the ISO and Gregorian Years are the same thing. // i64 += FACTOR_100NS_PER_WEEK*paf->iWeekOfYear; i64 += FACTOR_100NS_PER_DAY*paf->iDayOfWeek; lta.Set100ns(i64); lta.ReturnFields(&ft); // Validate that this week actually has a week 53. // if (paf->iWeekOfYear == 53) { int iDOW_ISO = (ft.iDayOfWeek == 0) ? 7 : ft.iDayOfWeek; int j = ft.iDayOfMonth - iDOW_ISO; if (ft.iMonth == 12) { if (28 <= j) { return false; } } else // if (ft.iMonth == 1) { if (-3 <= j) { return false; } } } } else { // Under-specified. // return false; } if (paf->iHourTime != NOT_PRESENT) { ft.iHour = static_cast(paf->iHourTime); if (paf->iMinuteTime != NOT_PRESENT) { ft.iMinute = static_cast(paf->iMinuteTime); if (paf->iSecondTime != NOT_PRESENT) { ft.iSecond = static_cast(paf->iSecondTime); if (paf->iMillisecondTime != NOT_PRESENT) { ft.iMillisecond = static_cast(paf->iMillisecondTime); ft.iMicrosecond = static_cast(paf->iMicrosecondTime); ft.iNanosecond = static_cast(paf->iNanosecondTime); } } } } if (lta.SetFields(&ft)) { CLinearTimeDelta ltd; if (paf->iMinuteTimeZone != NOT_PRESENT) { ltd.SetSeconds(60 * paf->iMinuteTimeZone); lta -= ltd; } if (iExtraDays) { ltd.Set100ns(FACTOR_100NS_PER_DAY); lta += ltd * iExtraDays; } return true; } return false; } bool ParseDate ( CLinearTimeAbsolute <, char *pDateString, bool *pbZoneSpecified ) { PD_Reset(); char *p = pDateString; PD_Node *pNode; for ( pNode = PD_ScanNextToken(&p); pNode; pNode = PD_ScanNextToken(&p)) { PD_AppendNode(pNode); } PD_Pass2(); PD_Deduction(); PD_BreakItDown(); PD_Pass5(); PD_Pass6(); PD_Deduction(); PD_BreakItDown(); PD_Pass5(); PD_Pass6(); ALLFIELDS af; if ( PD_GetFields(&af) && ConvertAllFieldsToLinearTime(lt, &af)) { *pbZoneSpecified = (af.iMinuteTimeZone != NOT_PRESENT); return true; } return false; } mux2.6/src/version.cpp0000600000175000017500000000665411025753746015002 0ustar sdennissdennis// version.cpp -- Version information. // // $Id: version.cpp 534 2006-12-11 16:57:52Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "_build.h" #include "command.h" void do_version(dbref executor, dbref caller, dbref enactor, int extra) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(extra); notify(executor, mudstate.version); char *buff = alloc_mbuf("do_version"); mux_sprintf(buff, MBUF_SIZE, "Build date: %s", MUX_BUILD_DATE); notify(executor, buff); free_mbuf(buff); } void build_version(void) { #if defined(WIN64) #if defined(ALPHA) mux_sprintf(mudstate.version, sizeof(mudstate.version), "MUX %s for Win64 #%s [ALPHA]", MUX_VERSION, MUX_BUILD_NUM); mux_sprintf(mudstate.short_ver, sizeof(mudstate.short_ver), "MUX %s Alpha Win64", MUX_VERSION); #elif defined(BETA) mux_sprintf(mudstate.version, sizeof(mudstate.version), "MUX %s for Win64 #%s [BETA]", MUX_VERSION, MUX_BUILD_NUM); mux_sprintf(mudstate.short_ver, sizeof(mudstate.short_ver), "MUX %s Beta Win64", MUX_VERSION); #else // RELEASED mux_sprintf(mudstate.version, sizeof(mudstate.version), "MUX %s for Win64 #%s [%s]", MUX_VERSION, MUX_BUILD_NUM, MUX_RELEASE_DATE); mux_sprintf(mudstate.short_ver, sizeof(mudstate.short_ver), "MUX %s Win64", MUX_VERSION); #endif // ALPHA, BETA, RELEASED #elif defined(WIN32) #if defined(ALPHA) mux_sprintf(mudstate.version, sizeof(mudstate.version), "MUX %s for Win32 #%s [ALPHA]", MUX_VERSION, MUX_BUILD_NUM); mux_sprintf(mudstate.short_ver, sizeof(mudstate.short_ver), "MUX %s Alpha Win32", MUX_VERSION); #elif defined(BETA) mux_sprintf(mudstate.version, sizeof(mudstate.version), "MUX %s for Win32 #%s [BETA]", MUX_VERSION, MUX_BUILD_NUM); mux_sprintf(mudstate.short_ver, sizeof(mudstate.short_ver), "MUX %s Beta Win32", MUX_VERSION); #else // RELEASED mux_sprintf(mudstate.version, sizeof(mudstate.version), "MUX %s for Win32 #%s [%s]", MUX_VERSION, MUX_BUILD_NUM, MUX_RELEASE_DATE); mux_sprintf(mudstate.short_ver, sizeof(mudstate.short_ver), "MUX %s Win32", MUX_VERSION); #endif // ALPHA, BETA, RELEASED #else // WIN32 #if defined(ALPHA) mux_sprintf(mudstate.version, sizeof(mudstate.version), "MUX %s #%s [ALPHA]", MUX_VERSION, MUX_BUILD_NUM); mux_sprintf(mudstate.short_ver, sizeof(mudstate.short_ver), "MUX %s Alpha", MUX_VERSION); #elif defined(BETA) mux_sprintf(mudstate.version, sizeof(mudstate.version), "MUX %s #%s [BETA]", MUX_VERSION, MUX_BUILD_NUM); mux_sprintf(mudstate.short_ver, sizeof(mudstate.short_ver), "MUX %s Beta", MUX_VERSION); #else // RELEASED mux_sprintf(mudstate.version, sizeof(mudstate.version), "MUX %s #%s [%s]", MUX_VERSION, MUX_BUILD_NUM, MUX_RELEASE_DATE); mux_sprintf(mudstate.short_ver, sizeof(mudstate.short_ver), "MUX %s", MUX_VERSION); #endif // ALPHA, BETA, RELEASED #endif // WIN32 } void init_version(void) { STARTLOG(LOG_ALWAYS, "INI", "START"); log_text("Starting: "); log_text(mudstate.version); ENDLOG; STARTLOG(LOG_ALWAYS, "INI", "START"); log_text("Build date: "); log_text(MUX_BUILD_DATE); ENDLOG; } mux2.6/src/svdhash.h0000600000175000017500000002211411025753746014407 0ustar sdennissdennis// svdhash.h -- CHashPage, CHashFile, CHashTable modules. // // $Id: svdhash.h 2475 2007-09-15 16:18:35Z brazilofmux $ // #ifndef SVDHASH_H #define SVDHASH_H #ifndef MEMORY_BASED // // These are from 'svdhash.cpp'. // extern int cs_writes; // total writes extern int cs_reads; // total reads extern int cs_dels; // total deletes extern int cs_fails; // attempts to grab nonexistent extern int cs_syncs; // total cache syncs extern int cs_dbreads; // total read-throughs extern int cs_dbwrites; // total write-throughs extern int cs_rhits; // total reads filled from cache extern int cs_whits; // total writes to dirty cache #endif // !MEMORY_BASED //#define HP_PROTECTION #define SECTOR_SIZE 512 #define LBUF_BLOCKED (SECTOR_SIZE*((LBUF_SIZE+SECTOR_SIZE-1)/SECTOR_SIZE)) #define HT_SIZEOF_PAGE (1*LBUF_BLOCKED) #define HF_SIZEOF_PAGE (3*LBUF_BLOCKED) extern UINT32 CRC32_ProcessBuffer ( UINT32 ulCrc, const void *pBuffer, size_t nBuffer ); extern UINT32 CRC32_ProcessInteger(UINT32 nInteger); extern UINT32 CRC32_ProcessInteger2 ( UINT32 nInteger1, UINT32 nInteger2 ); extern UINT32 HASH_ProcessBuffer ( UINT32 ulHash, const void *arg_pBuffer, size_t nBuffer ); #if defined(_SGI_SOURCE) || ((UINT16_MAX_VALUE-2) <= HF_SIZEOF_PAGE) typedef UINT32 UINT_OFFSET; #define UINT_OFFSET_MAX_VALUE UINT32_MAX_VALUE #define EXPAND_TO_BOUNDARY(x) (((x) + 3) & (~3)) #else typedef UINT16 UINT_OFFSET; #define UINT_OFFSET_MAX_VALUE UINT16_MAX_VALUE #define EXPAND_TO_BOUNDARY(x) (static_cast(((x) + 1) & (~1))) #endif typedef UINT_OFFSET HP_HEAPOFFSET, *HP_PHEAPOFFSET; typedef UINT_OFFSET HP_HEAPLENGTH, *HP_PHEAPLENGTH; typedef UINT_OFFSET HP_DIRINDEX, *HP_PDIRINDEX; #define HP_SIZEOF_HEAPOFFSET sizeof(HP_HEAPOFFSET) #define HP_SIZEOF_HEAPLENGTH sizeof(HP_HEAPLENGTH) #define HP_SIZEOF_DIRINDEX sizeof(HP_DIRINDEX); #pragma pack(1) typedef struct tagHPHeader { UINT32 m_nTotalInsert; UINT32 m_nDirEmptyLeft; UINT32 m_nHashGroup; HP_DIRINDEX m_nDirSize; HP_DIRINDEX m_Primes[16]; HP_HEAPOFFSET m_oFreeList; HP_DIRINDEX m_nDepth; } HP_HEADER, *HP_PHEADER; #define HP_NIL_OFFSET UINT_OFFSET_MAX_VALUE // Possible special values for m_pDirectory[i] // #define HP_DIR_EMPTY UINT_OFFSET_MAX_VALUE #define HP_DIR_DELETED (UINT_OFFSET_MAX_VALUE-1) typedef struct tagHPTrailer { UINT32 m_checksum; } HP_TRAILER, *HP_PTRAILER; typedef struct tagHPHeapNode { HP_HEAPLENGTH nBlockSize; union { HP_HEAPOFFSET oNext; struct { HP_HEAPLENGTH nRecordSize; UINT32 nHash; } s; } u; } HP_HEAPNODE, *HP_PHEAPNODE; #define HP_SIZEOF_HEAPNODE sizeof(HP_HEAPNODE) #pragma pack() #define HP_MIN_HEAP_ALLOC HP_SIZEOF_HEAPNODE #if !defined(MEMORY_BASED) typedef unsigned long HF_FILEOFFSET, *HF_PFILEOFFSET; #define HF_SIZEOF_FILEOFFSET sizeof(HF_FILEOFFSET) #endif // MEMORY_BASED class CHashPage { private: unsigned char *m_pPage; unsigned int m_nPageSize; HP_PHEADER m_pHeader; HP_PHEAPOFFSET m_pDirectory; unsigned char *m_pHeapStart; unsigned char *m_pHeapEnd; HP_PTRAILER m_pTrailer; int m_iDir; int m_nProbesLeft; UINT32 m_nDirEmptyTrigger; #ifdef HP_PROTECTION bool ValidateAllocatedBlock(UINT32 iDir); bool ValidateFreeBlock(HP_HEAPOFFSET oBlock); bool ValidateFreeList(void); #endif // HP_PROTECTION bool HeapAlloc(UINT32 iDir, HP_HEAPLENGTH nRecord, UINT32 nHash, void *pRecord); void SetVariablePointers(void); void SetFixedPointers(void); void GetStats(HP_HEAPLENGTH nExtra, int *pnRecords, HP_HEAPLENGTH *pnAllocatedSize, UINT32 *pnGoodDirSize); public: CHashPage(void); bool Allocate(unsigned int nPageSize); ~CHashPage(void); void Empty(UINT32 arg_nDepth, UINT32 arg_nHashGroup, UINT32 arg_nDirSize); #ifdef HP_PROTECTION void Protection(void); bool Validate(void); #endif // HP_PROTECTION #define HP_INSERT_SUCCESS_DEFRAG 0 #define HP_INSERT_SUCCESS 1 #define HP_INSERT_ERROR_FULL 2 #define HP_INSERT_ERROR_ILLEGAL 3 #define IS_HP_SUCCESS(x) ((x) <= HP_INSERT_SUCCESS) int Insert(HP_HEAPLENGTH nRecord, UINT32 nHash, void *pRecord); UINT32 FindFirstKey(UINT32 nHash, unsigned int *numchecks); UINT32 FindNextKey(UINT32 i, UINT32 nHash, unsigned int *numchecks); UINT32 FindFirst(HP_PHEAPLENGTH pnRecord, void *pRecord); UINT32 FindNext(HP_PHEAPLENGTH pnRecord, void *pRecord); void HeapCopy(UINT32 iDir, HP_PHEAPLENGTH pnRecord, void *pRecord); void HeapFree(UINT32 iDir); void HeapUpdate(UINT32 iDir, HP_HEAPLENGTH nRecord, void *pRecord); #if !defined(MEMORY_BASED) bool WritePage(HANDLE hFile, HF_FILEOFFSET oWhere); bool ReadPage(HANDLE hFile, HF_FILEOFFSET oWhere); #endif // MEMORY_BASED UINT32 GetDepth(void); bool Split(CHashPage &hp0, CHashPage &hp1); bool Defrag(HP_HEAPLENGTH nExtra); void GetRange(UINT32 arg_nDirDepth, UINT32 &nStart, UINT32 &nEnd); }; #define HF_FIND_FIRST HP_DIR_EMPTY #define HF_FIND_END HP_DIR_EMPTY #if !defined(MEMORY_BASED) #define HF_CACHE_EMPTY 0 #define HF_CACHE_CLEAN 1 #define HF_CACHE_UNPROTECTED 2 #define HF_CACHE_UNWRITTEN 3 #define HF_CACHE_NUM_STATES 4 typedef struct tagHashFileCache { CHashPage m_hp; HF_FILEOFFSET m_o; int m_iState; int m_iYounger; int m_iOlder; } HF_CACHE; class CHashFile { private: HANDLE m_hDirFile; HANDLE m_hPageFile; int iCache; int m_iOldest; int m_iLastFlushed; int *m_hpCacheLookup; HF_FILEOFFSET oEndOfFile; unsigned int m_nDir; unsigned int m_nDirDepth; HF_CACHE *m_Cache; int m_nCache; HF_PFILEOFFSET m_pDir; bool DoubleDirectory(void); int AllocateEmptyPage(int nSafe, int Safe[]); int ReadCache(UINT32 iFileDir, int *pHits); bool FlushCache(int iCache); void WriteDirectory(void); bool InitializeDirectory(unsigned int nSize); void ResetAge(int iEntry); void Init(void); void InitCache(int nCachePages); void FinalCache(void); bool CreateFileSet(const char *szDirFile, const char *szPageFile); bool RebuildDirectory(void); bool ReadDirectory(void); public: CHashFile(void); #define HF_OPEN_STATUS_ERROR -1 #define HF_OPEN_STATUS_NEW 0 #define HF_OPEN_STATUS_OLD 1 int Open(const char *szDirFile, const char *szPageFile, int nCachePages); bool Insert(HP_HEAPLENGTH nRecord, UINT32 nHash, void *pRecord); UINT32 FindFirstKey(UINT32 nHash); UINT32 FindNextKey(UINT32 iDir, UINT32 nHash); void Copy(UINT32 iDir, HP_PHEAPLENGTH pnRecord, void *pRecord); void Remove(UINT32 iDir); void CloseAll(void); void Sync(void); void Tick(void); ~CHashFile(void); }; #endif // MEMORY_BASED typedef CHashPage *pCHashPage; class CHashTable { private: unsigned int m_nDir; unsigned int m_nDirDepth; pCHashPage *m_pDir; CHashPage *m_hpLast; unsigned int m_iPage; unsigned int m_nPages; unsigned int m_nEntries; INT64 m_nDeletions; INT64 m_nScans; INT64 m_nHits; INT64 m_nChecks; unsigned int m_nMaxScan; bool DoubleDirectory(void); void Init(void); void Final(void); public: CHashTable(void); void ResetStats(void); void GetStats( unsigned int *hashsize, int *entries, INT64 *deletes, INT64 *scans, INT64 *hits, INT64 *checks, int *max_scan); unsigned int GetEntryCount(); void Reset(void); bool Insert(HP_HEAPLENGTH nRecord, UINT32 nHash, void *pRecord); UINT32 FindFirstKey(UINT32 nHash); UINT32 FindNextKey(UINT32 iDir, UINT32 nHash); UINT32 FindFirst(HP_PHEAPLENGTH pnRecord, void *pRecord); UINT32 FindNext(HP_PHEAPLENGTH pnRecord, void *pRecord); void Copy(UINT32 iDir, HP_PHEAPLENGTH pnRecord, void *pRecord); void Remove(UINT32 iDir); void Update(UINT32 iDir, HP_HEAPLENGTH nRecord, void *pRecord); ~CHashTable(void); }; #define SIZEOF_LOG_BUFFER 1024 class CLogFile { private: CLinearTimeAbsolute m_ltaStarted; #ifdef WIN32 CRITICAL_SECTION csLog; HANDLE m_hFile; #else int m_fdFile; #endif // WIN32 size_t m_nSize; size_t m_nBuffer; char m_aBuffer[SIZEOF_LOG_BUFFER]; bool bEnabled; bool bUseStderr; char *m_pBasename; char m_szPrefix[32]; char m_szFilename[SIZEOF_PATHNAME]; bool CreateLogFile(void); void AppendLogFile(void); void CloseLogFile(void); public: CLogFile(void); ~CLogFile(void); void WriteBuffer(size_t nString, const char *pString); void WriteString(const char *pString); void WriteInteger(int iNumber); void DCL_CDECL tinyprintf(const char *pFormatSpec, ...); void Flush(void); void SetPrefix(const char *pPrefix); void SetBasename(const char *pBasename); void StartLogging(void); void StopLogging(void); }; extern CLogFile Log; #endif //!SVDHASH_H mux2.6/src/svdreport.cpp0000600000175000017500000000317111025753746015334 0ustar sdennissdennis// svdreport.cpp -- Aggregate User Statistics module. // // $Id: svdreport.cpp 8 2006-09-05 01:55:58Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #define NPERIODS 24 void do_report(dbref executor, dbref caller, dbref enactor, int extra) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(extra); char *buff = alloc_mbuf("do_report"); int nBin[NPERIODS]; int i; for (i = 0; i < NPERIODS; i++) { nBin[i] = 0; } CLinearTimeAbsolute ltaNow, ltaPlayer; ltaNow.GetLocal(); const int PeriodInSeconds = 28800; int iPlayer; DO_WHOLE_DB(iPlayer) { if (isPlayer(iPlayer)) { int aowner, aflags; char *player_last = atr_get(iPlayer, A_LAST, &aowner, &aflags); if (ltaPlayer.SetString(player_last)) { CLinearTimeDelta ltd(ltaPlayer, ltaNow); int ltdSeconds = ltd.ReturnSeconds(); int iBin = ltdSeconds / PeriodInSeconds; if (0 <= iBin && iBin < NPERIODS) { nBin[iBin]++; } } free_lbuf(player_last); } } int iHour, nSum = 0; notify(executor, "Day Hours Players Total"); for (i = 0, iHour = 0; i < NPERIODS; i++, iHour += 8) { nSum += nBin[i]; mux_sprintf(buff, MBUF_SIZE, "%3d %03d - %03d: %6d %6d", iHour/24 + 1, iHour, iHour+8, nBin[i], nSum); notify(executor, buff); } free_mbuf(buff); } mux2.6/src/object.cpp0000600000175000017500000013102011025753746014545 0ustar sdennissdennis// object.cpp -- Low-level object manipulation routines. // // $Id: object.cpp 3211 2008-01-22 19:17:24Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "mguests.h" #include "powers.h" #define IS_CLEAN(i) (isGarbage(i) && Going(i) && \ ((i) >= 0) && ((i) < mudstate.db_top) && \ (Location(i) == NOTHING) && \ (Contents(i) == NOTHING) && (Exits(i) == NOTHING) && \ (Next(i) == NOTHING) && (Owner(i) == GOD)) static int check_type; /* * --------------------------------------------------------------------------- * * Log_pointer_err, Log_header_err, Log_simple_damage: Write errors to the * * log file. */ static void Log_pointer_err(dbref prior, dbref obj, dbref loc, dbref ref, const char *reftype, const char *errtype) { STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG"); log_type_and_name(obj); if (loc != NOTHING) { log_text(" in "); log_type_and_name(loc); } log_text(": "); if (prior == NOTHING) { log_text(reftype); } else { log_text("Next pointer"); } log_text(" "); log_type_and_name(ref); log_text(" "); log_text(errtype); ENDLOG; } static void Log_header_err(dbref obj, dbref loc, dbref val, bool is_object, const char *valtype, const char *errtype) { STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG"); log_type_and_name(obj); if (loc != NOTHING) { log_text(" in "); log_type_and_name(loc); } log_text(": "); log_text(valtype); log_text(" "); if (is_object) { log_type_and_name(val); } else { log_number(val); } log_text(" "); log_text(errtype); ENDLOG; } static void Log_simple_err(dbref obj, dbref loc, const char *errtype) { STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG"); log_type_and_name(obj); if (loc != NOTHING) { log_text(" in "); log_type_and_name(loc); } log_text(": "); log_text(errtype); ENDLOG; } /* * --------------------------------------------------------------------------- * * start_home, default_home, can_set_home, new_home, clone_home: * * Routines for validating and determining homes. */ dbref start_home(void) { if (mudconf.start_home != NOTHING) { return mudconf.start_home; } return mudconf.start_room; } dbref default_home(void) { if (mudconf.default_home != NOTHING) { return mudconf.default_home; } if (mudconf.start_home != NOTHING) { return mudconf.start_home; } return mudconf.start_room; } bool can_set_home(dbref player, dbref thing, dbref home) { if ( !Good_obj(player) || !Good_obj(home) || thing == home) { return false; } switch (Typeof(home)) { case TYPE_PLAYER: case TYPE_ROOM: case TYPE_THING: if (Going(home)) { return false; } if ( Controls(player, home) || Abode(home)) { return true; } } return false; } dbref new_home(dbref player) { dbref loc = Location(player); if (can_set_home(Owner(player), player, loc)) { return loc; } loc = Home(Owner(player)); if (can_set_home(Owner(player), player, loc)) { return loc; } return default_home(); } dbref clone_home(dbref player, dbref thing) { dbref loc = Home(thing); if (can_set_home(Owner(player), player, loc)) { return loc; } return new_home(player); } /* * --------------------------------------------------------------------------- * * create_obj: Create an object of the indicated type IF the player can * * afford it. */ dbref create_obj(dbref player, int objtype, const char *name, int cost) { dbref obj, owner; int quota = 0, value = 0; size_t nValidName; FLAGSET f; char *buff; const char *pValidName; const char *tname; bool okname = false, self_owned = false, require_inherit = false; switch (objtype) { case TYPE_ROOM: cost = mudconf.digcost; quota = mudconf.room_quota; f = mudconf.room_flags; pValidName = MakeCanonicalObjectName(name, &nValidName, &okname); tname = "a room"; break; case TYPE_THING: if (cost < mudconf.createmin) cost = mudconf.createmin; if (cost > mudconf.createmax) cost = mudconf.createmax; quota = mudconf.thing_quota; f = mudconf.thing_flags; value = OBJECT_ENDOWMENT(cost); pValidName = MakeCanonicalObjectName(name, &nValidName, &okname); tname = "a thing"; break; case TYPE_EXIT: cost = mudconf.opencost; quota = mudconf.exit_quota; f = mudconf.exit_flags; pValidName = MakeCanonicalExitName(name, &nValidName, &okname); tname = "an exit"; break; case TYPE_PLAYER: if (cost) { cost = mudconf.robotcost; quota = mudconf.player_quota; f = mudconf.robot_flags; value = 0; tname = "a robot"; require_inherit = true; } else { cost = 0; quota = 0; f = mudconf.player_flags; value = mudconf.paystart; quota = mudconf.start_quota; self_owned = true; tname = "a player"; } buff = munge_space(name); pValidName = name; if (!badname_check(buff)) { notify(player, "That name is not allowed."); free_lbuf(buff); return NOTHING; } if (*buff) { okname = ValidatePlayerName(buff); if (!okname) { notify(player, "That's a silly name for a player."); free_lbuf(buff); return NOTHING; } } if (okname) { okname = (lookup_player(NOTHING, buff, false) == NOTHING); if (!okname) { notify(player, tprintf("The name %s is already taken.", name)); free_lbuf(buff); return NOTHING; } } free_lbuf(buff); break; default: LOG_SIMPLE(LOG_BUGS, "BUG", "OTYPE", tprintf("Bad object type in create_obj: %d.", objtype)); return NOTHING; } if (!okname) { notify(player, tprintf("That's a silly name for %s!", tname)); return NOTHING; } if (!self_owned) { if (!Good_obj(player)) { return NOTHING; } owner = Owner(player); if (!Good_obj(owner)) { return NOTHING; } } else { owner = NOTHING; } if (require_inherit) { if (!Inherits(player)) { notify(player, NOPERM_MESSAGE); return NOTHING; } } // Make sure the creator can pay for the object. // if ((player != NOTHING) && !canpayfees(player, player, cost, quota)) { return NOTHING; } // Get the first object from the freelist. If the object is not clean, // discard the remainder of the freelist and go get a completely new object. // obj = NOTHING; if (mudstate.freelist != NOTHING) { obj = mudstate.freelist; if (IS_CLEAN(obj)) { mudstate.freelist = Link(obj); } else { LOG_SIMPLE(LOG_PROBLEMS, "FRL", "DAMAG", tprintf("Freelist damaged, bad object #%d.", obj)); obj = NOTHING; mudstate.freelist = NOTHING; } } if (obj == NOTHING) { obj = mudstate.db_top; db_grow(mudstate.db_top + 1); } atr_free(obj); // just in case. // Set things up according to the object type. // s_Location(obj, NOTHING); s_Contents(obj, NOTHING); s_Exits(obj, NOTHING); s_Next(obj, NOTHING); s_Link(obj, NOTHING); s_Parent(obj, NOTHING); if (mudconf.autozone && player != NOTHING) { s_Zone(obj, Zone(player)); } else { s_Zone(obj, NOTHING); } f.word[FLAG_WORD1] |= objtype; db[obj].fs = f; s_Owner(obj, (self_owned ? obj : owner)); s_Pennies(obj, value); Unmark(obj); pValidName = munge_space(pValidName); s_Name(obj, pValidName); free_lbuf(pValidName); db[obj].cpu_time_used.Set100ns(0); db[obj].tThrottleExpired.Set100ns(0); s_ThAttrib(obj, 0); s_ThMail(obj, 0); CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); buff = ltaNow.ReturnDateString(7); atr_add_raw(obj, A_CREATED, buff); atr_add_raw(obj, A_MODIFIED, buff); if (objtype == TYPE_PLAYER) { atr_add_raw(obj, A_LAST, buff); buff = alloc_sbuf("create_obj.quota"); mux_ltoa(quota, buff); atr_add_raw(obj, A_QUOTA, buff); atr_add_raw(obj, A_RQUOTA, buff); add_player_name(obj, Name(obj)); free_sbuf(buff); s_Zone(obj, NOTHING); } return obj; } /* * --------------------------------------------------------------------------- * * destroy_obj: Destroy an object. Assumes it has already been removed from * * all lists and has no contents or exits. */ static void destroy_bad_obj(dbref obj) { if (!mudstate.bStandAlone) { halt_que(NOTHING, obj); nfy_que(obj, 0, NFY_DRAIN, 0); fwdlist_clr(obj); #ifdef DEPRECATED stack_clr(obj); #endif // DEPRECATED ReleaseAllResources(obj); } atr_free(obj); s_Name(obj, NULL); s_Flags(obj, FLAG_WORD1, (TYPE_GARBAGE | GOING)); s_Flags(obj, FLAG_WORD2, 0); s_Flags(obj, FLAG_WORD3, 0); s_Powers(obj, 0); s_Powers2(obj, 0); s_Location(obj, NOTHING); s_Contents(obj, NOTHING); s_Exits(obj, NOTHING); s_Next(obj, NOTHING); s_Link(obj, NOTHING); s_Owner(obj, GOD); s_Pennies(obj, 0); s_Parent(obj, NOTHING); s_Zone(obj, NOTHING); } void destroy_obj(dbref obj) { if (!Good_obj(obj)) { if ( (obj >= 0) && (obj < mudstate.db_top)) { destroy_bad_obj(obj); } return; } // Validate the owner. // dbref owner = Owner(obj); bool good_owner = Good_owner(owner); // Halt any pending commands (waiting or semaphore). // if (!mudstate.bStandAlone) { if ( halt_que(NOTHING, obj) > 0 && good_owner && !Quiet(obj) && !Quiet(owner)) { notify(owner, "Halted."); } nfy_que(obj, 0, NFY_DRAIN, 0); // Remove forwardlists and stacks. // fwdlist_clr(obj); #ifdef DEPRECATED stack_clr(obj); #endif // DEPRECATED } // Compensate the owner for the object. // if ( good_owner && owner != obj) { int val = 0; int quota = 0; switch (Typeof(obj)) { case TYPE_ROOM: val = mudconf.digcost; quota = mudconf.room_quota; break; case TYPE_THING: val = OBJECT_DEPOSIT(Pennies(obj)); quota = mudconf.thing_quota; break; case TYPE_EXIT: if (Location(obj) == NOTHING) { val = mudconf.opencost; } else { val = mudconf.opencost + mudconf.linkcost; } quota = mudconf.exit_quota; break; case TYPE_PLAYER: if (Robot(obj)) { val = mudconf.robotcost; } else { val = 0; } quota = mudconf.player_quota; break; } if (val) { giveto(owner, val); if ( !Quiet(owner) && !Quiet(obj)) { notify(owner, tprintf( "You get back your %d %s deposit for %s(#%d).", val, mudconf.one_coin, Moniker(obj), obj)); } } if ( mudconf.quotas && quota) { add_quota(owner, quota); } } if (!mudstate.bStandAlone) { ReleaseAllResources(obj); } atr_free(obj); s_Name(obj, NULL); s_Flags(obj, FLAG_WORD1, (TYPE_GARBAGE | GOING)); s_Flags(obj, FLAG_WORD2, 0); s_Flags(obj, FLAG_WORD3, 0); s_Powers(obj, 0); s_Powers2(obj, 0); s_Location(obj, NOTHING); s_Contents(obj, NOTHING); s_Exits(obj, NOTHING); s_Next(obj, NOTHING); s_Link(obj, NOTHING); s_Owner(obj, GOD); s_Pennies(obj, 0); s_Parent(obj, NOTHING); s_Zone(obj, NOTHING); local_data_free(obj); } /* * --------------------------------------------------------------------------- * * make_freelist: Build a freelist */ static void make_freelist(void) { dbref i; mudstate.freelist = NOTHING; DO_WHOLE_DB_BACKWARDS(i) { if (IS_CLEAN(i)) { s_Link(i, mudstate.freelist); mudstate.freelist = i; } } } /* * --------------------------------------------------------------------------- * * divest_object: Get rid of KEY contents of object. */ void divest_object(dbref thing) { dbref curr, temp; SAFE_DOLIST(curr, temp, Contents(thing)) { if ( !Controls(thing, curr) && Has_location(curr) && Key(curr)) { if ( !Good_obj(Home(curr)) || Going(Home(curr))) { s_Home(curr, new_home(curr)); } move_via_generic(curr, HOME, NOTHING, 0); } } } /* * --------------------------------------------------------------------------- * * empty_obj, purge_going: Get rid of GOING objects in the db. */ void empty_obj(dbref obj) { dbref targ, next; // Send the contents home // SAFE_DOLIST(targ, next, Contents(obj)) { if (!Has_location(targ)) { Log_simple_err(targ, obj, "Funny object type in contents list of GOING location. Flush terminated."); break; } else if (Location(targ) != obj) { Log_header_err(targ, obj, Location(targ), true, "Location", "indicates object really in another location during cleanup of GOING location. Flush terminated."); break; } else { s_Location(targ, NOTHING); s_Next(targ, NOTHING); if ( !Good_obj(Home(targ)) || Going(Home(targ)) || Home(targ) == obj) { s_Home(targ, new_home(targ)); } move_via_generic(targ, HOME, NOTHING, 0); divest_object(targ); } } // Destroy the exits. // SAFE_DOLIST(targ, next, Exits(obj)) { if (!isExit(targ) && !isGarbage(targ)) { Log_simple_err(targ, obj, "Funny object type in exit list of GOING location. Flush terminated."); break; } else if (Exits(targ) != obj) { Log_header_err(targ, obj, Exits(targ), true, "Location", "indicates exit really in another location during cleanup of GOING location. Flush terminated."); break; } else { destroy_obj(targ); } } } /* * --------------------------------------------------------------------------- * * destroy_exit, destroy_thing, destroy_player */ void destroy_exit(dbref exit) { dbref loc = Exits(exit); s_Exits(loc, remove_first(Exits(loc), exit)); destroy_obj(exit); } void destroy_thing(dbref thing) { move_via_generic(thing, NOTHING, Owner(thing), 0); empty_obj(thing); destroy_obj(thing); } void destroy_player(dbref player, dbref victim) { // Bye bye... // boot_off(victim, "You have been destroyed!"); halt_que(victim, NOTHING); int count = chown_all(victim, player, player, CHOWN_NOZONE); // Remove the name from the name hash table. // delete_player_name(victim, Name(victim)); dbref aowner; int aflags; char *buf = atr_pget(victim, A_ALIAS, &aowner, &aflags); delete_player_name(victim, buf); free_lbuf(buf); move_via_generic(victim, NOTHING, player, 0); destroy_obj(victim); notify_quiet(player, tprintf("(%d objects @chowned to you)", count)); } static void purge_going(void) { dbref i; DO_WHOLE_DB(i) { if (!Going(i)) { continue; } const char *p; switch (Typeof(i)) { case TYPE_PLAYER: p = atr_get_raw(i, A_DESTROYER); if (!p) { STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG"); log_type_and_name(i); dbref loc = Location(i); if (loc != NOTHING) { log_text(" in "); log_type_and_name(loc); } log_text("GOING object doesn't remember it's destroyer. GOING reset."); ENDLOG; db[i].fs.word[FLAG_WORD1] &= ~GOING; } else { dbref player = (dbref) mux_atol(p); destroy_player(player, i); } break; case TYPE_ROOM: // Room scheduled for destruction... do it. // empty_obj(i); destroy_obj(i); break; case TYPE_THING: destroy_thing(i); break; case TYPE_EXIT: destroy_exit(i); break; case TYPE_GARBAGE: break; default: // Something else... How did this happen? // Log_simple_err(i, NOTHING, "GOING object with unexpected type. Destroyed."); destroy_obj(i); } } } // --------------------------------------------------------------------------- // check_dead_refs: Look for references to GOING or illegal objects. // static void check_pennies(dbref thing, int limit, const char *qual) { if (Going(thing)) { return; } int j = Pennies(thing); if (j) { if (isRoom(thing) || isExit(thing)) { Log_header_err(thing, NOTHING, j, false, qual, "is strange. Reset."); s_Pennies(thing, 0); } else if (j < 0) { Log_header_err(thing, NOTHING, j, false, qual, "is negative."); } else if (limit < j) { Log_header_err(thing, NOTHING, j, false, qual, "is excessive."); } } else { if(isPlayer(thing) || isThing(thing)) { Log_header_err(thing, NOTHING, j, false, qual, "is zero."); } } } static void check_dead_refs(void) { dbref targ, owner, i, j; int aflags; char *str; FWDLIST *fp; bool dirty; DO_WHOLE_DB(i) { // Check the owner. // owner = Owner(i); if (!Good_obj(owner)) { if (isPlayer(i)) { Log_header_err(i, NOTHING, owner, true, "Owner", "is invalid. Set to player."); owner = i; } else { Log_header_err(i, NOTHING, owner, true, "Owner", "is invalid. Set to GOD."); owner = GOD; } s_Owner(i, owner); if (!mudstate.bStandAlone) { halt_que(NOTHING, i); } s_Halted(i); } else if (check_type & DBCK_FULL) { if (Going(owner)) { if (isPlayer(i)) { Log_header_err(i, NOTHING, owner, true, "Owner", "is set GOING. Set to player."); owner = i; } else { Log_header_err(i, NOTHING, owner, true, "Owner", "is set GOING. Set to GOD."); owner = GOD; } s_Owner(i, owner); if (!mudstate.bStandAlone) { halt_que(NOTHING, i); } s_Halted(i); } else if (!OwnsOthers(owner)) { if (isPlayer(i)) { Log_header_err(i, NOTHING, owner, true, "Owner", "is not a valid owner type. Set to player."); owner = i; } else { Log_header_err(i, NOTHING, owner, true, "Owner", "is not a valid owner type. Set to GOD."); owner = GOD; } s_Owner(i, owner); } } // Check the parent // targ = Parent(i); if (Good_obj(targ)) { if (Going(targ)) { s_Parent(i, NOTHING); if (!mudstate.bStandAlone) { if ( !Quiet(i) && !Quiet(owner)) { notify(owner, tprintf("Parent cleared on %s(#%d)", Moniker(i), i)); } } else { Log_header_err(i, Location(i), targ, true, "Parent", "is invalid. Cleared."); } } } else if (targ != NOTHING) { Log_header_err(i, Location(i), targ, true, "Parent", "is invalid. Cleared."); s_Parent(i, NOTHING); } // Check the zone. // targ = Zone(i); if (Good_obj(targ)) { if (Going(targ)) { s_Zone(i, NOTHING); if (!mudstate.bStandAlone) { owner = Owner(i); if ( !Quiet(i) && !Quiet(owner)) { notify(owner, tprintf("Zone cleared on %s(#%d)", Moniker(i), i)); } } else { Log_header_err(i, Location(i), targ, true, "Zone", "is invalid. Cleared."); } } } else if (targ != NOTHING) { Log_header_err(i, Location(i), targ, true, "Zone", "is invalid. Cleared."); s_Zone(i, NOTHING); } // Check forwardlist // fp = fwdlist_get(i); dirty = false; if (fp) { for (j = 0; j < fp->count; j++) { targ = fp->data[j]; if ( Good_obj(targ) && Going(targ)) { fp->data[j] = NOTHING; dirty = true; } else if ( !Good_obj(targ) && targ != NOTHING) { fp->data[j] = NOTHING; dirty = true; } } } if (dirty) { str = alloc_lbuf("purge_going"); (void)fwdlist_rewrite(fp, str); atr_get_info(i, A_FORWARDLIST, &owner, &aflags); atr_add(i, A_FORWARDLIST, str, owner, aflags); free_lbuf(str); } if (check_type & DBCK_FULL) { // Check for wizards // if (RealWizard(i)) { if (isPlayer(i)) { Log_simple_err(i, NOTHING, "Player is a WIZARD."); } if (!Wizard(Owner(i))) { Log_header_err(i, NOTHING, Owner(i), true, "Owner", "of a WIZARD object is not a wizard"); } } } switch (Typeof(i)) { case TYPE_PLAYER: // Check home. // targ = Home(i); if ( !Good_obj(targ) || !Has_contents(targ)) { Log_simple_err(i, Location(i), "Bad home. Reset."); s_Home(i, default_home()); } // Check the location. // targ = Location(i); if ( !Good_obj(targ) || !Has_contents(targ)) { Log_pointer_err(NOTHING, i, NOTHING, targ, "Location", "is invalid. Moved to home."); move_object(i, Home(i)); } // Check for self-referential Next(). // if (Next(i) == i) { Log_simple_err(i, NOTHING, "Next points to self. Next cleared."); s_Next(i, NOTHING); } if (check_type & DBCK_FULL) { // Check wealth. // targ = mudconf.paylimit; check_pennies(i, targ, "Wealth"); } break; case TYPE_THING: // Check home. // targ = Home(i); if ( !Good_obj(targ) || !Has_contents(targ)) { if (!mudstate.bStandAlone) { if ( !Quiet(i) && !Quiet(owner)) { notify(owner, tprintf("Home reset on %s(#%d)", Moniker(i), i)); } else { Log_header_err(i, Location(i), targ, true, "Home", "is invalid. Cleared."); } } s_Home(i, new_home(i)); } // Check the location. // targ = Location(i); if ( !Good_obj(targ) || !Has_contents(targ)) { Log_pointer_err(NOTHING, i, NOTHING, targ, "Location", "is invalid. Moved to home."); move_object(i, HOME); } // Check for self-referential Next(). // if (Next(i) == i) { Log_simple_err(i, NOTHING, "Next points to self. Next cleared."); s_Next(i, NOTHING); } if (check_type & DBCK_FULL) { // Check value. // targ = OBJECT_ENDOWMENT(mudconf.createmax); check_pennies(i, targ, "Value"); } break; case TYPE_ROOM: // Check the dropto. // targ = Dropto(i); if (Good_obj(targ)) { if (Going(targ)) { s_Dropto(i, NOTHING); if (!mudstate.bStandAlone) { if ( !Quiet(i) && !Quiet(owner)) { notify(owner, tprintf("Dropto removed from %s(#%d)", Moniker(i), i)); } } else { Log_header_err(i, NOTHING, targ, true, "Dropto", "is invalid. Removed."); } } } else if ( targ != NOTHING && targ != HOME) { Log_header_err(i, NOTHING, targ, true, "Dropto", "is invalid. Cleared."); s_Dropto(i, NOTHING); } if (check_type & DBCK_FULL) { // NEXT should be null. // if (Next(i) != NOTHING) { Log_header_err(i, NOTHING, Next(i), true, "Next pointer", "should be NOTHING. Reset."); s_Next(i, NOTHING); } // LINK should be null. // if (Link(i) != NOTHING) { Log_header_err(i, NOTHING, Link(i), true, "Link pointer ", "should be NOTHING. Reset."); s_Link(i, NOTHING); } // Check value. // check_pennies(i, 1, "Value"); } break; case TYPE_EXIT: // If it points to something GOING, set it going. // targ = Location(i); if (Good_obj(targ)) { if (Going(targ)) { s_Going(i); } } else if (targ == HOME) { // null case, HOME is always valid. // } else if (targ != NOTHING) { Log_header_err(i, Exits(i), targ, true, "Destination", "is invalid. Exit destroyed."); s_Going(i); } else { if (!Has_contents(targ)) { Log_header_err(i, Exits(i), targ, true, "Destination", "is not a valid type. Exit destroyed."); s_Going(i); } } // Check for self-referential Next(). // if (Next(i) == i) { Log_simple_err(i, NOTHING, "Next points to self. Next cleared."); s_Next(i, NOTHING); } if (check_type & DBCK_FULL) { // CONTENTS should be null. // if (Contents(i) != NOTHING) { Log_header_err(i, Exits(i), Contents(i), true, "Contents", "should be NOTHING. Reset."); s_Contents(i, NOTHING); } // LINK should be null. // if (Link(i) != NOTHING) { Log_header_err(i, Exits(i), Link(i), true, "Link", "should be NOTHING. Reset."); s_Link(i, NOTHING); } // Check value. // check_pennies(i, 1, "Value"); } break; case TYPE_GARBAGE: break; default: // Funny object type, destroy it. // Log_simple_err(i, NOTHING, "Funny object type. Destroyed."); destroy_obj(i); } } } /* * --------------------------------------------------------------------------- * * check_loc_exits, check_exit_chains: Validate the exits chains * * of objects and attempt to correct problems. The following errors are * * found and corrected: * * Location not in database - skip it. * * Location GOING - skip it. * * Location not a PLAYER, ROOM, or THING - skip it. * * Location already visited - skip it. * * Exit/next pointer not in database - NULL it. * * Member is not an EXIT - terminate chain. * * Member is GOING - destroy exit. * * Member already checked (is in another list) - terminate chain. * * Member in another chain (recursive check) - terminate chain. * * Location of member is not specified location - reset it. */ static void check_loc_exits(dbref loc) { if (!Good_obj(loc)) { return; } // Only check players, rooms, and things that aren't GOING. // if ( isExit(loc) || Going(loc)) { return; } // If marked, we've checked here already. // if (Marked(loc)) { return; } Mark(loc); // Check all the exits. // dbref temp, exitloc, dest; dbref back = NOTHING; dbref exit = Exits(loc); while (exit != NOTHING) { exitloc = NOTHING; dest = NOTHING; if (Good_obj(exit)) { exitloc = Exits(exit); dest = Location(exit); } if (!Good_obj(exit)) { // A bad pointer - terminate chain. // Log_pointer_err(back, loc, NOTHING, exit, "Exit list", "is invalid. List nulled."); if (back != NOTHING) { s_Next(back, NOTHING); } else { s_Exits(loc, NOTHING); } exit = NOTHING; } else if (!isExit(exit)) { // Not an exit - terminate chain. // Log_pointer_err(back, loc, NOTHING, exit, "Exitlist member", "is not an exit. List terminated."); if (back != NOTHING) { s_Next(back, NOTHING); } else { s_Exits(loc, NOTHING); } exit = NOTHING; } else if (Going(exit)) { // Going - silently filter out. // temp = Next(exit); if (back != NOTHING) { s_Next(back, temp); } else { s_Exits(loc, temp); } destroy_obj(exit); exit = temp; continue; } else if (Marked(exit)) { // Already in another list - terminate chain. // Log_pointer_err(back, loc, NOTHING, exit, "Exitlist member", "is in another exitlist. Cleared."); if (back != NOTHING) { s_Next(back, NOTHING); } else { s_Exits(loc, NOTHING); } exit = NOTHING; } else if ( !Good_obj(dest) && dest != HOME && dest != NOTHING) { // Destination is not in the db. Null it. // Log_pointer_err(back, loc, NOTHING, exit, "Destination", "is invalid. Cleared."); s_Location(exit, NOTHING); } else if (exitloc != loc) { // Exit thinks it's in another place. Check the exitlist there // and see if it contains this exit. If it does, then our exitlist // somehow pointed into the middle of their exitlist. If not, // assume we own the exit.' // check_loc_exits(exitloc); if (Marked(exit)) { // It's in the other list, give it up. // Log_pointer_err(back, loc, NOTHING, exit, "", "is in another exitlist. List terminated."); if (back != NOTHING) { s_Next(back, NOTHING); } else { s_Exits(loc, NOTHING); } exit = NOTHING; } else { // Not in the other list, assume in ours. // Log_header_err(exit, loc, exitloc, true, "Not on chain for location", "Reset."); s_Exits(exit, loc); } } if (exit != NOTHING) { // All OK (or all was made OK). // if (check_type & DBCK_FULL) { // Make sure exit owner owns at least one of the source or // destination. Just warn if he doesn't. // temp = Owner(exit); if ( temp != Owner(loc) && temp != Owner(Location(exit))) { Log_header_err(exit, loc, temp, true, "Owner", "does not own either the source or destination."); } } Mark(exit); back = exit; exit = Next(exit); } } return; } static void check_exit_chains(void) { dbref i; Unmark_all(i); DO_WHOLE_DB(i) { check_loc_exits(i); } DO_WHOLE_DB(i) { if ( isExit(i) && !Marked(i)) { Log_simple_err(i, NOTHING, "Disconnected exit. Destroyed."); destroy_obj(i); } } } /* * --------------------------------------------------------------------------- * * check_misplaced_obj, check_loc_contents, check_contents_chains: Validate * * the contents chains of objects and attempt to correct problems. The * * following errors are found and corrected: * * Location not in database - skip it. * * Location GOING - skip it. * * Location not a PLAYER, ROOM, or THING - skip it. * * Location already visited - skip it. * * Contents/next pointer not in database - NULL it. * * Member is not an PLAYER or THING - terminate chain. * * Member is GOING - destroy exit. * * Member already checked (is in another list) - terminate chain. * * Member in another chain (recursive check) - terminate chain. * * Location of member is not specified location - reset it. */ static void check_loc_contents(dbref); static void check_misplaced_obj(dbref *obj, dbref back, dbref loc) { // Object thinks it's in another place. Check the contents list there // and see if it contains this object. If it does, then our contents // list somehow pointed into the middle of their contents list and we // should truncate our list. If not, assume we own the object. // if (!Good_obj(*obj)) { return; } loc = Location(*obj); Unmark(*obj); if (Good_obj(loc)) { check_loc_contents(loc); } if (Marked(*obj)) { // It's in the other list, give it up. // Log_pointer_err(back, loc, NOTHING, *obj, "", "is in another contents list. Cleared."); if (back != NOTHING) { s_Next(back, NOTHING); } else { s_Contents(loc, NOTHING); } *obj = NOTHING; } else { // Not in the other list, assume in ours. // Log_header_err(*obj, loc, Contents(*obj), true, "Location", "is invalid. Reset."); s_Contents(*obj, loc); } return; } static void check_loc_contents(dbref loc) { if (!Good_obj(loc)) { return; } // Only check players, rooms, and things that aren't GOING. // if ( isExit(loc) || Going(loc)) { return; } dbref back = NOTHING; dbref obj = Contents(loc); while (obj != NOTHING) { if (!Good_obj(obj)) { // A bad pointer - terminate chain. // Log_pointer_err(back, loc, NOTHING, obj, "Contents list", "is invalid. Cleared."); if (back != NOTHING) { s_Next(back, NOTHING); } else { s_Contents(loc, NOTHING); } obj = NOTHING; } else if (!Has_location(obj)) { // Not a player or thing - terminate chain. // Log_pointer_err(back, loc, NOTHING, obj, "", "is not a player or thing. Cleared."); if (back != NOTHING) { s_Next(back, NOTHING); } else { s_Contents(loc, NOTHING); } obj = NOTHING; } else if (Marked(obj)) { // Already visited - either truncate or ignore. // if (Location(obj) != loc) { // Location wrong - either truncate or fix. // check_misplaced_obj(&obj, back, loc); } else { // Location right - recursive contents. // } } else if (Location(obj) != loc) { // Location wrong - either truncate or fix. // check_misplaced_obj(&obj, back, loc); } if (obj != NOTHING) { // All OK (or all was made OK). // if (check_type & DBCK_FULL) { // Check for wizard command-handlers inside non-wizard. Just // warn if we find one. // if ( RealWizard(obj) && !Wizard(loc)) { if (Commer(obj)) { Log_simple_err(obj, loc, "Wizard command handling object inside non-wizard."); } } // Check for non-wizard objects inside wizard objects. // if ( RealWizard(loc) && !Wizard(obj) && !Wizard(Owner(obj))) { Log_simple_err(obj, loc, "Non-wizard object inside wizard."); } } Mark(obj); back = obj; obj = Next(obj); } } } static void check_contents_chains(void) { dbref i; Unmark_all(i); DO_WHOLE_DB(i) { check_loc_contents(i); } DO_WHOLE_DB(i) { if ( !Going(i) && !Marked(i) && Has_location(i)) { Log_simple_err(i, Location(i), "Orphaned object, moved home."); s_Location(i, NOTHING); s_Next(i, NOTHING); if ( !Good_obj(Home(i)) || Going(Home(i))) { s_Home(i, new_home(i)); } move_via_generic(i, HOME, NOTHING, 0); } } } /* * --------------------------------------------------------------------------- * * mark_place, check_floating: Look for floating rooms not set FLOATING. */ static void mark_place(dbref loc) { // If already marked, exit. Otherwise set marked. // if ( !Good_obj(loc) || Marked(loc)) { return; } Mark(loc); // Visit all places you can get to via exits from here. // dbref exit; for (exit = Exits(loc); exit != NOTHING; exit = Next(exit)) { if (Good_obj(Location(exit))) { mark_place(Location(exit)); } } } static void check_floating(void) { dbref i; // Mark everyplace you can get to via exits from the starting room. // Unmark_all(i); mark_place(mudconf.start_room); // Mark every room you can get to from a floating room. // DO_WHOLE_DB(i) { if ( isRoom(i) && Floating(i) && !Going(i)) { mark_place(i); } } // Look for unvisited rooms. // DO_WHOLE_DB(i) { if ( isRoom(i) && !Going(i) && !Marked(i)) { if (!mudstate.bStandAlone) { dbref owner = Owner(i); if (Good_owner(owner)) { notify(owner, tprintf( "You own a floating room: %s(#%d)", Moniker(i), i)); } } else { Log_simple_err(i, NOTHING, "Disconnected room."); } } } } /* * --------------------------------------------------------------------------- * * do_dbck: Perform a database consistency check and clean up damage. */ void do_dbck(dbref executor, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); check_type = key; check_dead_refs(); check_exit_chains(); check_contents_chains(); check_floating(); if ( !mudstate.bStandAlone && executor != NOTHING) { Guest.CleanUp(); } purge_going(); make_freelist(); scheduler.Shrink(); // Allow the local extensions to do data checks. // local_dbck(); if ( !mudstate.bStandAlone && executor != NOTHING && !Quiet(executor)) { notify(executor, "Done."); } } mux2.6/src/flags.h0000600000175000017500000005224011025753746014046 0ustar sdennissdennis// flags.h -- Object flags. // // $Id: flags.h 2734 2007-10-28 23:02:55Z brazilofmux $ // #include "copyright.h" #ifndef __FLAGS_H #define __FLAGS_H #define FLAG_WORD1 0x0 // 1st word of flags. #define FLAG_WORD2 0x1 // 2nd word of flags. #define FLAG_WORD3 0x2 // 3rd word of flags. /* Object types */ #define TYPE_ROOM 0x0 #define TYPE_THING 0x1 #define TYPE_EXIT 0x2 #define TYPE_PLAYER 0x3 /* Empty */ #define TYPE_GARBAGE 0x5 /* Empty */ #define NOTYPE 0x7 #define TYPE_MASK 0x7 /* First word of flags */ #define SEETHRU 0x00000008 /* Can see through to the other side */ #define WIZARD 0x00000010 /* gets automatic control */ #define LINK_OK 0x00000020 /* anybody can link to this room */ #define DARK 0x00000040 /* Don't show contents or presence */ #define JUMP_OK 0x00000080 /* Others may @tel here */ #define STICKY 0x00000100 /* Object goes home when dropped */ #define DESTROY_OK 0x00000200 /* Others may @destroy */ #define HAVEN 0x00000400 /* No killing here, or no pages */ #define QUIET 0x00000800 /* Prevent 'feelgood' messages */ #define HALT 0x00001000 /* object cannot perform actions */ #define TRACE 0x00002000 /* Generate evaluation trace output */ #define GOING 0x00004000 /* object is available for recycling */ #define MONITOR 0x00008000 /* Process ^x:action listens on obj? */ #define MYOPIC 0x00010000 /* See things as nonowner/nonwizard */ #define PUPPET 0x00020000 /* Relays ALL messages to owner */ #define CHOWN_OK 0x00040000 /* Object may be @chowned freely */ #define ENTER_OK 0x00080000 /* Object may be ENTERed */ #define VISUAL 0x00100000 /* Everyone can see properties */ #define IMMORTAL 0x00200000 /* Object can't be killed */ #define HAS_STARTUP 0x00400000 /* Load some attrs at startup */ #define TM_OPAQUE 0x00800000 /* Can't see inside */ #define VERBOSE 0x01000000 /* Tells owner everything it does. */ #define INHERIT 0x02000000 /* Gets owner's privs. (i.e. Wiz) */ #define NOSPOOF 0x04000000 /* Report originator of all actions. */ #define ROBOT 0x08000000 /* Player is a ROBOT */ #define SAFE 0x10000000 /* Need /override to @destroy */ #define ROYALTY 0x20000000 /* Sees like a wiz, but ca't modify */ #define HEARTHRU 0x40000000 /* Can hear out of this obj or exit */ #define TERSE 0x80000000 /* Only show room name on look */ /* Second word of flags */ #define KEY 0x00000001 /* No puppets */ #define ABODE 0x00000002 /* May @set home here */ #define FLOATING 0x00000004 /* Inhibit Floating room.. msgs */ #define UNFINDABLE 0x00000008 /* Cant loc() from afar */ #define PARENT_OK 0x00000010 /* Others may @parent to me */ #define LIGHT 0x00000020 /* Visible in dark places */ #define HAS_LISTEN 0x00000040 /* Internal: LISTEN attr set */ #define HAS_FWDLIST 0x00000080 /* Internal: FORWARDLIST attr set */ #define AUDITORIUM 0x00000100 /* Should we check the SpeechLock? */ #define ANSI 0x00000200 #define HEAD_FLAG 0x00000400 #define FIXED 0x00000800 #define UNINSPECTED 0x00001000 #define NO_COMMAND 0x00002000 #define CKEEPALIVE 0x00004000 /* User receives keepalives from the MUX */ #define NOBLEED 0x00008000 #define STAFF 0x00010000 #define HAS_DAILY 0x00020000 #define GAGGED 0x00040000 #define OPEN_OK 0x00080000 // You can open exits from here if you pass the openlock. #define VACATION 0x01000000 #define PLAYER_MAILS 0x02000000 #define HTML 0x04000000 /* Player supports HTML */ #define BLIND 0x08000000 // Suppress has arrived / left messages. #define SUSPECT 0x10000000 /* Report some activities to wizards */ #define NOACCENTS 0x20000000 // Strip accented characters. #define CONNECTED 0x40000000 /* Player is connected */ #define SLAVE 0x80000000 /* Disallow most commands */ // Third word of flags // #if defined(WOD_REALMS) || defined(REALITY_LVLS) #if defined(FIRANMUX) #error "FIRANMUX is incompatible with both WOD_REALMS and REALITY_LVLS" #endif #define OBF 0x00000001 // Obfuscate Flag #define HSS 0x00000002 // Auspex/Heightened Senses Flag #define UMBRA 0x00000004 // Umbra, UMBRADESC #define SHROUD 0x00000008 // Shroud, WRAITHDESC #define MATRIX 0x00000010 // Matrix, MATRIXDESC #define MEDIUM 0x00000020 #define DEAD 0x00000040 #define FAE 0x00000080 // Fae, FAEDESC #define CHIMERA 0x00000100 // Fae, FAEDESC #define PEERING 0x00000200 // Means the a looker is seeing a // different realm than they are in. #endif // WOD_REALMS #if defined(FIRANMUX) #define LINEWRAP 0x00000001 // Player linewraps. #define IMMOBILE 0x00000002 // Player immobile. #define QUELL 0x00000004 // Temporarily discard wizardry. #define WINTELNET 0x00000008 // Add extra \n for Win/Mac Telnet. #define REMOTEECHO 0x00000010 // Adds remote echo! #define RESTRICTED 0x00000020 // Player uses restricted commandset. #define PARENT 0x00000040 // Object is an official parent obj. #endif // FIRANMUX #define SITEMON 0x00000400 // Sitemonitor Flag #define CMDCHECK 0x00000800 // Has @icmd set #define MARK_0 0x00400000 // User-defined flags. #define MARK_1 0x00800000 #define MARK_2 0x01000000 #define MARK_3 0x02000000 #define MARK_4 0x04000000 #define MARK_5 0x08000000 #define MARK_6 0x10000000 #define MARK_7 0x20000000 #define MARK_8 0x40000000 #define MARK_9 0x80000000 /* --------------------------------------------------------------------------- * FLAGENT: Information about object flags. */ typedef struct flag_bit_entry { int flagvalue; // Which bit in the object is the flag. char flaglett; // Flag letter for listing. int flagflag; // Ctrl flags for this flag. int listperm; // Who sees this flag when set. bool (*handler)(dbref target, dbref player, FLAG flag, int fflags, bool reset); // Handler for setting/clearing this flag. } FLAGBITENT; typedef struct flag_name_entry { const char *pOrigName; // Original name of flag. bool bPositive; // Flag sense. FLAGBITENT *fbe; // Which bit is this associated with? char *flagname; // Name of the flag. } FLAGNAMEENT; extern FLAGNAMEENT gen_flag_names[]; /* --------------------------------------------------------------------------- * OBJENT: Fundamental object types */ typedef struct object_entry { const char *name; char lett; int perm; int flags; } OBJENT; extern OBJENT object_types[8]; #define OF_CONTENTS 0x0001 /* Object has contents: Contents() */ #define OF_LOCATION 0x0002 /* Object has a location: Location() */ #define OF_EXITS 0x0004 /* Object has exits: Exits() */ #define OF_HOME 0x0008 /* Object has a home: Home() */ #define OF_DROPTO 0x0010 /* Object has a dropto: Dropto() */ #define OF_OWNER 0x0020 /* Object can own other objects */ #define OF_SIBLINGS 0x0040 /* Object has siblings: Next() */ typedef struct flagset { FLAG word[3]; } FLAGSET; void init_flagtab(void); void display_flagtab(dbref); void flag_set(dbref, dbref, char *, int); char *flag_description(dbref, dbref); char *decode_flags(dbref, FLAGSET *); bool has_flag(dbref, dbref, const char *); char *unparse_object(dbref player, dbref target, bool obey_myopic, bool bAddColor = false); char *unparse_object_numonly(dbref); bool convert_flags(dbref, char *, FLAGSET *, FLAG *); void decompile_flags(dbref, dbref, char *); char *MakeCanonicalFlagName ( const char *pName, int *pnName, bool *pbValid ); #define GOD ((dbref) 1) /* ---------------------- Object Permission/Attribute Macros */ /* Typeof(X) - What object type is X */ /* God(X) - Is X player #1 */ /* Robot(X) - Is X a robot player */ /* Wizard(X) - Does X have wizard privs */ /* Immortal(X) - Is X unkillable */ /* Dark(X) - Is X dark */ /* Floating(X) - Prevent 'disconnected room' msgs for room X */ /* Quiet(X) - Should 'Set.' messages et al from X be disabled */ /* Verbose(X) - Should owner receive all commands executed? */ /* Trace(X) - Should owner receive eval trace output? */ /* Player_haven(X) - Is the owner of X no-page */ /* Haven(X) - Is X no-kill(rooms) or no-page(players) */ /* Halted(X) - Is X halted (not allowed to run commands)? */ /* Suspect(X) - Is X someone the wizzes should keep an eye on */ /* Slave(X) - Should X be prevented from db-changing commands */ /* Safe(X,P) - Does P need the /OVERRIDE switch to @destroy X? */ /* Monitor(X) - Should we check for ^xxx:xxx listens on player? */ /* Terse(X) - Should we only show the room name on a look? */ /* Myopic(X) - Should things as if we were nonowner/nonwiz */ /* Audible(X) - Should X forward messages? */ /* Findroom(X) - Can players in room X be found via @whereis? */ /* Unfindroom(X) - Is @whereis blocked for players in room X? */ /* Findable(X) - Can @whereis find X */ /* Unfindable(X) - Is @whereis blocked for X */ /* No_robots(X) - Does X disallow robot players from using */ /* Has_location(X) - Is X something with a location (ie plyr or obj) */ /* Has_home(X) - Is X something with a home (ie plyr or obj) */ /* Has_contents(X) - Is X something with contents (ie plyr/obj/room) */ /* Good_dbref(X) - Is X inside the DB? */ /* Good_obj(X) - Is X inside the DB and have a valid type? */ /* Good_owner(X) - Is X a good owner value? */ /* Going(X) - Is X marked GOING? */ /* Inherits(X) - Does X inherit the privs of its owner */ /* Examinable(P,X) - Can P look at attribs of X */ /* MyopicExam(P,X) - Can P look at attribs of X (obeys MYOPIC) */ /* Controls(P,X) - Can P force X to do something */ /* Abode(X) - Is X an ABODE room */ /* Link_exit(P,X) - Can P link from exit X */ /* Linkable(P,X) - Can P link to X */ /* Mark(x) - Set marked flag on X */ /* Unmark(x) - Clear marked flag on X */ /* Marked(x) - Check marked flag on X */ /* See_attr(P,X.A,O,F) - Can P see text attr A on X if attr has owner O */ /* KeepAlive(x) - Does the user want keepalives? */ #if defined(FIRANMUX) /* Linewrap(x) - Is X set Linewrap? */ /* Restricted(x) - Is X restricted to the restricted commandset? */ #endif // FIRANMUX #define Typeof(x) (Flags(x) & TYPE_MASK) #define God(x) ((x) == GOD) #define Robot(x) (isPlayer(x) && ((Flags(x) & ROBOT) != 0)) #define OwnsOthers(x) ((object_types[Typeof(x)].flags & OF_OWNER) != 0) #define Has_location(x) ((object_types[Typeof(x)].flags & OF_LOCATION) != 0) #define Has_contents(x) ((object_types[Typeof(x)].flags & OF_CONTENTS) != 0) #define Has_exits(x) ((object_types[Typeof(x)].flags & OF_EXITS) != 0) #define Has_siblings(x) ((object_types[Typeof(x)].flags & OF_SIBLINGS) != 0) #define Has_home(x) ((object_types[Typeof(x)].flags & OF_HOME) != 0) #define Has_dropto(x) ((object_types[Typeof(x)].flags & OF_DROPTO) != 0) #define Home_ok(x) ((object_types[Typeof(x)].flags & OF_HOME) != 0) #define isPlayer(x) (Typeof(x) == TYPE_PLAYER) #define isRoom(x) (Typeof(x) == TYPE_ROOM) #define isExit(x) (Typeof(x) == TYPE_EXIT) #define isThing(x) (Typeof(x) == TYPE_THING) #define isGarbage(x) (Typeof(x) == TYPE_GARBAGE) #define Good_dbref(x) (((x) >= 0) && ((x) < mudstate.db_top)) #define Good_obj(x) (Good_dbref(x) && (Typeof(x) < TYPE_GARBAGE)) #define Good_owner(x) (Good_obj(x) && OwnsOthers(x)) #define Staff(x) (Wizard(x) || Royalty(x) || ((Flags2(x) & STAFF) != 0)) #if defined(FIRANMUX) #define Royalty(x) ( ( (Flags(x) & ROYALTY) \ && (Flags3(x) & QUELL) == 0 \ ) \ || ( ( (Flags(Owner(x)) & ROYALTY) \ && (Flags3(Owner(x)) & QUELL) == 0 \ ) \ && Inherits(x) \ ) \ ) #define RealRoyalty(x) ( (Flags(x) & ROYALTY) \ || ( (Flags(Owner(x)) & ROYALTY) \ && Inherits(x) \ ) \ ) #else // FIRANMUX #define Royalty(x) ( (Flags(x) & ROYALTY) \ || ( (Flags(Owner(x)) & ROYALTY) \ && Inherits(x) \ ) \ ) #define RealRoyalty(x) (Royalty(x)) #endif // FIRANMUX #define WizRoy(x) (Royalty(x) || Wizard(x)) #define RealWizRoy(x) (RealRoyalty(x) || RealWizard(x)) #define Head(x) ((Flags2(x) & HEAD_FLAG) != 0) #define Fixed(x) ((Flags2(x) & FIXED) != 0) #define Uninspected(x) ((Flags2(x) & UNINSPECTED) != 0) #define Ansi(x) ((Flags2(x) & ANSI) != 0) #define NoAccents(x) ((Flags2(x) & NOACCENTS) != 0) #define No_Command(x) ((Flags2(x) & NO_COMMAND) != 0) #define NoBleed(x) ((Flags2(x) & NOBLEED) != 0) #define KeepAlive(x) ((Flags2(x) & CKEEPALIVE) != 0) #define Transparent(x) ((Flags(x) & SEETHRU) != 0) #define Link_ok(x) (((Flags(x) & LINK_OK) != 0) && Has_contents(x)) #define Open_ok(x) (((Flags2(x) & OPEN_OK) != 0) && Has_exits(x)) #if defined(FIRANMUX) #define Wizard(x) ( (Flags3(x) & QUELL) == 0 \ && ( (Flags(x) & WIZARD) \ || ( (Flags(Owner(x)) & WIZARD) \ && (Flags3(Owner(x)) & QUELL) == 0 \ && Inherits(x) \ ) \ ) \ ) #define RealWizard(x) ( (Flags(x) & WIZARD) \ || ( (Flags(Owner(x)) & WIZARD) \ && Inherits(x) \ ) \ ) #define Dark(x) ((Flags(x) & DARK) != 0) #else // FIRANMUX #define Wizard(x) ( (Flags(x) & WIZARD) \ || ( (Flags(Owner(x)) & WIZARD) \ && Inherits(x) \ ) \ ) #define RealWizard(x) (Wizard(x)) #define Dark(x) (((Flags(x) & DARK) != 0) && (Wizard(x) || \ !(isPlayer(x) || (Puppet(x) && Has_contents(x))))) #endif // FIRANMUX #define Jump_ok(x) (((Flags(x) & JUMP_OK) != 0) && Has_contents(x)) #define Sticky(x) ((Flags(x) & STICKY) != 0) #define Destroy_ok(x) ((Flags(x) & DESTROY_OK) != 0) #define Haven(x) ((Flags(x) & HAVEN) != 0) #define Player_haven(x) ((Flags(Owner(x)) & HAVEN) != 0) #define Quiet(x) ((Flags(x) & QUIET) != 0) #define Halted(x) ((Flags(x) & HALT) != 0) #define Trace(x) ((Flags(x) & TRACE) != 0) #define Going(x) ((Flags(x) & GOING) != 0) #define Monitor(x) ((Flags(x) & MONITOR) != 0) #define Myopic(x) ((Flags(x) & MYOPIC) != 0) #define Puppet(x) ((Flags(x) & PUPPET) != 0) #define Chown_ok(x) ((Flags(x) & CHOWN_OK) != 0) #define Enter_ok(x) (((Flags(x) & ENTER_OK) != 0) && \ Has_location(x) && Has_contents(x)) #define Immortal(x) ((Flags(x) & IMMORTAL) || \ ((Flags(Owner(x)) & IMMORTAL) && Inherits(x))) #define Opaque(x) ((Flags(x) & TM_OPAQUE) != 0) #define Verbose(x) ((Flags(x) & VERBOSE) != 0) #define Inherits(x) (((Flags(x) & INHERIT) != 0) || \ ((Flags(Owner(x)) & INHERIT) != 0) || \ ((x) == Owner(x))) #define Nospoof(x) ((Flags(x) & NOSPOOF) != 0) #define Safe(x,p) (OwnsOthers(x) || (Flags(x) & SAFE) || \ (mudconf.safe_unowned && (Owner(x) != Owner(p)))) #define Audible(x) ((Flags(x) & HEARTHRU) != 0) #define Terse(x) ((Flags(x) & TERSE) != 0) #define Gagged(x) ((Flags2(x) & GAGGED) != 0) #define Vacation(x) ((Flags2(x) & VACATION) != 0) #define Key(x) ((Flags2(x) & KEY) != 0) #define Abode(x) (((Flags2(x) & ABODE) != 0) && Home_ok(x)) #define Auditorium(x) ((Flags2(x) & AUDITORIUM) != 0) #define Floating(x) ((Flags2(x) & FLOATING) != 0) #define Findable(x) ((Flags2(x) & UNFINDABLE) == 0) #define Hideout(x) ((Flags2(x) & UNFINDABLE) != 0) #define Parent_ok(x) ((Flags2(x) & PARENT_OK) != 0) #define Light(x) ((Flags2(x) & LIGHT) != 0) #define Suspect(x) ((Flags2(Owner(x)) & SUSPECT) != 0) #define Connected(x) (((Flags2(x) & CONNECTED) != 0) && \ (Typeof(x) == TYPE_PLAYER)) #define Slave(x) ((Flags2(Owner(x)) & SLAVE) != 0) #define Hidden(x) ((Flags(x) & DARK) != 0) #define Blind(x) ((Flags2(x) & BLIND) != 0) #define H_Daily(x) ((Flags2(x) & HAS_DAILY) != 0) #define H_Fwdlist(x) ((Flags2(x) & HAS_FWDLIST) != 0) #define H_Listen(x) ((Flags2(x) & HAS_LISTEN) != 0) #define H_Startup(x) ((Flags(x) & HAS_STARTUP) != 0) #define s_Halted(x) s_Flags((x), FLAG_WORD1, Flags(x) | HALT) #define s_Going(x) s_Flags((x), FLAG_WORD1, Flags(x) | GOING) #define s_Connected(x) s_Flags((x), FLAG_WORD2, Flags2(x) | CONNECTED) #define c_Connected(x) s_Flags((x), FLAG_WORD2, Flags2(x) & ~CONNECTED) #define SiteMon(x) ((Flags3(x) & SITEMON) != 0) #define CmdCheck(x) ((Flags3(x) & CMDCHECK) != 0) #if defined(WOD_REALMS) || defined(REALITY_LVLS) #define isObfuscate(x) ((Flags3(x) & OBF) != 0) #define isHeightenedSenses(x) ((Flags3(x) & HSS) != 0) #define isUmbra(x) ((Flags3(x) & UMBRA) != 0) #define isShroud(x) ((Flags3(x) & SHROUD) != 0) #define isMatrix(x) ((Flags3(x) & MATRIX) != 0) #define isMedium(x) ((Flags3(x) & MEDIUM) != 0) #define isDead(x) ((Flags3(x) & DEAD) != 0) #define isFae(x) ((Flags3(x) & FAE) != 0) #define isChimera(x) ((Flags3(x) & CHIMERA) != 0) #define isPeering(x) ((Flags3(x) & PEERING) != 0) #endif // WOD_REALMS #define Parentable(p,x) (Controls(p,x) || \ (Parent_ok(x) && could_doit(p,x,A_LPARENT))) #define Examinable(p,x) (((Flags(x) & VISUAL) != 0) || \ (See_All(p)) || \ (Owner(p) == Owner(x)) || \ (check_zone(p,x))) #define MyopicExam(p,x) (((Flags(x) & VISUAL) != 0) || \ (!Myopic(p) && (See_All(p) || \ (Owner(p) == Owner(x)) || \ (check_zone(p,x))))) #define Controls(p,x) (Good_obj(x) && \ (!(God(x) && !God(p))) && \ (Control_All(p) || \ ((Owner(p) == Owner(x)) && \ (Inherits(p) || !Inherits(x))) || \ (check_zone(p,x)))) #define Mark(x) (mudstate.markbits->chunk[(x)>>3] |= \ mudconf.markdata[(x)&7]) #define Unmark(x) (mudstate.markbits->chunk[(x)>>3] &= \ ~mudconf.markdata[(x)&7]) #define Marked(x) ((mudstate.markbits->chunk[(x)>>3] & \ mudconf.markdata[(x)&7]) ? true : false) #define Mark_all(i) {for ((i)=0; (i)<((mudstate.db_top+7)>>3); (i)++) \ mudstate.markbits->chunk[i]=0xFFU;} #define Unmark_all(i) {for ((i)=0; (i)<((mudstate.db_top+7)>>3); (i)++) \ mudstate.markbits->chunk[i]=0x0;} #define Link_exit(p,x) ((Typeof(x) == TYPE_EXIT) && \ ((Location(x) == NOTHING) || Controls(p,x))) #define Linkable(p,x) (Good_obj(x) && Has_contents(x) && \ (((Flags(x) & LINK_OK) != 0) || Controls(p,x))) #define See_attr(p,x,a) (!((a)->flags & AF_IS_LOCK) && bCanReadAttr(p,x,a,false)) #define See_attr_explicit(p,x,a,o,f) (!((a)->flags & (AF_INTERNAL|AF_IS_LOCK)) && \ (((f) & AF_VISUAL) || (Owner(p) == (o)) && \ !((a)->flags & (AF_DARK|AF_MDARK)))) #define Has_power(p,x) (check_access((p),powers_nametab[x].flag)) #define Html(x) ((Flags2(x) & HTML) != 0) #define s_Html(x) s_Flags((x), FLAG_WORD2, Flags2(x) | HTML) #if defined(FIRANMUX) #define Linewrap(x) ((Flags3(x) & LINEWRAP) != 0) #define Immobile(x) ((Flags3(x) & IMMOBILE) != 0) #define Restricted(x) ((Flags3(x) & RESTRICTED) != 0) #endif // FIRANMUX #endif // !__FLAGS_H mux2.6/src/cque.cpp0000600000175000017500000011414011025753746014240 0ustar sdennissdennis/*! \file cque.cpp * Commands and functions for manipulating the command queue. * * $Id: cque.cpp 2803 2007-11-27 00:30:39Z brazilofmux $ * * This forms the upper-level command list queue, and includes timed commands * and semaphores. The lower-level task implementation is found in timer.cpp. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include #include "attrs.h" #include "command.h" #include "interface.h" #include "powers.h" bool break_called = false; static CLinearTimeDelta GetProcessorUsage(void) { CLinearTimeDelta ltd; #ifdef WIN32 if (fpGetProcessTimes) { FILETIME ftCreate; FILETIME ftExit; FILETIME ftKernel; FILETIME ftUser; fpGetProcessTimes(hGameProcess, &ftCreate, &ftExit, &ftKernel, &ftUser); ltd.Set100ns(*(INT64 *)(&ftUser)); return ltd; } #endif #if !defined(WIN32) && defined(HAVE_GETRUSAGE) struct rusage usage; getrusage(RUSAGE_SELF, &usage); ltd.SetTimeValueStruct(&usage.ru_utime); return ltd; #else // Either this Unix doesn't have getrusage or this is a // fall-through case for Win32. // CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); ltd = ltaNow - mudstate.start_time; return ltd; #endif } // --------------------------------------------------------------------------- // add_to: Adjust an object's queue or semaphore count. // static int add_to(dbref executor, int am, int attrnum) { int aflags; dbref aowner; char *atr_gotten = atr_get(executor, attrnum, &aowner, &aflags); int num = mux_atol(atr_gotten); free_lbuf(atr_gotten); num += am; char buff[20]; size_t nlen = 0; *buff = '\0'; if (num) { nlen = mux_ltoa(num, buff); } atr_add_raw_LEN(executor, attrnum, buff, nlen); return num; } // This Task assumes that pEntry is already unlinked from any lists it may // have been related to. // static void Task_RunQueueEntry(void *pEntry, int iUnused) { UNUSED_PARAMETER(iUnused); BQUE *point = (BQUE *)pEntry; dbref executor = point->executor; if ( Good_obj(executor) && !Going(executor)) { giveto(executor, mudconf.waitcost); mudstate.curr_enactor = point->enactor; mudstate.curr_executor = executor; a_Queue(Owner(executor), -1); point->executor = NOTHING; if (!Halted(executor)) { // Load scratch args. // for (int i = 0; i < MAX_GLOBAL_REGS; i++) { if (mudstate.global_regs[i]) { RegRelease(mudstate.global_regs[i]); mudstate.global_regs[i] = NULL; } mudstate.global_regs[i] = point->scr[i]; point->scr[i] = NULL; } char *command = point->comm; mux_assert(!mudstate.inpipe); mux_assert(mudstate.pipe_nest_lev == 0); mux_assert(mudstate.poutobj == NOTHING); mux_assert(!mudstate.pout); break_called = false; while ( command && !break_called) { mux_assert(!mudstate.poutnew); mux_assert(!mudstate.poutbufc); char *cp = parse_to(&command, ';', 0); if ( cp && *cp) { // Will command be piped? // if ( command && *command == '|' && mudstate.pipe_nest_lev < mudconf.ntfy_nest_lim) { command++; mudstate.pipe_nest_lev++; mudstate.inpipe = true; mudstate.poutnew = alloc_lbuf("process_command.pipe"); mudstate.poutbufc = mudstate.poutnew; mudstate.poutobj = executor; } else { mudstate.inpipe = false; mudstate.poutobj = NOTHING; } CLinearTimeAbsolute ltaBegin; ltaBegin.GetUTC(); MuxAlarm.Set(mudconf.max_cmdsecs); CLinearTimeDelta ltdUsageBegin = GetProcessorUsage(); char *log_cmdbuf = process_command(executor, point->caller, point->enactor, point->eval, false, cp, point->env, point->nargs); CLinearTimeAbsolute ltaEnd; ltaEnd.GetUTC(); if (MuxAlarm.bAlarmed) { notify(executor, "GAME: Expensive activity abbreviated."); s_Flags(point->enactor, FLAG_WORD1, Flags(point->enactor) | HALT); s_Flags(point->executor, FLAG_WORD1, Flags(point->executor) | HALT); halt_que(point->enactor, NOTHING); halt_que(executor, NOTHING); } MuxAlarm.Clear(); CLinearTimeDelta ltdUsageEnd = GetProcessorUsage(); CLinearTimeDelta ltd = ltdUsageEnd - ltdUsageBegin; db[executor].cpu_time_used += ltd; ltd = ltaEnd - ltaBegin; if (ltd > mudconf.rpt_cmdsecs) { STARTLOG(LOG_PROBLEMS, "CMD", "CPU"); log_name_and_loc(executor); char *logbuf = alloc_lbuf("do_top.LOG.cpu"); mux_sprintf(logbuf, LBUF_SIZE, " queued command taking %s secs (enactor #%d): ", ltd.ReturnSecondsString(4), point->enactor); log_text(logbuf); free_lbuf(logbuf); log_text(log_cmdbuf); ENDLOG; } } // Transition %| value. // if (mudstate.pout) { free_lbuf(mudstate.pout); mudstate.pout = NULL; } if (mudstate.poutnew) { *mudstate.poutbufc = '\0'; mudstate.pout = mudstate.poutnew; mudstate.poutnew = NULL; mudstate.poutbufc = NULL; } } // Clean up %| value. // if (mudstate.pout) { free_lbuf(mudstate.pout); mudstate.pout = NULL; } mudstate.pipe_nest_lev = 0; mudstate.inpipe = false; mudstate.poutobj = NOTHING; } } for (int i = 0; i < MAX_GLOBAL_REGS; i++) { if (point->scr[i]) { RegRelease(point->scr[i]); point->scr[i] = NULL; } if (mudstate.global_regs[i]) { RegRelease(mudstate.global_regs[i]); mudstate.global_regs[i] = NULL; } } MEMFREE(point->text); point->text = NULL; free_qentry(point); } // --------------------------------------------------------------------------- // que_want: Do we want this queue entry? // static bool que_want(BQUE *entry, dbref ptarg, dbref otarg) { if ( ptarg != NOTHING && ptarg != Owner(entry->executor)) { return false; } return ( otarg == NOTHING || otarg == entry->executor); } static void Task_SemaphoreTimeout(void *pExpired, int iUnused) { UNUSED_PARAMETER(iUnused); // A semaphore has timed out. // BQUE *point = (BQUE *)pExpired; add_to(point->sem, -1, point->attr); point->sem = NOTHING; Task_RunQueueEntry(point, 0); } #ifdef QUERY_SLAVE void Task_SQLTimeout(void *pExpired, int iUnused) { // A SQL Query has timed out. // BQUE *point = (BQUE *)pExpired; Task_RunQueueEntry(point, 0); } #endif // QUERY_SLAVE static dbref Halt_Player_Target; static dbref Halt_Object_Target; static int Halt_Entries; static dbref Halt_Player_Run; static dbref Halt_Entries_Run; static int CallBack_HaltQueue(PTASK_RECORD p) { if ( p->fpTask == Task_RunQueueEntry #ifdef QUERY_SLAVE || p->fpTask == Task_SQLTimeout #endif // QUERY_SLAVE || p->fpTask == Task_SemaphoreTimeout) { // This is a @wait, timed Semaphore Task, or timed SQL Query. // BQUE *point = (BQUE *)(p->arg_voidptr); if (que_want(point, Halt_Player_Target, Halt_Object_Target)) { // Accounting for pennies and queue quota. // dbref dbOwner = point->executor; if (!isPlayer(dbOwner)) { dbOwner = Owner(dbOwner); } if (dbOwner != Halt_Player_Run) { if (Halt_Player_Run != NOTHING) { giveto(Halt_Player_Run, mudconf.waitcost * Halt_Entries_Run); a_Queue(Halt_Player_Run, -Halt_Entries_Run); } Halt_Player_Run = dbOwner; Halt_Entries_Run = 0; } Halt_Entries++; Halt_Entries_Run++; if (p->fpTask == Task_SemaphoreTimeout) { add_to(point->sem, -1, point->attr); } for (int i = 0; i < MAX_GLOBAL_REGS; i++) { if (point->scr[i]) { RegRelease(point->scr[i]); point->scr[i] = NULL; } } MEMFREE(point->text); point->text = NULL; free_qentry(point); return IU_REMOVE_TASK; } } return IU_NEXT_TASK; } // ------------------------------------------------------------------ // // halt_que: Remove all queued commands that match (executor, object). // // (NOTHING, NOTHING) matches all queue entries. // (NOTHING, ) matches only queue entries run from . // (, NOTHING) matches only queue entries owned by . // (, ) matches only queue entries run from // and owned by . // int halt_que(dbref executor, dbref object) { Halt_Player_Target = executor; Halt_Object_Target = object; Halt_Entries = 0; Halt_Player_Run = NOTHING; Halt_Entries_Run = 0; // Process @wait, timed semaphores, and untimed semaphores. // scheduler.TraverseUnordered(CallBack_HaltQueue); if (Halt_Player_Run != NOTHING) { giveto(Halt_Player_Run, mudconf.waitcost * Halt_Entries_Run); a_Queue(Halt_Player_Run, -Halt_Entries_Run); Halt_Player_Run = NOTHING; } return Halt_Entries; } // --------------------------------------------------------------------------- // do_halt: Command interface to halt_que. // void do_halt(dbref executor, dbref caller, dbref enactor, int eval, int key, char *target) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); dbref executor_targ, obj_targ; if ((key & HALT_ALL) && !Can_Halt(executor)) { notify(executor, NOPERM_MESSAGE); return; } // Figure out what to halt. // if (!target || !*target) { obj_targ = NOTHING; if (key & HALT_ALL) { executor_targ = NOTHING; } else { executor_targ = Owner(executor); if (!isPlayer(executor)) { obj_targ = executor; } } } else { if (Can_Halt(executor)) { obj_targ = match_thing(executor, target); } else { obj_targ = match_controlled(executor, target); } if (!Good_obj(obj_targ)) { return; } if (key & HALT_ALL) { notify(executor, "Can't specify a target and /all"); return; } if (isPlayer(obj_targ)) { executor_targ = obj_targ; obj_targ = NOTHING; } else { executor_targ = NOTHING; } } int numhalted = halt_que(executor_targ, obj_targ); if (Quiet(executor)) { return; } notify(Owner(executor), tprintf("%d queue entr%s removed.", numhalted, numhalted == 1 ? "y" : "ies")); } static int Notify_Key; static int Notify_Num_Done; static int Notify_Num_Max; static int Notify_Sem; static int Notify_Attr; // NFY_DRAIN or NFY_NFYALL // static int CallBack_NotifySemaphoreDrainOrAll(PTASK_RECORD p) { if (p->fpTask == Task_SemaphoreTimeout) { // This represents a semaphore. // BQUE *point = (BQUE *)(p->arg_voidptr); if ( point->sem == Notify_Sem && ( point->attr == Notify_Attr || !Notify_Attr)) { Notify_Num_Done++; if (Notify_Key == NFY_DRAIN) { // Discard the command // giveto(point->executor, mudconf.waitcost); a_Queue(Owner(point->executor), -1); for (int i = 0; i < MAX_GLOBAL_REGS; i++) { if (point->scr[i]) { RegRelease(point->scr[i]); point->scr[i] = NULL; } } MEMFREE(point->text); point->text = NULL; free_qentry(point); return IU_REMOVE_TASK; } else { // Allow the command to run. The priority may have been // PRIORITY_SUSPEND, so we need to change it. // if (isPlayer(point->enactor)) { p->iPriority = PRIORITY_PLAYER; } else { p->iPriority = PRIORITY_OBJECT; } p->ltaWhen.GetUTC(); p->fpTask = Task_RunQueueEntry; return IU_UPDATE_TASK; } } } return IU_NEXT_TASK; } // NFY_NFY or NFY_QUIET // static int CallBack_NotifySemaphoreFirstOrQuiet(PTASK_RECORD p) { // If we've notified enough, exit. // if ( ( NFY_NFY == Notify_Key || NFY_QUIET == Notify_Key) && Notify_Num_Done >= Notify_Num_Max) { return IU_DONE; } if (p->fpTask == Task_SemaphoreTimeout) { // This represents a semaphore. // BQUE *point = (BQUE *)(p->arg_voidptr); if ( point->sem == Notify_Sem && ( point->attr == Notify_Attr || !Notify_Attr)) { Notify_Num_Done++; // Allow the command to run. The priority may have been // PRIORITY_SUSPEND, so we need to change it. // if (isPlayer(point->enactor)) { p->iPriority = PRIORITY_PLAYER; } else { p->iPriority = PRIORITY_OBJECT; } p->ltaWhen.GetUTC(); p->fpTask = Task_RunQueueEntry; return IU_UPDATE_TASK; } } return IU_NEXT_TASK; } // --------------------------------------------------------------------------- // nfy_que: Notify commands from the queue and perform or discard them. int nfy_que(dbref sem, int attr, int key, int count) { int cSemaphore = 1; if (attr) { int aflags; dbref aowner; char *str = atr_get(sem, attr, &aowner, &aflags); cSemaphore = mux_atol(str); free_lbuf(str); } Notify_Num_Done = 0; if (cSemaphore > 0) { Notify_Key = key; Notify_Sem = sem; Notify_Attr = attr; Notify_Num_Max = count; if ( key == NFY_NFY || key == NFY_QUIET) { scheduler.TraverseOrdered(CallBack_NotifySemaphoreFirstOrQuiet); } else { scheduler.TraverseUnordered(CallBack_NotifySemaphoreDrainOrAll); } } // Update the sem waiters count. // if ( NFY_NFY == key || NFY_QUIET == key) { add_to(sem, -count, attr); } else { atr_clr(sem, attr); } return Notify_Num_Done; } // --------------------------------------------------------------------------- // do_notify: Command interface to nfy_que void do_notify ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *what, char *count ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); char *obj = parse_to(&what, '/', 0); init_match(executor, obj, NOTYPE); match_everything(0); dbref thing = noisy_match_result(); if (!Good_obj(thing)) { return; } if (!Controls(executor, thing) && !Link_ok(thing)) { notify(executor, NOPERM_MESSAGE); } else { int atr = A_SEMAPHORE; if ( what && what[0] != '\0') { int i = mkattr(executor, what); if (0 < i) { atr = i; if (atr != A_SEMAPHORE) { // Do they have permission to set this attribute? // ATTR *ap = (ATTR *)anum_get(atr); if (!bCanSetAttr(executor, thing, ap)) { notify_quiet(executor, NOPERM_MESSAGE); return; } } } } int loccount; if ( count && count[0] != '\0') { loccount = mux_atol(count); } else { loccount = 1; } if (loccount > 0) { nfy_que(thing, atr, key, loccount); if ( (!(Quiet(executor) || Quiet(thing))) && key != NFY_QUIET) { if (key == NFY_DRAIN) { notify_quiet(executor, "Drained."); } else { notify_quiet(executor, "Notified."); } } } } } // --------------------------------------------------------------------------- // setup_que: Set up a queue entry. // static BQUE *setup_que ( dbref executor, dbref caller, dbref enactor, int eval, char *command, int nargs, char *args[], reg_ref *sargs[] ) { // Can we run commands at all? // if (Halted(executor)) { return NULL; } // Make sure executor can afford to do it. // int a = mudconf.waitcost; if (mudconf.machinecost && RandomINT32(0, mudconf.machinecost-1) == 0) { a++; } if (!payfor(executor, a)) { notify(Owner(executor), "Not enough money to queue command."); return NULL; } // Wizards and their objs may queue up to db_top+1 cmds. Players are // limited to QUEUE_QUOTA. -mnp // a = QueueMax(Owner(executor)); if (a_Queue(Owner(executor), 1) > a) { a_Queue(Owner(executor), -1); notify(Owner(executor), "Run away objects: too many commands queued. Halted."); halt_que(Owner(executor), NOTHING); // Halt also means no command execution allowed. // s_Halted(executor); return NULL; } // We passed all the tests. // // Calculate the length of the save string. // size_t tlen = 0; static size_t nCommand; static size_t nLenEnv[NUM_ENV_VARS]; if (command) { nCommand = strlen(command) + 1; tlen = nCommand; } if (nargs > NUM_ENV_VARS) { nargs = NUM_ENV_VARS; } for (a = 0; a < nargs; a++) { if (args[a]) { nLenEnv[a] = strlen(args[a]) + 1; tlen += nLenEnv[a]; } } // Create the qeue entry and load the save string. // BQUE *tmp = alloc_qentry("setup_que.qblock"); tmp->comm = NULL; char *tptr = tmp->text = (char *)MEMALLOC(tlen); ISOUTOFMEMORY(tptr); if (command) { memcpy(tptr, command, nCommand); tmp->comm = tptr; tptr += nCommand; } for (a = 0; a < nargs; a++) { if (args[a]) { memcpy(tptr, args[a], nLenEnv[a]); tmp->env[a] = tptr; tptr += nLenEnv[a]; } else { tmp->env[a] = NULL; } } for ( ; a < NUM_ENV_VARS; a++) { tmp->env[a] = NULL; } if (sargs) { for (a = 0; a < MAX_GLOBAL_REGS; a++) { tmp->scr[a] = sargs[a]; if (sargs[a]) { RegAddRef(sargs[a]); } } } else { for (a = 0; a < MAX_GLOBAL_REGS; a++) { tmp->scr[a] = NULL; } } // Load the rest of the queue block. // tmp->executor = executor; tmp->IsTimed = false; tmp->sem = NOTHING; tmp->attr = 0; tmp->enactor = enactor; tmp->caller = caller; tmp->eval = eval; tmp->nargs = nargs; return tmp; } // --------------------------------------------------------------------------- // wait_que: Add commands to the wait or semaphore queues. // void wait_que ( dbref executor, dbref caller, dbref enactor, int eval, bool bTimed, CLinearTimeAbsolute <aWhen, dbref sem, int attr, char *command, int nargs, char *args[], reg_ref *sargs[] ) { if (!(mudconf.control_flags & CF_INTERP)) { return; } BQUE *tmp = setup_que(executor, caller, enactor, eval, command, nargs, args, sargs); if (!tmp) { return; } int iPriority; if (isPlayer(tmp->enactor)) { iPriority = PRIORITY_PLAYER; } else { iPriority = PRIORITY_OBJECT; } tmp->IsTimed = bTimed; tmp->waittime = ltaWhen; tmp->sem = sem; tmp->attr = attr; if (sem == NOTHING) { // Not a semaphore, so let it run it immediately or put it on // the wait queue. // if (tmp->IsTimed) { scheduler.DeferTask(tmp->waittime, iPriority, Task_RunQueueEntry, tmp, 0); } else { scheduler.DeferImmediateTask(iPriority, Task_RunQueueEntry, tmp, 0); } } else { if (!tmp->IsTimed) { // In this case, the timeout task below will never run, // but it allows us to manage all semaphores together in // the same data structure. // iPriority = PRIORITY_SUSPEND; } scheduler.DeferTask(tmp->waittime, iPriority, Task_SemaphoreTimeout, tmp, 0); } } #ifdef QUERY_SLAVE // --------------------------------------------------------------------------- // sql_que: Add commands to the sql queue. // void sql_que ( dbref executor, dbref caller, dbref enactor, int eval, bool bTimed, CLinearTimeAbsolute <aWhen, dbref thing, int attr, char *command, int nargs, char *args[], reg_ref *sargs[] ) { if (!(mudconf.control_flags & CF_INTERP)) { return; } BQUE *tmp = setup_que(executor, caller, enactor, eval, command, nargs, args, sargs); if (!tmp) { return; } tmp->IsTimed = bTimed; tmp->waittime = ltaWhen; tmp->sem = thing; tmp->attr = attr; int iPriority; if (!tmp->IsTimed) { // In this case, the timeout task below will never run, // but it allows us to manage all semaphores together in // the same data structure. // iPriority = PRIORITY_SUSPEND; } else { iPriority = PRIORITY_OBJECT; } scheduler.DeferTask(tmp->waittime, iPriority, Task_SQLTimeout, tmp, 0); } #endif // QUERY_SLAVE // --------------------------------------------------------------------------- // do_wait: Command interface to wait_que // void do_wait ( dbref executor, dbref caller, dbref enactor, int eval, int key, char *event, char *cmd, char *cargs[], int ncargs ) { CLinearTimeAbsolute ltaWhen; CLinearTimeDelta ltd; // If arg1 is all numeric, do simple (non-sem) timed wait. // if (is_rational(event)) { if (key & WAIT_UNTIL) { ltaWhen.SetSecondsString(event); } else { ltaWhen.GetUTC(); ltd.SetSecondsString(event); ltaWhen += ltd; } wait_que(executor, caller, enactor, eval, true, ltaWhen, NOTHING, 0, cmd, ncargs, cargs, mudstate.global_regs); return; } // Semaphore wait with optional timeout. // char *what = parse_to(&event, '/', 0); init_match(executor, what, NOTYPE); match_everything(0); dbref thing = noisy_match_result(); if (!Good_obj(thing)) { return; } else if (!Controls(executor, thing) && !Link_ok(thing)) { notify(executor, NOPERM_MESSAGE); } else { // Get timeout, default 0. // int atr = A_SEMAPHORE; bool bTimed = false; if (event && *event) { if (is_rational(event)) { if (key & WAIT_UNTIL) { ltaWhen.SetSecondsString(event); } else { ltaWhen.GetUTC(); ltd.SetSecondsString(event); ltaWhen += ltd; } bTimed = true; } else { ATTR *ap = atr_str(event); if (!ap) { atr = mkattr(executor, event); if (atr <= 0) { notify_quiet(executor, "Invalid attribute."); return; } ap = atr_num(atr); } else { atr = ap->number; } if (!bCanSetAttr(executor, thing, ap)) { notify_quiet(executor, NOPERM_MESSAGE); return; } } } int num = add_to(thing, 1, atr); if (num <= 0) { // Thing over-notified, run the command immediately. // thing = NOTHING; bTimed = false; } wait_que(executor, caller, enactor, eval, bTimed, ltaWhen, thing, atr, cmd, ncargs, cargs, mudstate.global_regs); } } #ifdef QUERY_SLAVE // --------------------------------------------------------------------------- // do_query: Command interface to sql_que // void do_query ( dbref executor, dbref caller, dbref enactor, int eval, int key, char *dbref_attr, char *dbname_query, char *cargs[], int ncargs ) { if (key & QUERY_SQL) { // SQL Query. // dbref thing; ATTR *pattr; if (!( parse_attrib(executor, dbref_attr, &thing, &pattr) && pattr)) { notify_quiet(executor, "No match."); return; } if (!Controls(executor, thing)) { notify_quiet(executor, NOPERM_MESSAGE); return; } char *pQuery = dbname_query; char *pDBName = parse_to(&pQuery, '/', 0); if (NULL == pQuery) { notify(executor, "QUERY: No Query."); return; } STARTLOG(LOG_ALWAYS, "CMD", "QUERY"); Log.tinyprintf("Thing=#%d, Attr=%s, dbname=%s, query=%s", thing, pattr->name, pDBName, pQuery); ENDLOG; } else { notify_quiet(executor, "At least one query option is required."); } } #endif // QUERY_SLAVE static CLinearTimeAbsolute Show_lsaNow; static int Total_SystemTasks; static int Total_RunQueueEntry; static int Shown_RunQueueEntry; static int Total_SemaphoreTimeout; static int Shown_SemaphoreTimeout; static dbref Show_Player_Target; static dbref Show_Object_Target; static int Show_Key; static dbref Show_Player; static int Show_bFirstLine; #ifdef QUERY_SLAVE int Total_SQLTimeout; int Shown_SQLTimeout; #endif // QUERY_SLAVE static int CallBack_ShowDispatches(PTASK_RECORD p) { Total_SystemTasks++; CLinearTimeDelta ltd = p->ltaWhen - Show_lsaNow; if (p->fpTask == dispatch_DatabaseDump) { notify(Show_Player, tprintf("[%d]auto-@dump", ltd.ReturnSeconds())); } else if (p->fpTask == dispatch_FreeListReconstruction) { notify(Show_Player, tprintf("[%d]auto-@dbck", ltd.ReturnSeconds())); } else if (p->fpTask == dispatch_IdleCheck) { notify(Show_Player, tprintf("[%d]Check for idle players", ltd.ReturnSeconds())); } else if (p->fpTask == dispatch_CheckEvents) { notify(Show_Player, tprintf("[%d]Test for @daily time", ltd.ReturnSeconds())); } #ifndef MEMORY_BASED else if (p->fpTask == dispatch_CacheTick) { notify(Show_Player, tprintf("[%d]Database cache tick", ltd.ReturnSeconds())); } #endif else if (p->fpTask == Task_ProcessCommand) { notify(Show_Player, tprintf("[%d]Further command quota", ltd.ReturnSeconds())); } #ifdef WIN32 else if (p->fpTask == Task_FreeDescriptor) { notify(Show_Player, tprintf("[%d]Delayed descriptor deallocation", ltd.ReturnSeconds())); } else if (p->fpTask == Task_DeferredClose) { notify(Show_Player, tprintf("[%d]Delayed socket close", ltd.ReturnSeconds())); } #endif else { Total_SystemTasks--; } return IU_NEXT_TASK; } static void ShowPsLine(BQUE *tmp) { char *bufp = unparse_object(Show_Player, tmp->executor, false); if (tmp->IsTimed && (Good_obj(tmp->sem))) { CLinearTimeDelta ltd = tmp->waittime - Show_lsaNow; notify(Show_Player, tprintf("[#%d/%d]%s:%s", tmp->sem, ltd.ReturnSeconds(), bufp, tmp->comm)); } else if (tmp->IsTimed) { CLinearTimeDelta ltd = tmp->waittime - Show_lsaNow; notify(Show_Player, tprintf("[%d]%s:%s", ltd.ReturnSeconds(), bufp, tmp->comm)); } else if (Good_obj(tmp->sem)) { notify(Show_Player, tprintf("[#%d]%s:%s", tmp->sem, bufp, tmp->comm)); } else { notify(Show_Player, tprintf("%s:%s", bufp, tmp->comm)); } char *bp = bufp; if (Show_Key == PS_LONG) { for (int i = 0; i < tmp->nargs; i++) { if (tmp->env[i] != NULL) { safe_str("; Arg", bufp, &bp); safe_chr((char)(i + '0'), bufp, &bp); safe_str("='", bufp, &bp); safe_str(tmp->env[i], bufp, &bp); safe_chr('\'', bufp, &bp); } } *bp = '\0'; bp = unparse_object(Show_Player, tmp->enactor, false); notify(Show_Player, tprintf(" Enactor: %s%s", bp, bufp)); free_lbuf(bp); } free_lbuf(bufp); } static int CallBack_ShowWait(PTASK_RECORD p) { if (p->fpTask != Task_RunQueueEntry) { return IU_NEXT_TASK; } Total_RunQueueEntry++; BQUE *tmp = (BQUE *)(p->arg_voidptr); if (que_want(tmp, Show_Player_Target, Show_Object_Target)) { Shown_RunQueueEntry++; if (Show_Key == PS_SUMM) { return IU_NEXT_TASK; } if (Show_bFirstLine) { notify(Show_Player, "----- Wait Queue -----"); Show_bFirstLine = false; } ShowPsLine(tmp); } return IU_NEXT_TASK; } static int CallBack_ShowSemaphore(PTASK_RECORD p) { if (p->fpTask != Task_SemaphoreTimeout) { return IU_NEXT_TASK; } Total_SemaphoreTimeout++; BQUE *tmp = (BQUE *)(p->arg_voidptr); if (que_want(tmp, Show_Player_Target, Show_Object_Target)) { Shown_SemaphoreTimeout++; if (Show_Key == PS_SUMM) { return IU_NEXT_TASK; } if (Show_bFirstLine) { notify(Show_Player, "----- Semaphore Queue -----"); Show_bFirstLine = false; } ShowPsLine(tmp); } return IU_NEXT_TASK; } #ifdef QUERY_SLAVE int CallBack_ShowSQLQueries(PTASK_RECORD p) { if (p->fpTask != Task_SQLTimeout) { return IU_NEXT_TASK; } Total_SQLTimeout++; BQUE *tmp = (BQUE *)(p->arg_voidptr); if (que_want(tmp, Show_Player_Target, Show_Object_Target)) { Shown_SQLTimeout++; if (Show_Key == PS_SUMM) { return IU_NEXT_TASK; } if (Show_bFirstLine) { notify(Show_Player, "----- SQL Queries -----"); Show_bFirstLine = false; } ShowPsLine(tmp); } return IU_NEXT_TASK; } #endif // --------------------------------------------------------------------------- // do_ps: tell executor what commands they have pending in the queue // void do_ps(dbref executor, dbref caller, dbref enactor, int eval, int key, char *target) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); char *bufp; dbref executor_targ, obj_targ; // Figure out what to list the queue for. // if ((key & PS_ALL) && !See_Queue(executor)) { notify(executor, NOPERM_MESSAGE); return; } if (!target || !*target) { obj_targ = NOTHING; if (key & PS_ALL) { executor_targ = NOTHING; } else { executor_targ = Owner(executor); if (!isPlayer(executor)) { obj_targ = executor; } } } else { executor_targ = Owner(executor); obj_targ = match_controlled(executor, target); if (obj_targ == NOTHING) { return; } if (key & PS_ALL) { notify(executor, "Can't specify a target and /all"); return; } if (isPlayer(obj_targ)) { executor_targ = obj_targ; obj_targ = NOTHING; } } key = key & ~PS_ALL; switch (key) { case PS_BRIEF: case PS_SUMM: case PS_LONG: break; default: notify(executor, "Illegal combination of switches."); return; } Show_lsaNow.GetUTC(); Total_SystemTasks = 0; Total_RunQueueEntry = 0; Shown_RunQueueEntry = 0; Total_SemaphoreTimeout = 0; Shown_SemaphoreTimeout = 0; Show_Player_Target = executor_targ; Show_Object_Target = obj_targ; Show_Key = key; Show_Player = executor; Show_bFirstLine = true; scheduler.TraverseOrdered(CallBack_ShowWait); Show_bFirstLine = true; scheduler.TraverseOrdered(CallBack_ShowSemaphore); #ifdef QUERY_SLAVE Show_bFirstLine = true; scheduler.TraverseOrdered(CallBack_ShowSQLQueries); #endif // QUERY_SLAVE if (Wizard(executor)) { notify(executor, "----- System Queue -----"); scheduler.TraverseOrdered(CallBack_ShowDispatches); } // Display stats. // bufp = alloc_mbuf("do_ps"); #ifdef QUERY_SLAVE mux_sprintf(bufp, MBUF_SIZE, "Totals: Wait Queue...%d/%d Semaphores...%d/%d SQL %d/%d", Shown_RunQueueEntry, Total_RunQueueEntry, Shown_SemaphoreTimeout, Total_SemaphoreTimeout, Shown_SQLTimeout, Total_SQLTimeout); #else mux_sprintf(bufp, MBUF_SIZE, "Totals: Wait Queue...%d/%d Semaphores...%d/%d", Shown_RunQueueEntry, Total_RunQueueEntry, Shown_SemaphoreTimeout, Total_SemaphoreTimeout); #endif // QUERY_SLAVE notify(executor, bufp); if (Wizard(executor)) { mux_sprintf(bufp, MBUF_SIZE, " System Tasks.....%d", Total_SystemTasks); notify(executor, bufp); } free_mbuf(bufp); } static CLinearTimeDelta ltdWarp; static int CallBack_Warp(PTASK_RECORD p) { if ( p->fpTask == Task_RunQueueEntry #ifdef QUERY_SLAVE || p->fpTask == Task_SQLTimeout #endif // QUERY_SLAVE || p->fpTask == Task_SemaphoreTimeout) { BQUE *point = (BQUE *)(p->arg_voidptr); if (point->IsTimed) { point->waittime -= ltdWarp; p->ltaWhen -= ltdWarp; return IU_UPDATE_TASK; } } return IU_NEXT_TASK; } // --------------------------------------------------------------------------- // do_queue: Queue management // void do_queue(dbref executor, dbref caller, dbref enactor, int eval, int key, char *arg) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); if (key == QUEUE_KICK) { int i = mux_atol(arg); int save_minPriority = scheduler.GetMinPriority(); if (save_minPriority <= PRIORITY_CF_DEQUEUE_DISABLED) { notify(executor, "Warning: automatic dequeueing is disabled."); scheduler.SetMinPriority(PRIORITY_CF_DEQUEUE_ENABLED); } CLinearTimeAbsolute lsaNow; lsaNow.GetUTC(); scheduler.ReadyTasks(lsaNow); int ncmds = scheduler.RunTasks(i); scheduler.SetMinPriority(save_minPriority); if (!Quiet(executor)) { notify(executor, tprintf("%d commands processed.", ncmds)); } } else if (key == QUEUE_WARP) { int iWarp = mux_atol(arg); ltdWarp.SetSeconds(iWarp); if (scheduler.GetMinPriority() <= PRIORITY_CF_DEQUEUE_DISABLED) { notify(executor, "Warning: automatic dequeueing is disabled."); } scheduler.TraverseUnordered(CallBack_Warp); if (Quiet(executor)) { return; } if (iWarp > 0) { notify(executor, tprintf("WaitQ timer advanced %d seconds.", iWarp)); } else if (iWarp < 0) { notify(executor, tprintf("WaitQ timer set back %d seconds.", iWarp)); } else { notify(executor, "Object queue appended to player queue."); } } } mux2.6/src/strtod.cpp0000600000175000017500000024233311025753746014630 0ustar sdennissdennis/**************************************************************** * * The author of this software is David M. Gay. * * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. * ***************************************************************/ /* Please send bug reports to David M. Gay Bell Laboratories, Room 2C-463 600 Mountain Avenue Murray Hill, NJ 07974-0636 U.S.A. dmg@bell-labs.com */ /* On a machine with IEEE extended-precision registers, it is * necessary to specify double-precision (53-bit) rounding precision * before invoking strtod or dtoa. If the machine uses (the equivalent * of) Intel 80x87 arithmetic, the call * _control87(PC_53, MCW_PC); * does this with many compilers. Whether this or another call is * appropriate depends on the compiler; for this to work, it may be * necessary to #include "float.h" or another system-dependent header * file. */ /* strtod for IEEE-, VAX-, and IBM-arithmetic machines. * * This strtod returns a nearest machine number to the input decimal * string (or sets errno to ERANGE). With IEEE arithmetic, ties are * broken by the IEEE round-even rule. Otherwise ties are broken by * biased rounding (add half and chop). * * Inspired loosely by William D. Clinger's paper "How to Read Floating * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. * * Modifications: * * 1. We only require IEEE, IBM, or VAX double-precision * arithmetic (not IEEE double-extended). * 2. We get by with floating-point arithmetic in a case that * Clinger missed -- when we're computing d * 10^n * for a small integer d and the integer n is not too * much larger than 22 (the maximum integer k for which * we can represent 10^k exactly), we may be able to * compute (d*10^k) * 10^(e-k) with just one roundoff. * 3. Rather than a bit-at-a-time adjustment of the binary * result in the hard case, we use floating-point * arithmetic to determine the adjustment to within * one bit; only in really hard cases do we need to * compute a second residual. * 4. Because of 3., we don't need a large table of powers of 10 * for ten-to-e (just some small tables, e.g. of 10^k * for 0 <= k <= 22). */ /* * #define IEEE_8087 for IEEE-arithmetic machines where the least * significant byte has the lowest address. * #define IEEE_MC68k for IEEE-arithmetic machines where the most * significant byte has the lowest address. * #define Long int on machines with 32-bit ints and 64-bit longs. * #define IBM for IBM mainframe-style floating-point arithmetic. * #define VAX for VAX-style floating-point arithmetic (D_floating). * #define No_leftright to omit left-right logic in fast floating-point * computation of dtoa. * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 * and strtod and dtoa should round accordingly. * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 * and Honor_FLT_ROUNDS is not #defined. * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines * that use extended-precision instructions to compute rounded * products and quotients) with IBM. * #define ROUND_BIASED for IEEE-format with biased rounding. * #define Inaccurate_Divide for IEEE-format with correctly rounded * products but inaccurate quotients, e.g., for Intel i860. * #define Bad_float_h if your system lacks a float.h or if it does not * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making * memory allocations from a private pool of memory when possible. * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, * unless #defined to be a different length. This default length * suffices to get rid of MALLOC calls except for unusual cases, * such as decimal-to-binary conversion of a very long string of * digits. The longest string dtoa can return is about 751 bytes * long. For conversions by strtod of strings of 800 digits and * all dtoa conversions in single-threaded executions with 8-byte * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte * pointers, PRIVATE_MEM >= 7112 appears adequate. * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that * avoids underflows on inputs whose result does not underflow. * If you #define NO_IEEE_Scale on a machine that uses IEEE-format * floating-point numbers and flushes underflows to zero rather * than implementing gradual underflow, then you must also #define * Sudden_Underflow. * #define YES_ALIAS to permit aliasing certain double values with * arrays of ULongs. This leads to slightly better code with * some compilers and was always used prior to 19990916, but it * is not strictly legal and can cause trouble with aggressively * optimizing compilers (e.g., gcc 2.95.1 under -O2). * #define SET_INEXACT if IEEE arithmetic is being used and extra * computation should be done to set the inexact flag when the * result is inexact and avoid setting inexact when the result * is exact. In this case, dtoa.c must be compiled in * an environment, perhaps provided by #include "dtoa.c" in a * suitable wrapper, that defines two functions, * int get_inexact(void); * void clear_inexact(void); * such that get_inexact() returns a nonzero value if the * inexact bit is already set, and clear_inexact() sets the * inexact bit to 0. When SET_INEXACT is #defined, strtod * also does extra computations to set the underflow and overflow * flags when appropriate (i.e., when the result is tiny and * inexact or when it is a numeric value rounded to +-infinity). */ #include "autoconf.h" #include "config.h" #include "externs.h" #include "stringutil.h" #if defined(HAVE_FPU_CONTROL_H) #include #elif defined(IEEEFP_H_USEABLE) #include #elif defined(HAVE_FENV_H) #include #endif #if defined(WORDS_BIGENDIAN) #define IEEE_MC68k #elif defined(WORDS_LITTLEENDIAN) #define IEEE_8087 #else #error Must be either Big or Little Endian. #endif #define Long INT32 typedef UINT32 ULong; #ifndef Omit_Private_Memory #ifndef PRIVATE_MEM #define PRIVATE_MEM 2304 #endif #define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) static double private_mem[PRIVATE_mem], *pmem_next = private_mem; #endif #undef IEEE_Arith #undef Avoid_Underflow #ifdef IEEE_MC68k #define IEEE_Arith #endif #ifdef IEEE_8087 #define IEEE_Arith #endif #ifdef Bad_float_h #ifdef IEEE_Arith #define DBL_DIG 15 #define DBL_MAX_10_EXP 308 #define DBL_MAX_EXP 1024 #define FLT_RADIX 2 #endif /*IEEE_Arith*/ #ifdef IBM #define DBL_DIG 16 #define DBL_MAX_10_EXP 75 #define DBL_MAX_EXP 63 #define FLT_RADIX 16 #define DBL_MAX 7.2370055773322621e+75 #endif #ifdef VAX #define DBL_DIG 16 #define DBL_MAX_10_EXP 38 #define DBL_MAX_EXP 127 #define FLT_RADIX 2 #define DBL_MAX 1.7014118346046923e+38 #endif #ifndef LONG_MAX #define LONG_MAX 2147483647 #endif #else /* ifndef Bad_float_h */ #include "float.h" #endif /* Bad_float_h */ #ifndef __MATH_H__ #include "math.h" #endif #ifndef CONST #define CONST const #endif #if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. #endif typedef union { double d; ULong L[2]; } U; #ifdef YES_ALIAS #define dval(x) x #ifdef IEEE_8087 #define word0(x) ((ULong *)&x)[1] #define word1(x) ((ULong *)&x)[0] #else #define word0(x) ((ULong *)&x)[0] #define word1(x) ((ULong *)&x)[1] #endif #else #ifdef IEEE_8087 #define word0(x) ((U*)&x)->L[1] #define word1(x) ((U*)&x)->L[0] #else #define word0(x) ((U*)&x)->L[0] #define word1(x) ((U*)&x)->L[1] #endif #define dval(x) ((U*)&x)->d #endif /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) */ #if defined(IEEE_8087) + defined(VAX) #define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ ((unsigned short *)a)[0] = (unsigned short)c, a++) #else #define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ ((unsigned short *)a)[1] = (unsigned short)c, a++) #endif /* #define P DBL_MANT_DIG */ /* Ten_pmax = floor(P*log(2)/log(5)) */ /* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ /* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ /* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ #ifdef IEEE_Arith #define Exp_shift 20 #define Exp_shift1 20 #define Exp_msk1 0x100000 #define Exp_msk11 0x100000 #define Exp_mask 0x7ff00000 #define P 53 #define Bias 1023 #define Emin (-1022) #define Exp_1 0x3ff00000 #define Exp_11 0x3ff00000 #define Ebits 11 #define Frac_mask 0xfffff #define Frac_mask1 0xfffff #define Ten_pmax 22 #define Bletch 0x10 #define Bndry_mask 0xfffff #define Bndry_mask1 0xfffff #define LSB 1 #define Sign_bit 0x80000000 #define Log2P 1 #define Tiny0 0 #define Tiny1 1 #define Quick_max 14 #define Int_max 14 #ifndef NO_IEEE_Scale #define Avoid_Underflow #ifdef Flush_Denorm /* debugging option */ #undef Sudden_Underflow #endif #endif #ifndef Flt_Rounds #ifdef FLT_ROUNDS #define Flt_Rounds FLT_ROUNDS #else #define Flt_Rounds 1 #endif #endif /*Flt_Rounds*/ #ifdef Honor_FLT_ROUNDS #define Rounding rounding #undef Check_FLT_ROUNDS #define Check_FLT_ROUNDS #else #define Rounding Flt_Rounds #endif #else /* ifndef IEEE_Arith */ #undef Check_FLT_ROUNDS #undef Honor_FLT_ROUNDS #undef SET_INEXACT #undef Sudden_Underflow #define Sudden_Underflow #ifdef IBM #undef Flt_Rounds #define Flt_Rounds 0 #define Exp_shift 24 #define Exp_shift1 24 #define Exp_msk1 0x1000000 #define Exp_msk11 0x1000000 #define Exp_mask 0x7f000000 #define P 14 #define Bias 65 #define Exp_1 0x41000000 #define Exp_11 0x41000000 #define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ #define Frac_mask 0xffffff #define Frac_mask1 0xffffff #define Bletch 4 #define Ten_pmax 22 #define Bndry_mask 0xefffff #define Bndry_mask1 0xffffff #define LSB 1 #define Sign_bit 0x80000000 #define Log2P 4 #define Tiny0 0x100000 #define Tiny1 0 #define Quick_max 14 #define Int_max 15 #else /* VAX */ #undef Flt_Rounds #define Flt_Rounds 1 #define Exp_shift 23 #define Exp_shift1 7 #define Exp_msk1 0x80 #define Exp_msk11 0x800000 #define Exp_mask 0x7f80 #define P 56 #define Bias 129 #define Exp_1 0x40800000 #define Exp_11 0x4080 #define Ebits 8 #define Frac_mask 0x7fffff #define Frac_mask1 0xffff007f #define Ten_pmax 24 #define Bletch 2 #define Bndry_mask 0xffff007f #define Bndry_mask1 0xffff007f #define LSB 0x10000 #define Sign_bit 0x8000 #define Log2P 1 #define Tiny0 0x80 #define Tiny1 0 #define Quick_max 15 #define Int_max 15 #endif /* IBM, VAX */ #endif /* IEEE_Arith */ #ifndef IEEE_Arith #define ROUND_BIASED #endif #ifdef RND_PRODQUOT #define rounded_product(a,b) a = rnd_prod(a, b) #define rounded_quotient(a,b) a = rnd_quot(a, b) extern double rnd_prod(double, double), rnd_quot(double, double); #else #define rounded_product(a,b) a *= b #define rounded_quotient(a,b) a /= b #endif #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) #define Big1 0xffffffff #ifndef Pack_32 #define Pack_32 #endif #define FFFFFFFF 0xffffffffUL #ifndef Llong #define Llong INT64 #endif #ifndef ULLong #define ULLong UINT64 #endif #define Kmax 15 struct Bigint { struct Bigint *next; int k, maxwds, sign, wds; ULong x[1]; }; typedef struct Bigint Bigint; static Bigint *freelist[Kmax+1]; static Bigint *Balloc(int k) { int x; Bigint *rv; #ifndef Omit_Private_Memory unsigned int len; #endif rv = freelist[k]; if (rv) { freelist[k] = rv->next; } else { x = 1 << k; #ifdef Omit_Private_Memory rv = (Bigint *)MEMALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); ISOUTOFMEMORY(rv); #else len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) /sizeof(double); if (pmem_next - private_mem + len <= PRIVATE_mem) { rv = (Bigint*)pmem_next; pmem_next += len; } else { rv = (Bigint*)MEMALLOC(len*sizeof(double)); ISOUTOFMEMORY(rv); } #endif rv->k = k; rv->maxwds = x; } rv->sign = rv->wds = 0; return rv; } static void Bfree(Bigint *v) { if (v) { v->next = freelist[v->k]; freelist[v->k] = v; } } #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ y->wds*sizeof(Long) + 2*sizeof(int)) // multiply by m and add a. // static Bigint *multadd(Bigint *b, int m, int a) { int i, wds; #ifdef ULLong ULong *x; ULLong carry, y; #else ULong carry, *x, y; #ifdef Pack_32 ULong xi, z; #endif #endif Bigint *b1; wds = b->wds; x = b->x; i = 0; carry = a; do { #ifdef ULLong y = *x * (ULLong)m + carry; carry = y >> 32; *x++ = (unsigned int)(y & 0xFFFFFFFF); #else #ifdef Pack_32 xi = *x; y = (xi & 0xffff) * m + carry; z = (xi >> 16) * m + (y >> 16); carry = z >> 16; *x++ = (z << 16) + (y & 0xffff); #else y = *x * m + carry; carry = y >> 16; *x++ = y & 0xffff; #endif #endif } while (++i < wds); if (carry) { if (wds >= b->maxwds) { b1 = Balloc(b->k+1); Bcopy(b1, b); Bfree(b); b = b1; } b->x[wds++] = (unsigned int)carry; b->wds = wds; } return b; } static Bigint *s2b(CONST char *s, int nd0, int nd, ULong y9) { Bigint *b; int i, k; Long x, y; x = (nd + 8) / 9; for (k = 0, y = 1; x > y; y <<= 1, k++) { ; // Nothing. } #ifdef Pack_32 b = Balloc(k); b->x[0] = y9; b->wds = 1; #else b = Balloc(k+1); b->x[0] = y9 & 0xffff; b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; #endif i = 9; if (9 < nd0) { s += 9; do { b = multadd(b, 10, *s++ - '0'); } while (++i < nd0); s++; } else { s += 10; } for (; i < nd; i++) { b = multadd(b, 10, *s++ - '0'); } return b; } static int hi0bits(register ULong x) { register int k = 0; if (!(x & 0xffff0000)) { k = 16; x <<= 16; } if (!(x & 0xff000000)) { k += 8; x <<= 8; } if (!(x & 0xf0000000)) { k += 4; x <<= 4; } if (!(x & 0xc0000000)) { k += 2; x <<= 2; } if (!(x & 0x80000000)) { k++; if (!(x & 0x40000000)) { return 32; } } return k; } static int lo0bits(ULong *y) { register int k; register ULong x = *y; if (x & 7) { if (x & 1) { return 0; } if (x & 2) { *y = x >> 1; return 1; } *y = x >> 2; return 2; } k = 0; if (!(x & 0xffff)) { k = 16; x >>= 16; } if (!(x & 0xff)) { k += 8; x >>= 8; } if (!(x & 0xf)) { k += 4; x >>= 4; } if (!(x & 0x3)) { k += 2; x >>= 2; } if (!(x & 1)) { k++; x >>= 1; if (!(x & 1)) { return 32; } } *y = x; return k; } static Bigint *i2b(int i) { Bigint *b; b = Balloc(1); b->x[0] = i; b->wds = 1; return b; } static Bigint *mult(Bigint *a, Bigint *b) { Bigint *c; int k, wa, wb, wc; ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; ULong y; #ifdef ULLong ULLong carry, z; #else ULong carry, z; #ifdef Pack_32 ULong z2; #endif #endif if (a->wds < b->wds) { c = a; a = b; b = c; } k = a->k; wa = a->wds; wb = b->wds; wc = wa + wb; if (wc > a->maxwds) { k++; } c = Balloc(k); for (x = c->x, xa = x + wc; x < xa; x++) { *x = 0; } xa = a->x; xae = xa + wa; xb = b->x; xbe = xb + wb; xc0 = c->x; #ifdef ULLong for (; xb < xbe; xc0++) { y = *xb++; if (y) { x = xa; xc = xc0; carry = 0; do { z = *x++ * (ULLong)y + *xc + carry; carry = z >> 32; *xc++ = (unsigned int)(z & 0xFFFFFFFF); } while (x < xae); *xc = (unsigned int)carry; } } #else #ifdef Pack_32 for (; xb < xbe; xb++, xc0++) { if (y = *xb & 0xffff) { x = xa; xc = xc0; carry = 0; do { z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; carry = z >> 16; z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; carry = z2 >> 16; Storeinc(xc, z2, z); } while (x < xae); *xc = carry; } if (y = *xb >> 16) { x = xa; xc = xc0; carry = 0; z2 = *xc; do { z = (*x & 0xffff) * y + (*xc >> 16) + carry; carry = z >> 16; Storeinc(xc, z, z2); z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; carry = z2 >> 16; } while (x < xae); *xc = z2; } } #else for (; xb < xbe; xc0++) { if (y = *xb++) { x = xa; xc = xc0; carry = 0; do { z = *x++ * y + *xc + carry; carry = z >> 16; *xc++ = z & 0xffff; } while (x < xae); *xc = carry; } } #endif #endif for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) { ; // Nothing. } c->wds = wc; return c; } static Bigint *p5s; static Bigint *pow5mult(Bigint *b, int k) { Bigint *b1, *p5, *p51; int i; static int p05[3] = { 5, 25, 125 }; i = k & 3; if (i) { b = multadd(b, p05[i-1], 0); } if (!(k >>= 2)) { return b; } p5 = p5s; if (!p5) { /* first time */ p5 = p5s = i2b(625); p5->next = 0; } for (;;) { if (k & 1) { b1 = mult(b, p5); Bfree(b); b = b1; } if (!(k >>= 1)) { break; } p51 = p5->next; if (!p51) { p51 = p5->next = mult(p5,p5); p51->next = 0; } p5 = p51; } return b; } static Bigint *lshift(Bigint *b, int k) { int i, k1, n, n1; Bigint *b1; ULong *x, *x1, *xe, z; #ifdef Pack_32 n = k >> 5; #else n = k >> 4; #endif k1 = b->k; n1 = n + b->wds + 1; for (i = b->maxwds; n1 > i; i <<= 1) { k1++; } b1 = Balloc(k1); x1 = b1->x; for (i = 0; i < n; i++) { *x1++ = 0; } x = b->x; xe = x + b->wds; #ifdef Pack_32 if (k &= 0x1f) { k1 = 32 - k; z = 0; do { *x1++ = *x << k | z; z = *x++ >> k1; } while (x < xe); *x1 = z; if (*x1) { ++n1; } } #else if (k &= 0xf) { k1 = 16 - k; z = 0; do { *x1++ = *x << k & 0xffff | z; z = *x++ >> k1; } while (x < xe); if (*x1 = z) { ++n1; } } #endif else { do { *x1++ = *x++; } while (x < xe); } b1->wds = n1 - 1; Bfree(b); return b1; } static int cmp(Bigint *a, Bigint *b) { ULong *xa, *xa0, *xb, *xb0; int i, j; i = a->wds; j = b->wds; if (i -= j) { return i; } xa0 = a->x; xa = xa0 + j; xb0 = b->x; xb = xb0 + j; for (;;) { if (*--xa != *--xb) { return *xa < *xb ? -1 : 1; } if (xa <= xa0) { break; } } return 0; } static Bigint *diff(Bigint *a, Bigint *b) { Bigint *c; int i, wa, wb; ULong *xa, *xae, *xb, *xbe, *xc; #ifdef ULLong ULLong borrow, y; #else ULong borrow, y; #ifdef Pack_32 ULong z; #endif #endif i = cmp(a,b); if (!i) { c = Balloc(0); c->wds = 1; c->x[0] = 0; return c; } if (i < 0) { c = a; a = b; b = c; i = 1; } else { i = 0; } c = Balloc(a->k); c->sign = i; wa = a->wds; xa = a->x; xae = xa + wa; wb = b->wds; xb = b->x; xbe = xb + wb; xc = c->x; borrow = 0; #ifdef ULLong do { y = (ULLong)*xa++ - *xb++ - borrow; borrow = y >> 32 & (ULong)1; *xc++ = (unsigned int)(y & 0xFFFFFFFF); } while (xb < xbe); while (xa < xae) { y = *xa++ - borrow; borrow = y >> 32 & (ULong)1; *xc++ = (unsigned int)(y & 0xFFFFFFFF); } #else #ifdef Pack_32 do { y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); } while (xb < xbe); while (xa < xae) { y = (*xa & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*xa++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); } #else do { y = *xa++ - *xb++ - borrow; borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } while (xb < xbe); while (xa < xae) { y = *xa++ - borrow; borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } #endif #endif while (!*--xc) { wa--; } c->wds = wa; return c; } double ulp(double x) { register Long L; double a; L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; #ifndef Avoid_Underflow #ifndef Sudden_Underflow if (L > 0) { #endif #endif #ifdef IBM L |= Exp_msk1 >> 4; #endif word0(a) = L; word1(a) = 0; #ifndef Avoid_Underflow #ifndef Sudden_Underflow } else { L = -L >> Exp_shift; if (L < Exp_shift) { word0(a) = 0x80000 >> L; word1(a) = 0; } else { word0(a) = 0; L -= Exp_shift; word1(a) = L >= 31 ? 1 : 1 << 31 - L; } } #endif #endif return dval(a); } static double b2d(Bigint *a, int *e) { ULong *xa, *xa0, w, y, z; int k; double d; #ifdef VAX ULong d0, d1; #else #define d0 word0(d) #define d1 word1(d) #endif xa0 = a->x; xa = xa0 + a->wds; y = *--xa; k = hi0bits(y); *e = 32 - k; #ifdef Pack_32 if (k < Ebits) { d0 = Exp_1 | y >> (Ebits - k); w = xa > xa0 ? *--xa : 0; d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); goto ret_d; } z = xa > xa0 ? *--xa : 0; if (k -= Ebits) { d0 = Exp_1 | y << k | z >> (32 - k); y = xa > xa0 ? *--xa : 0; d1 = z << k | y >> (32 - k); } else { d0 = Exp_1 | y; d1 = z; } #else if (k < Ebits + 16) { z = xa > xa0 ? *--xa : 0; d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; w = xa > xa0 ? *--xa : 0; y = xa > xa0 ? *--xa : 0; d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; goto ret_d; } z = xa > xa0 ? *--xa : 0; w = xa > xa0 ? *--xa : 0; k -= Ebits + 16; d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; y = xa > xa0 ? *--xa : 0; d1 = w << k + 16 | y << k; #endif ret_d: #ifdef VAX word0(d) = d0 >> 16 | d0 << 16; word1(d) = d1 >> 16 | d1 << 16; #else #undef d0 #undef d1 #endif return dval(d); } static Bigint *d2b(double d, int *e, int *bits) { Bigint *b; int de, k; ULong *x, y, z; #ifndef Sudden_Underflow int i; #endif #ifdef VAX ULong d0, d1; d0 = word0(d) >> 16 | word0(d) << 16; d1 = word1(d) >> 16 | word1(d) << 16; #else #define d0 word0(d) #define d1 word1(d) #endif #ifdef Pack_32 b = Balloc(1); #else b = Balloc(2); #endif x = b->x; z = d0 & Frac_mask; d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ #ifdef Sudden_Underflow de = (int)(d0 >> Exp_shift); #ifndef IBM z |= Exp_msk11; #endif #else de = (int)(d0 >> Exp_shift); if (de) { z |= Exp_msk1; } #endif #ifdef Pack_32 y = d1; if (y) { k = lo0bits(&y); if (k) { x[0] = y | z << (32 - k); z >>= k; } else { x[0] = y; } #ifndef Sudden_Underflow i = #endif x[1] = z; b->wds = (x[1]) ? 2 : 1; } else { k = lo0bits(&z); x[0] = z; #ifndef Sudden_Underflow i = #endif b->wds = 1; k += 32; } #else if (y = d1) { if (k = lo0bits(&y)) { if (k >= 16) { x[0] = y | z << 32 - k & 0xffff; x[1] = z >> k - 16 & 0xffff; x[2] = z >> k; i = 2; } else { x[0] = y & 0xffff; x[1] = y >> 16 | z << 16 - k & 0xffff; x[2] = z >> k & 0xffff; x[3] = z >> k+16; i = 3; } } else { x[0] = y & 0xffff; x[1] = y >> 16; x[2] = z & 0xffff; x[3] = z >> 16; i = 3; } } else { k = lo0bits(&z); if (k >= 16) { x[0] = z; i = 0; } else { x[0] = z & 0xffff; x[1] = z >> 16; i = 1; } k += 32; } while (!x[i]) { --i; } b->wds = i + 1; #endif #ifndef Sudden_Underflow if (de) { #endif #ifdef IBM *e = (de - Bias - (P-1) << 2) + k; *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); #else *e = de - Bias - (P-1) + k; *bits = P - k; #endif #ifndef Sudden_Underflow } else { *e = de - Bias - (P-1) + 1 + k; #ifdef Pack_32 *bits = 32*i - hi0bits(x[i-1]); #else *bits = (i+2)*16 - hi0bits(x[i]); #endif } #endif return b; } #undef d0 #undef d1 static double ratio(Bigint *a, Bigint *b) { double lcl_da, lcl_db; int k, ka, kb; dval(lcl_da) = b2d(a, &ka); dval(lcl_db) = b2d(b, &kb); #ifdef Pack_32 k = ka - kb + 32*(a->wds - b->wds); #else k = ka - kb + 16*(a->wds - b->wds); #endif #ifdef IBM if (k > 0) { word0(lcl_da) += (k >> 2)*Exp_msk1; if (k &= 3) { dval(lcl_da) *= 1 << k; } } else { k = -k; word0(lcl_db) += (k >> 2)*Exp_msk1; if (k &= 3) { dval(lcl_db) *= 1 << k; } } #else if (k > 0) { word0(lcl_da) += k*Exp_msk1; } else { k = -k; word0(lcl_db) += k*Exp_msk1; } #endif return dval(lcl_da) / dval(lcl_db); } static CONST double tens[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 #ifdef VAX , 1e23, 1e24 #endif }; static CONST double #ifdef IEEE_Arith bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, #ifdef Avoid_Underflow 9007199254740992.*9007199254740992.e-256 /* = 2^106 * 1e-53 */ #else 1e-256 #endif }; /* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ /* flag unnecessarily. It leads to a song and dance at the end of strtod. */ #define Scale_Bit 0x10 #define n_bigtens 5 #else #ifdef IBM bigtens[] = { 1e16, 1e32, 1e64 }; static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; #define n_bigtens 3 #else bigtens[] = { 1e16, 1e32 }; static CONST double tinytens[] = { 1e-16, 1e-32 }; #define n_bigtens 2 #endif #endif DCL_INLINE int FltRounds(void) { return Flt_Rounds; } double mux_strtod(CONST char *s00, char **se) { #ifdef Avoid_Underflow int scale; #endif int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; CONST char *s, *s0, *s1; double aadj, aadj1, adj, rv, rv0; Long L; ULong y, z; Bigint *bb = NULL, *bb1 = NULL, *bd = NULL, *bd0 = NULL, *bs = NULL; Bigint *delta = NULL; #ifdef SET_INEXACT int inexact, oldinexact; #endif #ifdef Honor_FLT_ROUNDS int rounding; #endif sign = nz0 = nz = 0; dval(rv) = 0.; for (s = s00;;s++) { switch (*s) { case '-': sign = 1; /* no break */ case '+': if (*++s) goto break2; /* no break */ case 0: goto ret0; case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': continue; default: goto break2; } } break2: if (*s == '0') { nz0 = 1; while (*++s == '0') { ; // Nothing. } if (!*s) { goto ret; } } s0 = s; y = z = 0; for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) { if (nd < 9) { y = 10*y + c - '0'; } else if (nd < 16) { z = 10*z + c - '0'; } } nd0 = nd; if (c == '.') { c = *++s; if (!nd) { for (; c == '0'; c = *++s) { nz++; } if (c > '0' && c <= '9') { s0 = s; nf += nz; nz = 0; goto have_dig; } goto dig_done; } for (; c >= '0' && c <= '9'; c = *++s) { have_dig: nz++; if (c -= '0') { nf += nz; for (i = 1; i < nz; i++) { if (nd++ < 9) { y *= 10; } else if (nd <= DBL_DIG + 1) { z *= 10; } } if (nd++ < 9) { y = 10*y + c; } else if (nd <= DBL_DIG + 1) { z = 10*z + c; } nz = 0; } } } dig_done: e = 0; if (c == 'e' || c == 'E') { if (!nd && !nz && !nz0) { goto ret0; } s00 = s; esign = 0; switch (c = *++s) { case '-': esign = 1; case '+': c = *++s; } if (c >= '0' && c <= '9') { while (c == '0') { c = *++s; } if (c > '0' && c <= '9') { L = c - '0'; s1 = s; while ((c = *++s) >= '0' && c <= '9') { L = 10*L + c - '0'; } if (s - s1 > 8 || L > 19999) { /* Avoid confusion from exponents * so large that e might overflow. */ e = 19999; /* safe for 16 bit ints */ } else { e = (int)L; } if (esign) { e = -e; } } else { e = 0; } } else { s = s00; } } if (!nd) { if (!nz && !nz0) { ret0: s = s00; sign = 0; } goto ret; } e1 = e -= nf; /* Now we have nd0 digits, starting at s0, followed by a * decimal point, followed by nd-nd0 digits. The number we're * after is the integer represented by those digits times * 10**e */ if (!nd0) { nd0 = nd; } k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; dval(rv) = y; if (k > 9) { #ifdef SET_INEXACT if (k > DBL_DIG) { oldinexact = get_inexact(); } #endif dval(rv) = tens[k - 9] * dval(rv) + z; } bd0 = 0; if ( nd <= DBL_DIG #ifndef RND_PRODQUOT #ifndef Honor_FLT_ROUNDS && 1 == FltRounds() #endif #endif ) { if (!e) { goto ret; } if (e > 0) { if (e <= Ten_pmax) { #ifdef VAX goto vax_ovfl_check; #else #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv = -rv; sign = 0; } #endif /* rv = */ rounded_product(dval(rv), tens[e]); goto ret; #endif } i = DBL_DIG - nd; if (e <= Ten_pmax + i) { /* A fancier test would sometimes let us do * this for larger i values. */ #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv = -rv; sign = 0; } #endif e -= i; dval(rv) *= tens[i]; #ifdef VAX /* VAX exponent range is so narrow we must * worry about overflow here... */ vax_ovfl_check: word0(rv) -= P*Exp_msk1; /* rv = */ rounded_product(dval(rv), tens[e]); if ((word0(rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { goto ovfl; } word0(rv) += P*Exp_msk1; #else /* rv = */ rounded_product(dval(rv), tens[e]); #endif goto ret; } } #ifndef Inaccurate_Divide else if (e >= -Ten_pmax) { #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv = -rv; sign = 0; } #endif /* rv = */ rounded_quotient(dval(rv), tens[-e]); goto ret; } #endif } e1 += nd - k; #ifdef IEEE_Arith #ifdef SET_INEXACT inexact = 1; if (k <= DBL_DIG) { oldinexact = get_inexact(); } #endif #ifdef Avoid_Underflow scale = 0; #endif #ifdef Honor_FLT_ROUNDS if ((rounding = Flt_Rounds) >= 2) { if (sign) { rounding = rounding == 2 ? 0 : 2; } else { if (rounding != 2) { rounding = 0; } } } #endif #endif /*IEEE_Arith*/ /* Get starting approximation = rv * 10**e1 */ if (e1 > 0) { i = e1 & 15; if (i) { dval(rv) *= tens[i]; } if (e1 &= ~15) { if (e1 > DBL_MAX_10_EXP) { ovfl: /* Can't trust HUGE_VAL */ #ifdef IEEE_Arith #ifdef Honor_FLT_ROUNDS switch (rounding) { case 0: /* toward 0 */ case 3: /* toward -infinity */ word0(rv) = Big0; word1(rv) = Big1; break; default: word0(rv) = Exp_mask; word1(rv) = 0; } #else /*Honor_FLT_ROUNDS*/ word0(rv) = Exp_mask; word1(rv) = 0; #endif /*Honor_FLT_ROUNDS*/ #ifdef SET_INEXACT /* set overflow bit */ dval(rv0) = 1e300; dval(rv0) *= dval(rv0); #endif #else /*IEEE_Arith*/ word0(rv) = Big0; word1(rv) = Big1; #endif /*IEEE_Arith*/ if (bd0) { goto retfree; } goto ret; } e1 >>= 4; for (j = 0; e1 > 1; j++, e1 >>= 1) { if (e1 & 1) { dval(rv) *= bigtens[j]; } } /* The last multiplication could overflow. */ word0(rv) -= P*Exp_msk1; dval(rv) *= bigtens[j]; if ((z = word0(rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-P)) { goto ovfl; } if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { /* set to largest number */ /* (Can't trust DBL_MAX) */ word0(rv) = Big0; word1(rv) = Big1; } else { word0(rv) += P*Exp_msk1; } } } else if (e1 < 0) { e1 = -e1; i = e1 & 15; if (i) { dval(rv) /= tens[i]; } if (e1 >>= 4) { if (e1 >= 1 << n_bigtens) { goto undfl; } #ifdef Avoid_Underflow if (e1 & Scale_Bit) { scale = 2*P; } for (j = 0; e1 > 0; j++, e1 >>= 1) { if (e1 & 1) { dval(rv) *= tinytens[j]; } } if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask) >> Exp_shift)) > 0) { /* scaled rv is denormal; zap j low bits */ if (j >= 32) { word1(rv) = 0; if (j >= 53) { word0(rv) = (P+2)*Exp_msk1; } else { word0(rv) &= 0xffffffff << (j-32); } } else { word1(rv) &= 0xffffffff << j; } } #else for (j = 0; e1 > 1; j++, e1 >>= 1) { if (e1 & 1) { dval(rv) *= tinytens[j]; } } /* The last multiplication could underflow. */ dval(rv0) = dval(rv); dval(rv) *= tinytens[j]; if (!dval(rv)) { dval(rv) = 2.*dval(rv0); dval(rv) *= tinytens[j]; #endif if (!dval(rv)) { undfl: dval(rv) = 0.; if (bd0) { goto retfree; } goto ret; } #ifndef Avoid_Underflow word0(rv) = Tiny0; word1(rv) = Tiny1; /* The refinement below will clean * this approximation up. */ } #endif } } /* Now the hard part -- adjusting rv to the correct value.*/ /* Put digits into bd: true value = bd * 10^e */ bd0 = s2b(s0, nd0, nd, y); for (;;) { bd = Balloc(bd0->k); Bcopy(bd, bd0); bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ bs = i2b(1); if (e >= 0) { bb2 = bb5 = 0; bd2 = bd5 = e; } else { bb2 = bb5 = -e; bd2 = bd5 = 0; } if (bbe >= 0) { bb2 += bbe; } else { bd2 -= bbe; } bs2 = bb2; #ifdef Honor_FLT_ROUNDS if (rounding != 1) { bs2++; } #endif #ifdef Avoid_Underflow j = bbe - scale; i = j + bbbits - 1; /* logb(rv) */ if (i < Emin) /* denormal */ { j += P - Emin; } else { j = P + 1 - bbbits; } #else /*Avoid_Underflow*/ #ifdef Sudden_Underflow #ifdef IBM j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); #else j = P + 1 - bbbits; #endif #else /*Sudden_Underflow*/ j = bbe; i = j + bbbits - 1; /* logb(rv) */ if (i < Emin) /* denormal */ { j += P - Emin; } else { j = P + 1 - bbbits; } #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ bb2 += j; bd2 += j; #ifdef Avoid_Underflow bd2 += scale; #endif i = bb2 < bd2 ? bb2 : bd2; if (i > bs2) { i = bs2; } if (i > 0) { bb2 -= i; bd2 -= i; bs2 -= i; } if (bb5 > 0) { bs = pow5mult(bs, bb5); bb1 = mult(bs, bb); Bfree(bb); bb = bb1; } if (bb2 > 0) { bb = lshift(bb, bb2); } if (bd5 > 0) { bd = pow5mult(bd, bd5); } if (bd2 > 0) { bd = lshift(bd, bd2); } if (bs2 > 0) { bs = lshift(bs, bs2); } delta = diff(bb, bd); dsign = delta->sign; delta->sign = 0; i = cmp(delta, bs); #ifdef Honor_FLT_ROUNDS if (rounding != 1) { if (i < 0) { /* Error is less than an ulp */ if (!delta->x[0] && delta->wds <= 1) { /* exact */ #ifdef SET_INEXACT inexact = 0; #endif break; } if (rounding) { if (dsign) { adj = 1.; goto apply_adj; } } else if (!dsign) { adj = -1.; if ( !word1(rv) && !(word0(rv) & Frac_mask)) { y = word0(rv) & Exp_mask; #ifdef Avoid_Underflow if (!scale || y > 2*P*Exp_msk1) #else if (y) #endif { delta = lshift(delta,Log2P); if (cmp(delta, bs) <= 0) { adj = -0.5; } } } apply_adj: #ifdef Avoid_Underflow if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) { word0(adj) += (2*P+1)*Exp_msk1 - y; } #else #ifdef Sudden_Underflow if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { word0(rv) += P*Exp_msk1; dval(rv) += adj*ulp(dval(rv)); word0(rv) -= P*Exp_msk1; } else #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ dval(rv) += adj*ulp(dval(rv)); } break; } adj = ratio(delta, bs); if (adj < 1.) { adj = 1.; } if (adj <= 0x7ffffffe) { /* adj = rounding ? ceil(adj) : floor(adj); */ y = adj; if (y != adj) { if (!((rounding>>1) ^ dsign)) { y++; } adj = y; } } #ifdef Avoid_Underflow if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) { word0(adj) += (2*P+1)*Exp_msk1 - y; } #else #ifdef Sudden_Underflow if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { word0(rv) += P*Exp_msk1; adj *= ulp(dval(rv)); if (dsign) { dval(rv) += adj; } else { dval(rv) -= adj; } word0(rv) -= P*Exp_msk1; goto cont; } #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ adj *= ulp(dval(rv)); if (dsign) { dval(rv) += adj; } else { dval(rv) -= adj; } goto cont; } #endif /*Honor_FLT_ROUNDS*/ if (i < 0) { /* Error is less than half an ulp -- check for * special case of mantissa a power of two. */ if (dsign || word1(rv) || word0(rv) & Bndry_mask #ifdef IEEE_Arith #ifdef Avoid_Underflow || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1 #else || (word0(rv) & Exp_mask) <= Exp_msk1 #endif #endif ) { #ifdef SET_INEXACT if (!delta->x[0] && delta->wds <= 1) { inexact = 0; } #endif break; } if (!delta->x[0] && delta->wds <= 1) { /* exact result */ #ifdef SET_INEXACT inexact = 0; #endif break; } delta = lshift(delta,Log2P); if (cmp(delta, bs) > 0) { goto drop_down; } break; } if (i == 0) { /* exactly half-way between */ if (dsign) { if ((word0(rv) & Bndry_mask1) == Bndry_mask1 && word1(rv) == ( #ifdef Avoid_Underflow (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : #endif 0xffffffff)) { /*boundary case -- increment exponent*/ word0(rv) = (word0(rv) & Exp_mask) + Exp_msk1 #ifdef IBM | Exp_msk1 >> 4 #endif ; word1(rv) = 0; #ifdef Avoid_Underflow dsign = 0; #endif break; } } else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { drop_down: /* boundary case -- decrement exponent */ #ifdef Sudden_Underflow /*{{*/ L = word0(rv) & Exp_mask; #ifdef IBM if (L < Exp_msk1) #else #ifdef Avoid_Underflow if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) #else if (L <= Exp_msk1) #endif /*Avoid_Underflow*/ #endif /*IBM*/ { goto undfl; } L -= Exp_msk1; #else /*Sudden_Underflow}{*/ #ifdef Avoid_Underflow if (scale) { L = word0(rv) & Exp_mask; if (L <= (2*P+1)*Exp_msk1) { if (L > (P+2)*Exp_msk1) { /* round even ==> */ /* accept rv */ break; } /* rv = smallest denormal */ goto undfl; } } #endif /*Avoid_Underflow*/ L = (word0(rv) & Exp_mask) - Exp_msk1; #endif /*Sudden_Underflow}}*/ word0(rv) = L | Bndry_mask1; word1(rv) = 0xffffffff; #ifdef IBM goto cont; #else break; #endif } #ifndef ROUND_BIASED if (!(word1(rv) & LSB)) { break; } #endif if (dsign) { dval(rv) += ulp(dval(rv)); } #ifndef ROUND_BIASED else { dval(rv) -= ulp(dval(rv)); #ifndef Sudden_Underflow if (!dval(rv)) { goto undfl; } #endif } #ifdef Avoid_Underflow dsign = 1 - dsign; #endif #endif break; } if ((aadj = ratio(delta, bs)) <= 2.) { if (dsign) { aadj = aadj1 = 1.; } else if (word1(rv) || word0(rv) & Bndry_mask) { #ifndef Sudden_Underflow if (word1(rv) == Tiny1 && !word0(rv)) { goto undfl; } #endif aadj = 1.; aadj1 = -1.; } else { /* special case -- power of FLT_RADIX to be */ /* rounded down... */ if (aadj < 2./FLT_RADIX) { aadj = 1./FLT_RADIX; } else { aadj *= 0.5; } aadj1 = -aadj; } } else { aadj *= 0.5; aadj1 = dsign ? aadj : -aadj; #ifdef Check_FLT_ROUNDS switch (Rounding) { case 2: /* towards +infinity */ aadj1 -= 0.5; break; case 0: /* towards 0 */ case 3: /* towards -infinity */ aadj1 += 0.5; } #else if (0 == FltRounds()) { aadj1 += 0.5; } #endif /*Check_FLT_ROUNDS*/ } y = word0(rv) & Exp_mask; /* Check for overflow */ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { dval(rv0) = dval(rv); word0(rv) -= P*Exp_msk1; adj = aadj1 * ulp(dval(rv)); dval(rv) += adj; if ((word0(rv) & Exp_mask) >= Exp_msk1*(DBL_MAX_EXP+Bias-P)) { if (word0(rv0) == Big0 && word1(rv0) == Big1) { goto ovfl; } word0(rv) = Big0; word1(rv) = Big1; goto cont; } else { word0(rv) += P*Exp_msk1; } } else { #ifdef Avoid_Underflow if (scale && y <= 2*P*Exp_msk1) { if (aadj <= 0x7fffffff) { if ((z = (ULong)aadj) <= 0) { z = 1; } aadj = z; aadj1 = dsign ? aadj : -aadj; } word0(aadj1) += (2*P+1)*Exp_msk1 - y; } adj = aadj1 * ulp(dval(rv)); dval(rv) += adj; #else #ifdef Sudden_Underflow if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { dval(rv0) = dval(rv); word0(rv) += P*Exp_msk1; adj = aadj1 * ulp(dval(rv)); dval(rv) += adj; #ifdef IBM if ((word0(rv) & Exp_mask) < P*Exp_msk1) #else if ((word0(rv) & Exp_mask) <= P*Exp_msk1) #endif { if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1) { goto undfl; } word0(rv) = Tiny0; word1(rv) = Tiny1; goto cont; } else { word0(rv) -= P*Exp_msk1; } } else { adj = aadj1 * ulp(dval(rv)); dval(rv) += adj; } #else /*Sudden_Underflow*/ /* Compute adj so that the IEEE rounding rules will * correctly round rv + adj in some half-way cases. * If rv * ulp(rv) is denormalized (i.e., * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid * trouble from bits lost to denormalization; * example: 1.2e-307 . */ if (y <= (P-1)*Exp_msk1 && aadj > 1.) { aadj1 = (double)(int)(aadj + 0.5); if (!dsign) { aadj1 = -aadj1; } } adj = aadj1 * ulp(dval(rv)); dval(rv) += adj; #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ } z = word0(rv) & Exp_mask; #ifndef SET_INEXACT #ifdef Avoid_Underflow if (!scale) #endif if (y == z) { /* Can we stop now? */ L = (Long)aadj; aadj -= L; /* The tolerances below are conservative. */ if (dsign || word1(rv) || word0(rv) & Bndry_mask) { if (aadj < .4999999 || aadj > .5000001) { break; } } else if (aadj < .4999999/FLT_RADIX) { break; } } #endif cont: Bfree(bb); Bfree(bd); Bfree(bs); Bfree(delta); } #ifdef SET_INEXACT if (inexact) { if (!oldinexact) { word0(rv0) = Exp_1 + (70 << Exp_shift); word1(rv0) = 0; dval(rv0) += 1.; } } else if (!oldinexact) { clear_inexact(); } #endif #ifdef Avoid_Underflow if (scale) { word0(rv0) = Exp_1 - 2*P*Exp_msk1; word1(rv0) = 0; dval(rv) *= dval(rv0); } #endif /* Avoid_Underflow */ #ifdef SET_INEXACT if (inexact && !(word0(rv) & Exp_mask)) { /* set underflow bit */ dval(rv0) = 1e-300; dval(rv0) *= dval(rv0); } #endif retfree: Bfree(bb); Bfree(bd); Bfree(bs); Bfree(bd0); Bfree(delta); ret: if (se) { *se = (char *)s; } return sign ? -dval(rv) : dval(rv); } static int quorem(Bigint *b, Bigint *S) { int n; ULong *bx, *bxe, q, *sx, *sxe; #ifdef ULLong ULLong borrow, carry, y, ys; #else ULong borrow, carry, y, ys; #ifdef Pack_32 ULong si, z, zs; #endif #endif n = S->wds; if (b->wds < n) { return 0; } sx = S->x; sxe = sx + --n; bx = b->x; bxe = bx + n; q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ if (q) { borrow = 0; carry = 0; do { #ifdef ULLong ys = *sx++ * (ULLong)q + carry; carry = ys >> 32; y = *bx - (ys & FFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; *bx++ = (unsigned int)(y & 0xFFFFFFFF); #else #ifdef Pack_32 si = *sx++; ys = (si & 0xffff) * q + carry; zs = (si >> 16) * q + (ys >> 16); carry = zs >> 16; y = (*bx & 0xffff) - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(bx, z, y); #else ys = *sx++ * q + carry; carry = ys >> 16; y = *bx - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; *bx++ = y & 0xffff; #endif #endif } while (sx <= sxe); if (!*bxe) { bx = b->x; while (--bxe > bx && !*bxe) { --n; } b->wds = n; } } if (cmp(b, S) >= 0) { q++; borrow = 0; carry = 0; bx = b->x; sx = S->x; do { #ifdef ULLong ys = *sx++ + carry; carry = ys >> 32; y = *bx - (ys & 0xFFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; *bx++ = (unsigned int)(y & 0xFFFFFFFF); #else #ifdef Pack_32 si = *sx++; ys = (si & 0xffff) + carry; zs = (si >> 16) + (ys >> 16); carry = zs >> 16; y = (*bx & 0xffff) - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(bx, z, y); #else ys = *sx++ + carry; carry = ys >> 16; y = *bx - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; *bx++ = y & 0xffff; #endif #endif } while (sx <= sxe); bx = b->x; bxe = bx + n; if (!*bxe) { while (--bxe > bx && !*bxe) { --n; } b->wds = n; } } return q; } static char *dtoa_result; static char *rv_alloc(unsigned int i) { unsigned int j, k, *r; j = sizeof(ULong); for (k = 0; sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; j <<= 1) { k++; } r = (unsigned int*)Balloc(k); *r = k; dtoa_result = (char *)(r+1); return dtoa_result; } static char *nrv_alloc(const char *s, char **rve, int n) { char *rv, *t; t = rv = rv_alloc(n); *t = *s++; while (*t) { t++; *t = *s++; } if (rve) { *rve = t; } return rv; } /* freedtoa(s) must be used to free values s returned by dtoa. */ static void freedtoa(char *s) { Bigint *b = (Bigint *)((int *)s - 1); b->maxwds = 1 << (b->k = *(int*)b); Bfree(b); if (s == dtoa_result) { dtoa_result = 0; } } /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. * * Inspired by "How to Print Floating-Point Numbers Accurately" by * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. * * Modifications: * 1. Rather than iterating, we use a simple numeric overestimate * to determine k = floor(log10(d)). We scale relevant * quantities using O(log2(k)) rather than O(k) multiplications. * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't * try to generate digits strictly left to right. Instead, we * compute with fewer bits and propagate the carry if necessary * when rounding the final digit up. This is often faster. * 3. Under the assumption that input will be rounded nearest, * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. * That is, we allow equality in stopping tests when the * round-nearest rule will give the same floating-point value * as would satisfaction of the stopping test with strict * inequality. * 4. We remove common factors of powers of 2 from relevant * quantities. * 5. When converting floating-point integers less than 1e16, * we use floating-point arithmetic rather than resorting * to multiple-precision integers. * 6. When asked to produce fewer than 15 digits, we first try * to get by with floating-point arithmetic; we resort to * multiple-precision integer arithmetic only if we cannot * guarantee that the floating-point calculation has given * the correctly rounded result. For k requested digits and * "uniformly" distributed input, the probability is * something like 10^(k-15) that we must resort to the Long * calculation. */ char *mux_dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve) { /* Arguments ndigits, decpt, sign are similar to those of ecvt and fcvt; trailing zeros are suppressed from the returned string. If not null, *rve is set to point to the end of the return value. If d is +-Infinity or NaN, then *decpt is set to 9999. mode: 0 ==> shortest string that yields d when read in and rounded to nearest. 1 ==> like 0, but with Steele & White stopping rule; e.g. with IEEE P754 arithmetic , mode 0 gives 1e23 whereas mode 1 gives 9.999999999999999e22. 2 ==> max(1,ndigits) significant digits. This gives a return value similar to that of ecvt, except that trailing zeros are suppressed. 3 ==> through ndigits past the decimal point. This gives a return value similar to that from fcvt, except that trailing zeros are suppressed, and ndigits can be negative. 4,5 ==> similar to 2 and 3, respectively, but (in round-nearest mode) with the tests of mode 0 to possibly return a shorter string that rounds to d. With IEEE arithmetic and compilation with -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same as modes 2 and 3 when FLT_ROUNDS != 1. 6-9 ==> Debugging modes similar to mode - 4: don't try fast floating-point estimate (if applicable). Values of mode other than 0-9 are treated as mode 0. Sufficient space is allocated to the return value to hold the suppressed trailing zeros. */ int bbits, b2, b5, be, dig, i, ieps, ilim = 0, ilim0 = 0, ilim1 = 0, j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, spec_case, try_quick; Long L; #ifndef Sudden_Underflow int denorm; ULong x; #endif Bigint *b = NULL, *b1 = NULL, *delta = NULL, *mlo = NULL, *mhi = NULL, *S = NULL; double d2, ds, eps; char *s, *s0; #ifdef Honor_FLT_ROUNDS int rounding; #endif #ifdef SET_INEXACT int inexact, oldinexact; #endif if (dtoa_result) { freedtoa(dtoa_result); dtoa_result = 0; } if (word0(d) & Sign_bit) { /* set sign for everything, including 0's and NaNs */ *sign = 1; word0(d) &= ~Sign_bit; /* clear sign bit */ } else { *sign = 0; } #if defined(IEEE_Arith) + defined(VAX) #ifdef IEEE_Arith if ((word0(d) & Exp_mask) == Exp_mask) #else if (word0(d) == 0x8000) #endif { /* Infinity or NaN */ *decpt = 9999; #ifdef IEEE_Arith if (!word1(d) && !(word0(d) & 0xfffff)) { return nrv_alloc("Inf", rve, 8); } #endif return nrv_alloc("NaN", rve, 3); } #endif #ifdef IBM dval(d) += 0; /* normalize */ #endif if (!dval(d)) { *decpt = 1; return nrv_alloc("0", rve, 1); } #ifdef SET_INEXACT try_quick = oldinexact = get_inexact(); inexact = 1; #endif #ifdef Honor_FLT_ROUNDS if ((rounding = Flt_Rounds) >= 2) { if (*sign) { rounding = rounding == 2 ? 0 : 2; } else { if (rounding != 2) { rounding = 0; } } } #endif b = d2b(dval(d), &be, &bbits); #ifdef Sudden_Underflow i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); #else i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); if (i) { #endif dval(d2) = dval(d); word0(d2) &= Frac_mask1; word0(d2) |= Exp_11; #ifdef IBM if (j = 11 - hi0bits(word0(d2) & Frac_mask)) { dval(d2) /= 1 << j; } #endif /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 * log10(x) = log(x) / log(10) * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) * * This suggests computing an approximation k to log10(d) by * * k = (i - Bias)*0.301029995663981 * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); * * We want k to be too large rather than too small. * The error in the first-order Taylor series approximation * is in our favor, so we just round up the constant enough * to compensate for any error in the multiplication of * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, * adding 1e-13 to the constant term more than suffices. * Hence we adjust the constant term to 0.1760912590558. * (We could get a more accurate k by invoking log10, * but this is probably not worthwhile.) */ i -= Bias; #ifdef IBM i <<= 2; i += j; #endif #ifndef Sudden_Underflow denorm = 0; } else { /* d is denormalized */ i = bbits + be + (Bias + (P-1) - 1); x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32) : word1(d) << (32 - i); dval(d2) = x; word0(d2) -= 31*Exp_msk1; /* adjust exponent */ i -= (Bias + (P-1) - 1) + 1; denorm = 1; } #endif ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; k = (int)ds; if (ds < 0. && ds != k) { k--; /* want k = floor(ds) */ } k_check = 1; if (k >= 0 && k <= Ten_pmax) { if (dval(d) < tens[k]) { k--; } k_check = 0; } j = bbits - i - 1; if (j >= 0) { b2 = 0; s2 = j; } else { b2 = -j; s2 = 0; } if (k >= 0) { b5 = 0; s5 = k; s2 += k; } else { b2 -= k; b5 = -k; s5 = 0; } if (mode < 0 || mode > 9) { mode = 0; } #ifndef SET_INEXACT #ifdef Check_FLT_ROUNDS try_quick = Rounding == 1; #else try_quick = 1; #endif #endif /*SET_INEXACT*/ if (mode > 5) { mode -= 4; try_quick = 0; } leftright = 1; switch (mode) { case 0: case 1: ilim = ilim1 = -1; i = 18; ndigits = 0; break; case 2: leftright = 0; /* no break */ case 4: if (ndigits <= 0) { ndigits = 1; } ilim = ilim1 = i = ndigits; break; case 3: leftright = 0; /* no break */ case 5: i = ndigits + k + 1; ilim = i; ilim1 = i - 1; if (i <= 0) { i = 1; } } s = s0 = rv_alloc(i); #ifdef Honor_FLT_ROUNDS if (mode > 1 && rounding != 1) { leftright = 0; } #endif if (ilim >= 0 && ilim <= Quick_max && try_quick) { /* Try to get by with floating-point arithmetic. */ i = 0; dval(d2) = dval(d); k0 = k; ilim0 = ilim; ieps = 2; /* conservative */ if (k > 0) { ds = tens[k&0xf]; j = k >> 4; if (j & Bletch) { /* prevent overflows */ j &= Bletch - 1; dval(d) /= bigtens[n_bigtens-1]; ieps++; } for (; j; j >>= 1, i++) { if (j & 1) { ieps++; ds *= bigtens[i]; } } dval(d) /= ds; } else { j1 = -k; if (j1) { dval(d) *= tens[j1 & 0xf]; for (j = j1 >> 4; j; j >>= 1, i++) { if (j & 1) { ieps++; dval(d) *= bigtens[i]; } } } } if (k_check && dval(d) < 1. && ilim > 0) { if (ilim1 <= 0) { goto fast_failed; } ilim = ilim1; k--; dval(d) *= 10.; ieps++; } dval(eps) = ieps*dval(d) + 7.; word0(eps) -= (P-1)*Exp_msk1; if (ilim == 0) { S = mhi = 0; dval(d) -= 5.; if (dval(d) > dval(eps)) { goto one_digit; } if (dval(d) < -dval(eps)) { goto no_digits; } goto fast_failed; } #ifndef No_leftright if (leftright) { /* Use Steele & White method of only * generating digits needed. */ dval(eps) = 0.5/tens[ilim-1] - dval(eps); for (i = 0;;) { L = (Long)dval(d); dval(d) -= L; *s++ = static_cast('0' + (int)L); if (dval(d) < dval(eps)) { goto ret1; } if (1. - dval(d) < dval(eps)) { goto bump_up; } if (++i >= ilim) { break; } dval(eps) *= 10.; dval(d) *= 10.; } } else { #endif /* Generate ilim digits, then fix them up. */ dval(eps) *= tens[ilim-1]; for (i = 1;; i++, dval(d) *= 10.) { L = (Long)(dval(d)); if (!(dval(d) -= L)) { ilim = i; } *s++ = static_cast('0' + (int)L); if (i == ilim) { if (dval(d) > 0.5 + dval(eps)) { goto bump_up; } else if (dval(d) < 0.5 - dval(eps)) { while (*--s == '0') { ; // Nothing. } s++; goto ret1; } break; } } #ifndef No_leftright } #endif fast_failed: s = s0; dval(d) = dval(d2); k = k0; ilim = ilim0; } /* Do we have a "small" integer? */ if (be >= 0 && k <= Int_max) { /* Yes. */ ds = tens[k]; if (ndigits < 0 && ilim <= 0) { S = mhi = 0; if (ilim < 0 || dval(d) <= 5*ds) { goto no_digits; } goto one_digit; } for (i = 1; ; i++, dval(d) *= 10.0) { L = (Long)(dval(d) / ds); dval(d) -= L*ds; #ifdef Check_FLT_ROUNDS /* If FLT_ROUNDS == 2, L will usually be high by 1 */ if (dval(d) < 0) { L--; dval(d) += ds; } #endif if (ds <= dval(d)) { L++; dval(d) -= ds; } *s++ = static_cast('0' + (int)L); if (!dval(d)) { #ifdef SET_INEXACT inexact = 0; #endif break; } if (i == ilim) { #ifdef Honor_FLT_ROUNDS if (mode > 1) { switch (rounding) { case 0: goto ret1; case 2: goto bump_up; } } #endif dval(d) += dval(d); if (dval(d) > ds || dval(d) == ds && L & 1) { bump_up: while (*--s == '9') { if (s == s0) { k++; *s = '0'; break; } } ++*s++; } break; } } goto ret1; } m2 = b2; m5 = b5; mhi = mlo = 0; if (leftright) { i = #ifndef Sudden_Underflow denorm ? be + (Bias + (P-1) - 1 + 1) : #endif #ifdef IBM 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); #else 1 + P - bbits; #endif b2 += i; s2 += i; mhi = i2b(1); } if (m2 > 0 && s2 > 0) { i = m2 < s2 ? m2 : s2; b2 -= i; m2 -= i; s2 -= i; } if (b5 > 0) { if (leftright) { if (m5 > 0) { mhi = pow5mult(mhi, m5); b1 = mult(mhi, b); Bfree(b); b = b1; } j = b5 - m5; if (j) { b = pow5mult(b, j); } } else { b = pow5mult(b, b5); } } S = i2b(1); if (s5 > 0) { S = pow5mult(S, s5); } /* Check for special case that d is a normalized power of 2. */ spec_case = 0; if ((mode < 2 || leftright) #ifdef Honor_FLT_ROUNDS && rounding == 1 #endif ) { if (!word1(d) && !(word0(d) & Bndry_mask) #ifndef Sudden_Underflow && word0(d) & (Exp_mask & ~Exp_msk1) #endif ) { /* The special case */ b2 += Log2P; s2 += Log2P; spec_case = 1; } } /* Arrange for convenient computation of quotients: * shift left if necessary so divisor has 4 leading 0 bits. * * Perhaps we should just compute leading 28 bits of S once * and for all and pass them and a shift to quorem, so it * can do shifts and ors to compute the numerator for q. */ #ifdef Pack_32 i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f; if (i) { i = 32 - i; } #else if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)) { i = 16 - i; } #endif if (i > 4) { i -= 4; b2 += i; m2 += i; s2 += i; } else if (i < 4) { i += 28; b2 += i; m2 += i; s2 += i; } if (b2 > 0) { b = lshift(b, b2); } if (s2 > 0) { S = lshift(S, s2); } if (k_check) { if (cmp(b,S) < 0) { k--; b = multadd(b, 10, 0); /* we botched the k estimate */ if (leftright) { mhi = multadd(mhi, 10, 0); } ilim = ilim1; } } if (ilim <= 0 && (mode == 3 || mode == 5)) { if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { /* no digits, fcvt style */ no_digits: k = -1 - ndigits; goto ret; } one_digit: *s++ = '1'; k++; goto ret; } if (leftright) { if (m2 > 0) { mhi = lshift(mhi, m2); } /* Compute mlo -- check for special case * that d is a normalized power of 2. */ mlo = mhi; if (spec_case) { mhi = Balloc(mhi->k); Bcopy(mhi, mlo); mhi = lshift(mhi, Log2P); } for (i = 1;;i++) { dig = quorem(b,S) + '0'; /* Do we yet have the shortest decimal string * that will round to d? */ j = cmp(b, mlo); delta = diff(S, mhi); j1 = delta->sign ? 1 : cmp(b, delta); Bfree(delta); #ifndef ROUND_BIASED if (j1 == 0 && mode != 1 && !(word1(d) & 1) #ifdef Honor_FLT_ROUNDS && rounding >= 1 #endif ) { if (dig == '9') { goto round_9_up; } if (j > 0) { dig++; } #ifdef SET_INEXACT else if (!b->x[0] && b->wds <= 1) { inexact = 0; } #endif *s++ = static_cast(dig); goto ret; } #endif if (j < 0 || j == 0 && mode != 1 #ifndef ROUND_BIASED && !(word1(d) & 1) #endif ) { if (!b->x[0] && b->wds <= 1) { #ifdef SET_INEXACT inexact = 0; #endif goto accept_dig; } #ifdef Honor_FLT_ROUNDS if (mode > 1) { switch (rounding) { case 0: goto accept_dig; case 2: goto keep_dig; } } #endif /*Honor_FLT_ROUNDS*/ if (j1 > 0) { b = lshift(b, 1); j1 = cmp(b, S); if ( (j1 > 0 || j1 == 0 && dig & 1) && dig++ == '9') { goto round_9_up; } } accept_dig: *s++ = static_cast(dig); goto ret; } if (j1 > 0) { #ifdef Honor_FLT_ROUNDS if (!rounding) { goto accept_dig; } #endif if (dig == '9') { /* possible if i == 1 */ round_9_up: *s++ = '9'; goto roundoff; } *s++ = static_cast(dig + 1); goto ret; } #ifdef Honor_FLT_ROUNDS keep_dig: #endif *s++ = static_cast(dig); if (i == ilim) { break; } b = multadd(b, 10, 0); if (mlo == mhi) { mlo = mhi = multadd(mhi, 10, 0); } else { mlo = multadd(mlo, 10, 0); mhi = multadd(mhi, 10, 0); } } } else { for (i = 1;; i++) { dig = quorem(b,S) + '0'; *s++ = static_cast(dig); if (!b->x[0] && b->wds <= 1) { #ifdef SET_INEXACT inexact = 0; #endif goto ret; } if (i >= ilim) { break; } b = multadd(b, 10, 0); } } /* Round off last digit */ #ifdef Honor_FLT_ROUNDS switch (rounding) { case 0: goto trimzeros; case 2: goto roundoff; } #endif b = lshift(b, 1); j = cmp(b, S); if (j > 0 || j == 0 && dig & 1) { roundoff: while (*--s == '9') { if (s == s0) { k++; *s++ = '1'; goto ret; } } ++*s++; } else { #ifdef Honor_FLT_ROUNDS trimzeros: #endif while (*--s == '0') { ; // Nothing. } s++; } ret: Bfree(S); if (mhi) { if (mlo && mlo != mhi) { Bfree(mlo); } Bfree(mhi); } ret1: #ifdef SET_INEXACT if (inexact) { if (!oldinexact) { word0(d) = Exp_1 + (70 << Exp_shift); word1(d) = 0; dval(d) += 1.; } } else if (!oldinexact) { clear_inexact(); } #endif Bfree(b); *s = 0; *decpt = k + 1; if (rve) { *rve = s; } return s0; } #if defined(HAVE_FPU_CONTROL_H) \ && defined(_FPU_GETCW) \ && defined(_FPU_SETCW) fpu_control_t maskoff = 0 #if defined(_FPU_EXTENDED) | _FPU_EXTENDED #endif #if defined(_FPU_SINGLE) | _FPU_SINGLE #endif ; fpu_control_t maskon = 0 #if defined(_FPU_DOUBLE) | _FPU_DOUBLE #endif ; fpu_control_t origcw; void mux_FPInit(void) { _FPU_GETCW(origcw); } void mux_FPSet(void) { // Set double-precision. // fpu_control_t newcw; newcw = (origcw & ~maskoff) | maskon; _FPU_SETCW(newcw); } void mux_FPRestore(void) { _FPU_SETCW(origcw); } #elif defined(IEEEFP_H_USEABLE) fp_rnd_t orig_rnd; fp_prec_t orig_prec; void mux_FPInit(void) { orig_rnd = fpgetround(); orig_prec = fpgetprec(); } void mux_FPSet(void) { // Set double-precision. // fpsetprec(FP_PD); } void mux_FPRestore(void) { fpsetprec(orig_prec); } #elif defined(WIN32) && !defined(_WIN64) #if (_MSC_VER >= 1400) static unsigned int cw; void mux_FPInit(void) { _controlfp_s(&cw, 0, 0); } void mux_FPSet(void) { // Set double-precision. // _controlfp_s(&cw, _PC_53, _MCW_PC); } void mux_FPRestore(void) { _controlfp_s(&cw, _CW_DEFAULT, MCW_PC); } #else // _MSC_VER static unsigned origcw; void mux_FPInit(void) { origcw = _controlfp(0, 0); } void mux_FPSet(void) { // Set double-precision. // _controlfp(_PC_53, _MCW_PC); } void mux_FPRestore(void) { const unsigned int maskall = 0xFFFFFFFF; _controlfp(origcw, maskall); } #endif // _MSC_VER #elif defined(HAVE_FENV_H) \ && defined(HAVE_FESETPREC) \ && defined(HAVE_FEGETPREC) \ && defined(FE_DBLPREC) int origcw; void mux_FPInit(void) { origcw = fegetprec(); } void mux_FPSet(void) { // Set double-precision. // fesetprec(FE_DBLPREC); } void mux_FPRestore(void) { fesetprec(origcw); } #else #if !defined(_WIN64) && !(defined(__APPLE__) && defined(__MACH__) && !defined(__i386__)) #warning "No method of floating-point control was found, using dummy functions" #endif void mux_FPInit(void) { } void mux_FPSet(void) { } void mux_FPRestore(void) { } #endif void FLOAT_Initialize(void) { mux_FPInit(); mux_FPSet(); } mux2.6/src/attrs.h0000600000175000017500000002664711025753746014123 0ustar sdennissdennis// attrs.h -- Attribute definitions. // // $Id: attrs.h 492 2006-11-30 17:12:25Z brazilofmux $ // #ifndef _ATTRS_H #define _ATTRS_H /* Attribute flags */ #define AF_ODARK 0x00000001UL // players other than owner can't see it. #define AF_DARK 0x00000002UL // Only #1 can see it. #define AF_WIZARD 0x00000004UL // only wizards can change it. #define AF_MDARK 0x00000008UL // Only wizards can see it. Dark to mortals. #define AF_INTERNAL 0x00000010UL // Don't show even to #1. #define AF_NOCMD 0x00000020UL // Don't create a @ command for it. #define AF_LOCK 0x00000040UL // Attribute is locked. #define AF_DELETED 0x00000080UL // Attribute should be ignored. #define AF_NOPROG 0x00000100UL // Don't process $-commands from this attr. #define AF_GOD 0x00000200UL // Only #1 can change it. #define AF_IS_LOCK 0x00000400UL // Attribute is a lock. #define AF_VISUAL 0x00000800UL // Anyone can see. #define AF_PRIVATE 0x00001000UL // Not inherited by children. #define AF_HTML 0x00002000UL // Don't HTML escape this in did_it(). #define AF_NOPARSE 0x00004000UL // Don't evaluate when checking for $-cmds. #define AF_REGEXP 0x00008000UL // Do a regexp rather than wildcard match. #define AF_NOCLONE 0x00010000UL // Don't copy this attr when cloning. #define AF_CONST 0x00020000UL // No one can change it (set by server). #define AF_CASE 0x00040000UL // Regexp matches are case-sensitive. #define AF_TRACE 0x00080000UL // Trace evaluation of this attribute. #define AF_NONAME 0x00400000UL // Supress name in oattr cases. #define AF_ISUSED 0x10000000UL // Used to make efficient sweeps of stale // attributes. // Allow AF_TRACE in x to control the EV_TRACE bit in y. // #define AttrTrace(x, y) ( ((x) & AF_TRACE) \ ? ((y) | EV_TRACE) \ : ((y) & ~EV_TRACE)) #define A_OSUCC 1 /* Others success message */ #define A_OFAIL 2 /* Others fail message */ #define A_FAIL 3 /* Invoker fail message */ #define A_SUCC 4 /* Invoker success message */ #define A_PASS 5 /* Password (only meaningful for players) */ #define A_DESC 6 /* Description */ #define A_SEX 7 /* Sex */ #define A_ODROP 8 /* Others drop message */ #define A_DROP 9 /* Invoker drop message */ #define A_OKILL 10 /* Others kill message */ #define A_KILL 11 /* Invoker kill message */ #define A_ASUCC 12 /* Success action list */ #define A_AFAIL 13 /* Failure action list */ #define A_ADROP 14 /* Drop action list */ #define A_AKILL 15 /* Kill action list */ #define A_AUSE 16 /* Use action list */ #define A_CHARGES 17 /* Number of charges remaining */ #define A_RUNOUT 18 /* Actions done when no more charges */ #define A_STARTUP 19 /* Actions run when game started up */ #define A_ACLONE 20 /* Actions run when obj is cloned */ #define A_APAY 21 /* Actions run when given COST pennies */ #define A_OPAY 22 /* Others pay message */ #define A_PAY 23 /* Invoker pay message */ #define A_COST 24 /* Number of pennies needed to invoke xPAY */ #define A_MONEY 25 /* Value or Wealth (internal) */ #define A_LISTEN 26 /* (Wildcarded) string to listen for */ #define A_AAHEAR 27 /* Actions to do when anyone says LISTEN str */ #define A_AMHEAR 28 /* Actions to do when I say LISTEN str */ #define A_AHEAR 29 /* Actions to do when others say LISTEN str */ #define A_LAST 30 /* Date/time of last login (players only) */ #define A_QUEUEMAX 31 /* Max. # of entries obj has in the queue */ #define A_IDESC 32 /* Inside description (ENTER to get inside) */ #define A_ENTER 33 /* Invoker enter message */ #define A_OXENTER 34 /* Others enter message in dest */ #define A_AENTER 35 /* Enter action list */ #define A_ADESC 36 /* Describe action list */ #define A_ODESC 37 /* Others describe message */ #define A_RQUOTA 38 /* Relative object quota */ #define A_ACONNECT 39 /* Actions run when player connects */ #define A_ADISCONNECT 40 /* Actions run when player disconnects */ #define A_ALLOWANCE 41 /* Daily allowance, if diff from default */ #define A_LOCK 42 /* Object lock */ #define A_NAME 43 /* Object name */ #define A_COMMENT 44 /* Wizard-accessable comments */ #define A_USE 45 /* Invoker use message */ #define A_OUSE 46 /* Others use message */ #define A_SEMAPHORE 47 /* Semaphore control info */ #define A_TIMEOUT 48 /* Per-user disconnect timeout */ #define A_QUOTA 49 /* Absolute quota (to speed up @quota) */ #define A_LEAVE 50 /* Invoker leave message */ #define A_OLEAVE 51 /* Others leave message in src */ #define A_ALEAVE 52 /* Leave action list */ #define A_OENTER 53 /* Others enter message in src */ #define A_OXLEAVE 54 /* Others leave message in dest */ #define A_MOVE 55 /* Invoker move message */ #define A_OMOVE 56 /* Others move message */ #define A_AMOVE 57 /* Move action list */ #define A_ALIAS 58 /* Alias for player names */ #define A_LENTER 59 /* ENTER lock */ #define A_LLEAVE 60 /* LEAVE lock */ #define A_LPAGE 61 /* PAGE lock */ #define A_LUSE 62 /* USE lock */ #define A_LGIVE 63 /* Give lock (who may give me away?) */ #define A_EALIAS 64 /* Alternate names for ENTER */ #define A_LALIAS 65 /* Alternate names for LEAVE */ #define A_EFAIL 66 /* Invoker entry fail message */ #define A_OEFAIL 67 /* Others entry fail message */ #define A_AEFAIL 68 /* Entry fail action list */ #define A_LFAIL 69 /* Invoker leave fail message */ #define A_OLFAIL 70 /* Others leave fail message */ #define A_ALFAIL 71 /* Leave fail action list */ #define A_REJECT 72 /* Rejected page return message */ #define A_AWAY 73 /* Not_connected page return message */ #define A_IDLE 74 /* Success page return message */ #define A_UFAIL 75 /* Invoker use fail message */ #define A_OUFAIL 76 /* Others use fail message */ #define A_AUFAIL 77 /* Use fail action list */ #define A_PFAIL 78 /* Invoker page fail message */ #define A_TPORT 79 /* Invoker teleport message */ #define A_OTPORT 80 /* Others teleport message in src */ #define A_OXTPORT 81 /* Others teleport message in dst */ #define A_ATPORT 82 /* Teleport action list */ #define A_PRIVS 83 /* Individual permissions */ #define A_LOGINDATA 84 /* Recent login information */ #define A_LTPORT 85 /* Teleport lock (can others @tel to me?) */ #define A_LDROP 86 /* Drop lock (can I be dropped or @tel'ed) */ #define A_LRECEIVE 87 /* Receive lock (who may give me things?) */ #define A_LASTSITE 88 /* Last site logged in from, in cleartext */ #define A_INPREFIX 89 /* Prefix on incoming messages into objects */ #define A_PREFIX 90 /* Prefix used by exits/objects when audible */ #define A_INFILTER 91 /* Filter to zap incoming text into objects */ #define A_FILTER 92 /* Filter to zap text forwarded by audible. */ #define A_LLINK 93 /* Who may link to here */ #define A_LTELOUT 94 /* Who may teleport out from here */ #define A_FORWARDLIST 95 /* Recipients of AUDIBLE output */ #define A_MAILFOLDERS 96 /* @mail folders */ #define A_LUSER 97 /* Spare lock not referenced by server */ #define A_LPARENT 98 /* Who may @parent to me if PARENT_OK set */ #define A_LCONTROL 99 /* Who controls me if CONTROL_OK set */ #define A_VA 100 /* VA attribute (VB-VZ follow) */ // 126 unused #define A_LGET 127 /* Get lock (who may get stuff from me?) */ #define A_MFAIL 128 /* Mail rejected fail message */ #define A_GFAIL 129 /* Give fail message */ #define A_OGFAIL 130 /* Others give fail message */ #define A_AGFAIL 131 /* Give fail action */ #define A_RFAIL 132 /* Receive fail message */ #define A_ORFAIL 133 /* Others receive fail message */ #define A_ARFAIL 134 /* Receive fail action */ #define A_DFAIL 135 /* Drop fail message */ #define A_ODFAIL 136 /* Others drop fail message */ #define A_ADFAIL 137 /* Drop fail action */ #define A_TFAIL 138 /* Teleport (to) fail message */ #define A_OTFAIL 139 /* Others teleport (to) fail message */ #define A_ATFAIL 140 /* Teleport fail action */ #define A_TOFAIL 141 /* Teleport (from) fail message */ #define A_OTOFAIL 142 /* Others teleport (from) fail message */ #define A_ATOFAIL 143 /* Teleport (from) fail action */ #define A_LASTIP 144 /* Last IP logged in from */ // Optional WoD Realm descriptions. // #ifdef WOD_REALMS #define A_UMBRADESC 145 #define A_WRAITHDESC 146 #define A_FAEDESC 147 #define A_MATRIXDESC 148 #endif // WOD_REALMS // 149 - 197 unused #define A_CMDCHECK 198 // For @icmd. (From RhostMUSH) #define A_MONIKER 199 // Ansi-colored and/or accented name of object. #define A_LASTPAGE 200 /* Player last paged */ #define A_MAIL 201 /* Message echoed to sender */ #define A_AMAIL 202 /* Action taken when mail received */ #define A_SIGNATURE 203 /* Mail signature */ #define A_DAILY 204 /* Daily attribute to be executed */ #define A_MAILTO 205 /* Who is the mail to? */ #define A_MAILMSG 206 /* The mail message itself */ #define A_MAILSUB 207 /* The mail subject */ #define A_MAILCURF 208 /* The current @mail folder */ #define A_LSPEECH 209 /* Speechlocks */ #define A_PROGCMD 210 /* Command for execution by @prog */ #define A_MAILFLAGS 211 /* Flags for extended mail */ #define A_DESTROYER 212 /* Who is destroying this object? */ #define A_NEWOBJS 213 /* New object array */ #define A_SAYSTRING 214 // Replaces 'says,' #define A_SPEECHMOD 215 // Softcode to be applied to speech #define A_EXITVARDEST 216 /* Variable exit destination */ #define A_LCHOWN 217 /* ChownLock */ #define A_CREATED 218 // Date/time created #define A_MODIFIED 219 // Date/time last modified #define A_VRML_URL 220 /* URL of the VRML scene for this object */ #define A_HTDESC 221 /* HTML @desc */ // Added by D.Piper (del@doofer.org) 2000-APR // #define A_REASON 222 // Disconnect reason #ifdef GAME_DOOFERMUX #define A_REGINFO 223 // Registration Information #endif // GAME_DOOFERMUX #define A_CONNINFO 224 // Connection info: (total connected time, // longest connection last connection, total // connections, time of logout. #define A_LMAIL 225 // Lock who may @mail you #define A_LOPEN 226 // Lock for controlling OPEN_OK locations // 227 - 235 unused #if defined(FIRANMUX) #define A_COLOR 236 /* Color of name of object in look commands */ #define A_ALEAD 237 /* Lead action list */ #define A_LEAD 238 /* Invoker lead message */ #define A_OLEAD 239 /* Others lead message */ #endif // FIRANMUX #define A_IDLETMOUT 240 /* Idle message timeout */ #define A_EXITFORMAT 241 #define A_CONFORMAT 242 #define A_NAMEFORMAT 243 #define A_DESCFORMAT 244 // 245 - 249 unused #ifdef REALITY_LVLS #define A_RLEVEL 250 #endif // 251 unused #define A_VLIST 252 #define A_LIST 253 #define A_STRUCT 254 #define A_TEMP 255 #if defined(FIRANMUX_CONVERT) #define A_ALEAD_OLD 240 // Conflicts with A_IDLETMOUT #define A_COLOR_OLD 241 // Conflicts with A_EXITFORMAT #define A_EXITFORMAT_OLD 243 // Conflicts with A_NAMEFORMAT #endif // FIRANMUX_CONVERT #define A_USER_START 256 // Start of user-named attributes. #define ATR_BUF_CHUNK 100 /* Min size to allocate for attribute buffer */ #define ATR_BUF_INCR 6 /* Max size of one attribute */ #endif // _ATTRS_H mux2.6/src/buildnum.sh0000600000175000017500000000027311025753746014753 0ustar sdennissdennis#! /bin/sh # # Shell script to update the build number # PATH=/bin:/usr/bin:/usr/ucb # bnum=0`cat buildnum.data 2>/dev/null` bnum=`expr "$bnum" + 1` echo $bnum > buildnum.data echo $bnum mux2.6/src/powers.cpp0000600000175000017500000002752111025753746014630 0ustar sdennissdennis// powers.cpp -- Power manipulation routines. // // $Id: powers.cpp 29 2006-09-06 22:12:43Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "command.h" #include "powers.h" /* --------------------------------------------------------------------------- * ph_any: set or clear indicated bit, no security checking */ static bool ph_any(dbref target, dbref player, POWER power, int fpowers, bool reset) { UNUSED_PARAMETER(player); if (fpowers & POWER_EXT) { if (reset) { s_Powers2(target, Powers2(target) & ~power); } else { s_Powers2(target, Powers2(target) | power); } } else { if (reset) { s_Powers(target, Powers(target) & ~power); } else { s_Powers(target, Powers(target) | power); } } return true; } /* --------------------------------------------------------------------------- * ph_god: only GOD may set or clear the bit */ static bool ph_god(dbref target, dbref player, POWER power, int fpowers, bool reset) { if (!God(player)) { return false; } return (ph_any(target, player, power, fpowers, reset)); } /* --------------------------------------------------------------------------- * ph_wiz: only WIZARDS (or GOD) may set or clear the bit */ static bool ph_wiz(dbref target, dbref player, POWER power, int fpowers, bool reset) { if (!Wizard(player)) { return false; } return (ph_any(target, player, power, fpowers, reset)); } #if 0 /* --------------------------------------------------------------------------- * ph_wizroy: only WIZARDS, ROYALTY, (or GOD) may set or clear the bit */ bool ph_wizroy(dbref target, dbref player, POWER power, int fpowers, bool reset) { if (!WizRoy(player)) { return false; } return (ph_any(target, player, power, fpowers, reset)); } /* --------------------------------------------------------------------------- * ph_inherit: only players may set or clear this bit. */ bool ph_inherit(dbref target, dbref player, POWER power, int fpowers, bool reset) { if (!Inherits(player)) { return false; } return (ph_any(target, player, power, fpowers, reset)); } #endif static POWERENT gen_powers[] = { {"announce", POW_ANNOUNCE, 0, 0, ph_wiz}, {"boot", POW_BOOT, 0, 0, ph_wiz}, #if defined(FIRANMUX) {"builder", POW_BUILDER, POWER_EXT, 0, ph_any}, #else {"builder", POW_BUILDER, POWER_EXT, 0, ph_wiz}, #endif // FIRANMUX {"chown_anything", POW_CHOWN_ANY, 0, 0, ph_wiz}, {"comm_all", POW_COMM_ALL, 0, 0, ph_wiz}, {"control_all", POW_CONTROL_ALL,0, 0, ph_god}, {"expanded_who", POW_WIZARD_WHO, 0, 0, ph_wiz}, {"find_unfindable", POW_FIND_UNFIND,0, 0, ph_wiz}, {"free_money", POW_FREE_MONEY, 0, 0, ph_wiz}, {"free_quota", POW_FREE_QUOTA, 0, 0, ph_wiz}, {"guest", POW_GUEST, 0, 0, ph_god}, {"halt", POW_HALT, 0, 0, ph_wiz}, #if defined(FIRANMUX) {"hide", POW_HIDE, 0, 0, ph_any}, #else {"hide", POW_HIDE, 0, 0, ph_wiz}, #endif // FIRANMUX {"idle", POW_IDLE, 0, 0, ph_wiz}, #if defined(FIRANMUX) {"immutable", POW_IMMUTABLE, POWER_EXT, 0, ph_wiz}, #endif // FIRANMUX {"long_fingers", POW_LONGFINGERS,0, 0, ph_wiz}, #if defined(FIRANMUX) {"monitor", POW_MONITOR, 0, 0, ph_any}, #else {"monitor", POW_MONITOR, 0, 0, ph_wiz}, #endif // FIRANMUX {"no_destroy", POW_NO_DESTROY, 0, 0, ph_wiz}, {"pass_locks", POW_PASS_LOCKS, 0, 0, ph_wiz}, {"poll", POW_POLL, 0, 0, ph_wiz}, {"prog", POW_PROG, 0, 0, ph_wiz}, {"quota", POW_CHG_QUOTAS, 0, 0, ph_wiz}, {"search", POW_SEARCH, 0, 0, ph_wiz}, #if defined(FIRANMUX) {"see_all", POW_EXAM_ALL, 0, 0, ph_any}, #else {"see_all", POW_EXAM_ALL, 0, 0, ph_wiz}, #endif // FIRANMUX {"see_hidden", POW_SEE_HIDDEN, 0, 0, ph_wiz}, {"see_queue", POW_SEE_QUEUE, 0, 0, ph_wiz}, {"siteadmin", POW_SITEADMIN, 0, 0, ph_wiz}, {"stat_any", POW_STAT_ANY, 0, 0, ph_wiz}, {"steal_money", POW_STEAL, 0, 0, ph_wiz}, {"tel_anything", POW_TEL_UNRST, 0, 0, ph_wiz}, #if defined(FIRANMUX) {"tel_anywhere", POW_TEL_ANYWHR, 0, 0, ph_any}, #else {"tel_anywhere", POW_TEL_ANYWHR, 0, 0, ph_wiz}, #endif // FIRANMUX {"unkillable", POW_UNKILLABLE, 0, 0, ph_wiz}, {NULL, 0, 0, 0, 0} }; /* --------------------------------------------------------------------------- * init_powertab: initialize power hash tables. */ void init_powertab(void) { POWERENT *fp; char *nbuf = alloc_sbuf("init_powertab"); for (fp = gen_powers; fp->powername; fp++) { mux_strncpy(nbuf, fp->powername, SBUF_SIZE-1); mux_strlwr(nbuf); if (!hashfindLEN(nbuf, strlen(nbuf), &mudstate.powers_htab)) { hashaddLEN(nbuf, strlen(nbuf), fp, &mudstate.powers_htab); } } free_sbuf(nbuf); } /* --------------------------------------------------------------------------- * display_powers: display available powers. */ void display_powertab(dbref player) { char *buf, *bp; POWERENT *fp; bp = buf = alloc_lbuf("display_powertab"); safe_str("Powers:", buf, &bp); for (fp = gen_powers; fp->powername; fp++) { if ((fp->listperm & CA_WIZARD) && !Wizard(player)) { continue; } if ((fp->listperm & CA_GOD) && !God(player)) { continue; } safe_chr(' ', buf, &bp); safe_str(fp->powername, buf, &bp); } *bp = '\0'; notify(player, buf); free_lbuf(buf); } static POWERENT *find_power(dbref thing, char *powername) { UNUSED_PARAMETER(thing); // Convert powername to canonical lowercase. // char *buff = alloc_sbuf("find_power"); mux_strncpy(buff, powername, SBUF_SIZE-1); mux_strlwr(buff); POWERENT *p = (POWERENT *)hashfindLEN(buff, strlen(buff), &mudstate.powers_htab); free_sbuf(buff); return p; } bool decode_power(dbref player, char *powername, POWERSET *pset) { pset->word1 = 0; pset->word2 = 0; POWERENT *pent = (POWERENT *)hashfindLEN(powername, strlen(powername), &mudstate.powers_htab); if (!pent) { notify(player, tprintf("%s: Power not found.", powername)); return false; } if (pent->powerpower & POWER_EXT) { pset->word2 = pent->powervalue; } else { pset->word1 = pent->powervalue; } return true; } /* --------------------------------------------------------------------------- * power_set: Set or clear a specified power on an object. */ void power_set(dbref target, dbref player, char *power, int key) { bool bDone = false; do { // Trim spaces, and handle the negation character. // while (mux_isspace(*power)) { power++; } bool bNegate = false; if (*power == '!') { bNegate = true; do { power++; } while (mux_isspace(*power)); } // Beginning of power name is now 'power'. // char *npower = power; while ( *npower != '\0' && !mux_isspace(*npower)) { npower++; } if (*npower == '\0') { bDone = true; } else { *npower = '\0'; } // Make sure a power name was specified. // if (*power == '\0') { if (bNegate) { notify(player, "You must specify a power to clear."); } else { notify(player, "You must specify a power to set."); } } else { POWERENT *fp = find_power(target, power); if (fp == NULL) { notify(player, "I don't understand that power."); } else { // Invoke the power handler, and print feedback. // if (!fp->handler(target, player, fp->powervalue, fp->powerpower, bNegate)) { notify(player, NOPERM_MESSAGE); } else if (!(key & SET_QUIET) && !Quiet(player)) { notify(player, (bNegate ? "Cleared." : "Set.")); } } } power = npower + 1; } while (!bDone); } /* --------------------------------------------------------------------------- * has_power: does object have power visible to player? */ bool has_power(dbref player, dbref it, char *powername) { POWERENT *fp = find_power(it, powername); if (!fp) { return false; } POWER fv; if (fp->powerpower & POWER_EXT) { fv = Powers2(it); } else { fv = Powers(it); } if (fv & fp->powervalue) { if ((fp->listperm & CA_WIZARD) && !Wizard(player)) { return false; } if ((fp->listperm & CA_GOD) && !God(player)) { return false; } return true; } return false; } /* --------------------------------------------------------------------------- * powers_list: Return an LBUG containing the type and powers on thing. */ char *powers_list(dbref player, dbref target) { // Allocate the return buffer. // char *buff = alloc_lbuf("powers_list"); char *bp = buff; bool bFirst = true; POWERENT *fp; for (fp = gen_powers; fp->powername; fp++) { POWER fv; if (fp->powerpower & POWER_EXT) { fv = Powers2(target); } else { fv = Powers(target); } if (fv & fp->powervalue) { if ( (fp->listperm & CA_WIZARD) && !Wizard(player)) { continue; } if ( (fp->listperm & CA_GOD) && !God(player)) { continue; } if (bFirst) { bFirst = false; } else { safe_chr(' ', buff, &bp); } safe_str(fp->powername, buff, &bp); } } // Terminate the string, and return the buffer to the caller. // *bp = '\0'; return buff; } /* --------------------------------------------------------------------------- * decompile_powers: Produce commands to set powers on target. */ void decompile_powers(dbref player, dbref thing, char *thingname) { POWERENT *fp; // Report generic powers. // POWER f1 = Powers(thing); POWER f2 = Powers2(thing); for (fp = gen_powers; fp->powername; fp++) { // Skip if we shouldn't decompile this power // if (fp->listperm & CA_NO_DECOMP) { continue; } // Skip if this power is not set. // if (fp->powerpower & POWER_EXT) { if (!(f2 & fp->powervalue)) { continue; } } else { if (!(f1 & fp->powervalue)) { continue; } } // Skip if we can't see this power. // if (!check_access(player, fp->listperm)) { continue; } // We made it this far, report this power. // notify(player, tprintf("@power %s=%s", strip_ansi(thingname), fp->powername)); } } mux2.6/src/command.h0000600000175000017500000003735711025753746014404 0ustar sdennissdennis// command.h -- declarations used by the command processor. // // $Id: command.h 2734 2007-10-28 23:02:55Z brazilofmux $ // #ifndef __COMMAND_H #define __COMMAND_H #define CMD_NO_ARG(name) extern void name(dbref executor, dbref caller, dbref enactor, int) #define CMD_ONE_ARG(name) extern void name(dbref executor, dbref caller, dbref enactor, int eval, int, char *) #define CMD_ONE_ARG_CMDARG(name) extern void name(dbref executor, dbref caller, dbref enactor, int eval, int, char *, char *[], int) #define CMD_TWO_ARG(name) extern void name(dbref executor, dbref caller, dbref enactor, int, int, char *, char *) #define CMD_TWO_ARG_CMDARG(name) extern void name(dbref executor, dbref caller, dbref enactor, int eval, int, char *, char *, char*[], int) #define CMD_TWO_ARG_ARGV(name) extern void name(dbref executor, dbref caller, dbref enactor, int eval, int, char *, char *[], int) #define CMD_TWO_ARG_ARGV_CMDARG(name) extern void name(dbref executor, dbref caller, dbref enactor, int eval, int, char *, char *[], int, char*[], int) /* Command function handlers */ /* from comsys.c */ CMD_TWO_ARG(do_cemit); /* channel emit */ CMD_TWO_ARG(do_chboot); /* channel boot */ CMD_TWO_ARG(do_editchannel); /* edit a channel */ CMD_ONE_ARG(do_checkchannel); /* check a channel */ CMD_ONE_ARG(do_createchannel); /* create a channel */ CMD_ONE_ARG(do_destroychannel); /* destroy a channel */ CMD_TWO_ARG(do_edituser); /* edit a channel user */ CMD_ONE_ARG(do_chanlist); /* gives a channel listing */ CMD_TWO_ARG(do_chopen); /* opens a channel */ CMD_ONE_ARG(do_channelwho); /* who's on a channel */ CMD_TWO_ARG(do_addcom); /* adds a comalias */ CMD_ONE_ARG(do_allcom); /* on, off, who, all aliases */ CMD_ONE_ARG(do_comlist); /* channel who by alias */ CMD_TWO_ARG(do_comtitle); /* sets a title on a channel */ //CMD_NO_ARG(do_clearcom); /* clears all comaliases */ CMD_ONE_ARG(do_delcom); /* deletes a comalias */ /* from mail.c */ CMD_TWO_ARG(do_mail); /* mail command */ CMD_TWO_ARG(do_malias); /* mail alias command */ CMD_ONE_ARG(do_prepend); CMD_ONE_ARG(do_postpend); CMD_ONE_ARG_CMDARG(do_apply_marked); /* Apply command to marked objects */ CMD_TWO_ARG(do_admin); /* Change config parameters */ CMD_TWO_ARG(do_alias); /* Change the alias of something */ CMD_TWO_ARG(do_attribute); /* Manage user-named attributes */ CMD_ONE_ARG(do_boot); /* Force-disconnect a player */ CMD_TWO_ARG(do_chown); /* Change object or attribute owner */ CMD_TWO_ARG(do_chownall); /* Give away all of someone's objs */ CMD_TWO_ARG(do_chzone); /* Change an object's zone. */ CMD_TWO_ARG(do_clone); /* Create a copy of an object */ CMD_NO_ARG(do_comment); /* Ignore argument and do nothing */ CMD_TWO_ARG_ARGV(do_cpattr); /* Copy attributes */ CMD_TWO_ARG(do_create); /* Create a new object */ CMD_ONE_ARG(do_cut); /* Truncate contents or exits list */ CMD_NO_ARG(do_dbck); /* Consistency check */ CMD_TWO_ARG(do_decomp); /* Reproduce commands to recreate obj */ CMD_ONE_ARG(do_destroy); /* Destroy an object */ CMD_TWO_ARG_ARGV(do_dig); /* Dig a new room */ CMD_ONE_ARG(do_doing); /* Set doing string in WHO report */ CMD_TWO_ARG_CMDARG(do_dolist); /* Iterate command on list members */ CMD_ONE_ARG(do_drop); /* Drop an object */ CMD_NO_ARG(do_dump); /* Dump the database */ CMD_TWO_ARG_ARGV(do_edit); /* Edit one or more attributes */ CMD_ONE_ARG(do_enter); /* Enter an object */ CMD_ONE_ARG(do_entrances); /* List exits and links to loc */ CMD_ONE_ARG(do_examine); /* Examine an object */ CMD_ONE_ARG(do_find); /* Search for name in database */ CMD_TWO_ARG(do_fixdb); /* Database repair functions */ CMD_TWO_ARG_CMDARG(do_force); /* Force someone to do something */ CMD_ONE_ARG_CMDARG(do_force_prefixed); /* # variant of FORCE */ CMD_TWO_ARG(do_forwardlist); // Set a forwardlist on something CMD_TWO_ARG(do_function); /* Make user-def global function */ CMD_ONE_ARG(do_get); /* Get an object */ CMD_TWO_ARG(do_give); /* Give something away */ CMD_ONE_ARG(do_global); /* Enable/disable global flags */ CMD_ONE_ARG(do_halt); /* Remove commands from the queue */ CMD_ONE_ARG(do_help); /* Print info from help files */ CMD_TWO_ARG_ARGV_CMDARG(do_if); // Execute cmd based on truth of expression CMD_NO_ARG(do_inventory); /* Print what I am carrying */ CMD_TWO_ARG(do_prog); /* Interactive input */ CMD_ONE_ARG(do_quitprog); /* Quits @prog */ CMD_TWO_ARG(do_kill); /* Kill something */ CMD_ONE_ARG(do_last); /* Get recent login info */ CMD_NO_ARG(do_leave); /* Leave the current object */ CMD_TWO_ARG(do_link); /* Set home, dropto, or dest */ CMD_ONE_ARG(do_list); /* List contents of internal tables */ CMD_ONE_ARG(do_list_file); /* List contents of message files */ CMD_TWO_ARG(do_lock); /* Set a lock on an object */ CMD_TWO_ARG(do_log); /* Extra logging routine */ CMD_ONE_ARG(do_look); /* Look here or at something */ CMD_NO_ARG(do_markall); /* Mark or unmark all objects */ CMD_ONE_ARG(do_motd); /* Set/list MOTD messages */ CMD_ONE_ARG(do_move); /* Move about using exits */ CMD_TWO_ARG_ARGV(do_mvattr); /* Move attributes on object */ CMD_TWO_ARG(do_name); /* Change the name of something */ CMD_TWO_ARG(do_newpassword); /* Change passwords */ CMD_TWO_ARG(do_notify); /* Notify or drain semaphore */ CMD_TWO_ARG_ARGV(do_open); /* Open an exit */ CMD_TWO_ARG(do_page); /* Send message to faraway player */ CMD_TWO_ARG(do_parent); /* Set parent field */ CMD_TWO_ARG(do_password); /* Change my password */ CMD_TWO_ARG(do_pcreate); /* Create new characters */ CMD_TWO_ARG(do_pemit); /* Messages to specific player */ CMD_ONE_ARG(do_poor); /* Reduce wealth of all players */ CMD_TWO_ARG(do_power); /* Sets powers */ CMD_ONE_ARG(do_ps); /* List contents of queue */ CMD_ONE_ARG(do_queue); /* Force queue processing */ CMD_TWO_ARG(do_quota); /* Set or display quotas */ CMD_NO_ARG(do_readcache); /* Reread text file cache */ CMD_NO_ARG(do_restart); /* Restart the game. */ CMD_NO_ARG(do_backup); /* Backup the database and restart */ CMD_ONE_ARG(do_say); /* Messages to all */ CMD_NO_ARG(do_score); /* Display my wealth */ CMD_ONE_ARG(do_search); /* Search for objs matching criteria */ CMD_TWO_ARG(do_set); /* Set flags or attributes */ CMD_TWO_ARG(do_setattr); /* Set object attribute */ CMD_TWO_ARG(do_setvattr); /* Set variable attribute */ CMD_ONE_ARG(do_shout); /* Messages to all */ CMD_ONE_ARG(do_shutdown); /* Stop the game */ CMD_ONE_ARG(do_stats); /* Display object type breakdown */ CMD_ONE_ARG(do_sweep); /* Check for listeners */ CMD_TWO_ARG_ARGV_CMDARG(do_switch); /* Execute cmd based on match */ CMD_TWO_ARG(do_teleport); /* Teleport elsewhere */ CMD_ONE_ARG(do_think); /* Think command */ CMD_NO_ARG(do_timecheck); /* Check time used by objects */ CMD_ONE_ARG(do_timewarp); /* Warp various timers */ CMD_TWO_ARG(do_toad); /* Turn a tinyjerk into a tinytoad */ CMD_TWO_ARG_ARGV(do_trigger); /* Trigger an attribute */ CMD_ONE_ARG(do_unlock); /* Remove a lock from an object */ CMD_ONE_ARG(do_unlink); /* Unlink exit or remove dropto */ CMD_ONE_ARG(do_use); /* Use object */ CMD_NO_ARG(do_version); /* List MUX version number */ CMD_NO_ARG(do_report); /* Do player/game statistics report */ CMD_TWO_ARG_ARGV(do_verb); /* Execute a user-created verb */ CMD_TWO_ARG_CMDARG(do_wait); /* Perform command after a wait */ #ifdef QUERY_SLAVE CMD_TWO_ARG_CMDARG(do_query); /* Generic external queries (e.g., SQL) */ #endif // QUERY_SLAVE CMD_ONE_ARG(do_wipe); /* Mass-remove attrs from obj */ CMD_NO_ARG(do_dbclean); /* Remove stale vattr entries */ CMD_TWO_ARG(do_addcommand); /* Add or replace a global command */ CMD_TWO_ARG(do_delcommand); /* Delete an added global command */ CMD_ONE_ARG(do_listcommands); /* List added global commands */ CMD_ONE_ARG(do_break); /* Stop evaluating an action list */ #ifdef REALITY_LVLS CMD_TWO_ARG(do_rxlevel); /* set Rx Levels */ CMD_TWO_ARG(do_txlevel); /* set Tx Levels */ #endif CMD_TWO_ARG_ARGV(do_icmd); // Disable commands on a player or room CMD_ONE_ARG(do_hook); // Set additional operations for a command CMD_TWO_ARG(do_flag); // Rename a flag or remove flag aliases CMD_ONE_ARG(do_train); // Display code to room, then execute CMD_TWO_ARG(do_moniker); // Set accented, colorized name of object CMD_TWO_ARG(do_plusemail); typedef struct { const char *cmdname; NAMETAB *switches; int perms; int extra; int callseq; int hookmask; void (*handler)(dbref executor, dbref caller, dbref enactor, int); } CMDENT_NO_ARG; typedef struct { const char *cmdname; NAMETAB *switches; int perms; int extra; int callseq; int hookmask; void (*handler)(dbref executor, dbref caller, dbref enactor, int eval, int, char *); } CMDENT_ONE_ARG; typedef struct { const char *cmdname; NAMETAB *switches; int perms; int extra; int callseq; int hookmask; void (*handler)(dbref executor, dbref caller, dbref enactor, int eval, int, char *, char *[], int); } CMDENT_ONE_ARG_CMDARG; typedef struct { const char *cmdname; NAMETAB *switches; int perms; int extra; int callseq; int hookmask; void (*handler)(dbref executor, dbref caller, dbref enactor, int, int, char *, char *); } CMDENT_TWO_ARG; typedef struct { const char *cmdname; NAMETAB *switches; int perms; int extra; int callseq; int hookmask; void (*handler)(dbref executor, dbref caller, dbref enactor, int, int, char *, char *, char*[], int); } CMDENT_TWO_ARG_CMDARG; typedef struct { const char *cmdname; NAMETAB *switches; int perms; int extra; int callseq; int hookmask; void (*handler)(dbref executor, dbref caller, dbref enactor, int eval, int, char *, char *[], int); } CMDENT_TWO_ARG_ARGV; typedef struct { const char *cmdname; NAMETAB *switches; int perms; int extra; int callseq; int hookmask; void (*handler)(dbref executor, dbref caller, dbref enactor, int eval, int, char *, char *[], int, char*[], int); } CMDENT_TWO_ARG_ARGV_CMDARG; typedef struct addedentry ADDENT; struct addedentry { dbref thing; int atr; char *name; struct addedentry *next; }; typedef struct { char *cmdname; NAMETAB *switches; int perms; int extra; int callseq; int hookmask; union { void (*handler)(void); ADDENT *addent; }; } CMDENT; void commands_no_arg_add(CMDENT_NO_ARG cmdent[]); void commands_one_arg_add(CMDENT_ONE_ARG cmdent[]); void commands_one_arg_cmdarg_add(CMDENT_ONE_ARG_CMDARG cmdent[]); void commands_two_arg_add(CMDENT_TWO_ARG cmdent[]); void commands_two_arg_cmdarg_add(CMDENT_TWO_ARG_CMDARG cmdent[]); void commands_two_arg_argv_add(CMDENT_TWO_ARG_ARGV cmdent[]); void commands_two_arg_argv_cmdarg_add(CMDENT_TWO_ARG_ARGV_CMDARG cmdent[]); void init_cmdtab(void); extern NAMETAB access_nametab[]; extern NAMETAB attraccess_nametab[]; extern NAMETAB indiv_attraccess_nametab[]; extern NAMETAB lock_sw[]; extern NAMETAB logoptions_nametab[]; extern NAMETAB logdata_nametab[]; extern NAMETAB list_names[]; /* Command handler call conventions */ #define CS_NO_ARGS 0x0000 /* No arguments */ #define CS_ONE_ARG 0x0001 /* One argument */ #define CS_TWO_ARG 0x0002 /* Two arguments */ #define CS_NARG_MASK 0x0003 /* Argument count mask */ #define CS_ARGV 0x0004 /* ARG2 is in ARGV form */ #define CS_INTERP 0x0010 /* Interpret ARG2 if 2 args, ARG1 if 1 */ #define CS_NOINTERP 0x0020 /* Never interp ARG2 if 2 or ARG1 if 1 */ #define CS_CAUSE 0x0040 /* Pass cause to old command handler */ #define CS_UNPARSE 0x0080 /* Pass unparsed cmd to old-style handler */ #define CS_CMDARG 0x0100 /* Pass in given command args */ #define CS_STRIP 0x0200 /* Strip braces even when not interpreting */ #define CS_STRIP_AROUND 0x0400 /* Strip braces around entire string only */ #define CS_ADDED 0x0800 /* Command has been added by @addcommand */ #define CS_LEADIN 0x1000 /* Command is a single-letter lead-in */ #define CS_NOSQUISH 0x4000 // Do not space-compress. /* Command permission flags */ #define CA_PUBLIC 0x00000000 /* No access restrictions */ #define CA_GOD 0x00000001 /* GOD only... */ #define CA_WIZARD 0x00000002 /* Wizards only */ #define CA_BUILDER 0x00000004 /* Builders only */ #define CA_IMMORTAL 0x00000008 /* Immortals only */ #define CA_STAFF 0x00000010 /* Must have STAFF flag */ #define CA_HEAD 0x00000020 /* Must have HEAD flag */ //#define CA_SQL_OK 0x00000040 /* Must have SQL_OK power */ #define CA_ADMIN 0x00000080 /* Wizard or royal */ #define CA_ROBOT 0x00000100 /* Robots only */ #define CA_ANNOUNCE 0x00000200 /* Announce Power */ #define CA_UNINS 0x00000400 /* Uninspected players ONLY */ #define CA_MUSTBE_MASK (CA_GOD|CA_WIZARD|CA_BUILDER|CA_IMMORTAL|CA_STAFF|CA_HEAD|CA_ADMIN|CA_ROBOT|CA_ANNOUNCE|CA_UNINS) #define CA_NO_HAVEN 0x00001000 /* Not by HAVEN players */ #define CA_NO_ROBOT 0x00002000 /* Not by ROBOT players */ #define CA_NO_SLAVE 0x00004000 /* Not by SLAVE players */ #define CA_NO_SUSPECT 0x00008000 /* Not by SUSPECT players */ #define CA_NO_GUEST 0x00010000 /* Not by GUEST players */ #define CA_NO_UNINS 0x00020000 /* Not by UNINSPECTED players */ #if defined(FIRANMUX) #define CA_NO_IMMOBILE 0x00040000 /* Not by IMMOBILE players */ #define CA_NO_RESTRICTED 0x00080000 /* Not by RESTRICTED players */ #define CA_CANTBE_MASK (CA_NO_HAVEN|CA_NO_ROBOT|CA_NO_SLAVE|CA_NO_SUSPECT|CA_NO_GUEST|CA_NO_UNINS|CA_NO_IMMOBILE|CA_NO_RESTRICTED) #else #define CA_CANTBE_MASK (CA_NO_HAVEN|CA_NO_ROBOT|CA_NO_SLAVE|CA_NO_SUSPECT|CA_NO_GUEST|CA_NO_UNINS) #endif // FIRANMUX #define CA_MARKER0 0x00002000 #define CA_MARKER1 0x00004000 #define CA_MARKER2 0x00008000 #define CA_MARKER3 0x00010000 #define CA_MARKER4 0x00020000 #define CA_MARKER5 0x00040000 #define CA_MARKER6 0x00080000 #define CA_MARKER7 0x00100000 #define CA_MARKER8 0x00200000 #define CA_MARKER9 0x00400000 #define CA_GBL_BUILD 0x00800000 /* Requires the global BUILDING flag */ #define CA_GBL_INTERP 0x01000000 /* Requires the global INTERP flag */ #define CA_DISABLED 0x02000000 /* Command completely disabled */ #define CA_STATIC 0x04000000 /* Cannot be changed at runtime */ #define CA_NO_DECOMP 0x08000000 /* Don't include in @decompile */ #define CA_LOCATION 0x10000000 /* Invoker must have location */ #define CA_CONTENTS 0x20000000 /* Invoker must have contents */ #define CA_PLAYER 0x40000000 /* Invoker must be a player */ #define CF_DARK 0x80000000 /* Command doesn't show up in list */ #define SW_MULTIPLE 0x80000000 /* This sw may be spec'd w/others */ #define SW_GOT_UNIQUE 0x40000000 /* Already have a unique option */ #define SW_NOEVAL 0x20000000 /* Don't parse args before calling */ /* handler (typically via a switch */ /* alias) */ #endif // !__COMMAND_H mux2.6/src/predicates.cpp0000600000175000017500000020275511025753746015440 0ustar sdennissdennis// predicates.cpp // // $Id: predicates.cpp 2412 2007-09-05 15:24:29Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include #include "ansi.h" #include "attrs.h" #include "command.h" #include "interface.h" #include "powers.h" #ifdef REALITY_LVLS #include "levels.h" #endif // REALITY_LVLS char * DCL_CDECL tprintf(const char *fmt,...) { static char buff[LBUF_SIZE]; va_list ap; va_start(ap, fmt); mux_vsnprintf(buff, LBUF_SIZE, fmt, ap); va_end(ap); return buff; } void DCL_CDECL safe_tprintf_str(char *str, char **bp, const char *fmt,...) { va_list ap; va_start(ap, fmt); size_t nAvailable = LBUF_SIZE - (*bp - str); size_t len = mux_vsnprintf(*bp, (int)nAvailable, fmt, ap); va_end(ap); *bp += len; } /* --------------------------------------------------------------------------- * insert_first, remove_first: Insert or remove objects from lists. */ dbref insert_first(dbref head, dbref thing) { s_Next(thing, head); return thing; } dbref remove_first(dbref head, dbref thing) { if (head == thing) { return Next(thing); } dbref prev; DOLIST(prev, head) { if (Next(prev) == thing) { s_Next(prev, Next(thing)); return head; } } return head; } /* --------------------------------------------------------------------------- * reverse_list: Reverse the order of members in a list. */ dbref reverse_list(dbref list) { dbref newlist, rest; newlist = NOTHING; while (list != NOTHING) { rest = Next(list); s_Next(list, newlist); newlist = list; list = rest; } return newlist; } /* --------------------------------------------------------------------------- * member - indicate if thing is in list */ bool member(dbref thing, dbref list) { DOLIST(list, list) { if (list == thing) { return true; } } return false; } bool could_doit(dbref player, dbref thing, int locknum) { if (thing == HOME) { return true; } // If nonplayer tries to get key, then no. // if ( !isPlayer(player) && Key(thing)) { return false; } if (Pass_Locks(player)) { return true; } dbref aowner; int aflags; char *key = atr_get(thing, locknum, &aowner, &aflags); bool doit = eval_boolexp_atr(player, thing, thing, key); free_lbuf(key); return doit; } bool can_see(dbref player, dbref thing, bool can_see_loc) { // Don't show if all the following apply: Sleeping players should not be // seen. The thing is a disconnected player. The player is not a // puppet. // if ( mudconf.dark_sleepers && isPlayer(thing) && !Connected(thing) && !Puppet(thing)) { return false; } // You don't see yourself or exits. // if ( player == thing || isExit(thing)) { return false; } // If loc is not dark, you see it if it's not dark or you control it. If // loc is dark, you see it if you control it. Seeing your own dark // objects is controlled by mudconf.see_own_dark. In dark locations, you // also see things that are LIGHT and !DARK. // if (can_see_loc) { #ifdef REALITY_LVLS return ((!Dark(thing) && IsReal(player, thing)) || #else return (!Dark(thing) || #endif // REALITY_LVLS (mudconf.see_own_dark && MyopicExam(player, thing))); } else { #ifdef REALITY_LVLS return ((Light(thing) && !Dark(thing) && IsReal(player, thing)) || #else return ((Light(thing) && !Dark(thing)) || #endif // REALITY_LVLS (mudconf.see_own_dark && MyopicExam(player, thing))); } } static bool pay_quota(dbref who, int cost) { // If no cost, succeed // if (cost <= 0) { return true; } // determine quota // dbref aowner; int aflags; char *quota_str = atr_get(Owner(who), A_RQUOTA, &aowner, &aflags); int quota = mux_atol(quota_str); free_lbuf(quota_str); // enough to build? Wizards always have enough. // quota -= cost; if ( quota < 0 && !Free_Quota(who) && !Free_Quota(Owner(who))) { return false; } // Dock the quota. // char buf[20]; mux_ltoa(quota, buf); atr_add_raw(Owner(who), A_RQUOTA, buf); return true; } bool canpayfees(dbref player, dbref who, int pennies, int quota) { if ( !Wizard(who) && !Wizard(Owner(who)) && !Free_Money(who) && !Free_Money(Owner(who)) && (Pennies(Owner(who)) < pennies)) { if (player == who) { notify(player, tprintf("Sorry, you don't have enough %s.", mudconf.many_coins)); } else { notify(player, tprintf("Sorry, that player doesn't have enough %s.", mudconf.many_coins)); } return false; } if (mudconf.quotas) { if (!pay_quota(who, quota)) { if (player == who) { notify(player, "Sorry, your building contract has run out."); } else { notify(player, "Sorry, that player's building contract has run out."); } return false; } } payfor(who, pennies); return true; } bool payfor(dbref who, int cost) { if ( Wizard(who) || Wizard(Owner(who)) || Free_Money(who) || Free_Money(Owner(who))) { return true; } who = Owner(who); int tmp; if ((tmp = Pennies(who)) >= cost) { s_Pennies(who, tmp - cost); return true; } return false; } void add_quota(dbref who, int payment) { dbref aowner; int aflags; char buf[20]; char *quota = atr_get(who, A_RQUOTA, &aowner, &aflags); mux_ltoa(mux_atol(quota) + payment, buf); free_lbuf(quota); atr_add_raw(who, A_RQUOTA, buf); } void giveto(dbref who, int pennies) { if ( Wizard(who) || Wizard(Owner(who)) || Free_Money(who) || Free_Money(Owner(who))) { return; } who = Owner(who); s_Pennies(who, Pennies(who) + pennies); } // The following function validates that the object names (which will be // used for things and rooms, but not for players or exits) and generates // a canonical form of that name (with optimized ANSI). // char *MakeCanonicalObjectName(const char *pName, size_t *pnName, bool *pbValid) { static char Buf[MBUF_SIZE]; *pnName = 0; *pbValid = false; if (!pName) { return NULL; } // Build up what the real name would be. If we pass all the // checks, this is what we will return as a result. // size_t nVisualWidth; size_t nBuf = ANSI_TruncateToField(pName, sizeof(Buf), Buf, MBUF_SIZE, &nVisualWidth, ANSI_ENDGOAL_NORMAL); // Disallow pure ANSI names. There must be at least -something- // visible. // if (nVisualWidth <= 0) { return NULL; } // Get the stripped version (Visible parts without color info). // size_t nStripped; char *pStripped = strip_ansi(Buf, &nStripped); // Do not allow LOOKUP_TOKEN, NUMBER_TOKEN, NOT_TOKEN, or SPACE // as the first character, or SPACE as the last character // if ( strchr("*!#", *pStripped) || mux_isspace(pStripped[0]) || mux_isspace(pStripped[nStripped-1])) { return NULL; } // Only printable characters besides ARG_DELIMITER, AND_TOKEN, // and OR_TOKEN are allowed. // for (unsigned int i = 0; i < nStripped; i++) { if (!mux_ObjectNameSet(pStripped[i])) { return NULL; } } // Special names are specifically dis-allowed. // if ( (nStripped == 2 && memcmp("me", pStripped, 2) == 0) || (nStripped == 4 && ( memcmp("home", pStripped, 4) == 0 || memcmp("here", pStripped, 4) == 0))) { return NULL; } *pnName = nBuf; *pbValid = true; return Buf; } // The following function validates exit names. // char *MakeCanonicalExitName(const char *pName, size_t *pnName, bool *pbValid) { static char Buf[MBUF_SIZE]; static char Out[MBUF_SIZE]; *pnName = 0; *pbValid = false; if (!pName) { return NULL; } // Build the non-ANSI version so that we can parse for semicolons // safely. // char *pStripped = strip_ansi(pName); char *pBuf = Buf; safe_mb_str(pStripped, Buf, &pBuf); *pBuf = '\0'; size_t nBuf = pBuf - Buf; pBuf = Buf; bool bHaveDisplay = false; char *pOut = Out; for (; nBuf;) { // Build (q,n) as the next segment. Leave the the remaining segments as // (pBuf,nBuf). // char *q = strchr(pBuf, ';'); size_t n; if (q) { *q = '\0'; n = q - pBuf; q = pBuf; pBuf += n + 1; nBuf -= n + 1; } else { n = nBuf; q = pBuf; pBuf += nBuf; nBuf = 0; } if (bHaveDisplay) { // We already have the displayable name. We don't allow ANSI in // any segment but the first, so we can pull them directly from // the stripped buffer. // size_t nN; bool bN; char *pN = MakeCanonicalObjectName(q, &nN, &bN); if ( bN && nN < static_cast(MBUF_SIZE - (pOut - Out) - 1)) { safe_mb_chr(';', Out, &pOut); safe_mb_str(pN, Out, &pOut); } } else { // We don't have the displayable name, yet. We know where the next // semicolon occurs, so we limit the visible width of the // truncation to that. We should be picking up all the visible // characters leading up to the semicolon, but not including the // semi-colon. // size_t vw; ANSI_TruncateToField(pName, sizeof(Out), Out, n, &vw, ANSI_ENDGOAL_NORMAL); // vw should always be equal to n, but we'll just make sure. // if (vw == n) { size_t nN; bool bN; char *pN = MakeCanonicalObjectName(Out, &nN, &bN); if ( bN && nN <= MBUF_SIZE - 1) { safe_mb_str(pN, Out, &pOut); bHaveDisplay = true; } } } } if (bHaveDisplay) { *pnName = pOut - Out; *pbValid = true; *pOut = '\0'; return Out; } else { return NULL; } } // The following function validates the player name. ANSI is not // allowed in player names. However, a player name must satisfy // the requirements of a regular name as well. // bool ValidatePlayerName(const char *pName) { if (!pName) { return false; } size_t nName = strlen(pName); // Verify that name is not empty, but not too long, either. // if ( nName <= 0 || PLAYER_NAME_LIMIT <= nName) { return false; } // Do not allow LOOKUP_TOKEN, NUMBER_TOKEN, NOT_TOKEN, or SPACE // as the first character, or SPACE as the last character // if ( strchr("*!#", *pName) || mux_isspace(pName[0]) || mux_isspace(pName[nName-1])) { return false; } if ( mudstate.bStandAlone || mudconf.name_spaces) { mux_PlayerNameSet[(unsigned char)' '] = 1; } else { mux_PlayerNameSet[(unsigned char)' '] = 0; } // Only printable characters besides ARG_DELIMITER, AND_TOKEN, // and OR_TOKEN are allowed. // for (unsigned int i = 0; i < nName; i++) { if (!mux_PlayerNameSet(pName[i])) { return false; } } // Special names are specifically dis-allowed. // if ( (nName == 2 && memcmp("me", pName, 2) == 0) || (nName == 4 && ( memcmp("home", pName, 4) == 0 || memcmp("here", pName, 4) == 0))) { return false; } return true; } bool ok_password(const char *password, const char **pmsg) { *pmsg = NULL; if (*password == '\0') { *pmsg = "Null passwords are not allowed."; return false; } const char *scan; int num_upper = 0; int num_special = 0; int num_lower = 0; for (scan = password; *scan; scan++) { if ( !mux_isprint(*scan) || mux_isspace(*scan)) { *pmsg = "Illegal character in password."; return false; } if (mux_isupper(*scan)) { num_upper++; } else if (mux_islower(*scan)) { num_lower++; } else if ( *scan != '\'' && *scan != '-') { num_special++; } } if ( !mudstate.bStandAlone && mudconf.safer_passwords) { if (num_upper < 1) { *pmsg = "The password must contain at least one capital letter."; return false; } if (num_lower < 1) { *pmsg = "The password must contain at least one lowercase letter."; return false; } if (num_special < 1) { *pmsg = "The password must contain at least one number or a symbol other than the apostrophe or dash."; return false; } } return true; } /* --------------------------------------------------------------------------- * handle_ears: Generate the 'grows ears' and 'loses ears' messages. */ void handle_ears(dbref thing, bool could_hear, bool can_hear) { char *buff, *bp; int gender; static const char *poss[5] = {"", "its", "her", "his", "their"}; if (could_hear != can_hear) { buff = alloc_lbuf("handle_ears"); mux_strncpy(buff, Moniker(thing), LBUF_SIZE-1); if (isExit(thing)) { for (bp = buff; *bp && *bp != ';'; bp++) { ; // Nothing. } *bp = '\0'; } gender = get_gender(thing); if (can_hear) { notify_check(thing, thing, tprintf("%s grow%s ears and can now hear.", buff, (gender == 4) ? "" : "s"), (MSG_ME | MSG_NBR | MSG_LOC | MSG_INV)); } else { notify_check(thing, thing, tprintf("%s lose%s %s ears and become%s deaf.", buff, (gender == 4) ? "" : "s", poss[gender], (gender == 4) ? "" : "s"), (MSG_ME | MSG_NBR | MSG_LOC | MSG_INV)); } free_lbuf(buff); } } // For lack of better place the @switch code is here. // void do_switch ( dbref executor, dbref caller, dbref enactor, int eval, int key, char *expr, char *args[], int nargs, char *cargs[], int ncargs ) { if ( !expr || nargs <= 0) { return; } bool bMatchOne; switch (key & SWITCH_MASK) { case SWITCH_DEFAULT: if (mudconf.switch_df_all) { bMatchOne = false; } else { bMatchOne = true; } break; case SWITCH_ANY: bMatchOne = false; break; case SWITCH_ONE: default: bMatchOne = true; break; } // Now try a wild card match of buff with stuff in coms. // bool bAny = false; int a; char *buff, *bp, *str; buff = bp = alloc_lbuf("do_switch"); CLinearTimeAbsolute lta; for ( a = 0; ( !bMatchOne || !bAny) && a < nargs - 1 && args[a] && args[a + 1]; a += 2) { bp = buff; str = args[a]; mux_exec(buff, &bp, executor, caller, enactor, eval|EV_FCHECK|EV_EVAL|EV_TOP, &str, cargs, ncargs); *bp = '\0'; if (wild_match(buff, expr)) { char *tbuf = replace_tokens(args[a+1], NULL, NULL, expr); wait_que(executor, caller, enactor, eval, false, lta, NOTHING, 0, tbuf, ncargs, cargs, mudstate.global_regs); free_lbuf(tbuf); bAny = true; } } free_lbuf(buff); if ( a < nargs && !bAny && args[a]) { char *tbuf = replace_tokens(args[a], NULL, NULL, expr); wait_que(executor, caller, enactor, eval, false, lta, NOTHING, 0, tbuf, ncargs, cargs, mudstate.global_regs); free_lbuf(tbuf); } if (key & SWITCH_NOTIFY) { char *tbuf = alloc_lbuf("switch.notify_cmd"); mux_strncpy(tbuf, "@notify/quiet me", LBUF_SIZE-1); wait_que(executor, caller, enactor, eval, false, lta, NOTHING, A_SEMAPHORE, tbuf, ncargs, cargs, mudstate.global_regs); free_lbuf(tbuf); } } // Also for lack of better place the @ifelse code is here. // Idea for @ifelse from ChaoticMUX. // void do_if ( dbref player, dbref caller, dbref enactor, int eval, int key, char *expr, char *args[], int nargs, char *cargs[], int ncargs ) { UNUSED_PARAMETER(key); if ( !expr || nargs <= 0) { return; } char *buff, *bp; CLinearTimeAbsolute lta; buff = bp = alloc_lbuf("do_if"); mux_exec(buff, &bp, player, caller, enactor, eval|EV_FCHECK|EV_EVAL|EV_TOP, &expr, cargs, ncargs); *bp = '\0'; int a = !xlate(buff); free_lbuf(buff); if (a < nargs) { wait_que(player, caller, enactor, eval, false, lta, NOTHING, 0, args[a], ncargs, cargs, mudstate.global_regs); } } void do_addcommand ( dbref player, dbref caller, dbref enactor, int key, int nargs, char *name, char *command ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); // Validate command name. // char *pName = NULL; if (1 <= nargs) { char *pStripped = strip_ansi(name); pName = RemoveSetOfCharacters(pStripped, "\r\n\t "); mux_strlwr(pName); } if ( !pName || pName[0] == '\0' || ( pName[0] == '_' && pName[1] == '_')) { notify(player, "That is not a valid command name."); return; } // Validate object/attribute. // dbref thing; ATTR *pattr; if ( !parse_attrib(player, command, &thing, &pattr) || !pattr) { notify(player, "No such attribute."); return; } if (!See_attr(player, thing, pattr)) { notify(player, NOPERM_MESSAGE); return; } CMDENT *old = (CMDENT *)hashfindLEN(pName, strlen(pName), &mudstate.command_htab); CMDENT *cmd; ADDENT *add, *nextp; if ( old && (old->callseq & CS_ADDED)) { // Don't allow the same (thing,atr) in the list. // for (nextp = old->addent; nextp != NULL; nextp = nextp->next) { if ( nextp->thing == thing && nextp->atr == pattr->number) { notify(player, tprintf("%s already added.", pName)); return; } } // Otherwise, add another (thing,atr) to the list. // add = (ADDENT *)MEMALLOC(sizeof(ADDENT)); ISOUTOFMEMORY(add); add->thing = thing; add->atr = pattr->number; add->name = StringClone(pName); add->next = old->addent; old->addent = add; } else { if (old) { // Delete the old built-in (which will later be added back as // __name). // hashdeleteLEN(pName, strlen(pName), &mudstate.command_htab); } cmd = (CMDENT *)MEMALLOC(sizeof(CMDENT)); ISOUTOFMEMORY(cmd); cmd->cmdname = StringClone(pName); cmd->switches = NULL; cmd->perms = 0; cmd->extra = 0; if ( old && (old->callseq & CS_LEADIN)) { cmd->callseq = CS_ADDED|CS_ONE_ARG|CS_LEADIN; } else { cmd->callseq = CS_ADDED|CS_ONE_ARG; } cmd->hookmask = 0; add = (ADDENT *)MEMALLOC(sizeof(ADDENT)); ISOUTOFMEMORY(add); add->thing = thing; add->atr = pattr->number; add->name = StringClone(pName); add->next = NULL; cmd->addent = add; hashaddLEN(pName, strlen(pName), cmd, &mudstate.command_htab); if ( old && strcmp(pName, old->cmdname) == 0) { // We are @addcommand'ing over a built-in command by its // unaliased name, therefore, we want to re-target all the // aliases. // char *p = tprintf("__%s", pName); hashdeleteLEN(p, strlen(p), &mudstate.command_htab); hashreplall(old, cmd, &mudstate.command_htab); hashaddLEN(p, strlen(p), old, &mudstate.command_htab); } } // We reset the one letter commands here so you can overload them. // set_prefix_cmds(); notify(player, tprintf("Command %s added.", pName)); } void do_listcommands(dbref player, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); CMDENT *old; ADDENT *nextp; bool didit = false; // Let's make this case insensitive... // mux_strlwr(name); if (*name) { old = (CMDENT *)hashfindLEN(name, strlen(name), &mudstate.command_htab); if ( old && (old->callseq & CS_ADDED)) { // If it's already found in the hash table, and it's being added // using the same object and attribute... // for (nextp = old->addent; nextp != NULL; nextp = nextp->next) { ATTR *ap = (ATTR *)atr_num(nextp->atr); const char *pName = "(WARNING: Bad Attribute Number)"; if (ap) { pName = ap->name; } notify(player, tprintf("%s: #%d/%s", nextp->name, nextp->thing, pName)); } } else { notify(player, tprintf("%s not found in command table.",name)); } return; } else { char *pKeyName; int nKeyName; for (old = (CMDENT *)hash_firstkey(&mudstate.command_htab, &nKeyName, &pKeyName); old != NULL; old = (CMDENT *)hash_nextkey(&mudstate.command_htab, &nKeyName, &pKeyName)) { if (old->callseq & CS_ADDED) { pKeyName[nKeyName] = '\0'; for (nextp = old->addent; nextp != NULL; nextp = nextp->next) { if (strcmp(pKeyName, nextp->name) != 0) { continue; } ATTR *ap = (ATTR *)atr_num(nextp->atr); const char *pName = "(WARNING: Bad Attribute Number)"; if (ap) { pName = ap->name; } notify(player, tprintf("%s: #%d/%s", nextp->name, nextp->thing, pName)); didit = true; } } } } if (!didit) { notify(player, "No added commands found in command table."); } } void do_delcommand ( dbref player, dbref caller, dbref enactor, int key, int nargs, char *name, char *command ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nargs); if (!*name) { notify(player, "Sorry."); return; } dbref thing = NOTHING; int atr = NOTHING; ATTR *pattr; if (*command) { if ( !parse_attrib(player, command, &thing, &pattr) || !pattr) { notify(player, "No such attribute."); return; } if (!See_attr(player, thing, pattr)) { notify(player, NOPERM_MESSAGE); return; } atr = pattr->number; } // Let's make this case insensitive... // mux_strlwr(name); CMDENT *old, *cmd; ADDENT *prev = NULL, *nextp; size_t nName = strlen(name); old = (CMDENT *)hashfindLEN(name, nName, &mudstate.command_htab); if ( old && (old->callseq & CS_ADDED)) { char *p__Name = tprintf("__%s", name); size_t n__Name = strlen(p__Name); if (command[0] == '\0') { // Delete all @addcommand'ed associations with the given name. // for (prev = old->addent; prev != NULL; prev = nextp) { nextp = prev->next; MEMFREE(prev->name); prev->name = NULL; MEMFREE(prev); prev = NULL; } hashdeleteLEN(name, nName, &mudstate.command_htab); cmd = (CMDENT *)hashfindLEN(p__Name, n__Name, &mudstate.command_htab); if (cmd) { hashaddLEN(cmd->cmdname, strlen(cmd->cmdname), cmd, &mudstate.command_htab); if (strcmp(name, cmd->cmdname) != 0) { hashaddLEN(name, nName, cmd, &mudstate.command_htab); } hashdeleteLEN(p__Name, n__Name, &mudstate.command_htab); hashaddLEN(p__Name, n__Name, cmd, &mudstate.command_htab); hashreplall(old, cmd, &mudstate.command_htab); } else { // TODO: Delete everything related to 'old'. // } MEMFREE(old->cmdname); old->cmdname = NULL; MEMFREE(old); old = NULL; set_prefix_cmds(); notify(player, "Done."); } else { // Remove only the (name,thing,atr) association. // for (nextp = old->addent; nextp != NULL; nextp = nextp->next) { if ( nextp->thing == thing && nextp->atr == atr) { MEMFREE(nextp->name); nextp->name = NULL; if (!prev) { if (!nextp->next) { hashdeleteLEN(name, nName, &mudstate.command_htab); cmd = (CMDENT *)hashfindLEN(p__Name, n__Name, &mudstate.command_htab); if (cmd) { hashaddLEN(cmd->cmdname, strlen(cmd->cmdname), cmd, &mudstate.command_htab); if (strcmp(name, cmd->cmdname) != 0) { hashaddLEN(name, nName, cmd, &mudstate.command_htab); } hashdeleteLEN(p__Name, n__Name, &mudstate.command_htab); hashaddLEN(p__Name, n__Name, cmd, &mudstate.command_htab); hashreplall(old, cmd, &mudstate.command_htab); } MEMFREE(old->cmdname); old->cmdname = NULL; MEMFREE(old); old = NULL; } else { old->addent = nextp->next; MEMFREE(nextp); nextp = NULL; } } else { prev->next = nextp->next; MEMFREE(nextp); nextp = NULL; } set_prefix_cmds(); notify(player, "Done."); return; } prev = nextp; } notify(player, "Command not found in command table."); } } else { notify(player, "Command not found in command table."); } } /* * @prog 'glues' a user's input to a command. Once executed, the first string * input from any of the doers's logged in descriptors, will go into * A_PROGMSG, which can be substituted in with %0. Commands already * queued by the doer will be processed normally. */ void handle_prog(DESC *d, char *message) { // Allow the player to pipe a command while in interactive mode. // if (*message == '|') { do_command(d, message + 1); if (d->program_data != NULL) { queue_string(d, tprintf("%s>%s ", ANSI_HILITE, ANSI_NORMAL)); if (OPTION_YES == UsState(d, TELNET_EOR)) { // Use telnet protocol's EOR command to show prompt. // const char aEOR[2] = { NVT_IAC, NVT_EOR }; queue_write_LEN(d, aEOR, sizeof(aEOR)); } else if (OPTION_YES != UsState(d, TELNET_SGA)) { // Use telnet protocol's GOAHEAD command to show prompt. // const char aGoAhead[2] = { NVT_IAC, NVT_GA }; queue_write_LEN(d, aGoAhead, sizeof(aGoAhead)); } } return; } dbref aowner; int aflags, i; char *cmd = atr_get(d->player, A_PROGCMD, &aowner, &aflags); CLinearTimeAbsolute lta; wait_que(d->program_data->wait_enactor, d->player, d->player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, cmd, 1, &message, d->program_data->wait_regs); // First, set 'all' to a descriptor we find for this player. // DESC *all = (DESC *)hashfindLEN(&(d->player), sizeof(d->player), &mudstate.desc_htab) ; if ( all && all->program_data) { PROG *program = all->program_data; for (i = 0; i < MAX_GLOBAL_REGS; i++) { if (program->wait_regs[i]) { RegRelease(program->wait_regs[i]); program->wait_regs[i] = NULL; } } // Set info for all player descriptors to NULL // DESC_ITER_PLAYER(d->player, all) { mux_assert(program == all->program_data); all->program_data = NULL; } MEMFREE(program); } atr_clr(d->player, A_PROGCMD); free_lbuf(cmd); } void do_quitprog(dbref player, dbref caller, dbref enactor, int eval, int key, char *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(key); dbref doer; if (*name) { doer = match_thing(player, name); } else { doer = player; } if ( !( Prog(player) || Prog(Owner(player))) && player != doer) { notify(player, NOPERM_MESSAGE); return; } if ( !Good_obj(doer) || !isPlayer(doer)) { notify(player, "That is not a player."); return; } if (!Connected(doer)) { notify(player, "That player is not connected."); return; } DESC *d; bool isprog = false; DESC_ITER_PLAYER(doer, d) { if (NULL != d->program_data) { isprog = true; } } if (!isprog) { notify(player, "Player is not in an @program."); return; } d = (DESC *)hashfindLEN(&doer, sizeof(doer), &mudstate.desc_htab); int i; if ( d && d->program_data) { PROG *program = d->program_data; for (i = 0; i < MAX_GLOBAL_REGS; i++) { if (program->wait_regs[i]) { RegRelease(program->wait_regs[i]); program->wait_regs[i] = NULL; } } // Set info for all player descriptors to NULL. // DESC_ITER_PLAYER(doer, d) { mux_assert(program == d->program_data); d->program_data = NULL; } MEMFREE(program); } atr_clr(doer, A_PROGCMD); notify(player, "@program cleared."); notify(doer, "Your @program has been terminated."); } void do_prog ( dbref player, dbref caller, dbref enactor, int key, int nargs, char *name, char *command ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nargs); if ( !name || !*name) { notify(player, "No players specified."); return; } dbref doer = match_thing(player, name); if ( !( Prog(player) || Prog(Owner(player))) && player != doer) { notify(player, NOPERM_MESSAGE); return; } if ( !Good_obj(doer) || !isPlayer(doer)) { notify(player, "That is not a player."); return; } if (!Connected(doer)) { notify(player, "That player is not connected."); return; } char *msg = command; char *attrib = parse_to(&msg, ':', 1); if (msg && *msg) { notify(doer, msg); } dbref thing; ATTR *ap; if (!parse_attrib(player, attrib, &thing, &ap)) { notify(player, NOMATCH_MESSAGE); return; } if (ap) { dbref aowner; int aflags; int lev; dbref parent; char *pBuffer = NULL; bool bFound = false; ITER_PARENTS(thing, parent, lev) { pBuffer = atr_get(parent, ap->number, &aowner, &aflags); if (pBuffer[0]) { bFound = true; break; } free_lbuf(pBuffer); } if (bFound) { if ( ( God(player) || !God(thing)) && See_attr(player, thing, ap)) { atr_add_raw(doer, A_PROGCMD, pBuffer); } else { notify(player, NOPERM_MESSAGE); free_lbuf(pBuffer); return; } free_lbuf(pBuffer); } else { notify(player, "Attribute not present on object."); return; } } else { notify(player, "No such attribute."); return; } // Check to see if the enactor already has an @prog input pending. // DESC *d; DESC_ITER_PLAYER(doer, d) { if (d->program_data != NULL) { notify(player, "Input already pending."); return; } } PROG *program = (PROG *)MEMALLOC(sizeof(PROG)); ISOUTOFMEMORY(program); program->wait_enactor = player; for (int i = 0; i < MAX_GLOBAL_REGS; i++) { program->wait_regs[i] = mudstate.global_regs[i]; if (mudstate.global_regs[i]) { RegAddRef(mudstate.global_regs[i]); } } // Now, start waiting. // DESC_ITER_PLAYER(doer, d) { d->program_data = program; queue_string(d, tprintf("%s>%s ", ANSI_HILITE, ANSI_NORMAL)); if (OPTION_YES == UsState(d, TELNET_EOR)) { // Use telnet protocol's EOR command to show prompt. // const char aEOR[2] = { NVT_IAC, NVT_EOR }; queue_write_LEN(d, aEOR, sizeof(aEOR)); } else if (OPTION_YES != UsState(d, TELNET_SGA)) { // Use telnet protocol's GOAHEAD command to show prompt. // const char aGoAhead[2] = { NVT_IAC, NVT_GA }; queue_write_LEN(d, aGoAhead, sizeof(aGoAhead)); } } } /* --------------------------------------------------------------------------- * do_restart: Restarts the game. */ void do_restart(dbref executor, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); if (!Can_SiteAdmin(executor)) { notify(executor, NOPERM_MESSAGE); return; } bool bDenied = false; #ifndef WIN32 if (mudstate.dumping) { notify(executor, "Dumping. Please try again later."); bDenied = true; } #endif // !WIN32 if (!mudstate.bCanRestart) { notify(executor, "Server just started. Please try again in a few seconds."); bDenied = true; } if (bDenied) { STARTLOG(LOG_ALWAYS, "WIZ", "RSTRT"); log_text("Restart requested but not executed by "); log_name(executor); ENDLOG; return; } raw_broadcast(0, "GAME: Restart by %s, please wait.", Moniker(Owner(executor))); STARTLOG(LOG_ALWAYS, "WIZ", "RSTRT"); log_text("Restart by "); log_name(executor); ENDLOG; local_presync_database(); #ifndef MEMORY_BASED al_store(); #endif pcache_sync(); dump_database_internal(DUMP_I_RESTART); SYNC; CLOSE; #ifdef WIN32 // WIN32 WSACleanup(); exit(12345678); #else // WIN32 dump_restart_db(); CleanUpSlaveSocket(); CleanUpSlaveProcess(); Log.StopLogging(); #ifdef GAME_DOOFERMUX execl("bin/netmux", mudconf.mud_name, "-c", mudconf.config_file, "-p", mudconf.pid_file, "-e", mudconf.log_dir, NULL); #else execl("bin/netmux", "netmux", "-c", mudconf.config_file, "-p", mudconf.pid_file, "-e", mudconf.log_dir, NULL); #endif // GAME_DOOFERMUX #endif // !WIN32 } /* --------------------------------------------------------------------------- * do_backup: Backs up and restarts the game * By Wadhah Al-Tailji (7-21-97), altailji@nmt.edu * Ported to MUX2 by Patrick Hill (7-5-2001), hellspawn@anomux.org */ #ifdef WIN32 void do_backup(dbref player, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); notify(player, "This feature is not yet available on Win32-hosted MUX."); } #else // WIN32 void do_backup(dbref player, dbref caller, dbref enactor, int key) { #ifndef WIN32 if (mudstate.dumping) { notify(player, "Dumping. Please try again later."); } #endif // !WIN32 raw_broadcast(0, "GAME: Backing up database. Please wait."); STARTLOG(LOG_ALWAYS, "WIZ", "BACK"); log_text("Backup by "); log_name(player); ENDLOG; #ifdef MEMORY_BASED // Invoking _backupflat.sh with an argument prompts the backup script // to use it as the flatfile. // dump_database_internal(DUMP_I_FLAT); system(tprintf("./_backupflat.sh %s.FLAT 1>&2", mudconf.indb)); #else // MEMORY_BASED // Invoking _backupflat.sh without an argument prompts the backup script // to use dbconvert itself. // dump_database_internal(DUMP_I_NORMAL); system(tprintf("./_backupflat.sh 1>&2")); #endif // MEMORY_BASED raw_broadcast(0, "GAME: Backup finished."); } #endif // WIN32 /* --------------------------------------------------------------------------- * do_comment: Implement the @@ (comment) command. Very cpu-intensive :-) */ void do_comment(dbref player, dbref caller, dbref enactor, int key) { UNUSED_PARAMETER(player); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); } static dbref promote_dflt(dbref old, dbref new0) { if ( old == NOPERM || new0 == NOPERM) { return NOPERM; } if ( old == AMBIGUOUS || new0 == AMBIGUOUS) { return AMBIGUOUS; } return NOTHING; } dbref match_possessed(dbref player, dbref thing, char *target, dbref dflt, bool check_enter) { // First, check normally. // if (Good_obj(dflt)) { return dflt; } // Didn't find it directly. Recursively do a contents check. // dbref result, result1; char *buff, *place, *s1, *d1, *temp; char *start = target; while (*target) { // Fail if no ' characters. // place = target; target = strchr(place, '\''); if ( target == NULL || !*target) { return dflt; } // If string started with a ', skip past it // if (place == target) { target++; continue; } // If next character is not an s or a space, skip past // temp = target++; if (!*target) { return dflt; } if ( *target != 's' && *target != 'S' && *target != ' ') { continue; } // If character was not a space make sure the following character is // a space. // if (*target != ' ') { target++; if (!*target) { return dflt; } if (*target != ' ') { continue; } } // Copy the container name to a new buffer so we can terminate it. // buff = alloc_lbuf("is_posess"); for (s1 = start, d1 = buff; *s1 && (s1 < temp); *d1++ = (*s1++)) { ; // Nothing. } *d1 = '\0'; // Look for the container here and in our inventory. Skip past if we // can't find it. // init_match(thing, buff, NOTYPE); if (player == thing) { match_neighbor(); match_possession(); } else { match_possession(); } result1 = match_result(); free_lbuf(buff); if (!Good_obj(result1)) { dflt = promote_dflt(dflt, result1); continue; } // If we don't control it and it is either dark or opaque, skip past. // bool control = Controls(player, result1); if ( ( Dark(result1) || Opaque(result1)) && !control) { dflt = promote_dflt(dflt, NOTHING); continue; } // Validate object has the ENTER bit set, if requested. // if ( check_enter && !Enter_ok(result1) && !control) { dflt = promote_dflt(dflt, NOPERM); continue; } // Look for the object in the container. // init_match(result1, target, NOTYPE); match_possession(); result = match_result(); result = match_possessed(player, result1, target, result, check_enter); if (Good_obj(result)) { return result; } dflt = promote_dflt(dflt, result); } return dflt; } /* --------------------------------------------------------------------------- * parse_range: break up ,, syntax */ void parse_range(char **name, dbref *low_bound, dbref *high_bound) { char *buff1 = *name; if (buff1 && *buff1) { *name = parse_to(&buff1, ',', EV_STRIP_TS); } if (buff1 && *buff1) { char *buff2 = parse_to(&buff1, ',', EV_STRIP_TS); if (buff1 && *buff1) { while (mux_isspace(*buff1)) { buff1++; } if (*buff1 == NUMBER_TOKEN) { buff1++; } *high_bound = mux_atol(buff1); if (*high_bound >= mudstate.db_top) { *high_bound = mudstate.db_top - 1; } } else { *high_bound = mudstate.db_top - 1; } while (mux_isspace(*buff2)) { buff2++; } if (*buff2 == NUMBER_TOKEN) { buff2++; } *low_bound = mux_atol(buff2); if (*low_bound < 0) { *low_bound = 0; } } else { *low_bound = 0; *high_bound = mudstate.db_top - 1; } } bool parse_thing_slash(dbref player, char *thing, char **after, dbref *it) { // Get name up to '/'. // char *str = thing; while ( *str != '\0' && *str != '/') { str++; } // If no '/' in string, return failure. // if (*str == '\0') { *after = NULL; *it = NOTHING; return false; } *str++ = '\0'; *after = str; // Look for the object. // init_match(player, thing, NOTYPE); match_everything(MAT_EXIT_PARENTS); *it = match_result(); // Return status of search. // return Good_obj(*it); } bool get_obj_and_lock(dbref player, char *what, dbref *it, ATTR **attr, char *errmsg, char **bufc) { char *str, *tbuf; int anum; tbuf = alloc_lbuf("get_obj_and_lock"); mux_strncpy(tbuf, what, LBUF_SIZE-1); if (parse_thing_slash(player, tbuf, &str, it)) { // / syntax, use the named lock. // if (!search_nametab(player, lock_sw, str, &anum)) { free_lbuf(tbuf); safe_str("#-1 LOCK NOT FOUND", errmsg, bufc); return false; } } else { // Not /, do a normal get of the default lock. // *it = match_thing_quiet(player, what); if (!Good_obj(*it)) { free_lbuf(tbuf); safe_match_result(*it, errmsg, bufc); return false; } anum = A_LOCK; } // Get the attribute definition, fail if not found. // free_lbuf(tbuf); *attr = atr_num(anum); if (!(*attr)) { safe_str("#-1 LOCK NOT FOUND", errmsg, bufc); return false; } return true; } // --------------------------------------------------------------------------- // bCanReadAttr, bCanSetAttr: Verify permission to affect attributes. // --------------------------------------------------------------------------- bool bCanReadAttr(dbref executor, dbref target, ATTR *tattr, bool bCheckParent) { if (!tattr) { return false; } dbref aowner; int aflags; if ( !mudstate.bStandAlone && bCheckParent) { atr_pget_info(target, tattr->number, &aowner, &aflags); } else { atr_get_info(target, tattr->number, &aowner, &aflags); } int mAllow = AF_VISUAL; if ( (tattr->flags & mAllow) || (aflags & mAllow)) { if ( mudstate.bStandAlone || tattr->number != A_DESC || mudconf.read_rem_desc || nearby(executor, target)) { return true; } } int mDeny = 0; if (WizRoy(executor)) { if (God(executor)) { mDeny = AF_INTERNAL; } else { mDeny = AF_INTERNAL|AF_DARK; } } else if ( Owner(executor) == aowner || Examinable(executor, target)) { mDeny = AF_INTERNAL|AF_DARK|AF_MDARK; } if (mDeny) { if ( (tattr->flags & mDeny) || (aflags & mDeny)) { return false; } else { return true; } } return false; } bool bCanSetAttr(dbref executor, dbref target, ATTR *tattr) { if (!tattr) { return false; } int mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST; if (!God(executor)) { if (God(target)) { return false; } if (Wizard(executor)) { mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST|AF_LOCK|AF_GOD; } else if (Controls(executor, target)) { mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST|AF_LOCK|AF_WIZARD|AF_GOD; } else { return false; } } dbref aowner; int aflags; if ( (tattr->flags & mDeny) #ifdef FIRANMUX || Immutable(target) #endif || ( atr_get_info(target, tattr->number, &aowner, &aflags) && (aflags & mDeny))) { return false; } else { return true; } } bool bCanLockAttr(dbref executor, dbref target, ATTR *tattr) { if (!tattr) { return false; } int mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST; if (!God(executor)) { if (God(target)) { return false; } if (Wizard(executor)) { mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST|AF_GOD; } else { mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST|AF_WIZARD|AF_GOD; } } dbref aowner; int aflags; if ( (tattr->flags & mDeny) || !atr_get_info(target, tattr->number, &aowner, &aflags) || (aflags & mDeny)) { return false; } else if ( Wizard(executor) || Owner(executor) == aowner) { return true; } else { return false; } } /* --------------------------------------------------------------------------- * where_is: Returns place where obj is linked into a list. * ie. location for players/things, source for exits, NOTHING for rooms. */ dbref where_is(dbref what) { if (!Good_obj(what)) { return NOTHING; } dbref loc; switch (Typeof(what)) { case TYPE_PLAYER: case TYPE_THING: loc = Location(what); break; case TYPE_EXIT: loc = Exits(what); break; default: loc = NOTHING; break; } return loc; } /* --------------------------------------------------------------------------- * where_room: Return room containing player, or NOTHING if no room or * recursion exceeded. If player is a room, returns itself. */ dbref where_room(dbref what) { for (int count = mudconf.ntfy_nest_lim; count > 0; count--) { if (!Good_obj(what)) { break; } if (isRoom(what)) { return what; } if (!Has_location(what)) { break; } what = Location(what); } return NOTHING; } bool locatable(dbref player, dbref it, dbref enactor) { // No sense if trying to locate a bad object // if (!Good_obj(it)) { return false; } dbref loc_it = where_is(it); // Succeed if we can examine the target, if we are the target, if we can // examine the location, if a wizard caused the lookup, or if the target // caused the lookup. // if ( Examinable(player, it) || Find_Unfindable(player) || loc_it == player || ( loc_it != NOTHING && ( Examinable(player, loc_it) || loc_it == where_is(player))) || Wizard(enactor) || it == enactor) { return true; } dbref room_it = where_room(it); bool findable_room; if (Good_obj(room_it)) { findable_room = Findable(room_it); } else { findable_room = true; } // Succeed if we control the containing room or if the target is findable // and the containing room is not unfindable. // if ( ( room_it != NOTHING && Examinable(player, room_it)) || Find_Unfindable(player) || ( Findable(it) && findable_room)) { return true; } // We can't do it. // return false; } /* --------------------------------------------------------------------------- * nearby: Check if thing is nearby player (in inventory, in same room, or * IS the room. */ bool nearby(dbref player, dbref thing) { if ( !Good_obj(player) || !Good_obj(thing)) { return false; } if ( Can_Hide(thing) && Hidden(thing) && !See_Hidden(player)) { return false; } dbref thing_loc = where_is(thing); if (thing_loc == player) { return true; } dbref player_loc = where_is(player); if ( thing_loc == player_loc || thing == player_loc) { return true; } return false; } /* * --------------------------------------------------------------------------- * * exit_visible, exit_displayable: Is exit visible? */ bool exit_visible(dbref exit, dbref player, int key) { #ifdef WOD_REALMS if (!mudstate.bStandAlone) { int iRealmDirective = DoThingToThingVisibility(player, exit, ACTION_IS_STATIONARY); if (REALM_DO_HIDDEN_FROM_YOU == iRealmDirective) { return false; } } #endif // WOD_REALMS #ifdef REALITY_LVLS if (!mudstate.bStandAlone) { if (!IsReal(player, exit)) return 0; } #endif // REALITY_LVLS // Exam exit's location // if ( (key & VE_LOC_XAM) || Examinable(player, exit) || Light(exit)) { return true; } // Dark location or base // if ( (key & (VE_LOC_DARK | VE_BASE_DARK)) || Dark(exit)) { return false; } // Default // return true; } // Exit visible to look // bool exit_displayable(dbref exit, dbref player, int key) { #ifndef WOD_REALMS UNUSED_PARAMETER(player); #endif // WOD_REALMS // Dark exit // if (Dark(exit)) { return false; } #ifdef WOD_REALMS if (!mudstate.bStandAlone) { int iRealmDirective = DoThingToThingVisibility(player, exit, ACTION_IS_STATIONARY); if (REALM_DO_HIDDEN_FROM_YOU == iRealmDirective) { return false; } } #endif // WOD_REALMS // Light exit // if (Light(exit)) { return true; } // Dark location or base. // if (key & (VE_LOC_DARK | VE_BASE_DARK)) { return false; } // Default // return true; } /* --------------------------------------------------------------------------- * did_it: Have player do something to/with thing */ void did_it(dbref player, dbref thing, int what, const char *def, int owhat, const char *odef, int awhat, int ctrl_flags, char *args[], int nargs) { if (MuxAlarm.bAlarmed) { return; } char *d, *buff, *act, *charges, *bp, *str; dbref loc, aowner; int num, aflags; // If we need to call exec() from within this function, we first save // the state of the global registers, in order to avoid munging them // inappropriately. Do note that the restoration to their original // values occurs BEFORE the execution of the @a-attribute. Therefore, // any changing of setq() values done in the @-attribute and @o-attribute // will NOT be passed on. This prevents odd behaviors that result from // odd @verbs and so forth (the idea is to preserve the caller's control // of the global register values). // bool need_pres = false; reg_ref **preserve = NULL; // message to player. // if (what > 0) { d = atr_pget(thing, what, &aowner, &aflags); if (*d) { need_pres = true; preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); buff = bp = alloc_lbuf("did_it.1"); str = d; mux_exec(buff, &bp, thing, player, player, AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_FCHECK|EV_TOP), &str, args, nargs); *bp = '\0'; if ( (aflags & AF_HTML) && Html(player)) { safe_str("\r\n", buff, &bp); *bp = '\0'; notify_html(player, buff); } #if defined(FIRANMUX) else if ( A_DESC == what && Linewrap(player) && isPlayer(player) && ( !Linewrap(thing) || isPlayer(thing))) { notify(player, linewrap_desc(buff)); } #endif // FIRANMUX else { notify(player, buff); } free_lbuf(buff); } else if (def) { notify(player, def); } free_lbuf(d); } if (what < 0 && def) { notify(player, def); } // message to neighbors. // if ( 0 < owhat && Has_location(player) && Good_obj(loc = Location(player))) { d = atr_pget(thing, owhat, &aowner, &aflags); if (*d) { if (!need_pres) { need_pres = true; preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); } buff = bp = alloc_lbuf("did_it.2"); str = d; mux_exec(buff, &bp, thing, player, player, AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_FCHECK|EV_TOP), &str, args, nargs); *bp = '\0'; #if !defined(FIRANMUX) if (*buff) #endif // FIRANMUX { #ifdef REALITY_LVLS if (aflags & AF_NONAME) { notify_except2_rlevel(loc, player, player, thing, buff); } else { notify_except2_rlevel(loc, player, player, thing, tprintf("%s %s", Name(player), buff)); } #else if (aflags & AF_NONAME) { notify_except2(loc, player, player, thing, buff); } else { notify_except2(loc, player, player, thing, tprintf("%s %s", Name(player), buff)); } #endif // REALITY_LVLS } free_lbuf(buff); } else if (odef) { #ifdef REALITY_LVLS if (ctrl_flags & VERB_NONAME) { notify_except2_rlevel(loc, player, player, thing, odef); } else { notify_except2_rlevel(loc, player, player, thing, tprintf("%s %s", Name(player), odef)); } #else if (ctrl_flags & VERB_NONAME) { notify_except2(loc, player, player, thing, odef); } else { notify_except2(loc, player, player, thing, tprintf("%s %s", Name(player), odef)); } #endif // REALITY_LVLS } free_lbuf(d); } else if ( owhat < 0 && odef && Has_location(player) && Good_obj(loc = Location(player))) { #ifdef REALITY_LVLS if (ctrl_flags & VERB_NONAME) { notify_except2_rlevel(loc, player, player, thing, odef); } else { notify_except2_rlevel(loc, player, player, thing, tprintf("%s %s", Name(player), odef)); } #else if (ctrl_flags & VERB_NONAME) { notify_except2(loc, player, player, thing, odef); } else { notify_except2(loc, player, player, thing, tprintf("%s %s", Name(player), odef)); } #endif // REALITY_LVLS } // If we preserved the state of the global registers, restore them. // if (need_pres) { restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); } // Do the action attribute. // #ifdef REALITY_LVLS if ( 0 < awhat && IsReal(thing, player)) #else if (0 < awhat) #endif // REALITY_LVLS { if (*(act = atr_pget(thing, awhat, &aowner, &aflags))) { dbref aowner2; int aflags2; charges = atr_pget(thing, A_CHARGES, &aowner2, &aflags2); if (*charges) { num = mux_atol(charges); if (num > 0) { buff = alloc_sbuf("did_it.charges"); mux_ltoa(num-1, buff); atr_add_raw(thing, A_CHARGES, buff); free_sbuf(buff); } else if (*(buff = atr_pget(thing, A_RUNOUT, &aowner2, &aflags2))) { free_lbuf(act); act = buff; } else { free_lbuf(act); free_lbuf(buff); free_lbuf(charges); return; } } free_lbuf(charges); CLinearTimeAbsolute lta; wait_que(thing, player, player, AttrTrace(aflags, 0), false, lta, NOTHING, 0, act, nargs, args, mudstate.global_regs); } free_lbuf(act); } } /* --------------------------------------------------------------------------- * do_verb: Command interface to did_it. */ void do_verb(dbref executor, dbref caller, dbref enactor, int eval, int key, char *victim_str, char *args[], int nargs) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(key); // Look for the victim. // if ( !victim_str || !*victim_str) { notify(executor, "Nothing to do."); return; } // Get the victim. // init_match(executor, victim_str, NOTYPE); match_everything(MAT_EXIT_PARENTS); dbref victim = noisy_match_result(); if (!Good_obj(victim)) { return; } // Get the actor. Default is my cause. // dbref actor; if ( nargs >= 1 && args[0] && *args[0]) { init_match(executor, args[0], NOTYPE); match_everything(MAT_EXIT_PARENTS); actor = noisy_match_result(); if (!Good_obj(actor)) { return; } } else { actor = enactor; } // Check permissions. There are two possibilities: // // 1. Executor controls both victim and actor. In this case, // victim runs his action list. // // 2. Executor controls actor. In this case victim does not run // his action list and any attributes that executor cannot read // from victim are defaulted. // if (!Controls(executor, actor)) { notify_quiet(executor, "Permission denied,"); return; } ATTR *ap; int what = -1; int owhat = -1; int awhat = -1; const char *whatd = NULL; const char *owhatd = NULL; int nxargs = 0; dbref aowner = NOTHING; int aflags = NOTHING; char *xargs[10]; switch (nargs) // Yes, this IS supposed to fall through. { case 7: // Get arguments. // parse_arglist(victim, actor, actor, args[6], '\0', EV_STRIP_LS | EV_STRIP_TS, xargs, 10, NULL, 0, &nxargs); case 6: // Get action attribute. // ap = atr_str(args[5]); if (ap) { awhat = ap->number; } case 5: // Get others message default. // if (args[4] && *args[4]) { owhatd = args[4]; } case 4: // Get others message attribute. // ap = atr_str(args[3]); if (ap && (ap->number > 0)) { owhat = ap->number; } case 3: // Get enactor message default. // if (args[2] && *args[2]) { whatd = args[2]; } case 2: // Get enactor message attribute. // ap = atr_str(args[1]); if (ap && (ap->number > 0)) { what = ap->number; } } // If executor doesn't control both, enforce visibility restrictions. // if (!Controls(executor, victim)) { ap = NULL; if (what != -1) { atr_get_info(victim, what, &aowner, &aflags); ap = atr_num(what); } if ( !ap || !bCanReadAttr(executor, victim, ap, false) || ( ap->number == A_DESC && !mudconf.read_rem_desc && !Examinable(executor, victim) && !nearby(executor, victim))) { what = -1; } ap = NULL; if (owhat != -1) { atr_get_info(victim, owhat, &aowner, &aflags); ap = atr_num(owhat); } if ( !ap || !bCanReadAttr(executor, victim, ap, false) || ( ap->number == A_DESC && !mudconf.read_rem_desc && !Examinable(executor, victim) && !nearby(executor, victim))) { owhat = -1; } awhat = 0; } // Go do it. // did_it(actor, victim, what, whatd, owhat, owhatd, awhat, key & VERB_NONAME, xargs, nxargs); // Free user args. // for (int i = 0; i < nxargs; i++) { free_lbuf(xargs[i]); } } // -------------------------------------------------------------------------- // OutOfMemory: handle an out of memory condition. // void OutOfMemory(const char *SourceFile, unsigned int LineNo) { Log.tinyprintf("%s(%u): Out of memory." ENDLINE, SourceFile, LineNo); Log.Flush(); if ( !mudstate.bStandAlone && mudstate.bCanRestart) { do_restart(GOD, GOD, GOD, 0); } else { abort(); } } // -------------------------------------------------------------------------- // AssertionFailed: A logical assertion has failed. // bool AssertionFailed(const char *SourceFile, unsigned int LineNo) { Log.tinyprintf("%s(%u): Assertion failed." ENDLINE, SourceFile, LineNo); Log.Flush(); if ( !mudstate.bStandAlone && mudstate.bCanRestart) { do_restart(GOD, GOD, GOD, 0); } else { abort(); } return false; } mux2.6/src/pcre.h0000600000175000017500000001150611025753746013703 0ustar sdennissdennis/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* Copyright (c) 1997-2003 University of Cambridge */ /* Modified a bit by Shawn Wagner for inclusion in MUX. See pcre.cpp for details. */ #ifndef _PCRE_H #define _PCRE_H #define PCRE_MAJOR 4 #define PCRE_MINOR 5 #define PCRE_DATE 01-December-2003 #ifndef PCRE_DATA_SCOPE # define PCRE_DATA_SCOPE extern #endif /* Have to include stdlib.h in order to ensure that size_t is defined; it is needed here for malloc. */ #include /* Options */ #define PCRE_CASELESS 0x0001 #define PCRE_MULTILINE 0x0002 #define PCRE_DOTALL 0x0004 #define PCRE_EXTENDED 0x0008 #define PCRE_ANCHORED 0x0010 #define PCRE_DOLLAR_ENDONLY 0x0020 #define PCRE_EXTRA 0x0040 #define PCRE_NOTBOL 0x0080 #define PCRE_NOTEOL 0x0100 #define PCRE_UNGREEDY 0x0200 #define PCRE_NOTEMPTY 0x0400 #define PCRE_UTF8 0x0800 #define PCRE_NO_AUTO_CAPTURE 0x1000 #define PCRE_NO_UTF8_CHECK 0x2000 /* Exec-time and get/set-time error codes */ #define PCRE_ERROR_NOMATCH (-1) #define PCRE_ERROR_NULL (-2) #define PCRE_ERROR_BADOPTION (-3) #define PCRE_ERROR_BADMAGIC (-4) #define PCRE_ERROR_UNKNOWN_NODE (-5) #define PCRE_ERROR_NOMEMORY (-6) #define PCRE_ERROR_NOSUBSTRING (-7) #define PCRE_ERROR_MATCHLIMIT (-8) #define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */ #define PCRE_ERROR_BADUTF8 (-10) #define PCRE_ERROR_BADUTF8_OFFSET (-11) /* Request types for pcre_fullinfo() */ #define PCRE_INFO_OPTIONS 0 #define PCRE_INFO_SIZE 1 #define PCRE_INFO_CAPTURECOUNT 2 #define PCRE_INFO_BACKREFMAX 3 #define PCRE_INFO_FIRSTBYTE 4 #define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */ #define PCRE_INFO_FIRSTTABLE 5 #define PCRE_INFO_LASTLITERAL 6 #define PCRE_INFO_NAMEENTRYSIZE 7 #define PCRE_INFO_NAMECOUNT 8 #define PCRE_INFO_NAMETABLE 9 #define PCRE_INFO_STUDYSIZE 10 /* Request types for pcre_config() */ #define PCRE_CONFIG_UTF8 0 #define PCRE_CONFIG_NEWLINE 1 #define PCRE_CONFIG_LINK_SIZE 2 #define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3 #define PCRE_CONFIG_MATCH_LIMIT 4 #define PCRE_CONFIG_STACKRECURSE 5 /* Bit flags for the pcre_extra structure */ #define PCRE_EXTRA_STUDY_DATA 0x0001 #define PCRE_EXTRA_MATCH_LIMIT 0x0002 #define PCRE_EXTRA_CALLOUT_DATA 0x0004 /* Types */ struct real_pcre; /* declaration; the definition is private */ typedef struct real_pcre pcre; /* The structure for passing additional data to pcre_exec(). This is defined in such as way as to be extensible. */ typedef struct pcre_extra { unsigned long int flags; /* Bits for which fields are set */ void *study_data; /* Opaque data from pcre_study() */ unsigned long int match_limit; /* Maximum number of calls to match() */ void *callout_data; /* Data passed back in callouts */ } pcre_extra; /* The structure for passing out data via the pcre_callout_function. We use a structure so that new fields can be added on the end in future versions, without changing the API of the function, thereby allowing old clients to work without modification. */ typedef struct pcre_callout_block { int version; /* Identifies version of block */ /* ------------------------ Version 0 ------------------------------- */ int callout_number; /* Number compiled into pattern */ int *offset_vector; /* The offset vector */ const char *subject; /* The subject being matched */ int subject_length; /* The length of the subject */ int start_match; /* Offset to start of this match attempt */ int current_position; /* Where we currently are */ int capture_top; /* Max current capture */ int capture_last; /* Most recently closed capture */ void *callout_data; /* Data passed in with the call */ /* ------------------------------------------------------------------ */ } pcre_callout_block; /* Exported PCRE functions */ extern pcre *pcre_compile(const char *, int, const char **, int *, const unsigned char *); extern int pcre_copy_substring(const char *, int *, int, int, char *, int); extern int pcre_exec(const pcre *, const pcre_extra *, const char *, int, int, int, int *, int); extern const unsigned char *pcre_maketables(void); extern pcre_extra *pcre_study(const pcre *, int, const char **); #endif /* End of pcre.h */ mux2.6/src/config.guess0000700000175000017500000012626011025753746015123 0ustar sdennissdennis#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, # Inc. timestamp='2006-07-02' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; x86:Interix*:[3456]*) echo i586-pc-interix${UNAME_RELEASE} exit ;; EM64T:Interix*:[3456]*) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^LIBC/{ s: ::g p }'`" test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: mux2.6/src/db_rw.cpp0000600000175000017500000007614411025753746014413 0ustar sdennissdennis// db_rw.cpp // // $Id: db_rw.cpp 3050 2007-12-30 06:36:06Z brazilofmux $ // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "vattr.h" static int g_version; static int g_format; static int g_flags; /* --------------------------------------------------------------------------- * getboolexp1: Get boolean subexpression from file. */ static BOOLEXP *getboolexp1(FILE *f) { BOOLEXP *b; char *buff, *s; int d, anum; int c = getc(f); switch (c) { case '\n': ungetc(c, f); return TRUE_BOOLEXP; case EOF: // Unexpected EOF in boolexp. // mux_assert(0); break; case '(': b = alloc_bool("getboolexp1.openparen"); switch (c = getc(f)) { case NOT_TOKEN: b->type = BOOLEXP_NOT; b->sub1 = getboolexp1(f); if ((d = getc(f)) == '\n') { d = getc(f); } if (d != ')') { goto error; } return b; case INDIR_TOKEN: b->type = BOOLEXP_INDIR; b->sub1 = getboolexp1(f); if ((d = getc(f)) == '\n') { d = getc(f); } if (d != ')') { goto error; } return b; case IS_TOKEN: b->type = BOOLEXP_IS; b->sub1 = getboolexp1(f); if ((d = getc(f)) == '\n') { d = getc(f); } if (d != ')') { goto error; } return b; case CARRY_TOKEN: b->type = BOOLEXP_CARRY; b->sub1 = getboolexp1(f); if ((d = getc(f)) == '\n') { d = getc(f); } if (d != ')') { goto error; } return b; case OWNER_TOKEN: b->type = BOOLEXP_OWNER; b->sub1 = getboolexp1(f); if ((d = getc(f)) == '\n') { d = getc(f); } if (d != ')') { goto error; } return b; default: ungetc(c, f); b->sub1 = getboolexp1(f); if ((c = getc(f)) == '\n') { c = getc(f); } switch (c) { case AND_TOKEN: b->type = BOOLEXP_AND; break; case OR_TOKEN: b->type = BOOLEXP_OR; break; default: goto error; } b->sub2 = getboolexp1(f); if ((d = getc(f)) == '\n') { d = getc(f); } if (d != ')') { goto error; } return b; } case '-': // obsolete NOTHING key, eat it. // while ((c = getc(f)) != '\n') { mux_assert(c != EOF); } ungetc(c, f); return TRUE_BOOLEXP; case '"': ungetc(c, f); buff = alloc_lbuf("getboolexp_quoted"); { size_t nBuffer; char *pBuffer = getstring_noalloc(f, true, &nBuffer); if (LBUF_SIZE - 1 < nBuffer) { nBuffer = LBUF_SIZE - 1; pBuffer[nBuffer] = '\0'; } memcpy(buff, pBuffer, nBuffer+1); } c = fgetc(f); if (c == EOF) { free_lbuf(buff); return TRUE_BOOLEXP; } b = alloc_bool("getboolexp1_quoted"); anum = mkattr(GOD, buff); if (anum <= 0) { free_bool(b); free_lbuf(buff); goto error; } free_lbuf(buff); b->thing = anum; // If last character is : then this is an attribute lock. A // last character of / means an eval lock. // if ( c == ':' || c == '/') { if (c == '/') { b->type = BOOLEXP_EVAL; } else { b->type = BOOLEXP_ATR; } buff = alloc_lbuf("getboolexp1.attr_lock"); size_t nBuffer; char *pBuffer = getstring_noalloc(f, true, &nBuffer); if (LBUF_SIZE - 1 < nBuffer) { nBuffer = LBUF_SIZE - 1; pBuffer[nBuffer] = '\0'; } memcpy(buff, pBuffer, nBuffer+1); b->sub1 = (BOOLEXP *)StringClone(buff); free_lbuf(buff); } return b; default: // dbref or attribute. ungetc(c, f); b = alloc_bool("getboolexp1.default"); b->type = BOOLEXP_CONST; b->thing = 0; // This is either an attribute, eval, or constant lock. Constant locks // are of the form , while attribute and eval locks are of the // form : or / // respectively. The characters , |, and & terminate the string. // if (mux_isdigit(c)) { while (mux_isdigit(c = getc(f))) { b->thing = b->thing * 10 + c - '0'; } } else if (mux_AttrNameInitialSet(c)) { buff = alloc_lbuf("getboolexp1.atr_name"); for ( s = buff; (c = getc(f)) != EOF && c != '\n' && c != ':' && c != '/' && s < buff + LBUF_SIZE; *s++ = (char)c) { ; // Nothing. } if (c == EOF) { free_lbuf(buff); free_bool(b); goto error; } *s = '\0'; // Look the name up as an attribute. If not found, create a new // attribute. // anum = mkattr(GOD, buff); if (anum <= 0) { free_bool(b); free_lbuf(buff); goto error; } free_lbuf(buff); b->thing = anum; } else { free_bool(b); goto error; } // If last character is : then this is an attribute lock. A last // character of / means an eval lock. // if ( c == ':' || c == '/') { if (c == '/') { b->type = BOOLEXP_EVAL; } else { b->type = BOOLEXP_ATR; } buff = alloc_lbuf("getboolexp1.attr_lock"); for ( s = buff; (c = getc(f)) != EOF && c != '\n' && c != ')' && c != OR_TOKEN && c != AND_TOKEN && s < buff + LBUF_SIZE; *s++ = (char)c) { ; // Nothing } if (c == EOF) { goto error; } *s++ = 0; b->sub1 = (BOOLEXP *)StringClone(buff); free_lbuf(buff); } ungetc(c, f); return b; } error: // Bomb Out. // mux_assert(0); return TRUE_BOOLEXP; } /* --------------------------------------------------------------------------- * getboolexp: Read a boolean expression from the flat file. */ static BOOLEXP *getboolexp(FILE *f) { BOOLEXP *b = getboolexp1(f); int c = getc(f); mux_assert(c == '\n'); if ((c = getc(f)) != '\n') { ungetc(c, f); } return b; } int g_max_nam_atr = INT_MIN; int g_max_obj_atr = INT_MIN; /* --------------------------------------------------------------------------- * get_list: Read attribute list from flat file. */ static bool get_list(FILE *f, dbref i) { char *buff = alloc_lbuf("get_list"); for (;;) { dbref atr; int c; switch (c = getc(f)) { case '>': // read # then string atr = getref(f); if (atr > 0) { #if defined(FIRANMUX_CONVERT) switch (atr) { case A_COLOR_OLD: atr = A_COLOR; break; case A_ALEAD_OLD: atr = A_ALEAD; break; case A_EXITFORMAT_OLD: atr = A_EXITFORMAT; break; } #endif // FIRANMUX_CONVERT // Maximum attribute number across all objects. // if (g_max_obj_atr < atr) { g_max_obj_atr = atr; } // Store the attr // size_t nBuffer; const char *pBuffer; if (3 == g_version) { size_t nBufferUnicode; UTF8 *pBufferUnicode = (UTF8 *)getstring_noalloc(f, true, &nBufferUnicode); pBufferUnicode = convert_color(pBufferUnicode); pBuffer = ConvertToLatin(pBufferUnicode); nBuffer = strlen(pBuffer); } else { pBuffer = getstring_noalloc(f, true, &nBuffer); } atr_add_raw_LEN(i, atr, pBuffer, nBuffer); } else { // Silently discard // size_t nBuffer; (void)getstring_noalloc(f, true, &nBuffer); } break; case '\n': // ignore newlines. They're due to v(r). break; case '<': // end of list free_lbuf(buff); c = getc(f); if (c != '\n') { ungetc(c, f); Log.tinyprintf("No line feed on object %d" ENDLINE, i); return true; } return true; default: Log.tinyprintf("Bad character '%c' when getting attributes on object %d" ENDLINE, c, i); // We've found a bad spot. I hope things aren't too bad. // { size_t nBuffer; (void)getstring_noalloc(f, true, &nBuffer); } } } } /* --------------------------------------------------------------------------- * putbool_subexp: Write a boolean sub-expression to the flat file. */ static void putbool_subexp(FILE *f, BOOLEXP *b) { ATTR *va; switch (b->type) { case BOOLEXP_IS: putc('(', f); putc(IS_TOKEN, f); putbool_subexp(f, b->sub1); putc(')', f); break; case BOOLEXP_CARRY: putc('(', f); putc(CARRY_TOKEN, f); putbool_subexp(f, b->sub1); putc(')', f); break; case BOOLEXP_INDIR: putc('(', f); putc(INDIR_TOKEN, f); putbool_subexp(f, b->sub1); putc(')', f); break; case BOOLEXP_OWNER: putc('(', f); putc(OWNER_TOKEN, f); putbool_subexp(f, b->sub1); putc(')', f); break; case BOOLEXP_AND: putc('(', f); putbool_subexp(f, b->sub1); putc(AND_TOKEN, f); putbool_subexp(f, b->sub2); putc(')', f); break; case BOOLEXP_OR: putc('(', f); putbool_subexp(f, b->sub1); putc(OR_TOKEN, f); putbool_subexp(f, b->sub2); putc(')', f); break; case BOOLEXP_NOT: putc('(', f); putc(NOT_TOKEN, f); putbool_subexp(f, b->sub1); putc(')', f); break; case BOOLEXP_CONST: putref(f, b->thing); break; case BOOLEXP_ATR: va = atr_num(b->thing); if (va) { fprintf(f, "%s:%s", va->name, (char *)b->sub1); } else { fprintf(f, "%d:%s\n", b->thing, (char *)b->sub1); } break; case BOOLEXP_EVAL: va = atr_num(b->thing); if (va) { fprintf(f, "%s/%s\n", va->name, (char *)b->sub1); } else { fprintf(f, "%d/%s\n", b->thing, (char *)b->sub1); } break; default: Log.tinyprintf("Unknown boolean type in putbool_subexp: %d" ENDLINE, b->type); break; } } /* --------------------------------------------------------------------------- * putboolexp: Write boolean expression to the flat file. */ static void putboolexp(FILE *f, BOOLEXP *b) { if (b != TRUE_BOOLEXP) { putbool_subexp(f, b); } putc('\n', f); } dbref db_read(FILE *f, int *db_format, int *db_version, int *db_flags) { dbref i, anum; int ch; const char *tstr; int aflags; BOOLEXP *tempbool; char *buff; size_t nVisualWidth; size_t nBuffer; g_format = F_UNKNOWN; g_version = 0; g_flags = 0; g_max_nam_atr = INT_MIN; g_max_obj_atr = INT_MIN; bool header_gotten = false; bool size_gotten = false; bool nextattr_gotten = false; bool convert_values = false; bool read_attribs = true; bool read_name = true; bool read_key = true; bool read_money = true; size_t nName; bool bValid; char *pName; int iDotCounter = 0; if (mudstate.bStandAlone) { Log.WriteString("Reading "); Log.Flush(); } db_free(); for (i = 0;; i++) { if (mudstate.bStandAlone) { if (!iDotCounter) { iDotCounter = 100; fputc('.', stderr); fflush(stderr); } iDotCounter--; } ch = getc(f); switch (ch) { case '-': // Misc tag ch = getc(f); if (ch == 'R') { // Record number of players // mudstate.record_players = getref(f); if (mudconf.reset_players) { mudstate.record_players = 0; } } break; case '+': // MUX header // ch = getc(f); if (ch == 'A') { // USER-NAMED ATTRIBUTE // anum = getref(f); tstr = getstring_noalloc(f, true, &nBuffer); if (mux_isdigit(*tstr)) { aflags = 0; while (mux_isdigit(*tstr)) { aflags = (aflags * 10) + (*tstr++ - '0'); } tstr++; // skip ':' } else { aflags = mudconf.vattr_flags; } if (3 == g_version) { tstr = ConvertToLatin((UTF8 *)tstr); } pName = MakeCanonicalAttributeName(tstr, &nName, &bValid); if (bValid) { #if defined(FIRANMUX_CONVERT) { // Does this user attribute conflict with any built-in attribute names? // ATTR *a = (ATTR *)hashfindLEN(pName, nName, &mudstate.attr_name_htab); if (a) { Log.tinyprintf("Renaming conflicting user attribute, %s, to FIRAN_%s." ENDLINE, pName, pName); char *p = alloc_lbuf("db_read"); char *q = p; safe_str("FIRAN_", p, &q); safe_str(pName, p, &q); *q = '\0'; pName = MakeCanonicalAttributeName(p, &nName, &bValid); free_lbuf(p); a = vattr_find_LEN(pName, nName); if (a) { Log.tinyprintf("ERROR: Renamed user attribute, %s, already exists." ENDLINE, pName); } } } if (bValid) #endif // FIRANMUX_CONVERT { // Maximum attribute number across all names. // if (g_max_nam_atr < anum) { g_max_nam_atr = anum; } vattr_define_LEN(pName, nName, anum, aflags); } } } else if (ch == 'X') { // MUX VERSION // if (header_gotten) { Log.tinyprintf(ENDLINE "Duplicate MUX version header entry at object %d, ignored." ENDLINE, i); tstr = getstring_noalloc(f, false, &nBuffer); } else { header_gotten = true; g_format = F_MUX; g_version = getref(f); g_flags = g_version & ~V_MASK; g_version &= V_MASK; if ( g_version < MIN_SUPPORTED_VERSION || MAX_SUPPORTED_VERSION < g_version) { Log.tinyprintf(ENDLINE "Unsupported flatfile version: %d." ENDLINE, g_version); return -1; } mux_assert( ( ( 1 == g_version || 2 == g_version) && (g_flags & MANDFLAGS_V2) == MANDFLAGS_V2) || ( 3 == g_version && (g_flags & MANDFLAGS_V3) == MANDFLAGS_V3)); // Otherwise extract feature flags // if (g_flags & V_DATABASE) { if (3 == g_version) { // We'll convert the external database from UTF-8 // to Latin-1 at the end. // convert_values = true; } read_attribs = false; read_name = !(g_flags & V_ATRNAME); } read_key = !(g_flags & V_ATRKEY); read_money = !(g_flags & V_ATRMONEY); } } else if (ch == 'S') { // SIZE // if (size_gotten) { Log.tinyprintf(ENDLINE "Duplicate size entry at object %d, ignored." ENDLINE, i); tstr = getstring_noalloc(f, false, &nBuffer); } else { mudstate.min_size = getref(f); size_gotten = true; } } else if (ch == 'N') { // NEXT ATTR TO ALLOC WHEN NO FREELIST // if (nextattr_gotten) { Log.tinyprintf(ENDLINE "Duplicate next free vattr entry at object %d, ignored." ENDLINE, i); tstr = getstring_noalloc(f, false, &nBuffer); } else { mudstate.attr_next = getref(f); nextattr_gotten = true; } } else { Log.tinyprintf(ENDLINE "Unexpected character '%c' in MUX header near object #%d, ignored." ENDLINE, ch, i); tstr = getstring_noalloc(f, false, &nBuffer); } break; case '!': // MUX entry i = getref(f); db_grow(i + 1); if (read_name) { tstr = getstring_noalloc(f, true, &nBuffer); if (3 == g_version) { tstr = (char *)convert_color((UTF8 *)tstr); tstr = ConvertToLatin((UTF8 *)tstr); } buff = alloc_lbuf("dbread.s_Name"); (void)ANSI_TruncateToField(tstr, MBUF_SIZE, buff, MBUF_SIZE, &nVisualWidth, ANSI_ENDGOAL_NORMAL); s_Name(i, buff); free_lbuf(buff); s_Location(i, getref(f)); } else { s_Location(i, getref(f)); } // ZONE // int zone; zone = getref(f); if (zone < NOTHING) { zone = NOTHING; } s_Zone(i, zone); // CONTENTS and EXITS // s_Contents(i, getref(f)); s_Exits(i, getref(f)); // LINK // s_Link(i, getref(f)); // NEXT // s_Next(i, getref(f)); // LOCK // if (read_key) { tempbool = getboolexp(f); atr_add_raw(i, A_LOCK, unparse_boolexp_quiet(1, tempbool)); free_boolexp(tempbool); } // OWNER // s_Owner(i, getref(f)); // PARENT // s_Parent(i, getref(f)); // PENNIES // if (read_money) { s_PenniesDirect(i, getref(f)); } // FLAGS // s_Flags(i, FLAG_WORD1, getref(f)); s_Flags(i, FLAG_WORD2, getref(f)); s_Flags(i, FLAG_WORD3, getref(f)); // POWERS // s_Powers(i, getref(f)); s_Powers2(i, getref(f)); // ATTRIBUTES // if (read_attribs) { if (!get_list(f, i)) { Log.tinyprintf(ENDLINE "Error reading attrs for object #%d" ENDLINE, i); return -1; } } // check to see if it's a player // if (isPlayer(i)) { c_Connected(i); } break; case '*': // EOF marker tstr = getstring_noalloc(f, false, &nBuffer); if (strncmp(tstr, "**END OF DUMP***", 16)) { Log.tinyprintf(ENDLINE "Bad EOF marker at object #%d" ENDLINE, i); return -1; } else { // Attribute number warnings. // if (g_max_nam_atr < g_max_obj_atr) { Log.tinyprintf(ENDLINE "Warning: One or more attribute values are unnamed. Did you use ./Backup on a running game?"); } if (!nextattr_gotten) { Log.tinyprintf(ENDLINE "Warning: Missing +N. Adjusting."); } if (mudstate.attr_next <= g_max_nam_atr) { if (nextattr_gotten) { Log.tinyprintf(ENDLINE "Warning: +N conflicts with existing attribute names. Adjusting."); } mudstate.attr_next = g_max_nam_atr + 1; } if (mudstate.attr_next <= g_max_obj_atr) { if (nextattr_gotten) { Log.tinyprintf(ENDLINE "Warning: +N conflicts object attribute numbers. Adjusting."); } mudstate.attr_next = g_max_nam_atr + 1; } int max_atr = A_USER_START; if (max_atr < g_max_nam_atr) { max_atr = g_max_nam_atr; } if (max_atr < g_max_obj_atr) { max_atr = g_max_obj_atr; } if (max_atr + 1 < mudstate.attr_next) { if (nextattr_gotten) { Log.tinyprintf(ENDLINE "Info: +N can be safely adjusted down."); } mudstate.attr_next = max_atr + 1; } if (convert_values) { Log.WriteString("Converting external database to Latin-1 " ENDLINE); Log.Flush(); // Convert every attribute on every object in the external database. // dbref iObject; atr_push(); DO_WHOLE_DB(iObject) { char *as; for (int iAttr = atr_head(iObject, &as); iAttr; iAttr = atr_next(&as)) { if ( 0 < iAttr && iAttr <= anum_alc_top) { const UTF8 *pUnicode = (const UTF8 *)atr_get_raw(iObject, iAttr); if (NULL != pUnicode) { pUnicode = convert_color(pUnicode); const char *pLatin = ConvertToLatin(pUnicode); size_t nLatin = strlen(pLatin); atr_add_raw_LEN(iObject, iAttr, pLatin, nLatin); } } } } atr_pop(); } *db_version = g_version; *db_format = g_format; *db_flags = g_flags; if (mudstate.bStandAlone) { Log.WriteString(ENDLINE); Log.Flush(); } else { load_player_names(); } return mudstate.db_top; } case EOF: Log.tinyprintf(ENDLINE "Unexpected end of file near object #%d" ENDLINE, i); return -1; default: if (mux_isprint(ch)) { Log.tinyprintf(ENDLINE "Illegal character '%c' near object #%d" ENDLINE, ch, i); } else { Log.tinyprintf(ENDLINE "Illegal character 0x%02x near object #%d" ENDLINE, ch, i); } return -1; } } } static bool db_write_object(FILE *f, dbref i, int db_format, int flags) { UNUSED_PARAMETER(db_format); ATTR *a; char *got, *as; dbref aowner; int ca, aflags, j; BOOLEXP *tempbool; if (!(flags & V_ATRNAME)) { putstring(f, Name(i)); } putref(f, Location(i)); putref(f, Zone(i)); putref(f, Contents(i)); putref(f, Exits(i)); putref(f, Link(i)); putref(f, Next(i)); if (!(flags & V_ATRKEY)) { got = atr_get(i, A_LOCK, &aowner, &aflags); tempbool = parse_boolexp(GOD, got, true); free_lbuf(got); putboolexp(f, tempbool); if (tempbool) { free_boolexp(tempbool); } } putref(f, Owner(i)); putref(f, Parent(i)); if (!(flags & V_ATRMONEY)) { putref(f, Pennies(i)); } putref(f, Flags(i)); putref(f, Flags2(i)); putref(f, Flags3(i)); putref(f, Powers(i)); putref(f, Powers2(i)); // Write the attribute list. // if (!(flags & V_DATABASE)) { char buf[SBUF_SIZE]; buf[0] = '>'; for (ca = atr_head(i, &as); ca; ca = atr_next(&as)) { if (mudstate.bStandAlone) { j = ca; } else { a = atr_num(ca); if (!a) { continue; } j = a->number; } if (j < A_USER_START) { switch (j) { case A_NAME: if (!(flags & V_ATRNAME)) { continue; } break; case A_LOCK: if (!(flags & V_ATRKEY)) { continue; } break; case A_LIST: case A_MONEY: continue; } } // Format is: ">%d\n", j // const char *p = atr_get_raw(i, j); size_t n = mux_ltoa(j, buf+1) + 1; buf[n++] = '\n'; fwrite(buf, sizeof(char), n, f); putstring(f, p); } fwrite("<\n", sizeof(char), 2, f); } return false; } dbref db_write(FILE *f, int format, int version) { dbref i; int flags; ATTR *vp; switch (format) { case F_MUX: flags = version; break; default: Log.WriteString("Can only write MUX format." ENDLINE); return -1; } if (mudstate.bStandAlone) { Log.WriteString("Writing "); Log.Flush(); } i = mudstate.attr_next; fprintf(f, "+X%d\n+S%d\n+N%d\n", flags, mudstate.db_top, i); fprintf(f, "-R%d\n", mudstate.record_players); // Dump user-named attribute info. // char Buffer[LBUF_SIZE]; Buffer[0] = '+'; Buffer[1] = 'A'; int iAttr; for (iAttr = A_USER_START; iAttr <= anum_alc_top; iAttr++) { vp = (ATTR *) anum_get(iAttr); if ( vp != NULL && !(vp->flags & AF_DELETED)) { // Format is: "+A%d\n\"%d:%s\"\n", vp->number, vp->flags, vp->name // char *pBuffer = Buffer+2; pBuffer += mux_ltoa(vp->number, pBuffer); *pBuffer++ = '\n'; *pBuffer++ = '"'; pBuffer += mux_ltoa(vp->flags, pBuffer); *pBuffer++ = ':'; size_t nNameLength = strlen(vp->name); memcpy(pBuffer, vp->name, nNameLength); pBuffer += nNameLength; *pBuffer++ = '"'; *pBuffer++ = '\n'; fwrite(Buffer, sizeof(char), pBuffer-Buffer, f); } } int iDotCounter = 0; char buf[SBUF_SIZE]; buf[0] = '!'; DO_WHOLE_DB(i) { if (mudstate.bStandAlone) { if (!iDotCounter) { iDotCounter = 100; fputc('.', stderr); fflush(stderr); } iDotCounter--; } if (!isGarbage(i)) { // Format is: "!%d\n", i // size_t n = mux_ltoa(i, buf+1) + 1; buf[n++] = '\n'; fwrite(buf, sizeof(char), n, f); db_write_object(f, i, format, flags); } } fputs("***END OF DUMP***\n", f); if (mudstate.bStandAlone) { Log.WriteString(ENDLINE); Log.Flush(); } return mudstate.db_top; } mux2.6/src/_build.cpp0000600000175000017500000000024511025753746014541 0ustar sdennissdennis// _build.cpp // // $Id: _build.cpp 8 2006-09-05 01:55:58Z brazilofmux $ // #include "_build.h" char szBuildDate[] = __DATE__ " " __TIME__; char szBuildNum[] = "1"; mux2.6/src/file_c.h0000600000175000017500000000140511025753746014170 0ustar sdennissdennis// file_c.h -- File cache header file. // // $Id: file_c.h 8 2006-09-05 01:55:58Z brazilofmux $ // #include "copyright.h" #ifndef __FILE_C #define __FILE_C #include "interface.h" /* File caches. These _must_ track the fcache array in file_c.c */ #define FC_CONN 0 #define FC_CONN_SITE 1 #define FC_CONN_DOWN 2 #define FC_CONN_FULL 3 #define FC_CONN_GUEST 4 #define FC_CONN_REG 5 #define FC_CREA_NEW 6 #define FC_CREA_REG 7 #define FC_MOTD 8 #define FC_WIZMOTD 9 #define FC_QUIT 10 #define FC_LAST 10 /* File cache routines */ extern void fcache_rawdump(SOCKET fd, int num); extern void fcache_dump(DESC *d, int num); extern void fcache_send(dbref, int); extern void fcache_load(dbref); extern void fcache_init(void); #endif // !__FILE_C mux2.6/src/match.h0000600000175000017500000000402011025753746014037 0ustar sdennissdennis// match.h // // $Id: match.h 8 2006-09-05 01:55:58Z brazilofmux $ // #include "copyright.h" #ifndef M_MATCH_H #define M_MATCH_H typedef struct match_state MSTATE; struct match_state { int confidence; /* How confident are we? CON_xx */ int count; /* # of matches at this confidence */ int pref_type; /* The preferred object type */ bool check_keys; /* Should we test locks? */ dbref absolute_form; /* If #num, then the number */ dbref match; /* What I've found so far */ dbref player; /* Who is performing match */ char *string; /* The string to search for */ }; /* Match functions * Usage: * init_match(player, name, type); * match_this(); * match_that(); * ... * thing = match_result() */ extern void init_match(dbref, const char *, int); extern void init_match_check_keys(dbref, const char *, int); extern void match_player(void); extern void match_absolute(void); extern void match_me(void); extern void match_here(void); extern void match_possession(void); extern void match_neighbor(void); extern void match_exit(void); extern void match_exit_with_parents(void); extern void match_carried_exit(void); extern void match_carried_exit_with_parents(void); extern void match_master_exit(void); extern void match_everything(int); extern dbref match_result(void); extern dbref last_match_result(void); extern dbref match_status(dbref, dbref); extern dbref noisy_match_result(void); extern void save_match_state(MSTATE *); extern void restore_match_state(MSTATE *); extern void match_zone_exit(void); extern dbref match_thing(dbref player, char *name); extern dbref match_thing_quiet(dbref player, char *name); extern void safe_match_result(dbref it, char *buff, char **bufc); #define MAT_NO_EXITS 1 /* Don't check for exits */ #define MAT_EXIT_PARENTS 2 /* Check for exits in parents */ #define MAT_NUMERIC 4 /* Check for un-#ified dbrefs */ #define MAT_HOME 8 /* Check for 'home' */ #endif // !M_MATCH_H mux2.6/src/mail.cpp0000600000175000017500000035454011025753746014237 0ustar sdennissdennis// mail.cpp // // $Id: mail.cpp 3051 2007-12-30 06:36:17Z brazilofmux $ // // This code was taken from Kalkin's DarkZone code, which was // originally taken from PennMUSH 1.50 p10, and has been heavily modified // since being included in MUX. // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include #include "attrs.h" #include "command.h" #include "powers.h" #include "mail.h" #define SIZEOF_MALIAS 13 #define WIDTHOF_MALIASDESC 40 #define SIZEOF_MALIASDESC (WIDTHOF_MALIASDESC*2) #define MAX_MALIAS_MEMBERSHIP 100 typedef struct malias { int owner; int numrecep; char *name; char *desc; size_t desc_width; // The visual width of the Mail Alias Description. dbref list[MAX_MALIAS_MEMBERSHIP]; } malias_t; static int ma_size = 0; static int ma_top = 0; static malias_t **malias = NULL; static MAILBODY *mail_list = NULL; // Handling functions for the database of mail messages. // // mail_db_grow - We keep a database of mail text, so if we send a // message to more than one player, we won't have to duplicate the // text. // #define MAIL_FUDGE 1 static void mail_db_grow(int newtop) { if (newtop <= mudstate.mail_db_top) { return; } if (mudstate.mail_db_size <= newtop) { // We need to make the mail bag bigger. // int newsize = mudstate.mail_db_size + 100; if (newtop > newsize) { newsize = newtop; } MAILBODY *newdb = (MAILBODY *)MEMALLOC((newsize + MAIL_FUDGE) * sizeof(MAILBODY)); ISOUTOFMEMORY(newdb); if (mail_list) { mail_list -= MAIL_FUDGE; memcpy( newdb, mail_list, (mudstate.mail_db_top + MAIL_FUDGE) * sizeof(MAILBODY)); MEMFREE(mail_list); mail_list = NULL; } mail_list = newdb + MAIL_FUDGE; newdb = NULL; mudstate.mail_db_size = newsize; } // Initialize new parts of the mail bag. // for (int i = mudstate.mail_db_top; i < newtop; i++) { mail_list[i].m_nRefs = 0; mail_list[i].m_nMessage = 0; mail_list[i].m_pMessage = NULL; } mudstate.mail_db_top = newtop; } // MessageReferenceInc - Increments the reference count for any // particular message. // static DCL_INLINE void MessageReferenceInc(int number) { mail_list[number].m_nRefs++; } // MessageReferenceCheck - Checks whether the reference count for // any particular message indicates that the message body should be // freed. Also checks that if a message pointer is null, that the // reference count is zero. // static void MessageReferenceCheck(int number) { MAILBODY &m = mail_list[number]; if (m.m_nRefs <= 0) { if (m.m_pMessage) { MEMFREE(m.m_pMessage); m.m_pMessage = NULL; m.m_nMessage = 0; } } if (m.m_pMessage == NULL) { m.m_nRefs = 0; m.m_nMessage = 0; } } // MessageReferenceDec - Decrements the reference count for a message, and // will also delete the message if the counter reaches 0. // static void MessageReferenceDec(int number) { mail_list[number].m_nRefs--; MessageReferenceCheck(number); } // MessageFetch - returns the text for a particular message number. This // text should not be modified. // const char *MessageFetch(int number) { MessageReferenceCheck(number); if (mail_list[number].m_pMessage) { return mail_list[number].m_pMessage; } else { return "MAIL: This mail message does not exist in the database. Please alert your admin."; } } size_t MessageFetchSize(int number) { MessageReferenceCheck(number); if (mail_list[number].m_pMessage) { return mail_list[number].m_nMessage; } else { return 0; } } // This function returns a reference to the message and the the // reference count is increased to reflect that. // static int MessageAdd(char *pMessage) { int i; MAILBODY *pm; bool bFound = false; for (i = 0; i < mudstate.mail_db_top; i++) { pm = &mail_list[i]; if (NULL == pm->m_pMessage) { pm->m_nRefs = 0; bFound = true; break; } } if (!bFound) { mail_db_grow(i + 1); } pm = &mail_list[i]; pm->m_nMessage = strlen(pMessage); pm->m_pMessage = StringCloneLen(pMessage, pm->m_nMessage); MessageReferenceInc(i); return i; } // add_mail_message - adds a new text message to the mail database, and returns // a unique number for that message. // // IF return value is !NOTHING, you have a reference to the message, // and the reference count reflects that. // static int add_mail_message(dbref player, char *message) { if (!mux_stricmp(message, "clear")) { notify(player, "MAIL: You probably did not intend to send a @mail saying 'clear'."); return NOTHING; } // Evaluate signature. // int aflags; dbref aowner; char *bp = alloc_lbuf("add_mail_message"); char *atrstr = atr_get(player, A_SIGNATURE, &aowner, &aflags); char *execstr = bp; char *str = atrstr; mux_exec(execstr, &bp, player, player, player, AttrTrace(aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, NULL, 0); *bp = '\0'; // Save message body and return a reference to it. // int number = MessageAdd(tprintf("%s %s", message, execstr)); free_lbuf(atrstr); free_lbuf(execstr); return number; } // This function is -only- used from reading from the disk, and so // it does -not- manage the reference counts. // static bool MessageAddWithNumber(int i, char *pMessage) { mail_db_grow(i+1); MAILBODY *pm = &mail_list[i]; pm->m_nMessage = strlen(pMessage); pm->m_pMessage = StringCloneLen(pMessage, pm->m_nMessage); return true; } // new_mail_message - used for reading messages in from disk which // already have a number assigned to them. // // This function is -only- used from reading from the disk, and so // it does -not- manage the reference counts. // static void new_mail_message(char *message, int number) { bool bTruncated = false; if (strlen(message) > LBUF_SIZE-1) { bTruncated = true; message[LBUF_SIZE-1] = '\0'; } MessageAddWithNumber(number, message); if (bTruncated) { STARTLOG(LOG_BUGS, "BUG", "MAIL"); log_text(tprintf("new_mail_message: Mail message %d truncated.", number)); ENDLOG; } } /*-------------------------------------------------------------------------* * User mail functions (these are called from game.c) * * do_mail - cases * do_mail_read - read messages * do_mail_list - list messages * do_mail_flags - tagging, untagging, clearing, unclearing of messages * do_mail_file - files messages into a new folder * do_mail_fwd - forward messages to another player(s) * do_mail_reply - reply to a message * do_mail_count - count messages * do_mail_purge - purge cleared messages * do_mail_change_folder - change current folder *-------------------------------------------------------------------------*/ static void set_player_folder(dbref player, int fnum) { // Set a player's folder to fnum. // char *tbuf1 = alloc_lbuf("set_player_folder"); mux_ltoa(fnum, tbuf1); ATTR *a = atr_num(A_MAILCURF); if (a) { atr_add(player, A_MAILCURF, tbuf1, GOD, a->flags); } else { // Shouldn't happen, but... // atr_add(player, A_MAILCURF, tbuf1, GOD, AF_ODARK | AF_WIZARD | AF_NOPROG | AF_LOCK); } free_lbuf(tbuf1); } static void add_folder_name(dbref player, int fld, char *name) { // Fetch current list of folders // int aflags; size_t nFolders; dbref aowner; char *aFolders = alloc_lbuf("add_folder_name.str"); atr_get_str_LEN(aFolders, player, A_MAILFOLDERS, &aowner, &aflags, &nFolders); // Build new record ("%d:%s:%d", fld, uppercase(name), fld); // char *aNew = alloc_lbuf("add_folder_name.new"); char *q = aNew; q += mux_ltoa(fld, q); safe_chr(':', aNew, &q); char *p = name; while (*p) { safe_chr(mux_toupper(*p), aNew, &q); p++; } safe_chr(':', aNew, &q); q += mux_ltoa(fld, q); *q = '\0'; size_t nNew = q - aNew; if (nFolders != 0) { // Build pattern ("%d:", fld) // char *aPattern = alloc_lbuf("add_folder_name.pat"); q = aPattern; q += mux_ltoa(fld, q); safe_chr(':', aPattern, &q); *q = '\0'; size_t nPattern = q - aPattern; BMH_State bmhs; BMH_Prepare(&bmhs, nPattern, aPattern); for (;;) { size_t i; if (!BMH_Execute(&bmhs, &i, nPattern, aPattern, nFolders, aFolders)) { break; } // Remove old record. // q = aFolders + i; p = q + nPattern; // Eat leading spaces. // while ( aFolders < q && mux_isspace(q[-1])) { q--; } // Skip past old record and trailing spaces. // while ( *p && *p != ':') { p++; } while ( *p && !mux_isspace(*p)) { p++; } while (mux_isspace(*p)) { p++; } if (q != aFolders) { *q++ = ' '; } while (*p) { safe_chr(*p, aFolders, &q); p++; } *q = '\0'; nFolders = q - aFolders; } free_lbuf(aPattern); } if (nFolders + 1 + nNew < LBUF_SIZE) { // It will fit. Append new record. // q = aFolders + nFolders; if (nFolders) { *q++ = ' '; } memcpy(q, aNew, nNew); q += nNew; *q = '\0'; atr_add(player, A_MAILFOLDERS, aFolders, player, AF_MDARK | AF_WIZARD | AF_NOPROG | AF_LOCK); } free_lbuf(aFolders); free_lbuf(aNew); } static char *get_folder_name(dbref player, int fld) { // Get the name of the folder, or return "unnamed". // int aflags; size_t nFolders; dbref aowner; static char aFolders[LBUF_SIZE]; atr_get_str_LEN(aFolders, player, A_MAILFOLDERS, &aowner, &aflags, &nFolders); char *p; if (nFolders != 0) { char *aPattern = alloc_lbuf("get_folder_name"); p = aPattern; p += mux_ltoa(fld, p); *p++ = ':'; *p = '\0'; size_t nPattern = p - aPattern; size_t i; bool bSucceeded = BMH_StringSearch(&i, nPattern, aPattern, nFolders, aFolders); free_lbuf(aPattern); if (bSucceeded) { p = aFolders + i + nPattern; char *q = p; while ( *q && *q != ':') { q++; } *q = '\0'; return p; } } p = (char *)"unnamed"; return p; } static int get_folder_number(dbref player, char *name) { // Look up a folder name and return the corresponding folder number. // int aflags; size_t nFolders; dbref aowner; char *aFolders = alloc_lbuf("get_folder_num_str"); atr_get_str_LEN(aFolders, player, A_MAILFOLDERS, &aowner, &aflags, &nFolders); if (nFolders != 0) { char *aPattern = alloc_lbuf("get_folder_num_pat"); char *q = aPattern; safe_chr(':', aPattern, &q); char *p = name; while (*p) { safe_chr(mux_toupper(*p), aPattern, &q); p++; } safe_chr(':', aPattern, &q); *q = '\0'; size_t nPattern = q - aPattern; size_t i; bool bSucceeded = BMH_StringSearch(&i, nPattern, aPattern, nFolders, aFolders); free_lbuf(aPattern); if (bSucceeded) { p = aFolders + i + nPattern; q = p; while ( *q && !mux_isspace(*q)) { q++; } *q = '\0'; int iFolderNumber = mux_atol(p); free_lbuf(aFolders); return iFolderNumber; } } free_lbuf(aFolders); return -1; } static int parse_folder(dbref player, char *folder_string) { // Given a string, return a folder #, or -1. // if ( !folder_string || !*folder_string) { return -1; } if (mux_isdigit(*folder_string)) { int fnum = mux_atol(folder_string); if ( fnum < 0 || fnum > MAX_FOLDERS) { return -1; } else { return fnum; } } // Handle named folders here // return get_folder_number(player, folder_string); } #define MAIL_INVALID_RANGE 0 #define MAIL_INVALID_NUMBER 1 #define MAIL_INVALID_AGE 2 #define MAIL_INVALID_DBREF 3 #define MAIL_INVALID_PLAYER 4 #define MAIL_INVALID_SPEC 5 #define MAIL_INVALID_PLAYER_OR_USING_MALIAS 6 static const char *mailmsg[] = { "MAIL: Invalid message range", "MAIL: Invalid message number", "MAIL: Invalid age", "MAIL: Invalid dbref #", "MAIL: Invalid player", "MAIL: Invalid message specification", "MAIL: Invalid player or trying to send @mail to a @malias without a subject", }; static bool parse_msglist(char *msglist, struct mail_selector *ms, dbref player) { // Take a message list, and return the appropriate mail_selector setup. // For now, msglists are quite restricted. That'll change once all this // is working. Returns 0 if couldn't parse, and also notifies the player // why. // Initialize the mail selector - this matches all messages. // ms->low = 0; ms->high = 0; ms->flags = 0x0FFF | M_MSUNREAD; ms->player = 0; ms->days = -1; ms->day_comp = 0; // Now, parse the message list. // if (!msglist || !*msglist) { // All messages // return true; } char *p = msglist; while (mux_isspace(*p)) { p++; } if (*p == '\0') { return true; } if (mux_isdigit(*p)) { // Message or range. // char *q = strchr(p, '-'); if (q) { // We have a subrange, split it up and test to see if it is valid. // q++; ms->low = mux_atol(p); if (ms->low <= 0) { notify(player, mailmsg[MAIL_INVALID_RANGE]); return false; } if (*q == '\0') { // Unbounded range. // ms->high = 0; } else { ms->high = mux_atol(q); if (ms->low > ms->high) { notify(player, mailmsg[MAIL_INVALID_RANGE]); return false; } } } else { // A single message. // ms->low = ms->high = mux_atol(p); if (ms->low <= 0) { notify(player, mailmsg[MAIL_INVALID_NUMBER]); return false; } } } else { switch (mux_toupper(*p)) { case '-': // Range with no start. // p++; if (*p == '\0') { notify(player, mailmsg[MAIL_INVALID_RANGE]); return false; } ms->high = mux_atol(p); if (ms->high <= 0) { notify(player, mailmsg[MAIL_INVALID_RANGE]); return false; } break; case '~': // Exact # of days old. // p++; if (*p == '\0') { notify(player, mailmsg[MAIL_INVALID_AGE]); return false; } ms->day_comp = 0; ms->days = mux_atol(p); if (ms->days < 0) { notify(player, mailmsg[MAIL_INVALID_AGE]); return false; } break; case '<': // Less than # of days old. // p++; if (*p == '\0') { notify(player, mailmsg[MAIL_INVALID_AGE]); return false; } ms->day_comp = -1; ms->days = mux_atol(p); if (ms->days < 0) { notify(player, mailmsg[MAIL_INVALID_AGE]); return false; } break; case '>': // Greater than # of days old. // p++; if (*p == '\0') { notify(player, mailmsg[MAIL_INVALID_AGE]); return false; } ms->day_comp = 1; ms->days = mux_atol(p); if (ms->days < 0) { notify(player, mailmsg[MAIL_INVALID_AGE]); return false; } break; case '#': // From db#. // p++; if (*p == '\0') { notify(player, mailmsg[MAIL_INVALID_DBREF]); return false; } ms->player = mux_atol(p); if (!Good_obj(ms->player) || !(ms->player)) { notify(player, mailmsg[MAIL_INVALID_DBREF]); return false; } break; case '*': // From player name. // p++; if (*p == '\0') { notify(player, mailmsg[MAIL_INVALID_PLAYER]); return false; } ms->player = lookup_player(player, p, true); if (ms->player == NOTHING) { notify(player, mailmsg[MAIL_INVALID_PLAYER_OR_USING_MALIAS]); return false; } break; case 'A': // All messages, all folders // p++; switch (mux_toupper(*p)) { case '\0': notify(player, "MAIL: A isn't enough (all?)"); return false; case 'L': // All messages, all folders // p++; switch (mux_toupper(*p)) { case '\0': notify(player, "MAIL: AL isn't enough (all?)"); return false; case 'L': // All messages, all folders // p++; if (*p == '\0') { ms->flags = M_ALL; } else { notify(player, mailmsg[MAIL_INVALID_SPEC]); return false; } break; default: // Bad // notify(player, mailmsg[MAIL_INVALID_SPEC]); return false; } break; default: // Bad // notify(player, mailmsg[MAIL_INVALID_SPEC]); return false; } break; case 'U': // Urgent, Unread // p++; if (*p == '\0') { notify(player, "MAIL: U is ambiguous (urgent or unread?)"); return false; } switch (mux_toupper(*p)) { case 'R': // Urgent // ms->flags = M_URGENT; break; case 'N': // Unread // ms->flags = M_MSUNREAD; break; default: // Bad // notify(player, mailmsg[MAIL_INVALID_SPEC]); return false; } break; case 'R': // Read // ms->flags = M_ISREAD; break; case 'C': // Cleared. // ms->flags = M_CLEARED; break; case 'T': // Tagged. // ms->flags = M_TAG; break; case 'M': // Mass, me. // p++; if (*p == '\0') { notify(player, "MAIL: M is ambiguous (mass or me?)"); return false; } switch (mux_toupper(*p)) { case 'A': ms->flags = M_MASS; break; case 'E': ms->player = player; break; default: notify(player, mailmsg[MAIL_INVALID_SPEC]); return false; } break; default: // Bad news. // notify(player, mailmsg[MAIL_INVALID_SPEC]); return false; } } return true; } static int player_folder(dbref player) { // Return the player's current folder number. If they don't have one, set // it to 0. // int flags; char *atrstr = atr_pget(player, A_MAILCURF, &player, &flags); if (!*atrstr) { free_lbuf(atrstr); set_player_folder(player, 0); return 0; } int number = mux_atol(atrstr); free_lbuf(atrstr); return number; } // Change or rename a folder // static void do_mail_change_folder(dbref player, char *fld, char *newname) { int pfld; if (!fld || !*fld) { // Check mail in all folders // for (pfld = 0; pfld <= MAX_FOLDERS; pfld++) { check_mail(player, pfld, true); } pfld = player_folder(player); notify(player, tprintf("MAIL: Current folder is %d [%s].", pfld, get_folder_name(player, pfld))); return; } pfld = parse_folder(player, fld); if (pfld < 0) { notify(player, "MAIL: What folder is that?"); return; } if (newname && *newname) { // We're changing a folder name here // if (strlen(newname) > FOLDER_NAME_LEN) { notify(player, "MAIL: Folder name too long"); return; } char *p; for (p = newname; mux_isalnum(*p); p++) ; if (*p != '\0') { notify(player, "MAIL: Illegal folder name"); return; } add_folder_name(player, pfld, newname); notify(player, tprintf("MAIL: Folder %d now named '%s'", pfld, newname)); } else { // Set a new folder // set_player_folder(player, pfld); notify(player, tprintf("MAIL: Current folder set to %d [%s].", pfld, get_folder_name(player, pfld))); } } static int sign(int x) { if (x == 0) { return 0; } else if (x < 0) { return -1; } else { return 1; } } static bool mail_match(struct mail *mp, struct mail_selector ms, int num) { // Does a piece of mail match the mail_selector? // if (ms.low && num < ms.low) { return false; } if (ms.high && ms.high < num) { return false; } if (ms.player && mp->from != ms.player) { return false; } mail_flag mpflag = Read(mp) ? (mp->read | M_ALL) : (mp->read | M_ALL | M_MSUNREAD); if ((ms.flags & mpflag) == 0) { return false; } if (ms.days == -1) { return true; } // Get the time now, subtract mp->time, and compare the results with // ms.days (in manner of ms.day_comp) // CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); const char *pMailTimeStr = mp->time; CLinearTimeAbsolute ltaMail; if (ltaMail.SetString(pMailTimeStr)) { CLinearTimeDelta ltd(ltaMail, ltaNow); int iDiffDays = ltd.ReturnDays(); if (sign(iDiffDays - ms.days) == ms.day_comp) { return true; } } return false; } // Adjust the flags of a set of messages. // If negate is true, clear the flag. static void do_mail_flags(dbref player, char *msglist, mail_flag flag, bool negate) { struct mail_selector ms; if (!parse_msglist(msglist, &ms, player)) { return; } int i = 0, j = 0; int folder = player_folder(player); MailList ml(player); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if ( All(ms) || Folder(mp) == folder) { i++; if (mail_match(mp, ms, i)) { j++; if (negate) { mp->read &= ~flag; } else { mp->read |= flag; } switch (flag) { case M_TAG: notify(player, tprintf("MAIL: Msg #%d %s.", i, negate ? "untagged" : "tagged")); break; case M_CLEARED: if (Unread(mp) && !negate) { notify(player, tprintf("MAIL: Unread Msg #%d cleared! Use @mail/unclear %d to recover.", i, i)); } else { notify(player, tprintf("MAIL: Msg #%d %s.", i, negate ? "uncleared" : "cleared")); } break; case M_SAFE: notify(player, tprintf("MAIL: Msg #%d marked safe.", i)); break; } } } } if (!j) { // Ran off the end of the list without finding anything. // notify(player, "MAIL: You don't have any matching messages!"); } } static void do_mail_tag(dbref player, char *msglist) { do_mail_flags(player, msglist, M_TAG, false); } static void do_mail_safe(dbref player, char *msglist) { do_mail_flags(player, msglist, M_SAFE, false); } void do_mail_clear(dbref player, char *msglist) { do_mail_flags(player, msglist, M_CLEARED, false); } static void do_mail_untag(dbref player, char *msglist) { do_mail_flags(player, msglist, M_TAG, true); } static void do_mail_unclear(dbref player, char *msglist) { do_mail_flags(player, msglist, M_CLEARED, true); } // Change a message's folder. // static void do_mail_file(dbref player, char *msglist, char *folder) { struct mail_selector ms; if (!parse_msglist(msglist, &ms, player)) { return; } int foldernum; if ((foldernum = parse_folder(player, folder)) == -1) { notify(player, "MAIL: Invalid folder specification"); return; } int i = 0, j = 0; int origfold = player_folder(player); MailList ml(player); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if ( All(ms) || (Folder(mp) == origfold)) { i++; if (mail_match(mp, ms, i)) { j++; // Clear the folder. // mp->read &= M_FMASK; mp->read |= FolderBit(foldernum); notify(player, tprintf("MAIL: Msg %d filed in folder %d", i, foldernum)); } } } if (!j) { // Ran off the end of the list without finding anything. // notify(player, "MAIL: You don't have any matching messages!"); } } // A mail alias can be any combination of upper-case letters, lower-case // letters, and digits. No leading digits. No symbols. No ANSI. Length is // limited to SIZEOF_MALIAS-1. Case is preserved. // char *MakeCanonicalMailAlias ( char *pMailAlias, size_t *pnValidMailAlias, bool *pbValidMailAlias ) { static char Buffer[SIZEOF_MALIAS]; size_t nLeft = sizeof(Buffer)-1; char *q = Buffer; char *p = pMailAlias; if ( !p || !mux_isalpha(*p)) { *pnValidMailAlias = 0; *pbValidMailAlias = false; return NULL; } *q++ = *p++; nLeft--; while ( *p && nLeft) { if ( !mux_isalpha(*p) && !mux_isdigit(*p) && *p != '_') { break; } *q++ = *p++; nLeft--; } *q = '\0'; *pnValidMailAlias = q - Buffer; *pbValidMailAlias = true; return Buffer; } #define GMA_NOTFOUND 1 #define GMA_FOUND 2 #define GMA_INVALIDFORM 3 static malias_t *get_malias(dbref player, char *alias, int *pnResult) { *pnResult = GMA_INVALIDFORM; if (!alias) { return NULL; } if (alias[0] == '#') { if (ExpMail(player)) { int x = mux_atol(alias + 1); if (x < 0 || x >= ma_top) { *pnResult = GMA_NOTFOUND; return NULL; } *pnResult = GMA_FOUND; return malias[x]; } } else if (alias[0] == '*') { size_t nValidMailAlias; bool bValidMailAlias; char *pValidMailAlias = MakeCanonicalMailAlias ( alias+1, &nValidMailAlias, &bValidMailAlias ); if (bValidMailAlias) { for (int i = 0; i < ma_top; i++) { malias_t *m = malias[i]; if ( m->owner == player || m->owner == GOD || ExpMail(player)) { if (!strcmp(pValidMailAlias, m->name)) { // Found it! // *pnResult = GMA_FOUND; return m; } } } *pnResult = GMA_NOTFOUND; } } if (*pnResult == GMA_INVALIDFORM) { if (ExpMail(player)) { notify(player, "MAIL: Mail aliases must be of the form * or #."); } else { notify(player, "MAIL: Mail aliases must be of the form *."); } } return NULL; } static char *make_namelist(dbref player, char *arg) { UNUSED_PARAMETER(player); char *p; char *oldarg = alloc_lbuf("make_namelist.oldarg"); char *names = alloc_lbuf("make_namelist.names"); char *bp = names; mux_strncpy(oldarg, arg, LBUF_SIZE-1); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, oldarg); mux_strtok_ctl(&tts, " "); bool bFirst = true; for (p = mux_strtok_parse(&tts); p; p = mux_strtok_parse(&tts)) { if (!bFirst) { safe_str(", ", names, &bp); } bFirst = false; if ( mux_isdigit(p[0]) || ( p[0] == '!' && mux_isdigit(p[1]))) { char ch = p[0]; if (ch == '!') { p++; } dbref target = mux_atol(p); if ( Good_obj(target) && isPlayer(target)) { if (ch == '!') { safe_chr('!', names, &bp); } safe_str(Moniker(target), names, &bp); } } else { safe_str(p, names, &bp); } } *bp = '\0'; free_lbuf(oldarg); return names; } #define NUM_MAILSTATUSTABLE 7 static struct tag_mailstatusentry { int nMask; const char *pYes; int nYes; const char *pNo; int nNo; } aMailStatusTable[NUM_MAILSTATUSTABLE] = { { M_ISREAD, "Read", 4, "Unread", 6 }, { M_CLEARED, "Cleared", 7, 0, 0 }, { M_URGENT, "Urgent", 6, 0, 0 }, { M_MASS, "Mass", 4, 0, 0 }, { M_FORWARD, "Fwd", 3, 0, 0 }, { M_TAG, "Tagged", 6, 0, 0 }, { M_SAFE, "Safe", 4, 0, 0 } }; static char *status_string(struct mail *mp) { // Return a longer description of message flags. // char *tbuf1 = alloc_lbuf("status_string"); char *p = tbuf1; struct tag_mailstatusentry *mse = aMailStatusTable; for (int i = 0; i < NUM_MAILSTATUSTABLE; i++, mse++) { if (mp->read & mse->nMask) { if (p != tbuf1) *p++ = ' '; memcpy(p, mse->pYes, mse->nYes); p += mse->nYes; } else if (mse->pNo) { if (p != tbuf1) *p++ = ' '; memcpy(p, mse->pNo, mse->nNo); p += mse->nNo; } } *p++ = '\0'; return tbuf1; } static void GetFromField(dbref target, char szFrom[MBUF_SIZE]) { size_t vw = 0; size_t nFrom = ANSI_TruncateToField(Moniker(target), sizeof(szFrom)-16, szFrom, 16, &vw, ANSI_ENDGOAL_NORMAL); while ( vw < 16 && nFrom < MBUF_SIZE) { szFrom[nFrom] = ' '; nFrom++; vw++; } szFrom[nFrom] = '\0'; } static void do_mail_read(dbref player, char *msglist) { struct mail_selector ms; if (!parse_msglist(msglist, &ms, player)) { return; } char *status, *names; int i = 0, j = 0; char *buff = alloc_lbuf("do_mail_read.1"); int folder = player_folder(player); MailList ml(player); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (Folder(mp) == folder) { i++; if (mail_match(mp, ms, i)) { // Read it. // j++; char *bp = buff; safe_str(MessageFetch(mp->number), buff, &bp); *bp = '\0'; notify(player, DASH_LINE); status = status_string(mp); names = make_namelist(player, mp->tolist); char szFromName[MBUF_SIZE]; GetFromField(mp->from, szFromName); char szSubjectBuffer[MBUF_SIZE]; size_t iRealVisibleWidth; ANSI_TruncateToField(mp->subject, sizeof(szSubjectBuffer), szSubjectBuffer, 65, &iRealVisibleWidth, ANSI_ENDGOAL_NORMAL); notify(player, tprintf("%-3d From: %s At: %-25s %s\r\nFldr : %-2d Status: %s\r\nTo : %-65s\r\nSubject: %s", i, szFromName, mp->time, (Connected(mp->from) && (!Hidden(mp->from) || See_Hidden(player))) ? " (Conn)" : " ", folder, status, names, szSubjectBuffer)); free_lbuf(names); free_lbuf(status); notify(player, DASH_LINE); notify(player, buff); notify(player, DASH_LINE); if (Unread(mp)) { // Mark message as read. // mp->read |= M_ISREAD; } } } } free_lbuf(buff); if (!j) { // Ran off the end of the list without finding anything. // notify(player, "MAIL: You don't have that many matching messages!"); } } static char *status_chars(struct mail *mp) { // Return a short description of message flags. // static char res[10]; char *p = res; *p++ = Read(mp) ? '-' : 'N'; *p++ = M_Safe(mp) ? 'S' : '-'; *p++ = Cleared(mp) ? 'C' : '-'; *p++ = Urgent(mp) ? 'U' : '-'; *p++ = Mass(mp) ? 'M' : '-'; *p++ = Forward(mp) ? 'F' : '-'; *p++ = Tagged(mp) ? '+' : '-'; *p = '\0'; return res; } static void do_mail_review(dbref player, char *name, char *msglist) { dbref target = lookup_player(player, name, true); if (target == NOTHING) { notify(player, "MAIL: No such player."); return; } struct mail *mp; struct mail_selector ms; int i = 0, j = 0; size_t iRealVisibleWidth; char szSubjectBuffer[MBUF_SIZE]; if ( !msglist || !*msglist) { notify(player, tprintf("-------------------- MAIL: %-25s ------------------", Moniker(target))); MailList ml(target); for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (mp->from == player) { i++; char szFromName[MBUF_SIZE]; GetFromField(mp->from, szFromName); ANSI_TruncateToField(mp->subject, sizeof(szSubjectBuffer), szSubjectBuffer, 25, &iRealVisibleWidth, ANSI_ENDGOAL_NORMAL); size_t nSize = MessageFetchSize(mp->number); notify(player, tprintf("[%s] %-3d (%4d) From: %s Sub: %s", status_chars(mp), i, nSize, szFromName, szSubjectBuffer)); } } notify(player, DASH_LINE); } else { if (!parse_msglist(msglist, &ms, target)) { return; } MailList ml(target); for (mp = ml.FirstItem(); !ml.IsEnd() && !MuxAlarm.bAlarmed; mp = ml.NextItem()) { if (mp->from == player) { i++; if (mail_match(mp, ms, i)) { j++; char *status = status_string(mp); const char *str = MessageFetch(mp->number); char szFromName[MBUF_SIZE]; GetFromField(mp->from, szFromName); ANSI_TruncateToField(mp->subject, sizeof(szSubjectBuffer), szSubjectBuffer, 65, &iRealVisibleWidth, ANSI_ENDGOAL_NORMAL); notify(player, DASH_LINE); notify(player, tprintf("%-3d From: %s At: %-25s %s\r\nFldr : %-2d Status: %s\r\nSubject: %s", i, szFromName, mp->time, (Connected(mp->from) && (!Hidden(mp->from) || See_Hidden(player))) ? " (Conn)" : " ", 0, status, szSubjectBuffer)); free_lbuf(status); notify(player, DASH_LINE); notify(player, str); notify(player, DASH_LINE); } } } if (!j) { // Ran off the end of the list without finding anything. // notify(player, "MAIL: You don't have that many matching messages!"); } } } static char *mail_list_time(const char *the_time) { char *p = (char *)the_time; char *new0 = alloc_lbuf("mail_list_time"); char *q = new0; if (!p || !*p) { *new0 = '\0'; return new0; } // Format of the_time is: day mon dd hh:mm:ss yyyy // Chop out :ss // int i; for (i = 0; i < 16; i++) { if (*p) { *q++ = *p++; } } for (i = 0; i < 3; i++) { if (*p) { p++; } } for (i = 0; i < 5; i++) { if (*p) { *q++ = *p++; } } *q = '\0'; return new0; } static void do_mail_list(dbref player, char *msglist, bool sub) { struct mail_selector ms; if (!parse_msglist(msglist, &ms, player)) { return; } int i = 0; char *time; size_t iRealVisibleWidth; char szSubjectBuffer[MBUF_SIZE]; int folder = player_folder(player); notify(player, tprintf("--------------------------- MAIL: Folder %d ----------------------------", folder)); MailList ml(player); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (Folder(mp) == folder) { i++; if (mail_match(mp, ms, i)) { time = mail_list_time(mp->time); size_t nSize = MessageFetchSize(mp->number); char szFromName[MBUF_SIZE]; GetFromField(mp->from, szFromName); if (sub) { ANSI_TruncateToField(mp->subject, sizeof(szSubjectBuffer), szSubjectBuffer, 25, &iRealVisibleWidth, ANSI_ENDGOAL_NORMAL); notify(player, tprintf("[%s] %-3d (%4d) From: %s Sub: %s", status_chars(mp), i, nSize, szFromName, szSubjectBuffer)); } else { notify(player, tprintf("[%s] %-3d (%4d) From: %s At: %s %s", status_chars(mp), i, nSize, szFromName, time, ((Connected(mp->from) && (!Hidden(mp->from) || See_Hidden(player))) ? "Conn" : " "))); } free_lbuf(time); } } } notify(player, DASH_LINE); } void do_mail_purge(dbref player) { // Go through player's mail, and remove anything marked cleared. // MailList ml(player); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (Cleared(mp)) { ml.RemoveItem(); } } notify(player, "MAIL: Mailbox purged."); } static char *make_numlist(dbref player, char *arg, bool bBlind) { char *tail, spot; malias_t *m; dbref target; int nRecip = 0; dbref aRecip[(LBUF_SIZE+1)/2]; char *head = arg; while ( head && *head) { while (*head == ' ') { head++; } tail = head; while ( *tail && *tail != ' ') { if (*tail == '"') { head++; tail++; while ( *tail && *tail != '"') { tail++; } } if (*tail) { tail++; } } tail--; if (*tail != '"') { tail++; } spot = *tail; *tail = '\0'; if (*head == '*') { int nResult; m = get_malias(player, head, &nResult); if (nResult == GMA_NOTFOUND) { notify(player, tprintf("MAIL: Alias '%s' does not exist.", head)); return NULL; } else if (nResult == GMA_INVALIDFORM) { notify(player, tprintf("MAIL: '%s' is a badly-formed alias.", head)); return NULL; } for (int i = 0; i < m->numrecep; i++) { aRecip[nRecip++] = m->list[i]; } } else { target = lookup_player(player, head, true); if (Good_obj(target)) { aRecip[nRecip++] = target; } else { notify(player, tprintf("MAIL: '%s' does not exist.", head)); return NULL; } } // Get the next recip. // *tail = spot; head = tail; if (*head == '"') { head++; } } if (nRecip <= 0) { notify(player, "MAIL: No players specified."); return NULL; } else { ITL itl; char *numbuf, *numbp; numbp = numbuf = alloc_lbuf("mail.make_numlist"); ItemToList_Init(&itl, numbuf, &numbp, bBlind ? '!' : '\0'); int i; for (i = 0; i < nRecip; i++) { if (aRecip[i] != NOTHING) { for (int j = i + 1; j < nRecip; j++) { if (aRecip[i] == aRecip[j]) { aRecip[j] = NOTHING; } } if (Good_obj(aRecip[i])) { ItemToList_AddInteger(&itl, aRecip[i]); } } } ItemToList_Final(&itl); return numbuf; } } static void do_expmail_start(dbref player, char *arg, char *subject) { if (!arg || !*arg) { notify(player, "MAIL: I do not know whom you want to mail."); return; } if (!subject || !*subject) { notify(player, "MAIL: No subject."); return; } if (Flags2(player) & PLAYER_MAILS) { notify(player, "MAIL: Mail message already in progress."); return; } if ( !Wizard(player) && ThrottleMail(player)) { notify(player, "MAIL: Too much @mail sent recently."); return; } char *tolist = make_numlist(player, arg, false); if (!tolist) { return; } atr_add_raw(player, A_MAILTO, tolist); atr_add_raw(player, A_MAILSUB, subject); atr_add_raw(player, A_MAILFLAGS, "0"); atr_clr(player, A_MAILMSG); Flags2(player) |= PLAYER_MAILS; char *names = make_namelist(player, tolist); notify(player, tprintf("MAIL: You are sending mail to '%s'.", names)); free_lbuf(names); free_lbuf(tolist); } static void do_mail_fwd(dbref player, char *msg, char *tolist) { if (Flags2(player) & PLAYER_MAILS) { notify(player, "MAIL: Mail message already in progress."); return; } if (!msg || !*msg) { notify(player, "MAIL: No message list."); return; } if (!tolist || !*tolist) { notify(player, "MAIL: To whom should I forward?"); return; } if ( !Wizard(player) && ThrottleMail(player)) { notify(player, "MAIL: Too much @mail sent recently."); return; } int num = mux_atol(msg); if (!num) { notify(player, "MAIL: I don't understand that message number."); return; } struct mail *mp = mail_fetch(player, num); if (!mp) { notify(player, "MAIL: You can't forward non-existent messages."); return; } do_expmail_start(player, tolist, tprintf("%s (fwd from %s)", mp->subject, Moniker(mp->from))); atr_add_raw(player, A_MAILMSG, MessageFetch(mp->number)); const char *pValue = atr_get_raw(player, A_MAILFLAGS); int iFlag = M_FORWARD; if (pValue) { iFlag |= mux_atol(pValue); } atr_add_raw(player, A_MAILFLAGS, mux_ltoa_t(iFlag)); } static void do_mail_reply(dbref player, char *msg, bool all, int key) { if (Flags2(player) & PLAYER_MAILS) { notify(player, "MAIL: Mail message already in progress."); return; } if (!msg || !*msg) { notify(player, "MAIL: No message list."); return; } if ( !Wizard(player) && ThrottleMail(player)) { notify(player, "MAIL: Too much @mail sent recently."); return; } int num = mux_atol(msg); if (!num) { notify(player, "MAIL: I don't understand that message number."); return; } struct mail *mp = mail_fetch(player, num); if (!mp) { notify(player, "MAIL: You can't reply to non-existent messages."); return; } char *tolist = alloc_lbuf("do_mail_reply.tolist"); char *bp = tolist; if (all) { char *names = alloc_lbuf("do_mail_reply.names"); char *oldlist = alloc_lbuf("do_mail_reply.oldlist"); bp = names; *bp = '\0'; mux_strncpy(oldlist, mp->tolist, LBUF_SIZE-1); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, oldlist); mux_strtok_ctl(&tts, " "); char *p; for (p = mux_strtok_parse(&tts); p; p = mux_strtok_parse(&tts)) { if (mux_atol(p) != mp->from) { safe_chr('#', names, &bp); safe_str(p, names, &bp); safe_chr(' ', names, &bp); } } free_lbuf(oldlist); safe_chr('#', names, &bp); safe_ltoa(mp->from, names, &bp); *bp = '\0'; mux_strncpy(tolist, names, LBUF_SIZE-1); free_lbuf(names); } else { safe_chr('#', tolist, &bp); safe_ltoa(mp->from, tolist, &bp); *bp = '\0'; } const char *pSubject = mp->subject; const char *pMessage = MessageFetch(mp->number); const char *pTime = mp->time; if (strncmp(pSubject, "Re:", 3)) { do_expmail_start(player, tolist, tprintf("Re: %s", pSubject)); } else { do_expmail_start(player, tolist, tprintf("%s", pSubject)); } if (key & MAIL_QUOTE) { const char *pFromName = Moniker(mp->from); char *pMessageBody = tprintf("On %s, %s wrote:\r\n\r\n%s\r\n\r\n********** End of included message from %s\r\n", pTime, pFromName, pMessage, pFromName); atr_add_raw(player, A_MAILMSG, pMessageBody); } // The following combination of atr_get_raw() with atr_add_raw() is OK // because we are not passing a pointer to atr_add_raw() that came // directly from atr_get_raw(). // const char *pValue = atr_get_raw(player, A_MAILFLAGS); int iFlag = M_REPLY; if (pValue) { iFlag |= mux_atol(pValue); } atr_add_raw(player, A_MAILFLAGS, mux_ltoa_t(iFlag)); free_lbuf(tolist); } /*-------------------------------------------------------------------------* * Admin mail functions * * do_mail_nuke - clear & purge mail for a player, or all mail in db. * do_mail_stat - stats on mail for a player, or for all db. * do_mail_debug - fix mail with a sledgehammer *-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------* * Basic mail functions *-------------------------------------------------------------------------*/ struct mail *mail_fetch(dbref player, int num) { int i = 0; MailList ml(player); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (Folder(mp) == player_folder(player)) { i++; if (i == num) { return mp; } } } return NULL; } const char *mail_fetch_message(dbref player, int num) { struct mail *mp = mail_fetch(player, num); if (mp) { return MessageFetch(mp->number); } return NULL; } int mail_fetch_from(dbref player, int num) { struct mail *mp = mail_fetch(player, num); if (mp) { return mp->from; } return NOTHING; } // Returns count of read, unread, and cleared messages as rcount, ucount, ccount. // void count_mail(dbref player, int folder, int *rcount, int *ucount, int *ccount) { int rc = 0; int uc = 0; int cc = 0; MailList ml(player); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (Folder(mp) == folder) { if (Read(mp)) { rc++; } else { uc++; } if (Cleared(mp)) { cc++; } } } *rcount = rc; *ucount = uc; *ccount = cc; } static void urgent_mail(dbref player, int folder, int *ucount) { int uc = 0; MailList ml(player); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (Folder(mp) == folder) { if (Unread(mp) && Urgent(mp)) { uc++; } } } *ucount = uc; } static void mail_return(dbref player, dbref target) { dbref aowner; int aflags; char *str = atr_pget(target, A_MFAIL, &aowner, &aflags); if (*str) { char *str2, *buf, *bp; str2 = bp = alloc_lbuf("mail_return"); buf = str; mux_exec(str2, &bp, target, player, player, AttrTrace(aflags, EV_FCHECK|EV_EVAL|EV_TOP|EV_NO_LOCATION), &buf, NULL, 0); *bp = '\0'; if (*str2) { CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); FIELDEDTIME ft; ltaNow.ReturnFields(&ft); notify_with_cause_ooc(player, target, tprintf("MAIL: Reject message from %s: %s", Moniker(target), str2)); notify_with_cause_ooc(target, player, tprintf("[%d:%02d] MAIL: Reject message sent to %s.", ft.iHour, ft.iMinute, Moniker(player))); } free_lbuf(str2); } else { notify_with_cause_ooc(player, target, tprintf("Sorry, %s is not accepting mail.", Moniker(target))); } free_lbuf(str); } static bool mail_check(dbref player, dbref target) { if (!could_doit(player, target, A_LMAIL)) { mail_return(player, target); } else if (!could_doit(target, player, A_LMAIL)) { if (Wizard(player)) { notify(player, tprintf("Warning: %s can't return your mail.", Moniker(target))); return true; } else { notify(player, tprintf("Sorry, %s can't return your mail.", Moniker(target))); return false; } } else { return true; } return false; } static void send_mail ( dbref player, dbref target, const char *tolist, const char *subject, int number, mail_flag flags, bool silent ) { if (!isPlayer(target)) { notify(player, "MAIL: You cannot send mail to non-existent people."); return; } if (!mail_check(player, target)) { return; } CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); char *pTimeStr = ltaNow.ReturnDateString(0); // Initialize the appropriate fields. // struct mail *newp = NULL; try { newp = new struct mail; } catch (...) { ; // Nothing. } if (NULL == newp) { notify(player, "MAIL: Out of memory."); return; } newp->to = target; // HACK: Allow @mail/quick, if player is an object, then the // object's owner is the sender, if the owner is a wizard, then // we allow the object to be the sender. // if (isPlayer(player)) { newp->from = player; } else { dbref mailbag = Owner(player); if (Wizard(mailbag)) { newp->from = player; } else { newp->from = mailbag; } } if ( !tolist || tolist[0] == '\0') { newp->tolist = StringClone("*HIDDEN*"); } else { newp->tolist = StringClone(tolist); } newp->number = number; MessageReferenceInc(number); newp->time = StringClone(pTimeStr); newp->subject = StringClone(subject); // Send to folder 0 // newp->read = flags & M_FMASK; // If this is the first message, it is the head and the tail. // MailList ml(target); ml.AppendItem(newp); // Notify people. // if (!silent) { notify(player, tprintf("MAIL: You sent your message to %s.", Moniker(target))); } notify(target, tprintf("MAIL: You have a new message from %s.", Moniker(player))); did_it(player, target, A_MAIL, NULL, 0, NULL, A_AMAIL, 0, NULL, NOTHING); } static void do_mail_nuke(dbref player) { if (!God(player)) { notify(player, "The postal service issues a warrant for your arrest."); return; } // Walk the list. // dbref thing; DO_WHOLE_DB(thing) { MailList ml(thing); ml.RemoveAll(); } log_text(tprintf("** MAIL PURGE ** done by %s(#%d)." ENDLINE, Moniker(player), player)); notify(player, "You annihilate the post office. All messages cleared."); } static void do_mail_debug(dbref player, char *action, char *victim) { if (!ExpMail(player)) { notify(player, "Go get some bugspray."); return; } dbref thing; if (string_prefix("clear", action)) { dbref target = lookup_player(player, victim, true); if (target == NOTHING) { init_match(player, victim, NOTYPE); match_absolute(); target = match_result(); } if (target == NOTHING) { notify(player, tprintf("%s: no such player.", victim)); return; } if (Wizard(target)) { notify(player, tprintf("Let %s clear their own @mail.", Moniker(target))); return; } do_mail_clear(target, NULL); do_mail_purge(target); notify(player, tprintf("Mail cleared for %s(#%d).", Moniker(target), target)); return; } else if (string_prefix("sanity", action)) { int *ai = NULL; try { ai = new int[mudstate.mail_db_top]; } catch (...) { ; // Nothing. } if (NULL == ai) { notify(player, "Out of memory."); return; } memset(ai, 0, mudstate.mail_db_top * sizeof(int)); DO_WHOLE_DB(thing) { MailList ml(thing); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { bool bGoodReference; if (0 <= mp->number && mp->number < mudstate.mail_db_top) { ai[mp->number]++; bGoodReference = true; } else { bGoodReference = false; } if (!Good_obj(mp->to)) { if (bGoodReference) { notify(player, tprintf("Bad object #%d has mail.", mp->to)); } else { notify(player, tprintf("Bad object #%d has mail which refers to a non-existent mailbag item.", mp->to)); } } else if (!isPlayer(mp->to)) { if (bGoodReference) { notify(player, tprintf("%s(#%d) has mail, but is not a player.", Moniker(mp->to), mp->to)); } else { notify(player, tprintf("%s(#%d) is not a player, but has mail which refers to a non-existent mailbag item.", Moniker(mp->to), mp->to)); } } else if (!bGoodReference) { notify(player, tprintf("%s(#%d) has mail which refers to a non-existent mailbag item.", Moniker(mp->to), mp->to)); } } } // Check ref counts. // if (mail_list) { int i; int nCountHigher = 0; int nCountLower = 0; for (i = 0; i < mudstate.mail_db_top; i++) { if (mail_list[i].m_nRefs < ai[i]) { nCountLower++; } else if (mail_list[i].m_nRefs > ai[i]) { nCountHigher++; } } if (nCountLower) { notify(player, "Some mailbag items are referred to more often than the mailbag item indicates."); } if (nCountHigher) { notify(player, "Some mailbag items are referred to less often than the mailbag item indicates."); } } delete [] ai; ai = NULL; notify(player, "Mail sanity check completed."); } else if (string_prefix("fix", action)) { // First, we should fixup the reference counts. // if (mail_list) { notify(player, tprintf("Re-counting mailbag reference counts.")); int *ai = NULL; try { ai = new int[mudstate.mail_db_top]; } catch (...) { ; // Nothing. } if (NULL == ai) { notify(player, "Out of memory."); return; } memset(ai, 0, mudstate.mail_db_top * sizeof(int)); DO_WHOLE_DB(thing) { MailList ml(thing); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if ( 0 <= mp->number && mp->number < mudstate.mail_db_top) { ai[mp->number]++; } else { mp->number = NOTHING; } } } int i; int nCountWrong = 0; for (i = 0; i < mudstate.mail_db_top; i++) { if (mail_list[i].m_nRefs != ai[i]) { mail_list[i].m_nRefs = ai[i]; nCountWrong++; } } if (nCountWrong) { notify(player, "Some reference counts were wrong [FIXED]."); } delete [] ai; ai = NULL; } notify(player, tprintf("Removing @mail that is associated with non-players.")); // Now, remove all mail to non-good or non-players, or mail that // points to non-existent mailbag items. // DO_WHOLE_DB(thing) { MailList ml(thing); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if ( !Good_obj(mp->to) || !isPlayer(mp->to) || NOTHING == mp->number) { // Delete this item. // notify(player, tprintf("Fixing mail for #%d.", mp->to)); ml.RemoveItem(); } } } notify(player, "Mail sanity fix completed."); } else { notify(player, "That is not a debugging option."); return; } } static void do_mail_stats(dbref player, char *name, int full) { dbref target, thing; int fc, fr, fu, tc, tr, tu, count; size_t cchars = 0; size_t fchars = 0; size_t tchars = 0; fc = fr = fu = tc = tr = tu = count = 0; // Find player. // if ( !name || *name == '\0') { if (Wizard(player)) { target = AMBIGUOUS; } else { target = player; } } else if (*name == NUMBER_TOKEN) { target = mux_atol(&name[1]); if (!Good_obj(target) || !isPlayer(target)) { target = NOTHING; } } else if (!mux_stricmp(name, "me")) { target = player; } else { target = lookup_player(player, name, true); } if (target == NOTHING) { init_match(player, name, NOTYPE); match_absolute(); target = match_result(); } if (target == NOTHING) { notify(player, tprintf("%s: No such player.", name)); return; } if (!ExpMail(player) && (target != player)) { notify(player, "The post office protects privacy!"); return; } // This comand is computationally expensive. // if (!payfor(player, mudconf.searchcost)) { notify(player, tprintf("Finding mail stats costs %d %s.", mudconf.searchcost, (mudconf.searchcost == 1) ? mudconf.one_coin : mudconf.many_coins)); return; } if (AMBIGUOUS == target) { // Stats for all. // if (full == 0) { DO_WHOLE_DB(thing) { MailList ml(thing); for ((void)ml.FirstItem(); !ml.IsEnd(); (void)ml.NextItem()) { count++; } } notify(player, tprintf("There are %d messages in the mail spool.", count)); return; } else if (full == 1) { DO_WHOLE_DB(thing) { MailList ml(thing); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (Cleared(mp)) { fc++; } else if (Read(mp)) { fr++; } else { fu++; } } } notify(player, tprintf("MAIL: There are %d msgs in the mail spool, %d unread, %d cleared.", fc + fr + fu, fu, fc)); return; } else { DO_WHOLE_DB(thing) { MailList ml(thing); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (Cleared(mp)) { fc++; cchars += MessageFetchSize(mp->number) + 1; } else if (Read(mp)) { fr++; fchars += MessageFetchSize(mp->number) + 1; } else { fu++; tchars += MessageFetchSize(mp->number) + 1; } } } notify(player, tprintf("MAIL: There are %d old msgs in the mail spool, totalling %d characters.", fr, fchars)); notify(player, tprintf("MAIL: There are %d new msgs in the mail spool, totalling %d characters.", fu, tchars)); notify(player, tprintf("MAIL: There are %d cleared msgs in the mail spool, totalling %d characters.", fc, cchars)); return; } } // individual stats // if (full == 0) { // Just count the number of messages. // DO_WHOLE_DB(thing) { MailList ml(thing); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (mp->from == target) { fr++; } if (mp->to == target) { tr++; } } } notify(player, tprintf("%s sent %d messages.", Moniker(target), fr)); notify(player, tprintf("%s has %d messages.", Moniker(target), tr)); return; } // More detailed message count. // char last[50]; DO_WHOLE_DB(thing) { MailList ml(thing); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (mp->from == target) { if (Cleared(mp)) { fc++; } else if (Read(mp)) { fr++; } else { fu++; } if (full == 2) { fchars += MessageFetchSize(mp->number) + 1; } } if (mp->to == target) { if (!tr && !tu) { mux_strncpy(last, mp->time, 49); } if (Cleared(mp)) { tc++; } else if (Read(mp)) { tr++; } else { tu++; } if (full == 2) { tchars += MessageFetchSize(mp->number) + 1; } } } } notify(player, tprintf("Mail statistics for %s:", Moniker(target))); if (full == 1) { notify(player, tprintf("%d messages sent, %d unread, %d cleared.", fc + fr + fu, fu, fc)); notify(player, tprintf("%d messages received, %d unread, %d cleared.", tc + tr + tu, tu, tc)); } else { notify(player, tprintf("%d messages sent, %d unread, %d cleared, totalling %d characters.", fc + fr + fu, fu, fc, fchars)); notify(player, tprintf("%d messages received, %d unread, %d cleared, totalling %d characters.", tc + tr + tu, tu, tc, tchars)); } if (tc + tr + tu > 0) { notify(player, tprintf("Last is dated %s", last)); } } /*-------------------------------------------------------------------------* * Main mail routine for @mail w/o a switch *-------------------------------------------------------------------------*/ static void do_mail_stub(dbref player, char *arg1, char *arg2) { if (!arg1 || !*arg1) { if (arg2 && *arg2) { notify(player, "MAIL: Invalid mail command."); return; } // Just the "@mail" command. // do_mail_list(player, arg1, true); return; } // purge a player's mailbox // if (!mux_stricmp(arg1, "purge")) { do_mail_purge(player); return; } // clear message // if (!mux_stricmp(arg1, "clear")) { do_mail_clear(player, arg2); return; } if (!mux_stricmp(arg1, "unclear")) { do_mail_unclear(player, arg2); return; } if (arg2 && *arg2) { // Sending mail // do_expmail_start(player, arg1, arg2); return; } else { // Must be reading or listing mail - no arg2 // if ( mux_isdigit(*arg1) && !strchr(arg1, '-')) { do_mail_read(player, arg1); } else { do_mail_list(player, arg1, true); } return; } } static void malias_write(FILE *fp) { int i, j; malias_t *m; putref(fp, ma_top); for (i = 0; i < ma_top; i++) { m = malias[i]; fprintf(fp, "%d %d\n", m->owner, m->numrecep); fprintf(fp, "N:%s\n", m->name); fprintf(fp, "D:%s\n", m->desc); for (j = 0; j < m->numrecep; j++) { putref(fp, m->list[j]); } } } static void save_malias(FILE *fp) { fprintf(fp, "*** Begin MALIAS ***\n"); malias_write(fp); } int dump_mail(FILE *fp) { dbref thing; int count = 0, i; // Write out version number // fprintf(fp, "+V5\n"); putref(fp, mudstate.mail_db_top); DO_WHOLE_DB(thing) { if (isPlayer(thing)) { MailList ml(thing); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { putref(fp, mp->to); putref(fp, mp->from); putref(fp, mp->number); putstring(fp, mp->tolist); putstring(fp, mp->time); putstring(fp, mp->subject); putref(fp, mp->read); count++; } } } fprintf(fp, "*** END OF DUMP ***\n"); // Add the db of mail messages // for (i = 0; i < mudstate.mail_db_top; i++) { if (0 < mail_list[i].m_nRefs) { putref(fp, i); putstring(fp, MessageFetch(i)); } } fprintf(fp, "+++ END OF DUMP +++\n"); save_malias(fp); return count; } static void load_mail_V6(FILE *fp) { int mail_top = getref(fp); mail_db_grow(mail_top + 1); size_t nBuffer; char *pBuffer; char nbuf1[8]; char *p = fgets(nbuf1, sizeof(nbuf1), fp); while ( p && strncmp(nbuf1, "***", 3) != 0) { struct mail *mp = NULL; try { mp = new struct mail; } catch (...) { ; // Nothing. } if (NULL == mp) { STARTLOG(LOG_BUGS, "BUG", "MAIL"); log_text("Out of memory."); ENDLOG; return; } mp->to = mux_atol(nbuf1); mp->from = getref(fp); mp->number = getref(fp); MessageReferenceInc(mp->number); pBuffer = getstring_noalloc(fp, true, &nBuffer); pBuffer = (char *)convert_color((UTF8 *)pBuffer); pBuffer = ConvertToLatin((UTF8 *)pBuffer); nBuffer = strlen(pBuffer); mp->tolist = StringCloneLen(pBuffer, nBuffer); pBuffer = getstring_noalloc(fp, true, &nBuffer); pBuffer = (char *)convert_color((UTF8 *)pBuffer); pBuffer = ConvertToLatin((UTF8 *)pBuffer); nBuffer = strlen(pBuffer); mp->time = StringCloneLen(pBuffer, nBuffer); pBuffer = getstring_noalloc(fp, true, &nBuffer); pBuffer = (char *)convert_color((UTF8 *)pBuffer); pBuffer = ConvertToLatin((UTF8 *)pBuffer); nBuffer = strlen(pBuffer); mp->subject = StringCloneLen(pBuffer, nBuffer); mp->read = getref(fp); MailList ml(mp->to); ml.AppendItem(mp); p = fgets(nbuf1, sizeof(nbuf1), fp); } p = fgets(nbuf1, sizeof(nbuf1), fp); while ( p && strncmp(nbuf1, "+++", 3)) { int number = mux_atol(nbuf1); pBuffer = getstring_noalloc(fp, true, &nBuffer); pBuffer = (char *)convert_color((UTF8 *)pBuffer); pBuffer = ConvertToLatin((UTF8 *)pBuffer); nBuffer = strlen(pBuffer); new_mail_message(pBuffer, number); p = fgets(nbuf1, sizeof(nbuf1), fp); } } static void load_mail_V5(FILE *fp) { int mail_top = getref(fp); mail_db_grow(mail_top + 1); size_t nBuffer; char *pBuffer; char nbuf1[8]; char *p = fgets(nbuf1, sizeof(nbuf1), fp); while ( p && strncmp(nbuf1, "***", 3) != 0) { struct mail *mp = NULL; try { mp = new struct mail; } catch (...) { ; // Nothing. } if (NULL == mp) { STARTLOG(LOG_BUGS, "BUG", "MAIL"); log_text("Out of memory."); ENDLOG; return; } mp->to = mux_atol(nbuf1); mp->from = getref(fp); mp->number = getref(fp); MessageReferenceInc(mp->number); pBuffer = getstring_noalloc(fp, true, &nBuffer); mp->tolist = StringCloneLen(pBuffer, nBuffer); pBuffer = getstring_noalloc(fp, true, &nBuffer); mp->time = StringCloneLen(pBuffer, nBuffer); pBuffer = getstring_noalloc(fp, true, &nBuffer); mp->subject = StringCloneLen(pBuffer, nBuffer); mp->read = getref(fp); MailList ml(mp->to); ml.AppendItem(mp); p = fgets(nbuf1, sizeof(nbuf1), fp); } p = fgets(nbuf1, sizeof(nbuf1), fp); while (p && strncmp(nbuf1, "+++", 3)) { int number = mux_atol(nbuf1); pBuffer = getstring_noalloc(fp, true, &nBuffer); new_mail_message(pBuffer, number); p = fgets(nbuf1, sizeof(nbuf1), fp); } } // A mail alias description can be any combination of upper-case letters, // lower-case letters, digits, blanks, and symbols. ANSI is permitted. // Length is limited to SIZEOF_MALIASDESC-1. Visual width is limited to // WIDTHOF_MALIASDESC. Case is preserved. // char *MakeCanonicalMailAliasDesc ( char *pMailAliasDesc, size_t *pnValidMailAliasDesc, bool *pbValidMailAliasDesc, size_t *pnVisualWidth ) { if (!pMailAliasDesc) { return NULL; } // First, remove all '\r\n\t' from the string. // char *Buffer = RemoveSetOfCharacters(pMailAliasDesc, "\r\n\t"); // Optimize/terminate any ANSI in the string. // *pnVisualWidth = 0; static char szFittedMailAliasDesc[SIZEOF_MALIASDESC]; *pnValidMailAliasDesc = ANSI_TruncateToField ( Buffer, SIZEOF_MALIASDESC, szFittedMailAliasDesc, WIDTHOF_MALIASDESC, pnVisualWidth, ANSI_ENDGOAL_NORMAL ); *pbValidMailAliasDesc = true; return szFittedMailAliasDesc; } static void malias_read(FILE *fp, bool bConvert) { int i, j; i = getref(fp); if (i <= 0) { return; } char buffer[LBUF_SIZE]; ma_size = ma_top = i; malias = NULL; try { malias = new malias_t *[ma_size]; } catch (...) { ; // Nothing. } if (NULL == malias) { STARTLOG(LOG_BUGS, "BUG", "MAIL"); log_text("Out of memory."); ENDLOG; return; } for (i = 0; i < ma_top; i++) { // Format is: "%d %d\n", &(m->owner), &(m->numrecep) // if (!fgets(buffer, sizeof(buffer), fp)) { // We've hit the end of the file. Set the last recognized // @malias, and give up. // STARTLOG(LOG_BUGS, "BUG", "MAIL"); log_text("Unexpected end of file. Mail bag truncated."); ENDLOG; ma_top = i; return; } malias_t *m = NULL; try { m = new malias_t; } catch (...) { ; // Nothing. } if (NULL == m) { STARTLOG(LOG_BUGS, "BUG", "MAIL"); log_text("Out of memory. Mail bag truncated."); ENDLOG; ma_top = i; return; } malias[i] = m; char *p = strchr(buffer, ' '); m->owner = m->numrecep = 0; if (p) { m->owner = mux_atol(buffer); m->numrecep = mux_atol(p+1); } // The format of @malias name is "N:\n". // size_t nLen = GetLineTrunc(buffer, sizeof(buffer), fp); buffer[nLen-1] = '\0'; // Get rid of trailing '\n'. char *pBuffer = buffer; if (bConvert) { pBuffer = (char *)convert_color((UTF8 *)pBuffer); pBuffer = ConvertToLatin((UTF8 *)pBuffer); } size_t nMailAlias; bool bMailAlias; char *pMailAlias = MakeCanonicalMailAlias( pBuffer+2, &nMailAlias, &bMailAlias); if (bMailAlias) { m->name = StringCloneLen(pMailAlias, nMailAlias); } else { m->name = StringCloneLen("Invalid", 7); } // The format of the description is "D:\n" // nLen = GetLineTrunc(buffer, sizeof(buffer), fp); pBuffer = buffer; if (bConvert) { pBuffer = (char *)convert_color((UTF8 *)pBuffer); pBuffer = ConvertToLatin((UTF8 *)pBuffer); } size_t nMailAliasDesc; bool bMailAliasDesc; size_t nVisualWidth; char *pMailAliasDesc = MakeCanonicalMailAliasDesc( pBuffer+2, &nMailAliasDesc, &bMailAliasDesc, &nVisualWidth); if (bMailAliasDesc) { m->desc = StringCloneLen(pMailAliasDesc, nMailAliasDesc); m->desc_width = nVisualWidth; } else { m->desc = StringCloneLen("Invalid Desc", 12); m->desc_width = 12; } if (m->numrecep > 0) { for (j = 0; j < m->numrecep; j++) { int k = getref(fp); if (j < MAX_MALIAS_MEMBERSHIP) { m->list[j] = k; } } } else { m->list[0] = 0; } } } static void load_malias(FILE *fp, bool bConvert) { char buffer[200]; getref(fp); if ( fgets(buffer, sizeof(buffer), fp) && strcmp(buffer, "*** Begin MALIAS ***\n") == 0) { malias_read(fp, bConvert); } else { Log.WriteString("ERROR: Couldn't find Begin MALIAS." ENDLINE); return; } } void load_mail(FILE *fp) { char nbuf1[8]; // Read the version number. // if (!fgets(nbuf1, sizeof(nbuf1), fp)) { return; } bool bConvert = false; if (strncmp(nbuf1, "+V5", 3) == 0) { load_mail_V5(fp); } else if (strncmp(nbuf1, "+V6", 3) == 0) { // Started v6 on 2007-MAR-13. // load_mail_V6(fp); bConvert = true; } else { return; } load_malias(fp, bConvert); } void check_mail_expiration(void) { // Negative values for expirations never expire. // if (0 > mudconf.mail_expiration) { return; } dbref thing; int expire_secs = mudconf.mail_expiration * 86400; CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); CLinearTimeAbsolute ltaMail; DO_WHOLE_DB(thing) { MailList ml(thing); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (M_Safe(mp)) { continue; } const char *pMailTimeStr = mp->time; if (!ltaMail.SetString(pMailTimeStr)) { continue; } CLinearTimeDelta ltd(ltaMail, ltaNow); if (ltd.ReturnSeconds() <= expire_secs) { continue; } // Delete this one. // ml.RemoveItem(); } } } void check_mail(dbref player, int folder, bool silent) { // Check for new @mail // int rc; // Read messages. int uc; // Unread messages. int cc; // Cleared messages. int gc; // urgent messages. // Just count messages // count_mail(player, folder, &rc, &uc, &cc); urgent_mail(player, folder, &gc); #ifdef MAIL_ALL_FOLDERS notify(player, tprintf("MAIL: %d messages in folder %d [%s] (%d unread, %d cleared).\r\n", rc + uc, folder, get_folder_name(player, folder), uc, cc)); #else // MAIL_ALL_FOLDERS if (rc + uc > 0) { notify(player, tprintf("MAIL: %d messages in folder %d [%s] (%d unread, %d cleared).", rc + uc, folder, get_folder_name(player, folder), uc, cc)); } else if (!silent) { notify(player, tprintf("\r\nMAIL: You have no mail.\r\n")); } if (gc > 0) { notify(player, tprintf("URGENT MAIL: You have %d urgent messages in folder %d [%s].", gc, folder, get_folder_name(player, folder))); } #endif // MAIL_ALL_FOLDERS } static void do_malias_send ( dbref player, char *tolist, char *listto, char *subject, int number, mail_flag flags, bool silent ) { int nResult; malias_t *m = get_malias(player, tolist, &nResult); if (nResult == GMA_INVALIDFORM) { notify(player, tprintf("MAIL: I can't figure out from '%s' who you want to mail to.", tolist)); return; } else if (nResult == GMA_NOTFOUND) { notify(player, tprintf("MAIL: Alias '%s' not found.", tolist)); return; } // Parse the player list. // dbref vic; int k; for (k = 0; k < m->numrecep; k++) { vic = m->list[k]; if (isPlayer(vic)) { send_mail(player, m->list[k], listto, subject, number, flags, silent); } else { // Complain about it. // char *pMail = tprintf("Alias Error: Bad Player %d for %s", vic, tolist); int iMail = add_mail_message(player, pMail); if (iMail != NOTHING) { send_mail(GOD, GOD, listto, subject, iMail, 0, silent); MessageReferenceDec(iMail); } } } } static void do_malias_create(dbref player, char *alias, char *tolist) { malias_t **nm; int nResult; get_malias(player, alias, &nResult); if (nResult == GMA_INVALIDFORM) { notify(player, "MAIL: What alias do you want to create?."); return; } else if (nResult == GMA_FOUND) { notify(player, tprintf("MAIL: Mail Alias '%s' already exists.", alias)); return; } malias_t *pt = NULL; try { pt = new malias_t; } catch (...) { ; // Nothing. } if (NULL == pt) { notify(player, "MAIL: Out of memory."); return; } int i = 0; if (!ma_size) { ma_size = MA_INC; malias = NULL; try { malias = new malias_t *[ma_size]; } catch (...) { ; // Nothing. } if (NULL == malias) { notify(player, "MAIL: Out of memory."); delete pt; return; } } else if (ma_top >= ma_size) { ma_size += MA_INC; nm = NULL; try { nm = new malias_t *[ma_size]; } catch (...) { ; // Nothing. } if (NULL == nm) { notify(player, "MAIL: Out of memory."); delete pt; return; } for (i = 0; i < ma_top; i++) { nm[i] = malias[i]; } delete [] malias; malias = nm; } malias[ma_top] = pt; // Parse the player list. // char *head = tolist; char *tail, spot; char *buff; dbref target; i = 0; while ( head && *head && i < (MAX_MALIAS_MEMBERSHIP - 1)) { while (*head == ' ') { head++; } tail = head; while ( *tail && *tail != ' ') { if (*tail == '"') { head++; tail++; while ( *tail && *tail != '"') { tail++; } } if (*tail) { tail++; } } tail--; if (*tail != '"') { tail++; } spot = *tail; *tail = '\0'; // Now locate a target. // if (!mux_stricmp(head, "me")) { target = player; } else if (*head == '#') { target = mux_atol(head + 1); } else { target = lookup_player(player, head, true); } if ( !Good_obj(target) || !isPlayer(target)) { notify(player, "MAIL: No such player."); } else { buff = unparse_object(player, target, false); notify(player, tprintf("MAIL: %s added to alias %s", buff, alias)); malias[ma_top]->list[i] = target; i++; free_lbuf(buff); } // Get the next recip. // *tail = spot; head = tail; if (*head == '"') { head++; } } size_t nValidMailAlias; bool bValidMailAlias; char *pValidMailAlias = MakeCanonicalMailAlias ( alias+1, &nValidMailAlias, &bValidMailAlias ); if (!bValidMailAlias) { notify(player, "MAIL: Invalid mail alias."); return; } // The Mail Alias Description is a superset of the Mail Alias, // so, the following code is not necessary unless the specification // of the Mail Alias Description becomes more restrictive at some // future time. // #if 0 int nValidMailAliasDesc; bool bValidMailAliasDesc; char *pValidMailAliasDesc = MakeCanonicalMailAliasDesc ( alias+1, &nValidMailAliasDesc, &bValidMailAliasDesc ); if (!bValidMailAliasDesc) { notify(player, "MAIL: Invalid mail alias description."); break; } #else char *pValidMailAliasDesc = pValidMailAlias; size_t nValidMailAliasDesc = nValidMailAlias; #endif malias[ma_top]->list[i] = NOTHING; malias[ma_top]->name = StringCloneLen(pValidMailAlias, nValidMailAlias); malias[ma_top]->numrecep = i; malias[ma_top]->owner = player; malias[ma_top]->desc = StringCloneLen(pValidMailAliasDesc, nValidMailAliasDesc); malias[ma_top]->desc_width = nValidMailAliasDesc; ma_top++; notify(player, tprintf("MAIL: Alias set '%s' defined.", alias)); } static void do_malias_list(dbref player, char *alias) { int nResult; malias_t *m = get_malias(player, alias, &nResult); if (nResult == GMA_NOTFOUND) { notify(player, tprintf("MAIL: Alias '%s' not found.", alias)); return; } if (nResult != GMA_FOUND) { return; } if (!ExpMail(player) && (player != m->owner) && !(God(m->owner))) { notify(player, "MAIL: Permission denied."); return; } char *buff = alloc_lbuf("do_malias_list"); char *bp = buff; safe_tprintf_str(buff, &bp, "MAIL: Alias *%s: ", m->name); for (int i = m->numrecep - 1; i > -1; i--) { const char *p = Moniker(m->list[i]); if (strchr(p, ' ')) { safe_chr('"', buff, &bp); safe_str(p, buff, &bp); safe_chr('"', buff, &bp); } else { safe_str(p, buff, &bp); } safe_chr(' ', buff, &bp); } *bp = '\0'; notify(player, buff); free_lbuf(buff); } static char *Spaces(size_t n) { static char buffer[42] = " "; static size_t nLast = 0; buffer[nLast] = ' '; if (n < sizeof(buffer)-1) { buffer[n] = '\0'; nLast = n; } return buffer; } static void do_malias_list_all(dbref player) { bool notified = false; for (int i = 0; i < ma_top; i++) { malias_t *m = malias[i]; if ( m->owner == GOD || m->owner == player || God(player)) { if (!notified) { notify(player, "Name Description Owner"); notified = true; } char *pSpaces = Spaces(40 - m->desc_width); char *p = tprintf( "%-12s %s%s %-15.15s", m->name, m->desc, pSpaces, Moniker(m->owner)); notify(player, p); } } notify(player, "***** End of Mail Aliases *****"); } static void do_malias_switch(dbref player, char *a1, char *a2) { if (a1 && *a1) { if (a2 && *a2) { do_malias_create(player, a1, a2); } else { do_malias_list(player, a1); } } else { do_malias_list_all(player); } } static void do_mail_cc(dbref player, char *arg, bool bBlind) { if (!(Flags2(player) & PLAYER_MAILS)) { notify(player, "MAIL: No mail message in progress."); return; } if (!arg || !*arg) { notify(player, "MAIL: I do not know whom you want to mail."); return; } char *tolist = make_numlist(player, arg, bBlind); if (!tolist) { return; } char *fulllist = alloc_lbuf("do_mail_cc"); char *bp = fulllist; safe_str(tolist, fulllist, &bp); const char *pPlayerMailTo = atr_get_raw(player, A_MAILTO); if (pPlayerMailTo) { safe_chr(' ', fulllist, &bp); safe_str(pPlayerMailTo, fulllist, &bp); } *bp = '\0'; atr_add_raw(player, A_MAILTO, fulllist); char *names = make_namelist(player, fulllist); notify(player, tprintf("MAIL: You are sending mail to '%s'.", names)); free_lbuf(names); free_lbuf(tolist); free_lbuf(fulllist); } static void mail_to_list(dbref player, char *list, char *subject, char *message, int flags, bool silent) { if (!list) { return; } if (!*list) { free_lbuf(list); return; } // Construct a tolist which excludes all the Blind Carbon Copy (BCC) // recipients. // char *tolist = alloc_lbuf("mail_to_list"); char *p = tolist; char *tail; char *head = list; while (*head) { while (*head == ' ') { head++; } tail = head; while ( *tail && *tail != ' ') { if (*tail == '"') { head++; tail++; while ( *tail && *tail != '"') { tail++; } } if (*tail) { tail++; } } tail--; if (*tail != '"') { tail++; } if (*head != '!') { if (p != tolist) { safe_chr(' ', tolist, &p); } memcpy(p, head, tail-head); p += tail-head; } // Get the next recipient. // head = tail; if (*head == '"') { head++; } } *p = '\0'; int number = add_mail_message(player, message); if (number != NOTHING) { char spot; head = list; while (*head) { while (' ' == *head) { head++; } tail = head; while ( *tail && *tail != ' ') { if (*tail == '"') { head++; tail++; while ( *tail && *tail != '"') { tail++; } } if (*tail) { tail++; } } tail--; if (*tail != '"') { tail++; } spot = *tail; *tail = '\0'; if (*head == '!') { head++; } if (*head == '*') { do_malias_send(player, head, tolist, subject, number, flags, silent); } else { dbref target = mux_atol(head); if ( Good_obj(target) && isPlayer(target)) { send_mail(player, target, tolist, subject, number, flags, silent); } } // Get the next recipient. // *tail = spot; head = tail; if (*head == '"') { head++; } } MessageReferenceDec(number); } free_lbuf(tolist); free_lbuf(list); } static void do_mail_quick(dbref player, char *arg1, char *arg2) { if (!arg1 || !*arg1) { notify(player, "MAIL: I don't know who you want to mail."); return; } if (!arg2 || !*arg2) { notify(player, "MAIL: No message."); return; } if (Flags2(player) & PLAYER_MAILS) { notify(player, "MAIL: Mail message already in progress."); return; } if ( !Wizard(player) && ThrottleMail(player)) { notify(player, "MAIL: Too much @mail sent recently."); return; } char *bufDest = alloc_lbuf("do_mail_quick"); char *bpSubject = bufDest; mux_strncpy(bpSubject, arg1, LBUF_SIZE-1); parse_to(&bpSubject, '/', 1); if (!bpSubject) { notify(player, "MAIL: No subject."); free_lbuf(bufDest); return; } mail_to_list(player, make_numlist(player, bufDest, false), bpSubject, arg2, 0, false); free_lbuf(bufDest); } static void do_expmail_stop(dbref player, int flags) { if ((Flags2(player) & PLAYER_MAILS) != PLAYER_MAILS) { notify(player, "MAIL: No message started."); return; } dbref aowner; dbref aflags; char *tolist = atr_get(player, A_MAILTO, & aowner, &aflags); if (*tolist == '\0') { notify(player, "MAIL: No recipients."); free_lbuf(tolist); } else { char *pMailMsg = atr_get(player, A_MAILMSG, &aowner, &aflags); if (*pMailMsg == '\0') { notify(player, "MAIL: The body of this message is empty. Use - to add to the message."); free_lbuf(tolist); } else { char *mailsub = atr_get(player, A_MAILSUB, &aowner, &aflags); char *mailflags = atr_get(player, A_MAILFLAGS, &aowner, &aflags); mail_to_list(player, tolist, mailsub, pMailMsg, flags | mux_atol(mailflags), false); free_lbuf(mailflags); free_lbuf(mailsub); Flags2(player) &= ~PLAYER_MAILS; } free_lbuf(pMailMsg); } } static void do_expmail_abort(dbref player) { Flags2(player) &= ~PLAYER_MAILS; notify(player, "MAIL: Message aborted."); } void do_prepend(dbref executor, dbref caller, dbref enactor, int eval, int key, char *text) { UNUSED_PARAMETER(key); if (!mudconf.have_mailer) { return; } if (Flags2(executor) & PLAYER_MAILS) { if ( !text || !*text) { notify(executor, "No text prepended."); return; } char *bufText = alloc_lbuf("do_prepend"); char *bpText = bufText; char *strText = text+1; mux_exec(bufText, &bpText, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &strText, NULL, 0); *bpText = '\0'; dbref aowner; int aflags; char *oldmsg = atr_get(executor, A_MAILMSG, &aowner, &aflags); if (*oldmsg) { char *newmsg = alloc_lbuf("do_prepend"); char *bp = newmsg; safe_str(bufText, newmsg, &bp); safe_chr(' ', newmsg, &bp); safe_str(oldmsg, newmsg, &bp); *bp = '\0'; atr_add_raw(executor, A_MAILMSG, newmsg); free_lbuf(newmsg); } else { atr_add_raw(executor, A_MAILMSG, bufText); } free_lbuf(bufText); free_lbuf(oldmsg); size_t nLen; atr_get_raw_LEN(executor, A_MAILMSG, &nLen); notify(executor, tprintf("%d/%d characters prepended.", nLen, LBUF_SIZE-1)); } else { notify(executor, "MAIL: No message in progress."); } } void do_postpend(dbref executor, dbref caller, dbref enactor, int eval, int key, char *text) { UNUSED_PARAMETER(key); if (!mudconf.have_mailer) { return; } if ( text[1] == '-' && text[2] == '\0') { do_expmail_stop(executor, 0); return; } if (Flags2(executor) & PLAYER_MAILS) { if ( !text || !*text) { notify(executor, "No text added."); return; } char *bufText = alloc_lbuf("do_prepend"); char *bpText = bufText; char *strText = text+1; mux_exec(bufText, &bpText, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &strText, NULL, 0); *bpText = '\0'; dbref aowner; int aflags; char *oldmsg = atr_get(executor, A_MAILMSG, &aowner, &aflags); if (*oldmsg) { char *newmsg = alloc_lbuf("do_postpend"); char *bp = newmsg; safe_str(oldmsg, newmsg, &bp); safe_chr(' ', newmsg, &bp); safe_str(bufText, newmsg, &bp); *bp = '\0'; atr_add_raw(executor, A_MAILMSG, newmsg); free_lbuf(newmsg); } else { atr_add_raw(executor, A_MAILMSG, bufText); } free_lbuf(bufText); free_lbuf(oldmsg); size_t nLen; atr_get_raw_LEN(executor, A_MAILMSG, &nLen); notify(executor, tprintf("%d/%d characters added.", nLen, LBUF_SIZE-1)); } else { notify(executor, "MAIL: No message in progress."); } } static void do_edit_msg(dbref player, char *from, char *to) { if (Flags2(player) & PLAYER_MAILS) { dbref aowner; int aflags; char *msg = atr_get(player, A_MAILMSG, &aowner, &aflags); char *result = replace_string(from, to, msg); atr_add(player, A_MAILMSG, result, aowner, aflags); notify(player, "Text edited."); free_lbuf(result); free_lbuf(msg); } else { notify(player, "MAIL: No message in progress."); } } static void do_mail_proof(dbref player) { if (!(Flags2(player) & PLAYER_MAILS)) { notify(player, "MAIL: No message in progress."); return; } dbref aowner; int aflags; char *mailto = atr_get(player, A_MAILTO, &aowner, &aflags); char *pMailMsg = atr_get(player, A_MAILMSG, &aowner, &aflags); char *names = make_namelist(player, mailto); size_t iRealVisibleWidth; char szSubjectBuffer[MBUF_SIZE]; ANSI_TruncateToField(atr_get_raw(player, A_MAILSUB), sizeof(szSubjectBuffer), szSubjectBuffer, 35, &iRealVisibleWidth, ANSI_ENDGOAL_NORMAL); char szFromName[MBUF_SIZE]; GetFromField(player, szFromName); notify(player, DASH_LINE); notify(player, tprintf("From: %s Subject: %s\nTo: %s", szFromName, szSubjectBuffer, names)); notify(player, DASH_LINE); notify(player, pMailMsg); notify(player, DASH_LINE); free_lbuf(pMailMsg); free_lbuf(names); free_lbuf(mailto); } static void do_malias_desc(dbref player, char *alias, char *desc) { int nResult; malias_t *m = get_malias(player, alias, &nResult); if (nResult == GMA_NOTFOUND) { notify(player, tprintf("MAIL: Alias '%s' not found.", alias)); return; } if (nResult != GMA_FOUND) { return; } if ( m->owner != GOD || ExpMail(player)) { size_t nValidMailAliasDesc; bool bValidMailAliasDesc; size_t nVisualWidth; char *pValidMailAliasDesc = MakeCanonicalMailAliasDesc ( desc, &nValidMailAliasDesc, &bValidMailAliasDesc, &nVisualWidth ); if (bValidMailAliasDesc) { MEMFREE(m->desc); m->desc = StringCloneLen(pValidMailAliasDesc, nValidMailAliasDesc); m->desc_width = nVisualWidth; notify(player, "MAIL: Description changed."); } else { notify(player, "MAIL: Description is not valid."); } } else { notify(player, "MAIL: Permission denied."); } } static void do_malias_chown(dbref player, char *alias, char *owner) { if (!ExpMail(player)) { notify(player, "MAIL: You cannot do that!"); return; } int nResult; malias_t *m = get_malias(player, alias, &nResult); if (nResult == GMA_NOTFOUND) { notify(player, tprintf("MAIL: Alias '%s' not found.", alias)); return; } if (nResult != GMA_FOUND) { return; } dbref no = lookup_player(player, owner, true); if (no == NOTHING) { notify(player, "MAIL: I do not see that here."); return; } m->owner = no; notify(player, "MAIL: Owner changed for alias."); } static void do_malias_add(dbref player, char *alias, char *person) { int nResult; malias_t *m = get_malias(player, alias, &nResult); if (nResult == GMA_NOTFOUND) { notify(player, tprintf("MAIL: Alias '%s' not found.", alias)); return; } else if (nResult != GMA_FOUND) { return; } dbref thing = NOTHING; if (*person == '#') { thing = parse_dbref(person + 1); if (!isPlayer(thing)) { notify(player, "MAIL: Only players may be added."); return; } } if (thing == NOTHING) { thing = lookup_player(player, person, true); } if (thing == NOTHING) { notify(player, "MAIL: I do not see that person here."); return; } if ((m->owner == GOD) && !ExpMail(player)) { notify(player, "MAIL: Permission denied."); return; } int i; for (i = 0; i < m->numrecep; i++) { if (m->list[i] == thing) { notify(player, "MAIL: That person is already on the list."); return; } } if (i >= (MAX_MALIAS_MEMBERSHIP - 1)) { notify(player, "MAIL: The list is full."); return; } m->list[m->numrecep] = thing; m->numrecep = m->numrecep + 1; notify(player, tprintf("MAIL: %s added to %s", Moniker(thing), m->name)); } static void do_malias_remove(dbref player, char *alias, char *person) { int nResult; malias_t *m = get_malias(player, alias, &nResult); if (nResult == GMA_NOTFOUND) { notify(player, tprintf("MAIL: Alias '%s' not found.", alias)); return; } if (nResult != GMA_FOUND) { return; } if ((m->owner == GOD) && !ExpMail(player)) { notify(player, "MAIL: Permission denied."); return; } dbref thing = NOTHING; if (*person == '#') { thing = parse_dbref(person + 1); } if (thing == NOTHING) { thing = lookup_player(player, person, true); } if (thing == NOTHING) { notify(player, "MAIL: I do not see that person here."); return; } bool ok = false; for (int i = 0; i < m->numrecep; i++) { if (ok) { m->list[i] = m->list[i + 1]; } else if (m->list[i] == thing) { m->list[i] = m->list[i + 1]; ok = true; } } if (ok) { m->numrecep--; notify(player, tprintf("MAIL: %s removed from alias %s.", Moniker(thing), alias)); } else { notify(player, tprintf("MAIL: %s is not a member of alias %s.", Moniker(thing), alias)); } } static void do_malias_rename(dbref player, char *alias, char *newname) { int nResult; malias_t *m = get_malias(player, newname, &nResult); if (nResult == GMA_FOUND) { notify(player, "MAIL: That name already exists!"); return; } if (nResult != GMA_NOTFOUND) { return; } m = get_malias(player, alias, &nResult); if (nResult == GMA_NOTFOUND) { notify(player, "MAIL: I cannot find that alias!"); return; } if (nResult != GMA_FOUND) { return; } if (!ExpMail(player) && !(m->owner == player)) { notify(player, "MAIL: Permission denied."); return; } size_t nValidMailAlias; bool bValidMailAlias; char *pValidMailAlias = MakeCanonicalMailAlias ( newname+1, &nValidMailAlias, &bValidMailAlias ); if (bValidMailAlias) { MEMFREE(m->name); m->name = StringCloneLen(pValidMailAlias, nValidMailAlias); notify(player, "MAIL: Mailing Alias renamed."); } else { notify(player, "MAIL: Alias is not valid."); } } static void do_malias_delete(dbref player, char *alias) { int nResult; malias_t *m = get_malias(player, alias, &nResult); if (nResult == GMA_NOTFOUND) { notify(player, tprintf("MAIL: Alias '%s' not found.", alias)); return; } if (nResult != GMA_FOUND) { return; } bool done = false; for (int i = 0; i < ma_top; i++) { if (done) { malias[i] = malias[i + 1]; } else { if ((m->owner == player) || ExpMail(player)) { if (m == malias[i]) { done = true; notify(player, "MAIL: Alias Deleted."); malias[i] = malias[i + 1]; } } } } if (!done) { notify(player, tprintf("MAIL: Alias '%s' not found.", alias)); } else { ma_top--; } } static void do_malias_adminlist(dbref player) { if (!ExpMail(player)) { do_malias_list_all(player); return; } notify(player, "Num Name Description Owner"); malias_t *m; int i; for (i = 0; i < ma_top; i++) { m = malias[i]; char *pSpaces = Spaces(40 - m->desc_width); notify(player, tprintf("%-4d %-12s %s%s %-15.15s", i, m->name, m->desc, pSpaces, Moniker(m->owner))); } notify(player, "***** End of Mail Aliases *****"); } static void do_malias_status(dbref player) { if (!ExpMail(player)) { notify(player, "MAIL: Permission denied."); } else { notify(player, tprintf("MAIL: Number of mail aliases defined: %d", ma_top)); notify(player, tprintf("MAIL: Allocated slots %d", ma_size)); } } static void malias_cleanup1(malias_t *m, dbref target) { int count = 0; dbref j; for (int i = 0; i < m->numrecep; i++) { j = m->list[i]; if ( !Good_obj(j) || j == target) { count++; } if (count) { m->list[i] = m->list[i + count]; } } m->numrecep -= count; } void malias_cleanup(dbref player) { for (int i = 0; i < ma_top; i++) { malias_cleanup1(malias[i], player); } } static void do_mail_retract1(dbref player, char *name, char *msglist) { dbref target = lookup_player(player, name, true); if (target == NOTHING) { notify(player, "MAIL: No such player."); return; } struct mail_selector ms; if (!parse_msglist(msglist, &ms, target)) { return; } int i = 0, j = 0; MailList ml(target); struct mail *mp; for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem()) { if (mp->from == player) { i++; if (mail_match(mp, ms, i)) { j++; if (Unread(mp)) { ml.RemoveItem(); notify(player, "MAIL: Mail retracted."); } else { notify(player, "MAIL: That message has been read."); } } } } if (!j) { // Ran off the end of the list without finding anything. // notify(player, "MAIL: No matching messages."); } } static void do_mail_retract(dbref player, char *name, char *msglist) { if (*name == '*') { int pnResult; malias_t *m = get_malias(player, name, &pnResult); if (pnResult == GMA_NOTFOUND) { notify(player, tprintf("MAIL: Mail alias %s not found.", name)); return; } if (pnResult == GMA_FOUND) { for (int i = 0; i < m->numrecep; i++) { do_mail_retract1(player, tprintf("#%d", m->list[i]), msglist); } } } else { do_mail_retract1(player, name, msglist); } } void do_malias ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *arg1, char *arg2 ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); if (!mudconf.have_mailer) { notify(executor, "Mailer is disabled."); return; } switch (key) { case 0: do_malias_switch(executor, arg1, arg2); break; case MALIAS_DESC: do_malias_desc(executor, arg1, arg2); break; case MALIAS_CHOWN: do_malias_chown(executor, arg1, arg2); break; case MALIAS_ADD: do_malias_add(executor, arg1, arg2); break; case MALIAS_REMOVE: do_malias_remove(executor, arg1, arg2); break; case MALIAS_DELETE: do_malias_delete(executor, arg1); break; case MALIAS_RENAME: do_malias_rename(executor, arg1, arg2); break; case 7: // empty break; case MALIAS_LIST: do_malias_adminlist(executor); break; case MALIAS_STATUS: do_malias_status(executor); } } void do_mail ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *arg1, char *arg2 ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); if (!mudconf.have_mailer) { notify(executor, "Mailer is disabled."); return; } // HACK: Fix to allow @mail/quick from objects. // if ( (key & ~MAIL_QUOTE) != MAIL_QUICK && !isPlayer(executor)) { return; } switch (key & ~MAIL_QUOTE) { case 0: do_mail_stub(executor, arg1, arg2); break; case MAIL_STATS: do_mail_stats(executor, arg1, 0); break; case MAIL_DSTATS: do_mail_stats(executor, arg1, 1); break; case MAIL_FSTATS: do_mail_stats(executor, arg1, 2); break; case MAIL_DEBUG: do_mail_debug(executor, arg1, arg2); break; case MAIL_NUKE: do_mail_nuke(executor); break; case MAIL_FOLDER: do_mail_change_folder(executor, arg1, arg2); break; case MAIL_LIST: do_mail_list(executor, arg1, false); break; case MAIL_READ: do_mail_read(executor, arg1); break; case MAIL_CLEAR: do_mail_clear(executor, arg1); break; case MAIL_UNCLEAR: do_mail_unclear(executor, arg1); break; case MAIL_PURGE: do_mail_purge(executor); break; case MAIL_FILE: do_mail_file(executor, arg1, arg2); break; case MAIL_TAG: do_mail_tag(executor, arg1); break; case MAIL_UNTAG: do_mail_untag(executor, arg1); break; case MAIL_FORWARD: do_mail_fwd(executor, arg1, arg2); break; case MAIL_REPLY: do_mail_reply(executor, arg1, false, key); break; case MAIL_REPLYALL: do_mail_reply(executor, arg1, true, key); break; case MAIL_SEND: do_expmail_stop(executor, 0); break; case MAIL_EDIT: do_edit_msg(executor, arg1, arg2); break; case MAIL_URGENT: do_expmail_stop(executor, M_URGENT); break; case MAIL_ALIAS: do_malias_create(executor, arg1, arg2); break; case MAIL_ALIST: do_malias_list_all(executor); break; case MAIL_PROOF: do_mail_proof(executor); break; case MAIL_ABORT: do_expmail_abort(executor); break; case MAIL_QUICK: do_mail_quick(executor, arg1, arg2); break; case MAIL_REVIEW: do_mail_review(executor, arg1, arg2); break; case MAIL_RETRACT: do_mail_retract(executor, arg1, arg2); break; case MAIL_CC: do_mail_cc(executor, arg1, false); break; case MAIL_SAFE: do_mail_safe(executor, arg1); break; case MAIL_BCC: do_mail_cc(executor, arg1, true); break; } } struct mail *MailList::FirstItem(void) { m_miHead = (struct mail *)hashfindLEN(&m_player, sizeof(m_player), &mudstate.mail_htab); m_mi = m_miHead; m_bRemoved = false; return m_mi; } struct mail *MailList::NextItem(void) { if (!m_bRemoved) { if (NULL != m_mi) { m_mi = m_mi->next; if (m_mi == m_miHead) { m_mi = NULL; } } } m_bRemoved = false; return m_mi; } bool MailList::IsEnd(void) { return (NULL == m_mi); } MailList::MailList(dbref player) { m_mi = NULL; m_miHead = NULL; m_player = player; m_bRemoved = false; } void MailList::RemoveItem(void) { if ( NULL == m_mi || NOTHING == m_player) { return; } struct mail *miNext = m_mi->next; if (m_mi == m_miHead) { if (miNext == m_miHead) { hashdeleteLEN(&m_player, sizeof(m_player), &mudstate.mail_htab); miNext = NULL; } else { hashreplLEN(&m_player, sizeof(m_player), miNext, &mudstate.mail_htab); } m_miHead = miNext; } // Relink the list // m_mi->prev->next = m_mi->next; m_mi->next->prev = m_mi->prev; m_mi->next = NULL; m_mi->prev = NULL; MessageReferenceDec(m_mi->number); MEMFREE(m_mi->subject); m_mi->subject = NULL; MEMFREE(m_mi->time); m_mi->time = NULL; MEMFREE(m_mi->tolist); m_mi->tolist = NULL; delete m_mi; m_mi = miNext; m_bRemoved = true; } void MailList::AppendItem(struct mail *miNew) { struct mail *miHead = (struct mail *) hashfindLEN(&m_player, sizeof(m_player), &mudstate.mail_htab); if (miHead) { // Add new item to the end of the list. // struct mail *miEnd = miHead->prev; miNew->next = miHead; miNew->prev = miEnd; miHead->prev = miNew; miEnd->next = miNew; } else { hashaddLEN(&m_player, sizeof(m_player), miNew, &mudstate.mail_htab); miNew->next = miNew; miNew->prev = miNew; } } void MailList::RemoveAll(void) { struct mail *miHead = (struct mail *) hashfindLEN(&m_player, sizeof(m_player), &mudstate.mail_htab); if (NULL != miHead) { hashdeleteLEN(&m_player, sizeof(m_player), &mudstate.mail_htab); } struct mail *mi; struct mail *miNext; for (mi = miHead; NULL != mi; mi = miNext) { if (mi == miHead) { miNext = NULL; } else { miNext = mi->next; } MessageReferenceDec(mi->number); MEMFREE(mi->subject); mi->subject = NULL; MEMFREE(mi->tolist); mi->tolist = NULL; MEMFREE(mi->time); mi->time = NULL; delete mi; } m_mi = NULL; } mux2.6/src/functions.cpp0000600000175000017500000104551511025753746015325 0ustar sdennissdennis/*! \file functions.cpp * MUX function handlers * * $Id: functions.cpp 3193 2008-01-19 08:44:47Z brazilofmux $ * */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "ansi.h" #include "attrs.h" #include "command.h" #include "functions.h" #include "funmath.h" #include "interface.h" #include "misc.h" #include "pcre.h" #ifdef REALITY_LVLS #include "levels.h" #endif // REALITY_LVLS #if defined(FIRANMUX) #include extern MYSQL *mush_database; #endif // FIRANMUX UFUN *ufun_head; SEP sepSpace = { 1, " " }; // Trim off leading and trailing spaces if the separator char is a // space -- known length version. // char *trim_space_sep_LEN(char *str, size_t nStr, SEP *sep, size_t *nTrim) { if ( sep->n != 1 || sep->str[0] != ' ') { *nTrim = nStr; return str; } // Advance over leading spaces. // char *pBegin = str; char *pEnd = str + nStr - 1; while (*pBegin == ' ') { pBegin++; } // Advance over trailing spaces. // for (; pEnd > pBegin && *pEnd == ' '; pEnd--) { // Nothing. } pEnd++; *pEnd = '\0'; *nTrim = pEnd - pBegin; return pBegin; } // Trim off leading and trailing spaces if the separator char is a space. // char *trim_space_sep(char *str, SEP *sep) { if ( sep->n != 1 || sep->str[0] != ' ') { return str; } while (*str == ' ') { str++; } char *p; for (p = str; *p; p++) { // Nothing. } for (p--; p > str && *p == ' '; p--) { // Nothing. } p++; *p = '\0'; return str; } // next_token: Point at start of next token in string -- known length // version. // static char *next_token_LEN(char *str, size_t *nStr, SEP *psep) { char *pBegin = str; if (psep->n == 1) { while ( *pBegin != '\0' && *pBegin != psep->str[0]) { pBegin++; } if (!*pBegin) { *nStr = 0; return NULL; } pBegin++; if (psep->str[0] == ' ') { while (*pBegin == ' ') { pBegin++; } } } else { char *p = strstr(pBegin, psep->str); if (p) { pBegin = p + psep->n; } else { *nStr = 0; return NULL; } } *nStr -= pBegin - str; return pBegin; } // next_token: Point at start of next token in string // char *next_token(char *str, SEP *psep) { if (psep->n == 1) { while ( *str != '\0' && *str != psep->str[0]) { str++; } if (!*str) { return NULL; } str++; if (psep->str[0] == ' ') { while (*str == ' ') { str++; } } } else { char *p = strstr(str, psep->str); if (p) { str = p + psep->n; } else { return NULL; } } return str; } // split_token: Get next token from string as null-term string. String is // destructively modified -- known length version. // static char *split_token_LEN(char **sp, size_t *nStr, SEP *psep, size_t *nToken) { char *str = *sp; char *save = str; if (!str) { *nStr = 0; *sp = NULL; *nToken = 0; return NULL; } if (psep->n == 1) { // Advance over token // while ( *str && *str != psep->str[0]) { str++; } *nToken = str - save; if (*str) { *str++ = '\0'; if (psep->str[0] == ' ') { while (*str == ' ') { str++; } } *nStr -= str - save; } else { *nStr = 0; str = NULL; } } else { char *p = strstr(str, psep->str); if (p) { *p = '\0'; str = p + psep->n; } else { str = NULL; } } *sp = str; return save; } // split_token: Get next token from string as null-term string. String is // destructively modified. // char *split_token(char **sp, SEP *psep) { char *str = *sp; char *save = str; if (!str) { *sp = NULL; return NULL; } if (psep->n == 1) { while ( *str && *str != psep->str[0]) { str++; } if (*str) { *str++ = '\0'; if (psep->str[0] == ' ') { while (*str == ' ') { str++; } } } else { str = NULL; } } else { char *p = strstr(str, psep->str); if (p) { *p = '\0'; str = p + psep->n; } else { str = NULL; } } *sp = str; return save; } /* --------------------------------------------------------------------------- * List management utilities. */ #define ASCII_LIST 1 #define NUMERIC_LIST 2 #define DBREF_LIST 4 #define FLOAT_LIST 8 #define CI_ASCII_LIST 16 #define ALL_LIST (ASCII_LIST|NUMERIC_LIST|DBREF_LIST|FLOAT_LIST) static int autodetect_list(char *ptrs[], int nitems) { int could_be = ALL_LIST; for (int i = 0; i < nitems; i++) { char *p = ptrs[i]; if (p[0] != NUMBER_TOKEN) { could_be &= ~DBREF_LIST; } if ( (could_be & DBREF_LIST) && !is_integer(p+1, NULL)) { could_be &= ~(DBREF_LIST|NUMERIC_LIST|FLOAT_LIST); } if ( (could_be & FLOAT_LIST) && !is_real(p)) { could_be &= ~(NUMERIC_LIST|FLOAT_LIST); } if ( (could_be & NUMERIC_LIST) && !is_integer(p, NULL)) { could_be &= ~NUMERIC_LIST; } if (could_be == ASCII_LIST) { return ASCII_LIST; } } if (could_be & NUMERIC_LIST) { return NUMERIC_LIST; } else if (could_be & FLOAT_LIST) { return FLOAT_LIST; } else if (could_be & DBREF_LIST) { return DBREF_LIST; } return ASCII_LIST; } static int get_list_type ( char *fargs[], int nfargs, int type_pos, char *ptrs[], int nitems ) { if (nfargs >= type_pos) { switch (mux_tolower(*fargs[type_pos - 1])) { case 'd': return DBREF_LIST; case 'n': return NUMERIC_LIST; case 'f': return FLOAT_LIST; case 'i': return CI_ASCII_LIST; case '\0': return autodetect_list(ptrs, nitems); default: return ASCII_LIST; } } return autodetect_list(ptrs, nitems); } int list2arr(char *arr[], int maxlen, char *list, SEP *psep) { list = trim_space_sep(list, psep); if (list[0] == '\0') { return 0; } char *p = split_token(&list, psep); int i; for (i = 0; p && i < maxlen; i++, p = split_token(&list, psep)) { arr[i] = p; } return i; } void arr2list(char *arr[], int alen, char *list, char **bufc, SEP *psep) { int i; for (i = 0; i < alen-1; i++) { safe_str(arr[i], list, bufc); print_sep(psep, list, bufc); } if (alen) { safe_str(arr[i], list, bufc); } } static int dbnum(char *dbr) { if (dbr[0] != '#' || dbr[1] == '\0') { return 0; } else { return mux_atol(dbr + 1); } } /* --------------------------------------------------------------------------- * nearby_or_control: Check if player is near or controls thing */ static bool nearby_or_control(dbref player, dbref thing) { if (!Good_obj(player) || !Good_obj(thing)) { return false; } if (Controls(player, thing)) { return true; } if (!nearby(player, thing)) { return false; } return true; } /* --------------------------------------------------------------------------- * delim_check: obtain delimiter */ bool delim_check ( char *buff, char **bufc, dbref executor, dbref caller, dbref enactor, int eval, char *fargs[], int nfargs, char *cargs[], int ncargs, int sep_arg, SEP *sep, int dflags ) { bool bSuccess = true; if (sep_arg <= nfargs) { // First, we decide whether to evalute fargs[sep_arg-1] or not. // char *tstr = fargs[sep_arg-1]; size_t tlen = strlen(tstr); if (tlen <= 1) { dflags &= ~DELIM_EVAL; } if (dflags & DELIM_EVAL) { char *str = tstr; char *bp = tstr = alloc_lbuf("delim_check"); mux_exec(tstr, &bp, executor, caller, enactor, eval|EV_EVAL|EV_FCHECK, &str, cargs, ncargs); *bp = '\0'; tlen = bp - tstr; } // Regardless of evaulation or no, tstr contains what we need to // look at, and tlen is the length of this string. // if (tlen == 1) { sep->n = 1; memcpy(sep->str, tstr, tlen+1); } else if (tlen == 0) { sep->n = 1; memcpy(sep->str, " ", 2); } else if ( tlen == 2 && (dflags & DELIM_NULL) && memcmp(tstr, NULL_DELIM_VAR, 2) == 0) { sep->n = 0; sep->str[0] = '\0'; } else if ( tlen == 2 && (dflags & DELIM_EVAL) && memcmp(tstr, "\r\n", 2) == 0) { sep->n = 2; memcpy(sep->str, "\r\n", 3); } else if (dflags & DELIM_STRING) { if (tlen <= MAX_SEP_LEN) { sep->n = tlen; memcpy(sep->str, tstr, tlen); sep->str[sep->n] = '\0'; } else { safe_str("#-1 SEPARATOR IS TOO LARGE", buff, bufc); bSuccess = false; } } else { safe_str("#-1 SEPARATOR MUST BE ONE CHARACTER", buff, bufc); bSuccess = false; } // Clean up the evaluation buffer. // if (dflags & DELIM_EVAL) { free_lbuf(tstr); } } else if (!(dflags & DELIM_INIT)) { sep->n = 1; memcpy(sep->str, " ", 2); } return bSuccess; } /* --------------------------------------------------------------------------- * fun_words: Returns number of words in a string. * Added 1/28/91 Philip D. Wasson */ int countwords(char *str, SEP *psep) { int n; str = trim_space_sep(str, psep); if (!*str) { return 0; } for (n = 0; str; str = next_token(str, psep), n++) { ; // Nothing. } return n; } static FUNCTION(fun_words) { if (nfargs == 0) { safe_chr('0', buff, bufc); return; } SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } safe_ltoa(countwords(strip_ansi(fargs[0]), &sep), buff, bufc); } /* --------------------------------------------------------------------------- * fun_flags: Returns the flags on an object or an object's attribute. * Because @switch is case-insensitive, not quite as useful as it could be. */ static FUNCTION(fun_flags) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it; ATTR *pattr; if (parse_attrib(executor, fargs[0], &it, &pattr)) { if ( pattr && See_attr(executor, it, pattr)) { dbref aowner; int aflags; atr_pget_info(it, pattr->number, &aowner, &aflags); char xbuf[11]; decode_attr_flags(aflags, xbuf); safe_str(xbuf, buff, bufc); } } else { it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } if ( mudconf.pub_flags || Examinable(executor, it) || it == enactor) { char *buff2 = decode_flags(executor, &(db[it].fs)); safe_str(buff2, buff, bufc); free_sbuf(buff2); } else { safe_noperm(buff, bufc); } } } /* --------------------------------------------------------------------------- * fun_rand: Return a random number from 0 to arg1-1 */ static FUNCTION(fun_rand) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int nDigits; switch (nfargs) { case 1: if (is_integer(fargs[0], &nDigits)) { int num = mux_atol(fargs[0]); if (num < 1) { safe_chr('0', buff, bufc); } else { safe_ltoa(RandomINT32(0, num-1), buff, bufc); } } else { safe_str("#-1 ARGUMENT MUST BE INTEGER", buff, bufc); } break; case 2: if ( is_integer(fargs[0], &nDigits) && is_integer(fargs[1], &nDigits)) { int lower = mux_atol(fargs[0]); int higher = mux_atol(fargs[1]); if ( lower <= higher && (unsigned int)(higher-lower) <= INT32_MAX_VALUE) { safe_ltoa(RandomINT32(lower, higher), buff, bufc); } else { safe_range(buff, bufc); } } else { safe_str("#-1 ARGUMENT MUST BE INTEGER", buff, bufc); } break; } } // --------------------------------------------------------------------------- // fun_time: // // With no arguments, it returns local time in the 'Ddd Mmm DD HH:MM:SS YYYY' // format. // // If an argument is provided, "utc" gives a UTC time string, and "local" // gives the local time string. // static FUNCTION(fun_time) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); CLinearTimeAbsolute ltaNow; if ( nfargs == 0 || mux_stricmp("utc", fargs[0]) != 0) { ltaNow.GetLocal(); } else { ltaNow.GetUTC(); } int nPrecision = 0; if (nfargs == 2) { nPrecision = mux_atol(fargs[1]); } char *temp = ltaNow.ReturnDateString(nPrecision); safe_str(temp, buff, bufc); } // --------------------------------------------------------------------------- // fun_secs. // // With no arguments, it returns seconds since Jan 01 00:00:00 1970 UTC not // counting leap seconds. // // If an argument is provided, "utc" gives UTC seconds, and "local" gives // an integer which corresponds to a local time string. It is not useful // as a count, but it can be given to convsecs(secs(),raw) to get the // corresponding time string. // static FUNCTION(fun_secs) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); CLinearTimeAbsolute ltaNow; if ( nfargs == 0 || mux_stricmp("local", fargs[0]) != 0) { ltaNow.GetUTC(); } else { ltaNow.GetLocal(); } int nPrecision = 0; if (nfargs == 2) { nPrecision = mux_atol(fargs[1]); } safe_str(ltaNow.ReturnSecondsString(nPrecision), buff, bufc); } // --------------------------------------------------------------------------- // fun_convsecs. // // With one arguments, it converts seconds from Jan 01 00:00:00 1970 UTC to a // local time string in the 'Ddd Mmm DD HH:MM:SS YYYY' format. // // If a second argument is given, it is the : // // local - indicates that a conversion for timezone/DST of the server should // be applied (default if no second argument is given). // // utc - indicates that no timezone/DST conversions should be applied. // This is useful to give a unique one-to-one mapping between an // integer and it's corresponding text-string. // static FUNCTION(fun_convsecs) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); CLinearTimeAbsolute lta; if (lta.SetSecondsString(fargs[0])) { if ( nfargs == 1 || mux_stricmp("utc", fargs[1]) != 0) { lta.UTC2Local(); } int nPrecision = 0; if (nfargs == 3) { nPrecision = mux_atol(fargs[2]); } char *temp = lta.ReturnDateString(nPrecision); safe_str(temp, buff, bufc); } else { safe_str("#-1 INVALID DATE", buff, bufc); } } // --------------------------------------------------------------------------- // fun_convtime. // // With one argument, it converts a local time string in the format //'[Ddd] Mmm DD HH:MM:SS YYYY' to a count of seconds from Jan 01 00:00:00 1970 // UTC. // // If a second argument is given, it is the : // // local - indicates that the given time string is for the local timezone // local DST adjustments (default if no second argument is given). // // utc - indicates that no timezone/DST conversions should be applied. // This is useful to give a unique one-to-one mapping between an // integer and it's corresponding text-string. // // This function returns -1 if there was a problem parsing the time string. // static FUNCTION(fun_convtime) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); CLinearTimeAbsolute lta; bool bZoneSpecified = false; if ( lta.SetString(fargs[0]) || ParseDate(lta, fargs[0], &bZoneSpecified)) { if ( !bZoneSpecified && ( nfargs == 1 || mux_stricmp("utc", fargs[1]) != 0)) { lta.Local2UTC(); } int nPrecision = 0; if (nfargs == 3) { nPrecision = mux_atol(fargs[2]); } safe_str(lta.ReturnSecondsString(nPrecision), buff, bufc); } else { safe_str("#-1 INVALID DATE", buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_starttime: What time did this system last reboot? */ static FUNCTION(fun_starttime) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *temp = mudstate.start_time.ReturnDateString(); safe_str(temp, buff, bufc); } // fun_timefmt // // timefmt([, ]) // // If isn't given, the current time is used. Escape sequences // in are expanded out. // // All escape sequences start with a $. Any unrecognized codes or other // text will be returned unchanged. // static const char *DayOfWeekStringLong[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; static const char *MonthTableLong[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static const int Map24to12[24] = { 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; static FUNCTION(fun_timefmt) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); CLinearTimeAbsolute lta, ltaUTC; if (nfargs == 2) { ltaUTC.SetSecondsString(fargs[1]); } else { ltaUTC.GetUTC(); } lta = ltaUTC; lta.UTC2Local(); FIELDEDTIME ft; lta.ReturnFields(&ft); // Calculate Time Zone Info // CLinearTimeDelta ltd = lta - ltaUTC; int iTZSecond = ltd.ReturnSeconds(); int iTZSign; if (iTZSecond < 0) { iTZSign = '-'; iTZSecond = -iTZSecond; } else { iTZSign = '+'; } int iTZHour = iTZSecond / 3600; iTZSecond %= 3600; int iTZMinute = iTZSecond/60; int iHour12 = Map24to12[ft.iHour]; // Calculate Monday and Sunday-oriented week numbers. // int iWeekOfYearSunday = (ft.iDayOfYear-ft.iDayOfWeek+6)/7; int iDayOfWeekMonday = (ft.iDayOfWeek == 0)?7:ft.iDayOfWeek; int iWeekOfYearMonday = (ft.iDayOfYear-iDayOfWeekMonday+7)/7; // Calculate ISO Week and Year. Remember that the ISO Year can be the // same, one year ahead, or one year behind of the Gregorian Year. // int iYearISO = ft.iYear; int iWeekISO = 0; int iTemp = 0; if ( ft.iMonth == 12 && 35 <= 7 + ft.iDayOfMonth - iDayOfWeekMonday) { iYearISO++; iWeekISO = 1; } else if ( ft.iMonth == 1 && ft.iDayOfMonth <= 3 && (iTemp = 7 - ft.iDayOfMonth + iDayOfWeekMonday) >= 11) { iYearISO--; if ( iTemp == 11 || ( iTemp == 12 && isLeapYear(iYearISO))) { iWeekISO = 53; } else { iWeekISO = 52; } } else { iWeekISO = (7 + ft.iDayOfYear - iDayOfWeekMonday)/7; if (4 <= (7 + ft.iDayOfYear - iDayOfWeekMonday)%7) { iWeekISO++; } } const char *pValidLongMonth = NULL; const char *pValidShortMonth = NULL; if ( 1 <= ft.iMonth && ft.iMonth <= 12) { pValidLongMonth = MonthTableLong[ft.iMonth-1]; pValidShortMonth = monthtab[ft.iMonth-1]; } else { pValidLongMonth = ""; pValidShortMonth = ""; } const char *pValidLongDayOfWeek = NULL; const char *pValidShortDayOfWeek = NULL; if (ft.iDayOfWeek <= 6) { pValidLongDayOfWeek = DayOfWeekStringLong[ft.iDayOfWeek]; pValidShortDayOfWeek = DayOfWeekString[ft.iDayOfWeek]; } else { pValidLongDayOfWeek = ""; pValidShortDayOfWeek = ""; } char *q; char *p = fargs[0]; while ((q = strchr(p, '$')) != NULL) { size_t nLen = q - p; safe_copy_buf(p, nLen, buff, bufc); p = q; // Now, p points to a '$'. // p++; // Handle modifiers // int iOption = 0; int ch = *p++; if (ch == '#' || ch == 'E' || ch == 'O') { iOption = ch; ch = *p++; } // Handle format letter. // switch (ch) { case 'a': // $a - Abbreviated weekday name safe_str(pValidShortDayOfWeek, buff, bufc); break; case 'A': // $A - Full weekday name safe_str(pValidLongDayOfWeek, buff, bufc); break; case 'b': // $b - Abbreviated month name case 'h': safe_str(pValidShortMonth, buff, bufc); break; case 'B': // $B - Full month name safe_str(pValidLongMonth, buff, bufc); break; case 'c': // $c - Date and time if (iOption == '#') { // Long version. // safe_tprintf_str(buff, bufc, "%s, %s %d, %d, %02d:%02d:%02d", pValidLongDayOfWeek, pValidLongMonth, ft.iDayOfMonth, ft.iYear, ft.iHour, ft.iMinute, ft.iSecond); } else { safe_str(lta.ReturnDateString(7), buff, bufc); } break; case 'C': // $C - The century (year/100). safe_tprintf_str(buff, bufc, "%d", ft.iYear / 100); break; case 'd': // $d - Day of Month as decimal number (1-31) safe_tprintf_str(buff, bufc, (iOption=='#')?"%d":"%02d", ft.iDayOfMonth); break; case 'x': // $x - Date if (iOption == '#') { safe_tprintf_str(buff, bufc, "%s, %s %d, %d", pValidLongDayOfWeek, pValidLongMonth, ft.iDayOfMonth, ft.iYear); break; } // FALL THROUGH case 'D': // $D - Equivalent to %m/%d/%y safe_tprintf_str(buff, bufc, "%02d/%02d/%02d", ft.iMonth, ft.iDayOfMonth, ft.iYear % 100); break; case 'e': // $e - Like $d, the day of the month as a decimal number, // but a leading zero is replaced with a space. safe_tprintf_str(buff, bufc, "%2d", ft.iDayOfMonth); break; case 'F': // $F - The ISO 8601 formated date. safe_tprintf_str(buff, bufc, "%d-%02d-%02d", ft.iYear, ft.iMonth, ft.iDayOfMonth); break; case 'g': // $g - Like $G, two-digit ISO 8601 year. safe_tprintf_str(buff, bufc, "%02d", iYearISO%100); break; case 'G': // $G - The ISO 8601 year. safe_tprintf_str(buff, bufc, "%04d", iYearISO); break; case 'H': // $H - Hour of the 24-hour day. safe_tprintf_str(buff, bufc, (iOption=='#')?"%d":"%02d", ft.iHour); break; case 'I': // $I - Hour of the 12-hour day safe_tprintf_str(buff, bufc, (iOption=='#')?"%d":"%02d", iHour12); break; case 'j': // $j - Day of the year. safe_tprintf_str(buff, bufc, (iOption=='#')?"%d":"%03d", ft.iDayOfYear); break; case 'k': // $k - Hour of the 24-hour day. Pad with a space. safe_tprintf_str(buff, bufc, "%2d", ft.iHour); break; case 'l': // $l - Hour of the 12-hour clock. Pad with a space. safe_tprintf_str(buff, bufc, "%2d", iHour12); break; case 'm': // $m - Month of the year safe_tprintf_str(buff, bufc, (iOption=='#')?"%d":"%02d", ft.iMonth); break; case 'M': // $M - Minutes after the hour safe_tprintf_str(buff, bufc, (iOption=='#')?"%d":"%02d", ft.iMinute); break; case 'n': // $n - Newline. safe_str("\r\n", buff, bufc); break; case 'p': // $p - AM/PM safe_str((ft.iHour < 12)?"AM":"PM", buff, bufc); break; case 'P': // $p - am/pm safe_str((ft.iHour < 12)?"am":"pm", buff, bufc); break; case 'r': // $r - Equivalent to $I:$M:$S $p safe_tprintf_str(buff, bufc, (iOption=='#')?"%d:%02d:%02d %s":"%02d:%02d:%02d %s", iHour12, ft.iMinute, ft.iSecond, (ft.iHour<12)?"AM":"PM"); break; case 'R': // $R - Equivalent to $H:$M safe_tprintf_str(buff, bufc, (iOption=='#')?"%d:%02d":"%02d:%02d", ft.iHour, ft.iMinute); break; case 's': // $s - Number of seconds since the epoch. safe_str(ltaUTC.ReturnSecondsString(7), buff, bufc); break; case 'S': // $S - Seconds after the minute safe_tprintf_str(buff, bufc, (iOption=='#')?"%d":"%02d", ft.iSecond); break; case 't': safe_chr('\t', buff, bufc); break; case 'X': // $X - Time case 'T': // $T - Equivalent to $H:$M:$S safe_tprintf_str(buff, bufc, (iOption=='#')?"%d:%02d:%02d":"%02d:%02d:%02d", ft.iHour, ft.iMinute, ft.iSecond); break; case 'u': // $u - Day of the Week, range 1 to 7. Monday = 1. safe_ltoa(iDayOfWeekMonday, buff, bufc); break; case 'U': // $U - Week of the year from 1st Sunday safe_tprintf_str(buff, bufc, (iOption=='#')?"%d":"%02d", iWeekOfYearSunday); break; case 'V': // $V - ISO 8601:1988 week number. safe_tprintf_str(buff, bufc, "%02d", iWeekISO); break; case 'w': // $w - Day of the week. 0 = Sunday safe_ltoa(ft.iDayOfWeek, buff, bufc); break; case 'W': // $W - Week of the year from 1st Monday safe_tprintf_str(buff, bufc, (iOption=='#')?"%d":"%02d", iWeekOfYearMonday); break; case 'y': // $y - Two-digit year safe_tprintf_str(buff, bufc, (iOption=='#')?"%d":"%02d", ft.iYear % 100); break; case 'Y': // $Y - All-digit year safe_tprintf_str(buff, bufc, (iOption=='#')?"%d":"%04d", ft.iYear); break; case 'z': // $z - Time zone safe_tprintf_str(buff, bufc, "%c%02d%02d", iTZSign, iTZHour, iTZMinute); break; case 'Z': // $Z - Time zone name // TODO break; case '$': // $$ safe_chr(ch, buff, bufc); break; default: safe_chr('$', buff, bufc); p = q + 1; break; } } safe_str(p, buff, bufc); } static FUNCTION(fun_etimefmt) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); CLinearTimeDelta ltd; ltd.SetSecondsString(fargs[1]); long seconds = ltd.ReturnSeconds(); long minutes = seconds/60; seconds -= 60*minutes; long hours = minutes/60; minutes -= 60*hours; long days = hours/24; hours -= 24*days; char *q; char *p = fargs[0]; while ((q = strchr(p, '$')) != NULL) { size_t nLen = q - p; safe_copy_buf(p, nLen, buff, bufc); p = q; // Now, p points to a '$'. // p++; int ch = *p++; // Look for a field width. // bool bHasWidth = false; int width = 0; if (mux_isdigit(ch)) { bHasWidth = true; do { width = 10 * width + (ch - '0'); ch = *p++; } while (mux_isdigit(ch)); if (11 < width) { width = 11; } } // Handle modifiers // bool bDoSuffix = false; bool bZeroIsBlank = false; while ( 'z' == mux_tolower(ch) || 'x' == mux_tolower(ch)) { switch (mux_tolower(ch)) { case 'x': bDoSuffix = true; break; case 'z': bZeroIsBlank = true; break; } ch = *p++; } char field[MBUF_SIZE]; size_t n = 0; // Handle format letter. // switch (ch) { case 's': // $s - The number of seconds. if ( 0 != seconds || !bZeroIsBlank) { if (bHasWidth) { n = RightJustifyNumber(field, width, seconds, ' '); field[n] = '\0'; safe_str(field, buff, bufc); } else { safe_ltoa(seconds, buff, bufc); } if (bDoSuffix) { safe_chr('s', buff, bufc); } } break; case 'S': // $S - The number of seconds, left-padded with zero. if ( 0 != seconds || !bZeroIsBlank) { if (bHasWidth) { n = RightJustifyNumber(field, width, seconds, '0'); field[n] = '\0'; safe_str(field, buff, bufc); } else { safe_ltoa(seconds, buff, bufc); } if (bDoSuffix) { safe_chr('s', buff, bufc); } } break; case 'm': // $m - The number of minutes. if ( 0 != minutes || !bZeroIsBlank) { if (bHasWidth) { n = RightJustifyNumber(field, width, minutes, ' '); field[n] = '\0'; safe_str(field, buff, bufc); } else { safe_ltoa(minutes, buff, bufc); } if (bDoSuffix) { safe_chr('m', buff, bufc); } } break; case 'M': // $M - The number of minutes, left-padded with zero. if ( 0 != minutes || !bZeroIsBlank) { if (bHasWidth) { n = RightJustifyNumber(field, width, minutes, '0'); field[n] = '\0'; safe_str(field, buff, bufc); } else { safe_ltoa(minutes, buff, bufc); } if (bDoSuffix) { safe_chr('m', buff, bufc); } } break; case 'h': // $h - The number of hours. if ( 0 != hours || !bZeroIsBlank) { if (bHasWidth) { n = RightJustifyNumber(field, width, hours, ' '); field[n] = '\0'; safe_str(field, buff, bufc); } else { safe_ltoa(hours, buff, bufc); } if (bDoSuffix) { safe_chr('h', buff, bufc); } } break; case 'H': // $H - The number of hours, left-padded with zero. if ( 0 != hours || !bZeroIsBlank) { if (bHasWidth) { n = RightJustifyNumber(field, width, hours, '0'); field[n] = '\0'; safe_str(field, buff, bufc); } else { safe_ltoa(hours, buff, bufc); } if (bDoSuffix) { safe_chr('h', buff, bufc); } } break; case 'd': // $d - The number of days. if ( 0 != days || !bZeroIsBlank) { if (bHasWidth) { n = RightJustifyNumber(field, width, days, ' '); field[n] = '\0'; safe_str(field, buff, bufc); } else { safe_ltoa(days, buff, bufc); } if (bDoSuffix) { safe_chr('d', buff, bufc); } } break; case 'D': // $D - The number of days, left-padded with zero. if ( 0 != days || !bZeroIsBlank) { if (bHasWidth) { n = RightJustifyNumber(field, width, days, '0'); field[n] = '\0'; safe_str(field, buff, bufc); } else { safe_ltoa(days, buff, bufc); } if (bDoSuffix) { safe_chr('d', buff, bufc); } } break; case 'n': // $n - Newline. safe_str("\r\n", buff, bufc); break; case '$': // $$ safe_chr(ch, buff, bufc); break; default: safe_chr('$', buff, bufc); p = q + 1; break; } } safe_str(p, buff, bufc); } #if defined(FIRANMUX) /* * --------------------------------------------------------------------------- * * fun_format: format a string (linewrap) with str, field, left, right */ FUNCTION(fun_format) { int fieldsize = mux_atol(fargs[1]); if ( fieldsize < 1 || 80 < fieldsize) { safe_str("#-1 ILLEGAL FIELDSIZE", buff, bufc); return; } size_t n2, n3; strip_ansi(fargs[2], &n2); strip_ansi(fargs[3], &n3); if (fieldsize + n2 + n3 > 79) { safe_str("#-1 COMBINED FIELD TOO LARGE", buff, bufc); return; } char *buf = alloc_lbuf("fun_format"); mux_strncpy(buf, fargs[0], LBUF_SIZE-1); linewrap_general(buf, fieldsize, fargs[2], fargs[3]); safe_str(buf, buff, bufc); free_lbuf(buf); } /* * --------------------------------------------------------------------------- * * text: return data from a file in game/text.. */ FUNCTION(fun_text) { FILE *textconf; if (!mux_fopen(&textconf, "textfiles.conf", "r")) { // Can't open the file. // safe_str("#-1 TEXTFILES.CONF MISSING", buff, bufc); return; } char mybuffer[80]; while (fgets(mybuffer, 80, textconf)) { int index = 0; while (mybuffer[index]) { if (mybuffer[index] == '\n') { mybuffer[index] = 0; } else { index++; } } /* Found the file listed, did I? */ if (!strcmp(mybuffer, fargs[0])) { FILE *myfile; if (!mux_fopen(&myfile, fargs[0], "r")) { /* But not here!? */ fclose(textconf); safe_str("#-1 FILE DOES NOT EXIST",buff,bufc); return; } while (fgets(mybuffer, 80, myfile)) { index = 0; while (mybuffer[index]) { if (mybuffer[index] == '\n') { mybuffer[index] = 0; } else { index++; } } if ('&' == mybuffer[0]) { if (!mux_stricmp(fargs[1]+strspn(fargs[1]," "), mybuffer+2)) { /* At this point I've found the file and the entry */ int thischar; int lastchar = '\0'; while ((thischar = fgetc(myfile)) != EOF) { if ('&' == thischar) { if ('\n' == lastchar) { fclose(textconf); fclose(myfile); return; } } safe_chr(thischar, buff, bufc); lastchar = thischar; } fclose(textconf); fclose(myfile); return; } } } fclose(textconf); fclose(myfile); safe_str("#-1 ENTRY NOT FOUND", buff, bufc); return; } } fclose(textconf); safe_str("#-1 FILE NOT LISTED",buff,bufc); } #endif // FIRANMUX // fun_successes // #define MAXDICE 11 #define MAXDIFF 10 #define MAXBOUND 14 typedef struct dice_node { short maxsuccs; short bound[MAXBOUND]; } dice_node; static const dice_node dice_table[MAXDICE][MAXDIFF] = { { // Dice 1 // Difficulty { 2, { 444, 842, 977, 998, 1000, -1 } }, // 1 { 2, { 359, 783, 963, 997, 1000, -1 } }, // 2 { 2, { 282, 717, 946, 995, 1000, -1 } }, // 3 { 2, { 215, 643, 923, 993, 1000, -1 } }, // 4 { 2, { 156, 562, 896, 989, 1000, -1 } }, // 5 { 2, { 108, 476, 861, 984, 999, 1000, -1 } }, // 6 { 2, { 68, 385, 820, 977, 999, 1000, -1 } }, // 7 { 2, { 39, 293, 770, 968, 998, 1000, -1 } }, // 8 { 2, { 18, 199, 711, 955, 997, 1000, -1 } }, // 9 { 2, { 5, 108, 642, 939, 996, 1000, -1 } } // 10 }, { // Dice 2 // Difficulty { 3, { 347, 755, 947, 994, 1000, -1 } }, // 1 { 3, { 253, 658, 910, 987, 999, 1000, -1 } }, // 2 { 3, { 178, 555, 861, 977, 998, 1000, -1 } }, // 3 { 3, { 119, 451, 798, 962, 997, 1000, -1 } }, // 4 { 3, { 74, 350, 721, 940, 994, 1000, -1 } }, // 5 { 3, { 43, 255, 630, 910, 990, 1000, -1 } }, // 6 { 3, { 22, 171, 526, 871, 984, 999, 1000, -1 } }, // 7 { 3, { 10, 101, 411, 819, 975, 999, 1000, -1 } }, // 8 { 3, { 3, 49, 287, 753, 962, 998, 1000, -1 } }, // 9 { 2, { 15, 159, 670, 944, 997, 1000, -1 } } // 10 }, { // Dice 3 // Difficulty { 4, { 271, 665, 905, 983, 998, 1000, -1 } }, // 1 { 4, { 178, 539, 836, 964, 995, 1000, -1 } }, // 2 { 4, { 112, 415, 747, 934, 990, 999, 1000, -1 } }, // 3 { 4, { 66, 302, 643, 888, 981, 998, 1000, -1 } }, // 4 { 4, { 35, 205, 526, 825, 966, 997, 1000, -1 } }, // 5 { 4, { 17, 128, 405, 742, 942, 994, 1000, -1 } }, // 6 { 4, { 7, 70, 286, 638, 907, 989, 1000, -1 } }, // 7 { 4, { 2, 32, 178, 512, 857, 981, 999, 1000, -1 } }, // 8 { 4, { 1, 11, 90, 367, 789, 968, 998, 1000, -1 } }, // 9 { 3, { 2, 29, 207, 696, 949, 997, 1000, -1 } } // 10 }, { // Dice 4 // Difficulty { 5, { 212, 579, 853, 966, 995, 1000, -1 } }, // 1 { 5, { 126, 432, 748, 926, 986, 998, 1000, -1 } }, // 2 { 5, { 70, 302, 624, 864, 969, 996, 1000, -1 } }, // 3 { 5, { 36, 196, 490, 778, 939, 991, 999, 1000, -1 } }, // 4 { 5, { 17, 116, 358, 669, 892, 980, 998, 1000, -1 } }, // 5 { 5, { 7, 61, 239, 540, 822, 963, 996, 1000, -1 } }, // 6 { 5, { 2, 28, 140, 400, 725, 934, 992, 1000, -1 } }, // 7 { 5, { 1, 10, 68, 261, 597, 888, 986, 999, 1000, -1 } }, // 8 { 4, { 2, 24, 137, 439, 819, 974, 999, 1000, -1 } }, // 9 { 3, { 4, 46, 254, 720, 954, 997, 1000, -1 } } // 10 }, { // Dice 5 // Difficulty { 6, { 165, 499, 793, 941, 989, 999, 1000, -1 } }, // 1 { 6, { 89, 342, 655, 874, 969, 995, 999, 1000, -1 } }, // 2 { 6, { 44, 216, 505, 775, 930, 986, 998, 1000, -1 } }, // 3 { 6, { 20, 125, 359, 649, 867, 968, 995, 1000, -1 } }, // 4 { 6, { 8, 64, 232, 506, 775, 934, 989, 999, 1000, -1 } }, // 5 { 6, { 3, 29, 132, 359, 653, 878, 976, 998, 1000, -1 } }, // 6 { 6, { 1, 11, 64, 224, 505, 793, 953, 995, 1000, -1 } }, // 7 { 5, { 3, 24, 116, 344, 669, 912, 989, 999, 1000, -1 } }, // 8 { 4, { 6, 44, 189, 504, 846, 978, 999, 1000, -1 } }, // 9 { 4, { 1, 8, 65, 298, 742, 958, 997, 1000, -1 } } // 10 }, { // Dice 6 // Difficulty { 7, { 129, 426, 728, 909, 978, 996, 1000, -1 } }, // 1 { 7, { 63, 267, 563, 809, 941, 987, 998, 1000, -1 } }, // 2 { 7, { 28, 152, 398, 675, 873, 965, 994, 999, 1000, -1 } }, // 3 { 7, { 11, 78, 254, 519, 770, 923, 983, 998, 1000, -1 } }, // 4 { 7, { 4, 35, 144, 362, 634, 851, 960, 994, 999, 1000, -1 } }, // 5 { 7, { 1, 13, 70, 223, 477, 743, 918, 985, 999, 1000, -1 } }, // 6 { 6, { 4, 28, 116, 315, 598, 844, 966, 996, 1000, -1 } }, // 7 { 6, { 1, 8, 47, 172, 424, 729, 931, 992, 1000, -1 } }, // 8 { 5, { 1, 13, 69, 243, 563, 868, 981, 999, 1000, -1 } }, // 9 { 4, { 1, 14, 87, 340, 763, 961, 998, 1000, -1 } } // 10 }, { // Dice 7 // Difficulty { 8, { 101, 361, 662, 869, 963, 992, 999, 1000, -1 } }, // 1 { 8, { 44, 207, 475, 736, 902, 973, 995, 999, 1000, -1 } }, // 2 { 8, { 17, 106, 307, 572, 799, 931, 983, 997, 1000, -1 } }, // 3 { 8, { 6, 48, 175, 401, 658, 854, 956, 991, 999, 1000, -1 } }, // 4 { 8, { 2, 19, 87, 248, 492, 737, 903, 976, 996, 1000, -1 } }, // 5 { 7, { 6, 36, 131, 324, 583, 813, 944, 990, 999, 1000, -1 } }, // 6 { 7, { 1, 12, 56, 180, 407, 678, 884, 976, 998, 1000, -1 } }, // 7 { 6, { 3, 18, 78, 235, 500, 779, 946, 994, 1000, -1 } }, // 8 { 5, { 3, 22, 98, 298, 615, 888, 984, 999, 1000, -1 } }, // 9 { 4, { 3, 21, 111, 380, 782, 965, 998, 1000, -1 } } // 10 }, { // Dice 8 // Difficulty { 9, { 79, 304, 596, 824, 943, 986, 997, 1000, -1 } }, // 1 { 9, { 31, 159, 396, 659, 853, 952, 989, 998, 1000, -1 } }, // 2 { 9, { 11, 73, 232, 473, 715, 882, 964, 992, 999, 1000, -1 } }, // 3 { 9, { 3, 29, 118, 300, 543, 766, 911, 975, 995, 999, 1000, -1 } }, // 4 { 9, { 1, 10, 51, 164, 364, 609, 816, 938, 986, 998, 1000, -1 } }, // 5 { 8, { 3, 18, 74, 209, 428, 675, 866, 963, 994, 999, 1000, -1 } }, // 6 { 7, { 5, 26, 97, 254, 495, 745, 914, 983, 998, 1000, -1 } }, // 7 { 7, { 1, 6, 33, 117, 300, 569, 821, 958, 995, 1000, -1 } }, // 8 { 6, { 1, 7, 35, 132, 352, 662, 904, 987, 999, 1000, -1 } }, // 9 { 4, { 4, 29, 137, 419, 799, 968, 998, 1000, -1 } } // 10 }, { // Dice 9 // Difficulty { 10, { 62, 255, 532, 774, 917, 977, 995, 999, 1000, -1 } }, // 1 { 10, { 22, 121, 326, 582, 796, 923, 978, 995, 999, 1000, -1 } }, // 2 { 10, { 7, 50, 173, 384, 625, 820, 933, 982, 996, 999, 1000, -1 } }, // 3 { 10, { 2, 18, 78, 219, 434, 666, 846, 946, 986, 998, 1000, -1 } }, // 4 { 9, { 5, 29, 105, 259, 481, 708, 874, 961, 992, 999, 1000, -1 } }, // 5 { 9, { 1, 9, 40, 128, 296, 527, 751, 904, 975, 996, 1000, -1 } }, // 6 { 8, { 2, 12, 49, 147, 332, 575, 799, 936, 988, 999, 1000, -1 } }, // 7 { 7, { 2, 13, 53, 162, 367, 631, 855, 967, 996, 1000, -1 } }, // 8 { 6, { 2, 11, 52, 170, 405, 703, 918, 989, 999, 1000, -1 } }, // 9 { 5, { 1, 7, 40, 164, 455, 815, 971, 998, 1000, -1 } } // 10 }, { // Dice 10 // Difficulty { 11, { 48, 213, 472, 721, 886, 963, 991, 998, 1000, -1 } }, // 1 { 11, { 15, 92, 266, 506, 733, 885, 962, 990, 998, 1000, -1 } }, // 2 { 11, { 4, 34, 127, 306, 536, 748, 891, 964, 991, 998, 1000, -1 } }, // 3 { 11, { 1, 11, 51, 156, 338, 562, 766, 901, 969, 993, 999, 1000, -1 } }, // 4 { 10, { 3, 17, 65, 178, 365, 589, 787, 915, 975, 995, 999, 1000, -1 } }, // 5 { 9, { 4, 21, 75, 195, 389, 617, 813, 933, 984, 998, 1000, -1 } }, // 6 { 9, { 1, 5, 24, 81, 207, 411, 648, 844, 953, 991, 999, 1000, -1 } }, // 7 { 8, { 1, 5, 23, 80, 213, 432, 687, 882, 974, 997, 1000, -1 } }, // 8 { 6, { 3, 18, 72, 210, 456, 740, 931, 991, 1000, -1 } }, // 9 { 5, { 1, 10, 51, 191, 489, 830, 974, 998, 1000, -1 } } // 10 }, { // Dice 11 // Difficulty { 12, { 38, 177, 415, 667, 850, 946, 985, 997, 999, -1 } }, // 1 { 12, { 11, 69, 214, 435, 666, 840, 939, 982, 996, 999, 1000, -1 } }, // 2 { 12, { 3, 23, 93, 239, 450, 669, 838, 937, 981, 996, 999, 1000, -1 } }, // 3 { 12, { 1, 6, 33, 109, 256, 462, 675, 841, 939, 982, 996, 999, 1000, -1 } }, // 4 { 11, { 1, 9, 40, 119, 267, 471, 683, 848, 944, 985, 997, 1000, -1 } }, // 5 { 10, { 2, 11, 43, 123, 273, 480, 695, 861, 953, 989, 998, 1000, -1 } }, // 6 { 9, { 2, 11, 42, 122, 273, 487, 711, 879, 965, 994, 999, 1000, -1 } }, // 7 { 8, { 2, 9, 37, 113, 267, 495, 735, 905, 980, 998, 1000, -1 } }, // 8 { 7, { 1, 6, 28, 96, 252, 505, 773, 941, 992, 1000, -1 } }, // 9 { 5, { 2, 14, 65, 220, 521, 844, 976, 999, 1000, -1 } }, // 10 } }; #define OLDSUCC_DIE_TO_ROLL 10 #define DIE_TO_ROLL 1000 #define NUMBER_TOO_LARGE (-200) /* * Roll a 10-sided die. If it's equal to or higher than the difficulty, * return true. */ static int simple_success(int diff) { int rand = RandomINT32(1, OLDSUCC_DIE_TO_ROLL); return rand >= diff; } /* The lookup function: Given a table in the form of table[dice][diff] and a given number this function returns the number of successes corresponding to that number in the table. If the number is larger than the largest boundary, it will return NUMBER_TOO_LARGE. */ static int lookup_succ_table(const dice_node *row, int *psucc) { int randnum = RandomINT32(0, DIE_TO_ROLL-1); int succs = row->maxsuccs; for (int i = 0; i < MAXBOUND && 0 < row->bound[i]; i++) { if (randnum < row->bound[i]) { *psucc = succs; return 0; } succs--; } return NUMBER_TOO_LARGE; } /* A simple function to trigger the lookup: Translates the dice, diff and random number into an entry point for the table and retrieves the appropriate number of successes. If the request is for a result outside of the table, use the following simple algorithm: Get the result from this algorithm with MAXDICE, then, for every die over the max, roll one die. If it's over the diff, add a success. If the diff is higher than MAXDIFF, return 0 successes. */ static int getsuccs(int dice, int diff, int *psucc) { if (dice <= 0) { *psucc = 0; return 0; } if (diff <= 0) { *psucc = dice; return 0; } else if (MAXDIFF < diff) { *psucc = 0; return 0; } int extra_successes = 0; if (MAXDICE < dice) { for (int i = MAXDICE; i < dice; i++) { if (simple_success(diff)) { extra_successes++; } } dice = MAXDICE; } int succs; const dice_node *node = &dice_table[dice-1][diff-1]; int err = lookup_succ_table(node, &succs); if (0 == err) { *psucc = succs + extra_successes; } return err; } /* The MUX-style function */ FUNCTION(fun_successes) { // Number of dice and difficulty. // if ( !is_integer(fargs[0], NULL) || !is_integer(fargs[1], NULL)) { safe_str("#-1 ARGUMENTS MUST BE INTEGERS", buff, bufc); return; } int ver = 1; if (3 <= nfargs) { ver = mux_atol(fargs[2]); } int num_dice = mux_atol(fargs[0]); if (0 == num_dice) { safe_str("0", buff, bufc); } else if (num_dice < 0) { safe_str("#-1 NUMBER OF DICE SHOULD BE > 0", buff, bufc); } else if (100 < num_dice) { safe_str("#-1 THAT'S TOO MANY DICE FOR ME TO ROLL", buff, bufc); } else { int difficulty = mux_atol(fargs[1]); int successes = 0; if (1 == ver) { switch (getsuccs(num_dice, difficulty, &successes)) { case 0: safe_tprintf_str(buff, bufc, "%d", successes); break; case NUMBER_TOO_LARGE: safe_str("#-1 INVALID SUCCESS TABLE", buff, bufc); break; default: safe_str("#-1 UNKNOWN ERROR", buff, bufc); break; } } else { // Roll some number of dice equal to num_dice and count successes and botches // int i; for (i = 0; i < num_dice; i++) { int roll = RandomINT32(1, OLDSUCC_DIE_TO_ROLL); if (1 == roll) { // Botch -- decrement successes. // --successes; } else if (difficulty <= roll) { // Success -- increment successes. // ++successes; } } if (difficulty < num_dice) { if (successes < 0) { successes = 0; } else if (successes == 0) { successes = 1; } } // Return final number of successes (positive, negative, or zero). // safe_ltoa(successes, buff, bufc); } } } /* * --------------------------------------------------------------------------- * * fun_get, fun_get_eval: Get attribute from object. */ #define GET_GET 1 #define GET_XGET 2 #define GET_EVAL 4 #define GET_GEVAL 8 static void get_handler(char *buff, char **bufc, dbref executor, char *fargs[], int key) { bool bFreeBuffer = false; char *pRefAttrib = fargs[0]; if ( key == GET_XGET || key == GET_EVAL) { pRefAttrib = alloc_lbuf("get_handler"); char *bufp = pRefAttrib; safe_tprintf_str(pRefAttrib, &bufp, "%s/%s", fargs[0], fargs[1]); bFreeBuffer = true; } dbref thing; ATTR *pattr; bool bNoMatch = !parse_attrib(executor, pRefAttrib, &thing, &pattr); if (bFreeBuffer) { free_lbuf(pRefAttrib); } if (bNoMatch) { safe_nomatch(buff, bufc); return; } if (!pattr) { return; } if ( (pattr->flags & AF_IS_LOCK) || !bCanReadAttr(executor, thing, pattr, true)) { safe_noperm(buff, bufc); return; } dbref aowner; int aflags; size_t nLen = 0; char *atr_gotten = atr_pget_LEN(thing, pattr->number, &aowner, &aflags, &nLen); if ( key == GET_EVAL || key == GET_GEVAL) { char *str = atr_gotten; mux_exec(buff, bufc, thing, executor, executor, AttrTrace(aflags, EV_FIGNORE|EV_EVAL), &str, NULL, 0); } else { if (nLen) { safe_copy_buf(atr_gotten, nLen, buff, bufc); } } free_lbuf(atr_gotten); } static FUNCTION(fun_get) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); get_handler(buff, bufc, executor, fargs, GET_GET); } static FUNCTION(fun_xget) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!*fargs[0] || !*fargs[1]) { return; } get_handler(buff, bufc, executor, fargs, GET_XGET); } static FUNCTION(fun_get_eval) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); get_handler(buff, bufc, executor, fargs, GET_GEVAL); } static FUNCTION(fun_subeval) { UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *str = fargs[0]; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_EVAL|EV_NO_LOCATION|EV_NOFCHECK|EV_FIGNORE|EV_NO_COMPRESS, &str, NULL, 0); } static FUNCTION(fun_eval) { UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (nfargs == 1) { char *str = fargs[0]; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_EVAL, &str, NULL, 0); return; } if (!*fargs[0] || !*fargs[1]) { return; } get_handler(buff, bufc, executor, fargs, GET_EVAL); } /* * --------------------------------------------------------------------------- * * fun_u and fun_ulocal: Call a user-defined function. */ static void do_ufun(char *buff, char **bufc, dbref executor, dbref caller, dbref enactor, char *fargs[], int nfargs, char *cargs[], int ncargs, bool is_local) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *atext; dbref thing; dbref aowner; int aflags; if (!parse_and_get_attrib(executor, fargs, &atext, &thing, &aowner, &aflags, buff, bufc)) { return; } // If we're evaluating locally, preserve the global registers. // reg_ref **preserve = NULL; if (is_local) { preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); } // Evaluate it using the rest of the passed function args. // char *str = atext; mux_exec(buff, bufc, thing, executor, enactor, AttrTrace(aflags, EV_FCHECK|EV_EVAL), &str, &(fargs[1]), nfargs - 1); free_lbuf(atext); // If we're evaluating locally, restore the preserved registers. // if (is_local) { restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); } } static FUNCTION(fun_u) { UNUSED_PARAMETER(eval); do_ufun(buff, bufc, executor, caller, enactor, fargs, nfargs, cargs, ncargs, false); } static FUNCTION(fun_ulocal) { UNUSED_PARAMETER(eval); do_ufun(buff, bufc, executor, caller, enactor, fargs, nfargs, cargs, ncargs, true); } /* * --------------------------------------------------------------------------- * * fun_parent: Get parent of object. */ static FUNCTION(fun_parent) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } if ( Examinable(executor, it) || it == enactor) { safe_tprintf_str(buff, bufc, "#%d", Parent(it)); } else { safe_noperm(buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_mid: mid(foobar,2,3) returns oba */ static FUNCTION(fun_mid) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // Initial checks for iPosition0 [0,LBUF_SIZE), nLength [0,LBUF_SIZE), // and iPosition1 [0,LBUF_SIZE). // int iPosition0 = mux_atol(fargs[1]); int nLength = mux_atol(fargs[2]); if (nLength < 0) { iPosition0 += nLength; nLength = -nLength; } if (iPosition0 < 0) { iPosition0 = 0; } else if (LBUF_SIZE-1 < iPosition0) { iPosition0 = LBUF_SIZE-1; } // At this point, iPosition0, nLength are reasonable numbers which may // -still- not refer to valid data in the string. // struct ANSI_In_Context aic; ANSI_String_In_Init(&aic, fargs[0], ANSI_ENDGOAL_NORMAL); size_t nDone; ANSI_String_Skip(&aic, iPosition0, &nDone); if (nDone < static_cast(iPosition0)) { return; } struct ANSI_Out_Context aoc; size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; ANSI_String_Out_Init(&aoc, *bufc, nBufferAvailable, nLength, ANSI_ENDGOAL_NORMAL); ANSI_String_Copy(&aoc, &aic, nLength); size_t nSize = ANSI_String_Finalize(&aoc, &nDone); *bufc += nSize; } // --------------------------------------------------------------------------- // fun_right: right(foobar,2) returns ar // --------------------------------------------------------------------------- static FUNCTION(fun_right) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // nLength on [0,LBUF_SIZE). // long lLength = mux_atol(fargs[1]); size_t nLength; if (lLength < 0) { safe_range(buff, bufc); return; } else if (LBUF_SIZE-1 < lLength) { nLength = LBUF_SIZE-1; } else { nLength = lLength; } // iPosition1 on [0,LBUF_SIZE) // size_t iPosition1 = strlen(strip_ansi(fargs[0])); // iPosition0 on [0,LBUF_SIZE) // size_t iPosition0; if (iPosition1 <= nLength) { iPosition0 = 0; } else { iPosition0 = iPosition1 - nLength; } // At this point, iPosition0, nLength, and iPosition1 are reasonable // numbers which may -still- not refer to valid data in the string. // struct ANSI_In_Context aic; ANSI_String_In_Init(&aic, fargs[0], ANSI_ENDGOAL_NORMAL); size_t nDone; ANSI_String_Skip(&aic, iPosition0, &nDone); if ((size_t)nDone < iPosition0) { return; } struct ANSI_Out_Context aoc; size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; ANSI_String_Out_Init(&aoc, *bufc, nBufferAvailable, nLength, ANSI_ENDGOAL_NORMAL); ANSI_String_Copy(&aoc, &aic, nLength); size_t nSize = ANSI_String_Finalize(&aoc, &nDone); *bufc += nSize; } /* * --------------------------------------------------------------------------- * * fun_first: Returns first word in a string */ static FUNCTION(fun_first) { // If we are passed an empty arglist return a null string. // if (nfargs == 0) { return; } SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } char *s = trim_space_sep(fargs[0], &sep); char *first = split_token(&s, &sep); if (first) { safe_str(first, buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_rest: Returns all but the first word in a string */ static FUNCTION(fun_rest) { // If we are passed an empty arglist return a null string. // if (nfargs == 0) { return; } SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } char *s = trim_space_sep(fargs[0], &sep); split_token(&s, &sep); if (s) { safe_str(s, buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_v: Function form of %-substitution */ static FUNCTION(fun_v) { UNUSED_PARAMETER(nfargs); dbref aowner; int aflags; char *sbuf, *sbufc, *tbuf, *str; ATTR *ap; tbuf = fargs[0]; if (mux_AttrNameInitialSet(tbuf[0]) && tbuf[1]) { // Fetch an attribute from me. First see if it exists, // returning a null string if it does not. // ap = atr_str(fargs[0]); if (!ap) { return; } // If we can access it, return it, otherwise return a null // string. // size_t nLen; tbuf = atr_pget_LEN(executor, ap->number, &aowner, &aflags, &nLen); if (See_attr(executor, executor, ap)) { safe_copy_buf(tbuf, nLen, buff, bufc); } free_lbuf(tbuf); return; } // Not an attribute, process as % // sbuf = alloc_sbuf("fun_v"); sbufc = sbuf; safe_sb_chr('%', sbuf, &sbufc); safe_sb_str(fargs[0], sbuf, &sbufc); *sbufc = '\0'; str = sbuf; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_EVAL|EV_FIGNORE, &str, cargs, ncargs); free_sbuf(sbuf); } /* * --------------------------------------------------------------------------- * * fun_s: Force substitution to occur. */ static FUNCTION(fun_s) { UNUSED_PARAMETER(nfargs); char *str = fargs[0]; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_FIGNORE|EV_EVAL, &str, cargs, ncargs); } /* * --------------------------------------------------------------------------- * * fun_con: Returns first item in contents list of object/room */ static FUNCTION(fun_con) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); } else if (Has_contents(it)) { if ( Examinable(executor, it) || where_is(executor) == it || it == enactor) { safe_tprintf_str(buff, bufc, "#%d", Contents(it)); } else { safe_noperm(buff, bufc); } } else { safe_nothing(buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_exit: Returns first exit in exits list of room. */ static FUNCTION(fun_exit) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); } else if ( Has_exits(it) && Good_obj(Exits(it))) { int key = 0; if (Examinable(executor, it)) { key |= VE_LOC_XAM; } if (Dark(it)) { key |= VE_LOC_DARK; } dbref exit; DOLIST(exit, Exits(it)) { if (exit_visible(exit, executor, key)) { safe_tprintf_str(buff, bufc, "#%d", exit); return; } } safe_notfound(buff, bufc); } else { safe_nothing(buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_next: return next thing in contents or exits chain */ static FUNCTION(fun_next) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); } else if (Has_siblings(it)) { dbref loc = where_is(it); bool ex_here = Good_obj(loc) ? Examinable(executor, loc) : false; if ( ex_here || loc == executor || loc == where_is(executor)) { if (!isExit(it)) { safe_tprintf_str(buff, bufc, "#%d", Next(it)); } else { int key = 0; if (ex_here) { key |= VE_LOC_XAM; } if (Dark(loc)) { key |= VE_LOC_DARK; } dbref exit; DOLIST(exit, it) { if ( exit != it && exit_visible(exit, executor, key)) { safe_tprintf_str(buff, bufc, "#%d", exit); return; } } safe_notfound(buff, bufc); } } else { safe_noperm(buff, bufc); } } else { safe_nothing(buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_loc: Returns the location of something */ static FUNCTION(fun_loc) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); } else if (locatable(executor, it, enactor)) { safe_tprintf_str(buff, bufc, "#%d", Location(it)); } else { safe_nothing(buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_where: Returns the "true" location of something */ static FUNCTION(fun_where) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); } else if (locatable(executor, it, enactor)) { safe_tprintf_str(buff, bufc, "#%d", where_is(it)); } else { safe_nothing(buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_rloc: Returns the recursed location of something (specifying #levels) */ static FUNCTION(fun_rloc) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int levels = mux_atol(fargs[1]); if (levels > mudconf.ntfy_nest_lim) { levels = mudconf.ntfy_nest_lim; } dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); } else if (locatable(executor, it, enactor)) { for (int i = 0; i < levels; i++) { if ( Good_obj(it) && ( isExit(it) || Has_location(it))) { it = Location(it); } else { break; } } safe_tprintf_str(buff, bufc, "#%d", it); } else { safe_nothing(buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_room: Find the room an object is ultimately in. */ static FUNCTION(fun_room) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); } else if (locatable(executor, it, enactor)) { int count; for (count = mudconf.ntfy_nest_lim; count > 0; count--) { it = Location(it); if (!Good_obj(it)) { break; } if (isRoom(it)) { safe_tprintf_str(buff, bufc, "#%d", it); return; } } safe_nothing(buff, bufc); } else if (isRoom(it)) { safe_tprintf_str(buff, bufc, "#%d", it); } else { safe_nothing(buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_owner: Return the owner of an object. */ static FUNCTION(fun_owner) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it; ATTR *pattr; if (parse_attrib(executor, fargs[0], &it, &pattr)) { if ( !pattr || !See_attr(executor, it, pattr)) { safe_nothing(buff, bufc); return; } else { dbref aowner; int aflags; atr_pget_info(it, pattr->number, &aowner, &aflags); it = aowner; } } else { it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } it = Owner(it); } safe_tprintf_str(buff, bufc, "#%d", it); } /* * --------------------------------------------------------------------------- * * fun_controls: Does x control y? */ static FUNCTION(fun_controls) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref x = match_thing_quiet(executor, fargs[0]); if (!Good_obj(x)) { safe_match_result(x, buff, bufc); safe_str(" (ARG1)", buff, bufc); return; } dbref y = match_thing_quiet(executor, fargs[1]); if (!Good_obj(y)) { safe_match_result(x, buff, bufc); safe_str(" (ARG2)", buff, bufc); return; } safe_bool(Controls(x,y), buff, bufc); } /* * --------------------------------------------------------------------------- * * fun_fullname: Return the fullname of an object (good for exits) */ static FUNCTION(fun_fullname) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } if (!mudconf.read_rem_name) { if ( !nearby_or_control(executor, it) && !isPlayer(it)) { safe_str("#-1 TOO FAR AWAY TO SEE", buff, bufc); return; } } safe_str(Name(it), buff, bufc); } /* * --------------------------------------------------------------------------- * * fun_name: Return the name of an object */ static FUNCTION(fun_name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } if (!mudconf.read_rem_name) { if ( !nearby_or_control(executor, it) && !isPlayer(it) && !Long_Fingers(executor)) { safe_str("#-1 TOO FAR AWAY TO SEE", buff, bufc); return; } } char *temp = *bufc; safe_str(Name(it), buff, bufc); if (isExit(it)) { char *s; for (s = temp; (s != *bufc) && (*s != ';'); s++) { // Do nothing // ; } if (*s == ';') { *bufc = s; } } } /* * --------------------------------------------------------------------------- * * fun_match, fun_strmatch: Match arg2 against each word of arg1 returning * * index of first match, or against the whole string. */ static FUNCTION(fun_match) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } // Check each word individually, returning the word number of the first // one that matches. If none match, return 0. // int wcount = 1; char *s = trim_space_sep(fargs[0], &sep); do { char *r = split_token(&s, &sep); mudstate.wild_invk_ctr = 0; if (quick_wild(fargs[1], r)) { safe_ltoa(wcount, buff, bufc); return; } wcount++; } while (s); safe_chr('0', buff, bufc); } static FUNCTION(fun_strmatch) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // Check if we match the whole string. If so, return 1. // mudstate.wild_invk_ctr = 0; bool cc = quick_wild(fargs[1], fargs[0]); safe_bool(cc, buff, bufc); } /* * --------------------------------------------------------------------------- * * fun_extract: extract words from string: * * extract(foo bar baz,1,2) returns 'foo bar' * * extract(foo bar baz,2,1) returns 'bar' * * extract(foo bar baz,2,2) returns 'bar baz' * * * * Now takes optional separator extract(foo-bar-baz,1,2,-) returns 'foo-bar' */ static FUNCTION(fun_extract) { SEP sep; if (!OPTIONAL_DELIM(4, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(5, osep, DELIM_NULL|DELIM_CRLF|DELIM_INIT|DELIM_STRING)) { return; } int start = mux_atol(fargs[1]); int len = mux_atol(fargs[2]); if ( start < 1 || len < 1) { return; } // Skip to the start of the string to save. // start--; char *s = trim_space_sep(fargs[0], &sep); while ( start && s) { s = next_token(s, &sep); start--; } // If we ran of the end of the string, return nothing. // if (!s || !*s) { return; } // Count off the words in the string to save. // bool bFirst = true; while ( len && s) { char *t = split_token(&s, &sep); if (!bFirst) { print_sep(&osep, buff, bufc); } else { bFirst = false; } safe_str(t, buff, bufc); len--; } } // xlate() controls the subtle definition of a softcode boolean. // bool xlate(char *arg) { const char *p = arg; if (p[0] == '#') { if (p[1] == '-') { // '#-...' is false. This includes '#-0000' and '#-ABC'. // This cases are unlikely in practice. We can always come back // and cover these. // return false; } return true; } PARSE_FLOAT_RESULT pfr; if (ParseFloat(&pfr, p)) { // Examine whether number was a zero value. // if (pfr.iString) { // This covers NaN, +Inf, -Inf, and Ind. // return false; } // We can ignore leading sign, exponent sign, and exponent as 0, -0, // and +0. Also, 0E+100 and 0.0e-100 are all zero. // // However, we need to cover 00000.0 and 0.00000 cases. // while (pfr.nDigitsA--) { if (*pfr.pDigitsA != '0') { return true; } pfr.pDigitsA++; } while (pfr.nDigitsB--) { if (*pfr.pDigitsB != '0') { return true; } pfr.pDigitsB++; } return false; } while (mux_isspace(*p)) { p++; } if (p[0] == '\0') { return false; } return true; } /* --------------------------------------------------------------------------- * fun_index: like extract(), but it works with an arbitrary separator. * index(a b | c d e | f g h | i j k, |, 2, 1) => c d e * index(a b | c d e | f g h | i j k, |, 2, 2) => c d e | f g h */ static FUNCTION(fun_index) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int start, end; char c, *s, *p; s = fargs[0]; c = *fargs[1]; start = mux_atol(fargs[2]); end = mux_atol(fargs[3]); if ((start < 1) || (end < 1) || (*s == '\0')) { return; } if (c == '\0') { c = ' '; } // Move s to point to the start of the item we want. // start--; while (start && s && *s) { if ((s = strchr(s, c)) != NULL) { s++; } start--; } // Skip over just spaces. // while (s && (*s == ' ')) { s++; } if (!s || !*s) { return; } // Figure out where to end the string. // p = s; while (end && p && *p) { if ((p = strchr(p, c)) != NULL) { if (--end == 0) { do { p--; } while ((*p == ' ') && (p > s)); *(++p) = '\0'; safe_str(s, buff, bufc); return; } else { p++; } } } // if we've gotten this far, we've run off the end of the string. // safe_str(s, buff, bufc); } static FUNCTION(fun_cat) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (nfargs) { safe_str(fargs[0], buff, bufc); for (int i = 1; i < nfargs; i++) { safe_chr(' ', buff, bufc); safe_str(fargs[i], buff, bufc); } } } static FUNCTION(fun_version) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_str(mudstate.version, buff, bufc); } static FUNCTION(fun_strlen) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); size_t n = 0; if (nfargs >= 1) { strip_ansi(fargs[0], &n); } safe_ltoa(static_cast(n), buff, bufc); } static FUNCTION(fun_strmem) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); size_t n = 0; if (nfargs >= 1) { n = strlen(fargs[0]); } safe_ltoa(static_cast(n), buff, bufc); } static FUNCTION(fun_num) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_tprintf_str(buff, bufc, "#%d", match_thing_quiet(executor, fargs[0])); } static void internalPlayerFind ( char* buff, char** bufc, dbref player, char* name, int bVerifyPlayer ) { dbref thing; if (*name == '#') { thing = match_thing_quiet(player, name); if (bVerifyPlayer) { if (!Good_obj(thing)) { safe_match_result(thing, buff, bufc); return; } if (!isPlayer(thing)) { safe_nomatch(buff, bufc); return; } } } else { char *nptr = name; if (*nptr == '*') { // Start with the second character in the name string. // nptr++; } thing = lookup_player(player, nptr, true); if ( (!Good_obj(thing)) || (!isPlayer(thing) && bVerifyPlayer)) { safe_nomatch(buff, bufc); return; } } ITL pContext; ItemToList_Init(&pContext, buff, bufc, '#'); ItemToList_AddInteger(&pContext, thing); ItemToList_Final(&pContext); } static FUNCTION(fun_pmatch) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); internalPlayerFind(buff, bufc, executor, fargs[0], true); } static FUNCTION(fun_pfind) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); internalPlayerFind(buff, bufc, executor, fargs[0], false); } /* * --------------------------------------------------------------------------- * * fun_comp: string compare. */ static FUNCTION(fun_comp) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int x; x = strcmp(fargs[0], fargs[1]); if (x < 0) { safe_str("-1", buff, bufc); } else { safe_bool((x != 0), buff, bufc); } } #if defined(WOD_REALMS) || defined(REALITY_LVLS) static FUNCTION(fun_cansee) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref looker = match_thing_quiet(executor, fargs[0]); if (!Good_obj(looker)) { safe_match_result(looker, buff, bufc); safe_str(" (LOOKER)", buff, bufc); return; } dbref lookee = match_thing_quiet(executor, fargs[1]); if (!Good_obj(lookee)) { safe_match_result(looker, buff, bufc); safe_str(" (LOOKEE)", buff, bufc); return; } int mode; if (nfargs == 3) { mode = mux_atol(fargs[2]); switch (mode) { case ACTION_IS_STATIONARY: case ACTION_IS_MOVING: case ACTION_IS_TALKING: break; default: mode = ACTION_IS_STATIONARY; break; } } else { mode = ACTION_IS_STATIONARY; } // Do it. // int Realm_Do = DoThingToThingVisibility(looker, lookee, mode); bool bResult = false; if ((Realm_Do & REALM_DO_MASK) != REALM_DO_HIDDEN_FROM_YOU) { #ifdef REALITY_LVLS bResult = (!Dark(lookee) && IsReal(looker, lookee)); #else bResult = !Dark(lookee); #endif // REALITY_LVLS } safe_bool(bResult, buff, bufc); } #endif typedef enum { lconAny = 0, lconPlayer, lconObject, lconConnect, lconPuppet, lconListen } lconSubset; static struct lconSubsetTable { const char *name; lconSubset subset; } SubsetTable[] = { { "PLAYER", lconPlayer }, { "OBJECT", lconObject }, { "CONNECT", lconConnect}, { "PUPPET", lconPuppet }, { "LISTEN", lconListen }, { NULL, lconAny } }; /* * --------------------------------------------------------------------------- * * fun_lcon: Return a list of contents. */ static FUNCTION(fun_lcon) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } if (!Has_contents(it)) { safe_nothing(buff, bufc); return; } lconSubset i_subset = lconAny; if (2 == nfargs) { // PLAYER -- include only Player objects. // OBJECT -- include only non-Player objects. // CONNECT -- include only Connected Players. // PUPPET -- include only Puppets. // LISTEN -- include only Listening objects. lconSubsetTable *p = SubsetTable; while (NULL != p->name) { if (mux_stricmp(fargs[1], p->name) == 0) { i_subset = p->subset; break; } p++; } } if ( Examinable(executor, it) || Location(executor) == it || it == enactor) { dbref thing; ITL pContext; ItemToList_Init(&pContext, buff, bufc, '#'); DOLIST(thing, Contents(it)) { #ifdef WOD_REALMS int iRealmAction = DoThingToThingVisibility(executor, thing, ACTION_IS_STATIONARY); if (iRealmAction != REALM_DO_HIDDEN_FROM_YOU) { #endif if ( Can_Hide(thing) && Hidden(thing) && !See_Hidden(executor)) { continue; } if (lconAny != i_subset) { if ( ( lconPlayer == i_subset && !isPlayer(thing)) || ( lconObject == i_subset && isPlayer(thing)) || ( lconConnect == i_subset && !Connected(thing)) || ( lconPuppet == i_subset && !Puppet(thing)) || ( lconListen == i_subset && !H_Listen(thing))) { continue; } } if (!ItemToList_AddInteger(&pContext, thing)) { break; } #ifdef WOD_REALMS } #endif } ItemToList_Final(&pContext); } else { safe_noperm(buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_lexits: Return a list of exits. */ static FUNCTION(fun_lexits) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } if (!Has_exits(it)) { safe_nothing(buff, bufc); return; } bool bExam = Examinable(executor, it); if ( !bExam && where_is(executor) != it && it != enactor) { safe_noperm(buff, bufc); return; } // Return info for all parent levels. // bool bDone = false; dbref parent; int lev; ITL pContext; ItemToList_Init(&pContext, buff, bufc, '#'); ITER_PARENTS(it, parent, lev) { // Look for exits at each level. // if (!Has_exits(parent)) { continue; } int key = 0; if (Examinable(executor, parent)) { key |= VE_LOC_XAM; } if (Dark(parent)) { key |= VE_LOC_DARK; } if (Dark(it)) { key |= VE_BASE_DARK; } dbref thing; DOLIST(thing, Exits(parent)) { if ( exit_visible(thing, executor, key) && !ItemToList_AddInteger(&pContext, thing)) { bDone = true; break; } } if (bDone) { break; } } ItemToList_Final(&pContext); } // --------------------------------------------------------------------------- // fun_entrances: Search database for entrances (inverse of exits). // FUNCTION(fun_entrances) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *p; dbref i; dbref low_bound = 0; if (3 <= nfargs) { p = fargs[2]; if (NUMBER_TOKEN == p[0]) { p++; } i = mux_atol(p); if (Good_dbref(i)) { low_bound = i; } } dbref high_bound = mudstate.db_top - 1; if (4 == nfargs) { p = fargs[3]; if (NUMBER_TOKEN == p[0]) { p++; } i = mux_atol(p); if (Good_dbref(i)) { high_bound = i; } } bool find_ex = false; bool find_th = false; bool find_pl = false; bool find_rm = false; if (2 <= nfargs) { for (p = fargs[1]; *p; p++) { switch(mux_toupper(*p)) { case 'A': find_ex = find_th = find_pl = find_rm = true; break; case 'E': find_ex = true; break; case 'T': find_th = true; break; case 'P': find_pl = true; break; case 'R': find_rm = true; break; default: safe_str("#-1 INVALID TYPE", buff, bufc); return; } } } if (!(find_ex || find_th || find_pl || find_rm)) { find_ex = find_th = find_pl = find_rm = true; } dbref thing; if ( nfargs == 0 || *fargs[0] == '\0') { if (Has_location(executor)) { thing = Location(executor); } else { thing = executor; } if (!Good_obj(thing)) { safe_nothing(buff, bufc); return; } } else { init_match(executor, fargs[0], NOTYPE); match_everything(MAT_EXIT_PARENTS); thing = noisy_match_result(); if (!Good_obj(thing)) { safe_nothing(buff, bufc); return; } } if (!payfor(executor, mudconf.searchcost)) { notify(executor, tprintf("You don't have enough %s.", mudconf.many_coins)); safe_nothing(buff, bufc); return; } int control_thing = Examinable(executor, thing); ITL itl; ItemToList_Init(&itl, buff, bufc, '#'); for (i = low_bound; i <= high_bound; i++) { if ( control_thing || Examinable(executor, i)) { if ( ( find_ex && isExit(i) && Location(i) == thing) || ( find_rm && isRoom(i) && Dropto(i) == thing) || ( find_th && isThing(i) && Home(i) == thing) || ( find_pl && isPlayer(i) && Home(i) == thing)) { if (!ItemToList_AddInteger(&itl, i)) { break; } } } } ItemToList_Final(&itl); } /* * -------------------------------------------------------------------------- * * fun_home: Return an object's home */ static FUNCTION(fun_home) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); } else if (!Examinable(executor, it)) { safe_noperm(buff, bufc); } else if (Has_home(it)) { safe_tprintf_str(buff, bufc, "#%d", Home(it)); } else if (Has_dropto(it)) { safe_tprintf_str(buff, bufc, "#%d", Dropto(it)); } else if (isExit(it)) { safe_tprintf_str(buff, bufc, "#%d", where_is(it)); } else { safe_nothing(buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_money: Return an object's value */ static FUNCTION(fun_money) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } if (Examinable(executor, it)) { safe_ltoa(Pennies(it), buff, bufc); } else { safe_noperm(buff, bufc); } } /* * --------------------------------------------------------------------------- * * fun_pos: Find a word in a string */ static FUNCTION(fun_pos) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // Strip ANSI from pattern and save. // // Note: We need to save it because the next call to strip_ansi() // will overwrite the prior result. Also, we save the pattern // instead of the source because the the pattern will tend to be // smaller (i.e., on average, fewer bytes to move). // size_t nPat = 0; char aPatBuf[LBUF_SIZE]; char *pPatStrip = strip_ansi(fargs[0], &nPat); if (sizeof(aPatBuf) < nPat) { nPat = sizeof(aPatBuf); } memcpy(aPatBuf, pPatStrip, nPat); // Strip ANSI from source. // size_t nSrc; char *pSrc = strip_ansi(fargs[1], &nSrc); // Search for pattern string inside source string. // size_t i; bool bSucceeded = false; if (nPat == 1) { // We can optimize the single-character case. // char *p = strchr(pSrc, aPatBuf[0]); if (p) { i = p - pSrc; bSucceeded = true; } } else if (nPat > 1) { // We have a multi-byte pattern. // bSucceeded = BMH_StringSearch(&i, nPat, aPatBuf, nSrc, pSrc); } if (bSucceeded) { safe_ltoa(static_cast(i+1), buff, bufc); } else { safe_nothing(buff, bufc); } } /* --------------------------------------------------------------------------- * fun_lpos: Find all occurrences of a character in a string, and return * a space-separated list of the positions, starting at 0. i.e., * lpos(a-bc-def-g,-) ==> 1 4 8 */ static FUNCTION(fun_lpos) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (*fargs[0] == '\0') { return; } char c = *fargs[1]; if (!c) { c = ' '; } int i; char *bb_p = *bufc; char *s = strip_ansi(fargs[0]); for (i = 0; *s; i++, s++) { if (*s == c) { if (*bufc != bb_p) { safe_chr(' ', buff, bufc); } safe_ltoa(i, buff, bufc); } } } /* * --------------------------------------------------------------------------- * * ldelete: Remove a word from a string by place * * ldelete(,[,]) * * * * insert: insert a word into a string by place * * insert(,, [,]) * * * * replace: replace a word into a string by place * * replace(,,[,]) */ #define IF_DELETE 0 #define IF_REPLACE 1 #define IF_INSERT 2 static void do_itemfuns(char *buff, char **bufc, char *str, int el, char *word, SEP *psep, int flag) { int ct; char *sptr, *iptr, *eptr; size_t slen = 0, ilen = 0, elen = 0; bool overrun; // If passed a null string return an empty string, except that we // are allowed to append to a null string. // if ( ( !str || !*str) && ( flag != IF_INSERT || el != 1)) { return; } size_t nStr = strlen(str); // We can't fiddle with anything before the first position. // if (el < 1) { safe_copy_buf(str, nStr, buff, bufc); return; } // Split the list up into 'before', 'target', and 'after' chunks // pointed to by sptr, iptr, and eptr respectively. // if (el == 1) { // No 'before' portion, just split off element 1 // sptr = NULL; slen = 0; if (!str || !*str) { eptr = NULL; iptr = NULL; } else { eptr = trim_space_sep_LEN(str, nStr, psep, &elen); iptr = split_token_LEN(&eptr, &elen, psep, &ilen); } } else { // Break off 'before' portion. // sptr = eptr = trim_space_sep_LEN(str, nStr, psep, &elen); overrun = true; for ( ct = el; ct > 2 && eptr; eptr = next_token_LEN(eptr, &elen, psep), ct--) { // Nothing } if (eptr) { // Note: We are using (iptr,ilen) temporarily. It // doesn't represent the 'target' word, but the // the last token in the 'before' portion. // overrun = false; iptr = split_token_LEN(&eptr, &elen, psep, &ilen); slen = (iptr - sptr) + ilen; } // If we didn't make it to the target element, just return // the string. Insert is allowed to continue if we are exactly // at the end of the string, but replace and delete are not. // if (!( eptr || ( flag == IF_INSERT && !overrun))) { safe_copy_buf(str, nStr, buff, bufc); return; } // Split the 'target' word from the 'after' portion. // if (eptr) { iptr = split_token_LEN(&eptr, &elen, psep, &ilen); } else { iptr = NULL; ilen = 0; } } switch (flag) { case IF_DELETE: // deletion // if (sptr) { safe_copy_buf(sptr, slen, buff, bufc); if (eptr) { safe_chr(psep->str[0], buff, bufc); } } if (eptr) { safe_copy_buf(eptr, elen, buff, bufc); } break; case IF_REPLACE: // replacing. // if (sptr) { safe_copy_buf(sptr, slen, buff, bufc); safe_chr(psep->str[0], buff, bufc); } safe_str(word, buff, bufc); if (eptr) { safe_chr(psep->str[0], buff, bufc); safe_copy_buf(eptr, elen, buff, bufc); } break; case IF_INSERT: // Insertion. // if (sptr) { safe_copy_buf(sptr, slen, buff, bufc); safe_chr(psep->str[0], buff, bufc); } safe_str(word, buff, bufc); if (iptr) { safe_chr(psep->str[0], buff, bufc); safe_copy_buf(iptr, ilen, buff, bufc); } if (eptr) { safe_chr(psep->str[0], buff, bufc); safe_copy_buf(eptr, elen, buff, bufc); } break; } } static FUNCTION(fun_ldelete) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } // Delete a word at position X of a list. // do_itemfuns(buff, bufc, fargs[0], mux_atol(fargs[1]), NULL, &sep, IF_DELETE); } static FUNCTION(fun_replace) { SEP sep; if (!OPTIONAL_DELIM(4, sep, DELIM_DFLT|DELIM_STRING)) { return; } // Replace a word at position X of a list. // do_itemfuns(buff, bufc, fargs[0], mux_atol(fargs[1]), fargs[2], &sep, IF_REPLACE); } static FUNCTION(fun_insert) { SEP sep; if (!OPTIONAL_DELIM(4, sep, DELIM_DFLT|DELIM_STRING)) { return; } // Insert a word at position X of a list. // do_itemfuns(buff, bufc, fargs[0], mux_atol(fargs[1]), fargs[2], &sep, IF_INSERT); } /* * --------------------------------------------------------------------------- * * fun_remove: Remove a word from a string */ static FUNCTION(fun_remove) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_INIT|DELIM_STRING)) { return; } char *s, *sp, *word; bool first, found; if (strstr(fargs[1], sep.str)) { safe_str("#-1 CAN ONLY REMOVE ONE ELEMENT", buff, bufc); return; } s = fargs[0]; word = fargs[1]; // Walk through the string copying words until (if ever) we get to // one that matches the target word. // sp = s; found = false; first = true; while (s) { sp = split_token(&s, &sep); if ( found || strcmp(sp, word) != 0) { if (!first) { print_sep(&osep, buff, bufc); } else { first = false; } safe_str(sp, buff, bufc); } else { found = true; } } } /* * --------------------------------------------------------------------------- * * fun_member: Is a word in a string */ static FUNCTION(fun_member) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } int wcount; char *r, *s; wcount = 1; s = trim_space_sep(fargs[0], &sep); do { r = split_token(&s, &sep); if (!strcmp(fargs[1], r)) { safe_ltoa(wcount, buff, bufc); return; } wcount++; } while (s); safe_chr('0', buff, bufc); } // fun_secure: This function replaces any character in the set // '%$\[](){},;' with a space. It handles ANSI by not replacing // the '[' character within an ANSI sequence. // static FUNCTION(fun_secure) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *pString = fargs[0]; size_t nString = strlen(pString); while (nString) { size_t nTokenLength0; size_t nTokenLength1; int iType = ANSI_lex(nString, pString, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { // Process TEXT portion (pString, nTokenLength0). // nString -= nTokenLength0; while (nTokenLength0--) { if (mux_issecure(*pString)) { safe_chr(' ', buff, bufc); } else { safe_chr(*pString, buff, bufc); } pString++; } nTokenLength0 = nTokenLength1; } if (nTokenLength0) { // Process ANSI portion (pString, nTokenLength0). // safe_copy_buf(pString, nTokenLength0, buff, bufc); pString += nTokenLength0; nString -= nTokenLength0; } } } // fun_escape: This function prepends a '\' to the beginning of a // string and before any character which occurs in the set '%\[]{};,()^$'. // It handles ANSI by not treating the '[' character within an ANSI // sequence as a special character. // static FUNCTION(fun_escape) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *pString = fargs[0]; size_t nString = strlen(pString); bool bBackslash = false; while (nString) { size_t nTokenLength0; size_t nTokenLength1; int iType = ANSI_lex(nString, pString, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { // Process TEXT portion (pString, nTokenLength0). // nString -= nTokenLength0; while (nTokenLength0--) { if ( mux_isescape(*pString) || !bBackslash) { safe_chr('\\', buff, bufc); bBackslash = true; } safe_chr(*pString, buff, bufc); pString++; } nTokenLength0 = nTokenLength1; } if (nTokenLength0) { // Process ANSI portion (pString, nTokenLength0). // safe_copy_buf(pString, nTokenLength0, buff, bufc); pString += nTokenLength0; nString -= nTokenLength0; } } } /* * Take a character position and return which word that char is in. * * wordpos(, ) */ static FUNCTION(fun_wordpos) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } unsigned int charpos = mux_atol(fargs[1]); char *cp = fargs[0]; size_t ncp = strlen(cp); if ( charpos > 0 && charpos <= ncp) { size_t ncp_trimmed; char *tp = &(cp[charpos - 1]); cp = trim_space_sep_LEN(cp, ncp, &sep, &ncp_trimmed); char *xp = split_token(&cp, &sep); int i; for (i = 1; xp; i++) { if (tp < xp + strlen(xp)) { break; } xp = split_token(&cp, &sep); } safe_ltoa(i, buff, bufc); return; } safe_nothing(buff, bufc); } static FUNCTION(fun_type) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } switch (Typeof(it)) { case TYPE_ROOM: safe_str("ROOM", buff, bufc); break; case TYPE_EXIT: safe_str("EXIT", buff, bufc); break; case TYPE_PLAYER: safe_str("PLAYER", buff, bufc); break; case TYPE_THING: safe_str("THING", buff, bufc); break; default: safe_str("#-1 ILLEGAL TYPE", buff, bufc); } } typedef struct { const char *pName; int iMask; } ATR_HAS_FLAG_ENTRY; static ATR_HAS_FLAG_ENTRY atr_has_flag_table[] = { { "dark", AF_DARK }, { "wizard", AF_WIZARD }, { "hidden", AF_MDARK }, { "html", AF_HTML }, { "locked", AF_LOCK }, { "no_command", AF_NOPROG }, { "no_name", AF_NONAME }, { "no_parse", AF_NOPARSE }, { "regexp", AF_REGEXP }, { "god", AF_GOD }, { "visual", AF_VISUAL }, { "no_inherit", AF_PRIVATE }, { "const", AF_CONST }, { NULL, 0 } }; static bool atr_has_flag ( dbref player, dbref thing, ATTR* pattr, dbref aowner, int aflags, const char *flagname ) { UNUSED_PARAMETER(aowner); if (See_attr(player, thing, pattr)) { ATR_HAS_FLAG_ENTRY *pEntry = atr_has_flag_table; while (pEntry->pName) { if (string_prefix(pEntry->pName, flagname)) { return ((aflags & (pEntry->iMask)) ? true : false); } pEntry++; } } return false; } static FUNCTION(fun_hasflag) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it; ATTR *pattr; if (parse_attrib(executor, fargs[0], &it, &pattr)) { if ( !pattr || !See_attr(executor, it, pattr)) { safe_notfound(buff, bufc); } else { int aflags; dbref aowner; atr_pget_info(it, pattr->number, &aowner, &aflags); bool cc = atr_has_flag(executor, it, pattr, aowner, aflags, fargs[1]); safe_bool(cc, buff, bufc); } } else { it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); } else if ( mudconf.pub_flags || Examinable(executor, it) || it == enactor) { bool cc = has_flag(executor, it, fargs[1]); safe_bool(cc, buff, bufc); } else { safe_noperm(buff, bufc); } } } static FUNCTION(fun_haspower) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } if ( mudconf.pub_flags || Examinable(executor, it) || it == enactor) { safe_bool(has_power(executor, it, fargs[1]), buff, bufc); } else { safe_noperm(buff, bufc); } } #ifdef REALITY_LVLS static FUNCTION(fun_hasrxlevel) { dbref it; RLEVEL rl; it = match_thing(executor, fargs[0]); if (!Good_obj(it)) { safe_str("#-1 NOT FOUND", buff, bufc); return; } rl = find_rlevel(fargs[1]); if (!rl) { safe_str("#-1 INVALID RLEVEL", buff, bufc); return; } if (Examinable(executor, it)) { if ((RxLevel(it) & rl) == rl) { safe_chr('1', buff, bufc); } else { safe_chr('0', buff, bufc); } } else { safe_str("#-1 PERMISSION DENIED", buff, bufc); } } static FUNCTION(fun_hastxlevel) { dbref it; RLEVEL rl; it = match_thing(executor, fargs[0]); if (!Good_obj(it)) { safe_str("#-1 NOT FOUND", buff, bufc); return; } rl = find_rlevel(fargs[1]); if (!rl) { safe_str("#-1 INVALID RLEVEL", buff, bufc); return; } if (Examinable(executor, it)) { if ((TxLevel(it) & rl) == rl) { safe_chr('1', buff, bufc); } else { safe_chr('0', buff, bufc); } } else { safe_str("#-1 PERMISSION DENIED", buff, bufc); } } static FUNCTION(fun_listrlevels) { int i, add_space; int cmp_z; int cmp_x = sizeof(mudconf.reality_level); int cmp_y = sizeof(mudconf.reality_level[0]); if (0 == cmp_y) { cmp_z = 0; } else { cmp_z = cmp_x / cmp_y; } if (mudconf.no_levels < 1) { safe_str("#-1 NO REALITY LEVELS DEFINED", buff, bufc); } else { for (add_space = i = 0; i < mudconf.no_levels && i < cmp_z; i++) { if (add_space) { safe_chr(' ', buff, bufc); } safe_str(mudconf.reality_level[i].name, buff, bufc); add_space = 1; } } } static FUNCTION(fun_rxlevel) { dbref it; char levelbuff[2048]; int i; RLEVEL lev; it = match_thing(executor, fargs[0]); if (!Good_obj(it)) { safe_str("#-1 NOT FOUND", buff, bufc); return; } if (Examinable(executor, it)) { lev = RxLevel(it); levelbuff[0]='\0'; for(i = 0; i < mudconf.no_levels; ++i) if((lev & mudconf.reality_level[i].value) == mudconf.reality_level[i].value) { strcat(levelbuff, mudconf.reality_level[i].name); strcat(levelbuff, " "); } safe_tprintf_str(buff, bufc, "%s", levelbuff); } else safe_str("#-1 PERMISSION DENIED", buff, bufc); } static FUNCTION(fun_txlevel) { dbref it; char levelbuff[2048]; int i; RLEVEL lev; it = match_thing(executor, fargs[0]); if (!Good_obj(it)) { safe_str("#-1 NOT FOUND", buff, bufc); return; } if (Examinable(executor, it)) { lev = TxLevel(it); levelbuff[0]='\0'; for(i = 0; i < mudconf.no_levels; ++i) if((lev & mudconf.reality_level[i].value) == mudconf.reality_level[i].value) { strcat(levelbuff, mudconf.reality_level[i].name); strcat(levelbuff, " "); } safe_tprintf_str(buff, bufc, "%s", levelbuff); } else safe_str("#-1 PERMISSION DENIED", buff, bufc); } #endif // REALITY_LVLS static FUNCTION(fun_powers) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it = match_thing_quiet(executor, fargs[0]); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } if ( mudconf.pub_flags || Examinable(executor, it) || it == enactor) { char *buf = powers_list(executor, it); safe_str(buf, buff, bufc); free_lbuf(buf); } else { safe_noperm(buff, bufc); } } static FUNCTION(fun_delete) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *s = fargs[0]; long iStart = mux_atol(fargs[1]); long nChars = mux_atol(fargs[2]); size_t nLen = strlen(s); long iEnd; if (0 <= nChars) { iEnd = iStart + nChars; } else { iEnd = iStart; iStart = iEnd + nChars; } // Are we deleting anything at all? // if ( iEnd <= 0 || nLen <= static_cast(iStart)) { if (nLen) { safe_copy_buf(s, nLen, buff, bufc); } return; } if (iStart < 0) { iStart = 0; } if (static_cast(nLen) < iEnd) { iEnd = static_cast(nLen); } // ASSERT: Now [iStart,iEnd) exist somewhere within the the string // [s,nLen). // if (iStart) { safe_copy_buf(s, iStart, buff, bufc); } if (iEnd < static_cast(nLen)) { safe_copy_buf(s + iEnd, nLen - iEnd, buff, bufc); } } static FUNCTION(fun_lock) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it, aowner; int aflags; ATTR *pattr; struct boolexp *pBoolExp; // Parse the argument into obj + lock // if (!get_obj_and_lock(executor, fargs[0], &it, &pattr, buff, bufc)) { return; } // Get the attribute and decode it if we can read it // char *tbuf = atr_get(it, pattr->number, &aowner, &aflags); if (bCanReadAttr(executor, it, pattr, false)) { pBoolExp = parse_boolexp(executor, tbuf, true); free_lbuf(tbuf); tbuf = unparse_boolexp_function(executor, pBoolExp); free_boolexp(pBoolExp); safe_str(tbuf, buff, bufc); } else { free_lbuf(tbuf); } } static FUNCTION(fun_elock) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref it, aowner; int aflags; ATTR *pattr; struct boolexp *pBoolExp; // Parse lock supplier into obj + lock. // if (!get_obj_and_lock(executor, fargs[0], &it, &pattr, buff, bufc)) { return; } else if (!locatable(executor, it, enactor)) { safe_nothing(buff, bufc); } // Get the victim and ensure we can do it. // dbref victim = match_thing_quiet(executor, fargs[1]); if (!Good_obj(victim)) { safe_match_result(victim, buff, bufc); } else if (!locatable(executor, victim, enactor)) { safe_nothing(buff, bufc); } else if ( nearby_or_control(executor, victim) || nearby_or_control(executor, it)) { char *tbuf = atr_get(it, pattr->number, &aowner, &aflags); if ( pattr->number == A_LOCK || bCanReadAttr(executor, it, pattr, false)) { pBoolExp = parse_boolexp(executor, tbuf, true); safe_bool(eval_boolexp(victim, it, it, pBoolExp), buff, bufc); free_boolexp(pBoolExp); } else { safe_chr('0', buff, bufc); } free_lbuf(tbuf); } else { safe_str("#-1 TOO FAR AWAY", buff, bufc); } } /* --------------------------------------------------------------------------- * fun_lwho: Return list of connected users. */ static FUNCTION(fun_lwho) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool bPorts = false; if (nfargs == 1) { bPorts = xlate(fargs[0]); if ( bPorts && !Wizard(executor)) { safe_noperm(buff, bufc); return; } } make_ulist(executor, buff, bufc, bPorts); } // --------------------------------------------------------------------------- // fun_lports: Return list of ports of connected users. // --------------------------------------------------------------------------- static FUNCTION(fun_lports) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); make_port_ulist(executor, buff, bufc); } /* --------------------------------------------------------------------------- * fun_nearby: Return whether or not obj1 is near obj2. */ static FUNCTION(fun_nearby) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref obj1 = match_thing_quiet(executor, fargs[0]); if (!Good_obj(obj1)) { safe_match_result(obj1, buff, bufc); safe_str(" (ARG1)", buff, bufc); return; } dbref obj2 = match_thing_quiet(executor, fargs[1]); if (!Good_obj(obj2)) { safe_match_result(obj2, buff, bufc); safe_str(" (ARG2)", buff, bufc); return; } bool bResult = ( ( nearby_or_control(executor, obj1) || nearby_or_control(executor, obj2)) && nearby(obj1, obj2)); safe_bool(bResult, buff, bufc); } /* * --------------------------------------------------------------------------- * * fun_obj, fun_poss, and fun_subj: perform pronoun sub for object. */ static void process_sex(dbref player, char *what, const char *token, char *buff, char **bufc) { dbref it = match_thing_quiet(player, strip_ansi(what)); if (!Good_obj(it)) { safe_match_result(it, buff, bufc); return; } if ( !isPlayer(it) && !nearby_or_control(player, it)) { safe_nomatch(buff, bufc); } else { char *str = (char *)token; mux_exec(buff, bufc, it, it, it, EV_EVAL, &str, NULL, 0); } } static FUNCTION(fun_obj) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); process_sex(executor, fargs[0], "%o", buff, bufc); } static FUNCTION(fun_poss) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); process_sex(executor, fargs[0], "%p", buff, bufc); } static FUNCTION(fun_subj) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); process_sex(executor, fargs[0], "%s", buff, bufc); } static FUNCTION(fun_aposs) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); process_sex(executor, fargs[0], "%a", buff, bufc); } /* * --------------------------------------------------------------------------- * * fun_mudname: Return the name of the mud. */ static FUNCTION(fun_mudname) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_str(mudconf.mud_name, buff, bufc); } // --------------------------------------------------------------------------- // fun_connrecord: Return the record number of connected players. // --------------------------------------------------------------------------- static FUNCTION(fun_connrecord) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_ltoa(mudstate.record_players, buff, bufc); } /*! \brief Return current function invocation counter. * * If no argument is given, FCOUNT() returns the current function invocation * counter which represents the number of functions invoked since the * beginning of the queue cycle. * * If given an argument, FCOUNT() returns the number of invocations required * to evaluate the argument. * */ FUNCTION(fun_fcount) { if (0 == nfargs) { safe_ltoa(mudstate.func_invk_ctr, buff, bufc); } else if (1 == nfargs) { long ficBefore = mudstate.func_invk_ctr; char *str = fargs[0]; char *bufc_save = *bufc; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_FCHECK|EV_STRIP_CURLY|EV_EVAL, &str, cargs, ncargs); long ficAfter = mudstate.func_invk_ctr; *bufc = bufc_save; safe_ltoa(ficAfter-ficBefore, buff, bufc); } } // --------------------------------------------------------------------------- // fun_fdepth: Return the current function nesting depth. // --------------------------------------------------------------------------- FUNCTION(fun_fdepth) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_ltoa(mudstate.func_nest_lev, buff, bufc); } // --------------------------------------------------------------------------- // fun_ctime: Return the value of an object's CREATED attribute. // --------------------------------------------------------------------------- static FUNCTION(fun_ctime) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref thing; if (nfargs == 1) { thing = match_thing_quiet(executor, fargs[0]); } else { thing = executor; } if (!Good_obj(thing)) { safe_match_result(thing, buff, bufc); } else if (Examinable(executor, thing)) { safe_str(atr_get_raw(thing, A_CREATED), buff, bufc); } else { safe_noperm(buff, bufc); } } // --------------------------------------------------------------------------- // fun_mtime: Return the value of an object's Modified attribute. // --------------------------------------------------------------------------- static FUNCTION(fun_mtime) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref thing; if (nfargs == 1) { thing = match_thing_quiet(executor, fargs[0]); } else { thing = executor; } if (!Good_obj(thing)) { safe_match_result(thing, buff, bufc); } else if (Examinable(executor, thing)) { safe_str(atr_get_raw(thing, A_MODIFIED), buff, bufc); } else { safe_noperm(buff, bufc); } } // --------------------------------------------------------------------------- // fun_moniker: Return the value of an object's @moniker attribute. // --------------------------------------------------------------------------- static FUNCTION(fun_moniker) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref thing; if (nfargs == 1) { thing = match_thing_quiet(executor, fargs[0]); } else { thing = executor; } if (!Good_obj(thing)) { safe_match_result(thing, buff, bufc); return; } safe_str(Moniker(thing), buff, bufc); } static void ANSI_TransformTextWithTable ( char *buff, char **bufc, char *pString, const unsigned char xfrmTable[256]) { size_t nString = strlen(pString); char *pBuffer = *bufc; size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; while (nString) { size_t nTokenLength0; size_t nTokenLength1; int iType = ANSI_lex(nString, pString, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { // Determine how much to move. // size_t nMove = nTokenLength0; if (nMove > nBufferAvailable) { nMove = nBufferAvailable; } nBufferAvailable -= nMove; // Update pointers and counts. // char *p = pString; nString -= nTokenLength0; pString += nTokenLength0; // Transform and Move text. // while (nMove--) { *pBuffer++ = xfrmTable[(unsigned char)*p++]; } // Determine whether to move the ANSI part. // if (nTokenLength1) { if (nTokenLength1 <= nBufferAvailable) { memcpy(pBuffer, pString, nTokenLength1); pBuffer += nTokenLength1; nBufferAvailable -= nTokenLength1; } nString -= nTokenLength1; pString += nTokenLength1; } } else { // TOKEN_ANSI // // Determine whether to move the ANSI part. // if (nTokenLength0 <= nBufferAvailable) { memcpy(pBuffer, pString, nTokenLength0); pBuffer += nTokenLength0; nBufferAvailable -= nTokenLength0; } nString -= nTokenLength0; pString += nTokenLength0; } } *pBuffer = '\0'; *bufc = pBuffer; } /* * --------------------------------------------------------------------------- * * fun_lcstr, fun_ucstr, fun_capstr: Lowercase, uppercase, or capitalize str. */ static FUNCTION(fun_lcstr) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); ANSI_TransformTextWithTable(buff, bufc, fargs[0], mux_tolower); } static FUNCTION(fun_ucstr) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); ANSI_TransformTextWithTable(buff, bufc, fargs[0], mux_toupper); } static FUNCTION(fun_capstr) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *pString = fargs[0]; char *pBuffer = *bufc; size_t nString = strlen(pString); nString = safe_copy_buf(pString, nString, buff, bufc); // Find the first text character in (nString, pBuffer). // while (nString) { size_t nTokenLength0; size_t nTokenLength1; int iType = ANSI_lex(nString, pBuffer, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { *pBuffer = mux_toupper(*pBuffer); return; } else { // iType == TOKEN_ANSI // pBuffer += nTokenLength0; nString -= nTokenLength0; } } } /* * --------------------------------------------------------------------------- * * fun_lnum: Return a list of numbers. */ static FUNCTION(fun_lnum) { SEP sep; if ( nfargs == 0 || !OPTIONAL_DELIM(3, sep, DELIM_NULL|DELIM_CRLF|DELIM_STRING)) { return; } int bot = 0, top; int step = 1; if (nfargs == 1) { top = mux_atol(fargs[0]) - 1; if (top < 0) { return; } } else { bot = mux_atol(fargs[0]); top = mux_atol(fargs[1]); if (nfargs == 4) { step = mux_atol(fargs[3]); if (step < 1) { step = 1; } } } int i; if (bot == top) { safe_ltoa(bot, buff, bufc); } else if (bot < top) { safe_ltoa(bot, buff, bufc); for (i = bot+step; i <= top; i += step) { print_sep(&sep, buff, bufc); char *p = *bufc; safe_ltoa(i, buff, bufc); if (p == *bufc) { return; } } } else if (top < bot) { safe_ltoa(bot, buff, bufc); for (i = bot-step; i >= top; i -= step) { print_sep(&sep, buff, bufc); char *p = *bufc; safe_ltoa(i, buff, bufc); if (p == *bufc) { return; } } } } /* --------------------------------------------------------------------------- * fun_lattr, fun_lattrp: Return list of attributes I can see on the object. */ static void lattr_handler(char *buff, char **bufc, dbref executor, char *fargs[], bool bCheckParent) { dbref thing; int ca; bool bFirst; // Check for wildcard matching. parse_attrib_wild checks for read // permission, so we don't have to. Have p_a_w assume the // slash-star if it is missing. // bFirst = true; olist_push(); if (parse_attrib_wild(executor, fargs[0], &thing, bCheckParent, false, true)) { for (ca = olist_first(); ca != NOTHING; ca = olist_next()) { ATTR *pattr = atr_num(ca); if (pattr) { if (!bFirst) { safe_chr(' ', buff, bufc); } bFirst = false; safe_str(pattr->name, buff, bufc); } } } else { safe_nomatch(buff, bufc); } olist_pop(); } static FUNCTION(fun_lattr) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); lattr_handler(buff, bufc, executor, fargs, false); } static FUNCTION(fun_lattrp) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); lattr_handler(buff, bufc, executor, fargs, true); } // --------------------------------------------------------------------------- // fun_attrcnt: Return number of attributes I can see on the object. // --------------------------------------------------------------------------- static FUNCTION(fun_attrcnt) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref thing; int ca, count = 0; // Mechanism from lattr. // olist_push(); if (parse_attrib_wild(executor, fargs[0], &thing, false, false, true)) { for (ca = olist_first(); ca != NOTHING; ca = olist_next()) { ATTR *pattr = atr_num(ca); if (pattr) { count++; } } safe_ltoa(count, buff, bufc); } else { safe_nomatch(buff, bufc); } olist_pop(); } /* * --------------------------------------------------------------------------- * * fun_reverse, fun_revwords: Reverse things. */ static void mux_memrevcpy(char *dest, char *src, size_t n) { dest += n - 1; while (n--) { *dest-- = *src++; } } typedef void MEMXFORM(char *dest, char *src, size_t n); static void ANSI_TransformTextReverseWithFunction ( char *buff, char **bufc, char *pString, MEMXFORM *pfMemXForm ) { // Bounds checking. // size_t nString = strlen(pString); char *pBuffer = *bufc; size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; if (nString > nBufferAvailable) { nString = nBufferAvailable; pString[nString] = '\0'; } // How it's done: We have a source string (pString, nString) and a // destination buffer (pBuffer, nString) of equal size. // // We recognize (ANSI,TEXT) phrases and place them at the end of // destination buffer working our way to the front. The ANSI part // is left inviolate, but the text part is reversed. // // In this way, (ANSI1,TEXT1)(ANSI2,TEXT2) is traslated into // (ANSI2,reverse(TEST2))(ANSI1,reverse(TEXT1)). // // TODO: Do not reverse the CRLF in the text part either. // size_t nANSI = 0; char *pANSI = pString; pBuffer += nString; *bufc = pBuffer; **bufc = '\0'; while (nString) { size_t nTokenLength0; size_t nTokenLength1; int iType = ANSI_lex(nString, pString, &nTokenLength0, &nTokenLength1); if (iType == TOKEN_TEXT_ANSI) { // (ANSI,TEXT) is given by (nANSI, nTokenLength0) // pBuffer -= nANSI + nTokenLength0; memcpy(pBuffer, pANSI, nANSI); pfMemXForm(pBuffer+nANSI, pString, nTokenLength0); // Adjust pointers and counts. // nString -= nTokenLength0; pString += nTokenLength0; pANSI = pString; nANSI = 0; nTokenLength0 = nTokenLength1; } // TOKEN_ANSI // nString -= nTokenLength0; pString += nTokenLength0; nANSI += nTokenLength0; } // Copy the last ANSI part (if present). It will be overridden by // ANSI further on, but we need to fill up the space. Code // elsewhere will compact it before it's sent to the client. // pBuffer -= nANSI; memcpy(pBuffer, pANSI, nANSI); } static FUNCTION(fun_reverse) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); ANSI_TransformTextReverseWithFunction(buff, bufc, fargs[0], mux_memrevcpy); } static char ReverseWordsInText_Seperator; static void ReverseWordsInText(char *dest, char *src, size_t n) { char chSave = src[n]; src[n] = '\0'; dest += n; while (n) { char *pWord = strchr(src, ReverseWordsInText_Seperator); size_t nLen; if (pWord) { nLen = (pWord - src); } else { nLen = n; } dest -= nLen; memcpy(dest, src, nLen); src += nLen; n -= nLen; if (pWord) { dest--; *dest = ReverseWordsInText_Seperator; src++; n--; } } src[n] = chSave; } static FUNCTION(fun_revwords) { // If we are passed an empty arglist return a null string. // if (nfargs == 0) { return; } SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT)) { return; } ReverseWordsInText_Seperator = sep.str[0]; ANSI_TransformTextReverseWithFunction(buff, bufc, fargs[0], ReverseWordsInText); } /* * --------------------------------------------------------------------------- * * fun_after, fun_before: Return substring after or before a specified string. */ static FUNCTION(fun_after) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); const char *mp; size_t mlen; // Sanity-check arg1 and arg2. // char *bp = fargs[0]; if (nfargs > 1) { mp = fargs[1]; mlen = strlen(mp); } else { mp = " "; mlen = 1; } if ( mlen == 1 && *mp == ' ') { bp = trim_space_sep(bp, &sepSpace); } // Look for the target string. // size_t nText = strlen(bp); size_t i; bool bSucceeded = BMH_StringSearch(&i, mlen, mp, nText, bp); if (bSucceeded) { // Yup, return what follows. // bp += i + mlen; safe_copy_buf(bp, nText-i-mlen, buff, bufc); } // // Ran off the end without finding it. } static FUNCTION(fun_before) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); const char *mp; char *ip; size_t mlen; // Sanity-check arg1 and arg2. // char *bp = fargs[0]; if (nfargs > 1) { mp = fargs[1]; mlen = strlen(mp); } else { mp = " "; mlen = 1; } if ( mlen == 1 && *mp == ' ') { bp = trim_space_sep(bp, &sepSpace); } ip = bp; // Look for the target string. // size_t i; bool bSucceeded = BMH_StringSearch(&i, mlen, mp, strlen(bp), bp); if (bSucceeded) { // Yup, return what follows. // safe_copy_buf(ip, i, buff, bufc); return; } // Ran off the end without finding it. // safe_str(ip, buff, bufc); } /* * --------------------------------------------------------------------------- * * fun_search: Search the db for things, returning a list of what matches */ static FUNCTION(fun_search) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *pArg = NULL; if (nfargs != 0) { pArg = fargs[0]; } // Set up for the search. If any errors, abort. // SEARCH searchparm; if (!search_setup(executor, pArg, &searchparm)) { safe_str("#-1 ERROR DURING SEARCH", buff, bufc); return; } // Do the search and report the results. // olist_push(); search_perform(executor, caller, enactor, &searchparm); dbref thing; ITL pContext; ItemToList_Init(&pContext, buff, bufc, '#'); for (thing = olist_first(); thing != NOTHING; thing = olist_next()) { if (!ItemToList_AddInteger(&pContext, thing)) { break; } } ItemToList_Final(&pContext); olist_pop(); } /* * --------------------------------------------------------------------------- * * fun_stats: Get database size statistics. */ static FUNCTION(fun_stats) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref who; if ( nfargs == 0 || (!fargs[0]) || !*fargs[0] || !string_compare(fargs[0], "all")) { who = NOTHING; } else { who = lookup_player(executor, fargs[0], true); if (who == NOTHING) { safe_str("#-1 PLAYER NOT FOUND", buff, bufc); return; } } STATS statinfo; if (!get_stats(executor, who, &statinfo)) { safe_str("#-1 ERROR GETTING STATS", buff, bufc); return; } safe_tprintf_str(buff, bufc, "%d %d %d %d %d %d", statinfo.s_total, statinfo.s_rooms, statinfo.s_exits, statinfo.s_things, statinfo.s_players, statinfo.s_garbage); } /* * --------------------------------------------------------------------------- * * fun_merge: given two strings and a character, merge the two strings * * by replacing characters in string1 that are the same as the given * * character by the corresponding character in string2 (by position). * * The strings must be of the same length. */ static FUNCTION(fun_merge) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // Do length checks first. // size_t n0, n1; (void)strip_ansi(fargs[0], &n0); (void)strip_ansi(fargs[1], &n1); if (n0 != n1) { safe_str("#-1 STRING LENGTHS MUST BE EQUAL", buff, bufc); return; } size_t n2; char *pMatch = strip_ansi(fargs[2], &n2); if (1 < n2) { safe_str("#-1 TOO MANY CHARACTERS", buff, bufc); return; } // If no character is given, space is used. // char c; if (0 == n2) { c = ' '; } else { c = pMatch[0]; } // Walk strings, copy from the appropriate string. // struct ANSI_In_Context aicStr; struct ANSI_In_Context aicRep; struct ANSI_Out_Context aoc; ANSI_String_In_Init(&aicStr, fargs[0], ANSI_ENDGOAL_NORMAL); ANSI_String_In_Init(&aicRep, fargs[1], ANSI_ENDGOAL_NORMAL); size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; ANSI_String_Out_Init(&aoc, *bufc, nBufferAvailable, LBUF_SIZE-1, ANSI_ENDGOAL_NORMAL); size_t vw; ANSI_String_Skip(&aicStr, 0, &vw); ANSI_String_Skip(&aicRep, 0, &vw); for (size_t i = 0; i < n0; i++) { if (aicStr.m_p[0] == c) { ANSI_String_Copy(&aoc, &aicRep, 1); ANSI_String_Skip(&aicStr, 1, &vw); } else { ANSI_String_Copy(&aoc, &aicStr, 1); ANSI_String_Skip(&aicRep, 1, &vw); } } size_t nSize = ANSI_String_Finalize(&aoc, &vw); *bufc += nSize; } /* --------------------------------------------------------------------------- * fun_splice: similar to MERGE(), eplaces by word instead of by character. */ static FUNCTION(fun_splice) { SEP sep; if (!OPTIONAL_DELIM(4, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(5, osep, DELIM_NULL|DELIM_CRLF|DELIM_INIT|DELIM_STRING)) { return; } // Length checks. // if (countwords(fargs[2], &sep) > 1) { safe_str("#-1 TOO MANY WORDS", buff, bufc); return; } int words = countwords(fargs[0], &sep); if (words != countwords(fargs[1], &sep)) { safe_str("#-1 NUMBER OF WORDS MUST BE EQUAL", buff, bufc); return; } // Loop through the two lists. // char *p1 = fargs[0]; char *q1 = fargs[1]; char *p2, *q2; bool first = true; int i; for (i = 0; i < words; i++) { p2 = split_token(&p1, &sep); q2 = split_token(&q1, &sep); if (!first) { print_sep(&osep, buff, bufc); } if (strcmp(p2, fargs[2]) == 0) { safe_str(q2, buff, bufc); // replace } else { safe_str(p2, buff, bufc); // copy } first = false; } } /*--------------------------------------------------------------------------- * fun_repeat: repeats a string */ static FUNCTION(fun_repeat) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int times = mux_atol(fargs[1]); if (times < 1 || *fargs[0] == '\0') { // Legal but no work to do. // return; } else if (times == 1) { // It turns into a string copy. // safe_str(fargs[0], buff, bufc); } else { size_t len = strlen(fargs[0]); if (len == 1) { // It turns into a memset. // safe_fill(buff, bufc, *fargs[0], times); } else { size_t nSize = len*times; if ( times > LBUF_SIZE - 1 || nSize > LBUF_SIZE - 1) { safe_str("#-1 STRING TOO LONG", buff, bufc); } else { size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; if (nSize > nBufferAvailable) { nSize = nBufferAvailable; } size_t nFullCopies = nSize / len; size_t nPartial = nSize - nFullCopies * len; while (nFullCopies--) { memcpy(*bufc, fargs[0], len); *bufc += len; } if (nPartial) { memcpy(*bufc, fargs[0], nPartial); *bufc += nPartial; } } } } } /* * --------------------------------------------------------------------------- * * fun_iter: Make list from evaluating arg2 with each member of arg1. * * NOTE: This function expects that its arguments have not been evaluated. */ static FUNCTION(fun_iter) { // Optional Input Delimiter. // SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_EVAL|DELIM_STRING)) { return; } // Optional Output Delimiter. // SEP osep; if (!OPTIONAL_DELIM(4, osep, DELIM_EVAL|DELIM_NULL|DELIM_CRLF|DELIM_STRING)) { return; } char *curr = alloc_lbuf("fun_iter"); char *dp = curr; char *str = fargs[0]; mux_exec(curr, &dp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *dp = '\0'; size_t ncp; char *cp = trim_space_sep_LEN(curr, dp-curr, &sep, &ncp); if (!*cp) { free_lbuf(curr); return; } bool first = true; int number = 0; bool bLoopInBounds = ( 0 <= mudstate.in_loop && mudstate.in_loop < MAX_ITEXT); if (bLoopInBounds) { mudstate.itext[mudstate.in_loop] = NULL; mudstate.inum[mudstate.in_loop] = number; } mudstate.in_loop++; while ( cp && mudstate.func_invk_ctr < mudconf.func_invk_lim && !MuxAlarm.bAlarmed) { if (!first) { print_sep(&osep, buff, bufc); } first = false; number++; char *objstring = split_token(&cp, &sep); if (bLoopInBounds) { mudstate.itext[mudstate.in_loop-1] = objstring; mudstate.inum[mudstate.in_loop-1] = number; } char *buff2 = replace_tokens(fargs[1], objstring, mux_ltoa_t(number), NULL); str = buff2; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); free_lbuf(buff2); } mudstate.in_loop--; if (bLoopInBounds) { mudstate.itext[mudstate.in_loop] = NULL; mudstate.inum[mudstate.in_loop] = 0; } free_lbuf(curr); } static void iter_value(char *buff, char **bufc, char *fargs[], int nfargs, bool bWhich) { int number = 0; if (nfargs > 0) { number = mux_atol(fargs[0]); if (number < 0) { number = 0; } } number++; int val = mudstate.in_loop - number; if ( 0 <= val && val < MAX_ITEXT) { if (bWhich) { safe_ltoa(mudstate.inum[val], buff, bufc); } else { safe_str(mudstate.itext[val], buff, bufc); } } } static FUNCTION(fun_itext) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); iter_value(buff, bufc, fargs, nfargs, false); } static FUNCTION(fun_inum) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); iter_value(buff, bufc, fargs, nfargs, true); } static FUNCTION(fun_list) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_EVAL|DELIM_STRING)) { return; } char *objstring, *result, *str; char *curr = alloc_lbuf("fun_list"); char *dp = curr; str = fargs[0]; mux_exec(curr, &dp, executor, caller, enactor, eval|EV_TOP|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *dp = '\0'; size_t ncp; char *cp = trim_space_sep_LEN(curr, dp-curr, &sep, &ncp); if (!*cp) { free_lbuf(curr); return; } int number = 0; bool bLoopInBounds = ( 0 <= mudstate.in_loop && mudstate.in_loop < MAX_ITEXT); if (bLoopInBounds) { mudstate.itext[mudstate.in_loop] = NULL; mudstate.inum[mudstate.in_loop] = number; } mudstate.in_loop++; while ( cp && mudstate.func_invk_ctr < mudconf.func_invk_lim && !MuxAlarm.bAlarmed) { number++; objstring = split_token(&cp, &sep); if (bLoopInBounds) { mudstate.itext[mudstate.in_loop-1] = objstring; mudstate.inum[mudstate.in_loop-1] = number; } char *buff2 = replace_tokens(fargs[1], objstring, mux_ltoa_t(number), NULL); dp = result = alloc_lbuf("fun_list.2"); str = buff2; mux_exec(result, &dp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *dp = '\0'; free_lbuf(buff2); notify(enactor, result); free_lbuf(result); } mudstate.in_loop--; if (bLoopInBounds) { mudstate.itext[mudstate.in_loop] = NULL; mudstate.inum[mudstate.in_loop] = 0; } free_lbuf(curr); } static FUNCTION(fun_ilev) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); safe_ltoa(mudstate.in_loop-1, buff, bufc); } /* --------------------------------------------------------------------------- * fun_fold: Iteratively eval an attrib with a list of arguments and an * optional base case. With no base case, the first list element is * passed as %0 and the second is %1. The attrib is then evaluated * with these args, the result is then used as %0 and the next arg * is %1 and so it goes as long as there are elements left in the * list. The optional base case gives the user a nice starting point. * * > &REP_NUM object=[%0][repeat(%1,%1)] * > say fold(OBJECT/REP_NUM,1 2 3 4 5,->) * You say, "->122333444455555" * * NOTE: To use added list separator, you must use base case! */ static FUNCTION(fun_fold) { SEP sep; if (!OPTIONAL_DELIM(4, sep, DELIM_DFLT|DELIM_STRING)) { return; } char *atext; dbref thing; dbref aowner; int aflags; if (!parse_and_get_attrib(executor, fargs, &atext, &thing, &aowner, &aflags, buff, bufc)) { return; } // Evaluate it using the rest of the passed function args. // char *curr = fargs[1]; char *cp = curr; char *atextbuf = alloc_lbuf("fun_fold"); mux_strncpy(atextbuf, atext, LBUF_SIZE-1); char *result, *bp, *str, *clist[2]; // May as well handle first case now. // if ( nfargs >= 3 && fargs[2]) { clist[0] = fargs[2]; clist[1] = split_token(&cp, &sep); result = bp = alloc_lbuf("fun_fold"); str = atextbuf; mux_exec(result, &bp, thing, executor, enactor, AttrTrace(aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, clist, 2); *bp = '\0'; } else { clist[0] = split_token(&cp, &sep); clist[1] = split_token(&cp, &sep); result = bp = alloc_lbuf("fun_fold"); str = atextbuf; mux_exec(result, &bp, thing, executor, enactor, AttrTrace(aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, clist, 2); *bp = '\0'; } char *rstore = result; result = alloc_lbuf("fun_fold"); while ( cp && mudstate.func_invk_ctr < mudconf.func_invk_lim && !MuxAlarm.bAlarmed) { clist[0] = rstore; clist[1] = split_token(&cp, &sep); mux_strncpy(atextbuf, atext, LBUF_SIZE-1); bp = result; str = atextbuf; mux_exec(result, &bp, thing, executor, enactor, AttrTrace(aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, clist, 2); *bp = '\0'; mux_strncpy(rstore, result, LBUF_SIZE-1); } free_lbuf(result); safe_str(rstore, buff, bufc); free_lbuf(rstore); free_lbuf(atext); free_lbuf(atextbuf); } // Taken from PennMUSH with permission. // // itemize([,[,[,]]]) // It takes the elements of list and: // If there's just one, returns it. // If there's two, returns // If there's >2, returns ... // Default is "and", default punctuation is "," // static FUNCTION(fun_itemize) { SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING)) { return; } const char *lconj = "and"; if (nfargs > 2) { lconj = fargs[2]; } const char *punc = ","; if (nfargs > 3) { punc = fargs[3]; } int pos = 1; char *cp = trim_space_sep(fargs[0], &sep); char *word = split_token(&cp, &sep); while (cp && *cp) { pos++; safe_str(word, buff, bufc); char *nextword = split_token(&cp, &sep); if (!cp || !*cp) { // We're at the end. // if (pos >= 3) { safe_str(punc, buff, bufc); } safe_chr(' ', buff, bufc); safe_str(lconj, buff, bufc); } else { safe_str(punc, buff, bufc); } safe_chr(' ', buff, bufc); word = nextword; } safe_str(word, buff, bufc); } // --------------------------------------------------------------------------- // fun_choose: Weighted random choice from a list. // choose(,,) // static FUNCTION(fun_choose) { SEP isep; if (!OPTIONAL_DELIM(3, isep, DELIM_DFLT|DELIM_STRING)) { return; } char **elems = NULL; try { elems = new char *[LBUF_SIZE/2]; } catch (...) { ; // Nothing. } if (NULL == elems) { return; } char **weights = NULL; try { weights = new char *[LBUF_SIZE/2]; } catch (...) { ; // Nothing. } if (NULL == weights) { delete [] elems; return; } int n_elems = list2arr(elems, LBUF_SIZE/2, fargs[0], &isep); int n_weights = list2arr(weights, LBUF_SIZE/2, fargs[1], &sepSpace); if (n_elems != n_weights) { safe_str("#-1 LISTS MUST BE OF EQUAL SIZE", buff, bufc); delete [] elems; delete [] weights; return; } // Calculate the the breakpoints, not the weights themselves. // int i; int sum = 0; int ip[LBUF_SIZE/2]; for (i = 0; i < n_weights; i++) { int num = mux_atol(weights[i]); if (num < 0) { num = 0; } if (num == 0) { ip[i] = 0; } else { int sum_next = sum + num; if (sum_next < sum) { safe_str("#-1 OVERFLOW", buff, bufc); delete [] elems; delete [] weights; return; } sum = sum_next; ip[i] = sum; } } INT32 num = RandomINT32(0, sum-1); for (i = 0; i < n_weights; i++) { if ( ip[i] != 0 && num < ip[i]) { safe_str(elems[i], buff, bufc); break; } } delete [] elems; delete [] weights; } /* * --------------------------------------------------------------------------- * * distribute: randomly distribute M total points into N total bins... * * each bin has an equal 'weight'. * * syntax: distribute(points, bins, outputsep) * example: distribute(100, 5, |) might return "25|16|17|22|20" */ FUNCTION(fun_distribute) { // Get parameters and evaluate each of them. // SEP osep; if (!OPTIONAL_DELIM(3, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING)) { return; } // Validate arguments. // if (!is_integer(fargs[0], NULL)) { safe_str("#-1 ARG1 IS NOT AN INTEGER", buff, bufc); return; } if (!is_integer(fargs[1], NULL)) { safe_str("#-1 ARG2 IS NOT AN INTEGER", buff, bufc); return; } const int points_limit = 1000000; const int bins_limit = 2000; int points = mux_atol(fargs[0]); int bins = mux_atol(fargs[1]); if ( points < 0 || points_limit < points || bins <= 0 || bins_limit < bins) { safe_range(buff, bufc); return; } int *bin_array = NULL; try { bin_array = new int[bins]; } catch (...) { ; // Nothing. } if (NULL == bin_array) { safe_str("#-1 NOT ENOUGH MEMORY TO DISTRIBUTE", buff, bufc); } else { // Initialize bins. // int current_bin; for (current_bin = 0; current_bin < bins; current_bin++) { bin_array[current_bin] = 0; } // Distribute points over bin. For each point, pick a random bin for // it and increment that bin's count. // int current_point; for (current_point = 0; current_point < points; current_point++) { int which_bin = RandomINT32(0, bins-1); ++(bin_array[which_bin]); } // Convert the array to real output. // bool first = true; for (current_bin = 0; current_bin < bins; current_bin++) { if (!first) { print_sep(&osep, buff, bufc); } first = false; safe_ltoa(bin_array[current_bin], buff, bufc); } delete [] bin_array; } } #if defined(FIRANMUX) /* sql() function -- Rachel 'Jeanne' Blackman * 2003/09/30 * * A more-or-less functionally equivalent version of * TinyMUSH 3.1's sql() call. */ FUNCTION(fun_sql) { if (!mush_database) { safe_str("#-1 NO DATABASE", buff, bufc); return; } SEP sepRow; if (!OPTIONAL_DELIM(2, sepRow, DELIM_NULL|DELIM_CRLF|DELIM_STRING)) { return; } SEP sepColumn = sepRow; if (!OPTIONAL_DELIM(3, sepColumn, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT)) { return; } char *curr = alloc_lbuf("fun_sql"); char *dp = curr; char *str = fargs[0]; mux_exec(curr, &dp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *dp = '\0'; char *cp = curr; cp = trim_space_sep(cp, &sepSpace); if (!*cp) { free_lbuf(curr); return; } if (mysql_ping(mush_database)) { free_lbuf(curr); safe_str("#-1 SQL UNAVAILABLE", buff, bufc); return; } if (mysql_real_query(mush_database, cp, strlen(cp))) { free_lbuf(curr); safe_str("#-1 QUERY ERROR", buff, bufc); return; } MYSQL_RES *result = mysql_store_result(mush_database); if (!result) { free_lbuf(curr); return; } int num_fields = mysql_num_fields(result); MYSQL_ROW row = mysql_fetch_row(result); while (row) { int loop; for (loop = 0; loop < num_fields; loop++) { if (loop) { print_sep(&sepColumn, buff, bufc); } safe_str(row[loop], buff, bufc); } row = mysql_fetch_row(result); if (row) { print_sep(&sepRow, buff, bufc); } } free_lbuf(curr); mysql_free_result(result); } #endif // FIRANMUX /* --------------------------------------------------------------------------- * fun_filter: Iteratively perform a function with a list of arguments and * return the arg, if the function evaluates to true using the arg. * * > &IS_ODD object=mod(%0,2) * > say filter(object/is_odd,1 2 3 4 5) * You say, "1 3 5" * > say filter(object/is_odd,1-2-3-4-5,-) * You say, "1-3-5" * * NOTE: If you specify a separator, it is used to delimit the returned list. */ static void filter_handler(char *buff, char **bufc, dbref executor, dbref enactor, char *fargs[], int nfargs, SEP *psep, SEP *posep, bool bBool) { char *atext; dbref thing; dbref aowner; int aflags; if (!parse_and_get_attrib(executor, fargs, &atext, &thing, &aowner, &aflags, buff, bufc)) { return; } // Process optional arguments %1-%9. // char *filter_args[10]; int filter_nargs = 1; for (int iArg = 4; iArg < nfargs; iArg++) { filter_args[filter_nargs++] = fargs[iArg]; } // Now iteratively eval the attrib with the argument list. // char *cp = trim_space_sep(fargs[1], psep); if ('\0' != cp[0]) { char *atextbuf = alloc_lbuf("fun_filter"); char *result = alloc_lbuf("fun_filter"); bool bFirst = true; while ( cp && mudstate.func_invk_ctr < mudconf.func_invk_lim && !MuxAlarm.bAlarmed) { char *objstring = split_token(&cp, psep); mux_strncpy(atextbuf, atext, LBUF_SIZE-1); char *bp = result; char *str = atextbuf; filter_args[0] = objstring; mux_exec(result, &bp, thing, executor, enactor, AttrTrace(aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, filter_args, filter_nargs); *bp = '\0'; if ( ( bBool && xlate(result)) || ( !bBool && result[0] == '1' && result[1] == '\0')) { if (!bFirst) { print_sep(posep, buff, bufc); } safe_str(objstring, buff, bufc); bFirst = false; } } free_lbuf(result); free_lbuf(atextbuf); } free_lbuf(atext); } static FUNCTION(fun_filter) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_INIT|DELIM_STRING)) { return; } filter_handler(buff, bufc, executor, enactor, fargs, nfargs, &sep, &osep, false); } static FUNCTION(fun_filterbool) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_INIT|DELIM_STRING)) { return; } filter_handler(buff, bufc, executor, enactor, fargs, nfargs, &sep, &osep, true); } /* --------------------------------------------------------------------------- * fun_map: Iteratively evaluate an attribute with a list of arguments. * * > &DIV_TWO object=fdiv(%0,2) * > say map(1 2 3 4 5,object/div_two) * You say, "0.5 1 1.5 2 2.5" * > say map(object/div_two,1-2-3-4-5,-) * You say, "0.5-1-1.5-2-2.5" */ static FUNCTION(fun_map) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_INIT|DELIM_STRING)) { return; } char *atext; dbref thing; dbref aowner; int aflags; if (!parse_and_get_attrib(executor, fargs, &atext, &thing, &aowner, &aflags, buff, bufc)) { return; } // Process optional arguments %1-%9. // char *map_args[10]; int map_nargs = 1; for (int iArg = 4; iArg < nfargs; iArg++) { map_args[map_nargs++] = fargs[iArg]; } // Now process the list one element at a time. // char *cp = trim_space_sep(fargs[1], &sep); if ('\0' != cp[0]) { char *atextbuf = alloc_lbuf("fun_map"); bool first = true; while ( cp && mudstate.func_invk_ctr < mudconf.func_invk_lim && !MuxAlarm.bAlarmed) { if (!first) { print_sep(&osep, buff, bufc); } first = false; char *objstring = split_token(&cp, &sep); mux_strncpy(atextbuf, atext, LBUF_SIZE-1); char *str = atextbuf; map_args[0] = objstring; mux_exec(buff, bufc, thing, executor, enactor, AttrTrace(aflags, EV_STRIP_CURLY|EV_FCHECK|EV_EVAL), &str, map_args, map_nargs); } free_lbuf(atextbuf); } free_lbuf(atext); } /* * --------------------------------------------------------------------------- * * fun_edit: Edit text. */ static FUNCTION(fun_edit) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); char *tstr; edit_string(strip_ansi(fargs[0]), &tstr, fargs[1], fargs[2]); safe_str(tstr, buff, bufc); free_lbuf(tstr); } /* --------------------------------------------------------------------------- * fun_locate: Search for things with the perspective of another obj. */ static FUNCTION(fun_locate) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool check_locks, verbose, multiple; dbref thing, what; char *cp; int pref_type = NOTYPE; check_locks = verbose = multiple = false; // Find the thing to do the looking, make sure we control it. // if (See_All(executor)) { thing = match_thing_quiet(executor, fargs[0]); } else { thing = match_controlled_quiet(executor, fargs[0]); } if (!Good_obj(thing)) { safe_match_result(thing, buff, bufc); return; } // Get pre- and post-conditions and modifiers // for (cp = fargs[2]; *cp; cp++) { switch (*cp) { case 'E': pref_type = TYPE_EXIT; break; case 'L': check_locks = true; break; case 'P': pref_type = TYPE_PLAYER; break; case 'R': pref_type = TYPE_ROOM; break; case 'T': pref_type = TYPE_THING; break; case 'V': verbose = true; break; case 'X': multiple = true; break; } } // Set up for the search // if (check_locks) { init_match_check_keys(thing, fargs[1], pref_type); } else { init_match(thing, fargs[1], pref_type); } // Search for each requested thing // for (cp = fargs[2]; *cp; cp++) { switch (*cp) { case 'a': match_absolute(); break; case 'c': match_carried_exit_with_parents(); break; case 'e': match_exit_with_parents(); break; case 'h': match_here(); break; case 'i': match_possession(); break; case 'm': match_me(); break; case 'n': match_neighbor(); break; case 'p': match_player(); break; case '*': match_everything(MAT_EXIT_PARENTS); break; } } // Get the result and return it to the caller // if (multiple) { what = last_match_result(); } else { what = match_result(); } if (verbose) { (void)match_status(executor, what); } safe_tprintf_str(buff, bufc, "#%d", what); } static void switch_handler ( char *buff, char **bufc, dbref executor, dbref caller, dbref enactor, int eval, char *fargs[], int nfargs, char *cargs[], int ncargs, bool bSwitch ) { // Evaluate the target in fargs[0]. // char *mbuff = alloc_lbuf("fun_switch"); char *bp = mbuff; char *str = fargs[0]; mux_exec(mbuff, &bp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *bp = '\0'; char *tbuff = alloc_lbuf("fun_switch.2"); // Loop through the patterns looking for a match. // int i; for (i = 1; i < nfargs-1 && fargs[i] && fargs[i+1] && !MuxAlarm.bAlarmed; i += 2) { bp = tbuff; str = fargs[i]; mux_exec(tbuff, &bp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); *bp = '\0'; if (bSwitch ? wild_match(tbuff, mbuff) : strcmp(tbuff, mbuff) == 0) { free_lbuf(tbuff); tbuff = replace_tokens(fargs[i+1], NULL, NULL, mbuff); free_lbuf(mbuff); str = tbuff; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); free_lbuf(tbuff); return; } } free_lbuf(tbuff); // Nope, return the default if there is one. // if ( i < nfargs && fargs[i]) { tbuff = replace_tokens(fargs[i], NULL, NULL, mbuff); str = tbuff; mux_exec(buff, bufc, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL, &str, cargs, ncargs); free_lbuf(tbuff); } free_lbuf(mbuff); } /* --------------------------------------------------------------------------- * fun_switch: Return value based on pattern matching (ala @switch) * NOTE: This function expects that its arguments have not been evaluated. */ static FUNCTION(fun_switch) { switch_handler ( buff, bufc, executor, caller, enactor, eval, fargs, nfargs, cargs, ncargs, true ); } static FUNCTION(fun_case) { switch_handler ( buff, bufc, executor, caller, enactor, eval, fargs, nfargs, cargs, ncargs, false ); } /* * --------------------------------------------------------------------------- * * fun_space: Make spaces. */ static FUNCTION(fun_space) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // Validate request. // int num; if (nfargs == 0 || *fargs[0] == '\0') { num = 1; } else { num = mux_atol(fargs[0]); if (num == 0) { // If 'space(0)', 'space(00)', ..., then allow num == 0, // otherwise, we force to num to be 1. // if (!is_integer(fargs[0], NULL)) { num = 1; } } else if (num < 0) { num = 0; } } safe_fill(buff, bufc, ' ', num); } static FUNCTION(fun_height) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); long nHeight = 24; if (is_rational(fargs[0])) { SOCKET s = mux_atol(fargs[0]); DESC *d; DESC_ITER_CONN(d) { if (d->descriptor == s) { nHeight = d->height; break; } } } else { char *pTargetName = fargs[0]; if ('*' == *pTargetName) { pTargetName++; } dbref target = lookup_player(executor, pTargetName, true); if (Good_obj(target)) { nHeight = fetch_height(target); } } safe_ltoa(nHeight, buff, bufc); } static FUNCTION(fun_width) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); long nWidth = 78; if (is_rational(fargs[0])) { SOCKET s = mux_atol(fargs[0]); DESC *d; DESC_ITER_CONN(d) { if (d->descriptor == s) { nWidth = d->width; break; } } } else { char *pTargetName = fargs[0]; if ('*' == *pTargetName) { pTargetName++; } dbref target = lookup_player(executor, pTargetName, true); if (Good_obj(target)) { nWidth = fetch_width(target); } } safe_ltoa(nWidth, buff, bufc); } /* * --------------------------------------------------------------------------- * * fun_idle, fun_conn: return seconds idle or connected. */ static FUNCTION(fun_idle) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); long nIdle = -1; if (is_rational(fargs[0])) { SOCKET s = mux_atol(fargs[0]); bool bFound = false; DESC *d; CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); DESC_ITER_CONN(d) { if (d->descriptor == s) { bFound = true; break; } } if ( bFound && ( d->player == executor || Wizard_Who(executor))) { CLinearTimeDelta ltdResult = ltaNow - d->last_time; nIdle = ltdResult.ReturnSeconds(); } } else { char *pTargetName = fargs[0]; if (*pTargetName == '*') { pTargetName++; } dbref target = lookup_player(executor, pTargetName, true); if ( Good_obj(target) && ( !Hidden(target) || See_Hidden(executor))) { nIdle = fetch_idle(target); } } safe_ltoa(nIdle, buff, bufc); } static FUNCTION(fun_conn) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); long nConnected = -1; if (is_rational(fargs[0])) { SOCKET s = mux_atol(fargs[0]); bool bFound = false; DESC *d; CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); DESC_ITER_CONN(d) { if (d->descriptor == s) { bFound = true; break; } } if ( bFound && ( d->player == executor || Wizard_Who(executor))) { CLinearTimeDelta ltdResult = ltaNow - d->connected_at; nConnected = ltdResult.ReturnSeconds(); } } else { char *pTargetName = fargs[0]; if (*pTargetName == '*') { pTargetName++; } dbref target = lookup_player(executor, pTargetName, true); if ( Good_obj(target) && ( !Hidden(target) || See_Hidden(executor))) { nConnected = fetch_connect(target); } } safe_ltoa(nConnected, buff, bufc); } /* * --------------------------------------------------------------------------- * * fun_sort: Sort lists. */ typedef struct f_record { double data; char *str; } f_rec; typedef struct i_record { long data; char *str; } i_rec; typedef struct i64_record { INT64 data; char *str; } i64_rec; static int DCL_CDECL a_comp(const void *s1, const void *s2) { return strcmp(*(char **)s1, *(char **)s2); } static int DCL_CDECL a_casecomp(const void *s1, const void *s2) { return mux_stricmp(*(char **)s1, *(char **)s2); } static int DCL_CDECL f_comp(const void *s1, const void *s2) { if (((f_rec *) s1)->data > ((f_rec *) s2)->data) { return 1; } else if (((f_rec *) s1)->data < ((f_rec *) s2)->data) { return -1; } return 0; } static int DCL_CDECL i_comp(const void *s1, const void *s2) { if (((i_rec *) s1)->data > ((i_rec *) s2)->data) { return 1; } else if (((i_rec *) s1)->data < ((i_rec *) s2)->data) { return -1; } return 0; } static int DCL_CDECL i64_comp(const void *s1, const void *s2) { if (((i64_rec *) s1)->data > ((i64_rec *) s2)->data) { return 1; } else if (((i64_rec *) s1)->data < ((i64_rec *) s2)->data) { return -1; } return 0; } static void do_asort(char *s[], int n, int sort_type) { if ( n <= 0 || LBUF_SIZE <= n) { return; } int i; f_rec *fp; i_rec *ip; i64_rec *i64p; switch (sort_type) { case ASCII_LIST: qsort(s, n, sizeof(char *), a_comp); break; case NUMERIC_LIST: i64p = (i64_rec *) MEMALLOC(n * sizeof(i64_rec)); if (NULL != i64p) { for (i = 0; i < n; i++) { i64p[i].str = s[i]; i64p[i].data = mux_atoi64(s[i]); } qsort(i64p, n, sizeof(i64_rec), i64_comp); for (i = 0; i < n; i++) { s[i] = i64p[i].str; } MEMFREE(i64p); i64p = NULL; } break; case DBREF_LIST: ip = (i_rec *) MEMALLOC(n * sizeof(i_rec)); if (NULL != ip) { for (i = 0; i < n; i++) { ip[i].str = s[i]; ip[i].data = dbnum(s[i]); } qsort(ip, n, sizeof(i_rec), i_comp); for (i = 0; i < n; i++) { s[i] = ip[i].str; } MEMFREE(ip); ip = NULL; } break; case FLOAT_LIST: fp = (f_rec *) MEMALLOC(n * sizeof(f_rec)); if (NULL != fp) { for (i = 0; i < n; i++) { fp[i].str = s[i]; fp[i].data = mux_atof(s[i], false); } qsort(fp, n, sizeof(f_rec), f_comp); for (i = 0; i < n; i++) { s[i] = fp[i].str; } MEMFREE(fp); fp = NULL; } break; case CI_ASCII_LIST: qsort(s, n, sizeof(char *), a_casecomp); break; } } static FUNCTION(fun_sort) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_INIT|DELIM_STRING)) { return; } char *ptrs[LBUF_SIZE / 2]; // Convert the list to an array. // char *list = alloc_lbuf("fun_sort"); mux_strncpy(list, fargs[0], LBUF_SIZE-1); int nitems = list2arr(ptrs, LBUF_SIZE / 2, list, &sep); int sort_type = get_list_type(fargs, nfargs, 2, ptrs, nitems); do_asort(ptrs, nitems, sort_type); arr2list(ptrs, nitems, buff, bufc, &osep); free_lbuf(list); } /* --------------------------------------------------------------------------- * fun_setunion, fun_setdiff, fun_setinter: Set management. */ #define SET_UNION 1 #define SET_INTERSECT 2 #define SET_DIFF 3 static void handle_sets ( char *fargs[], char *buff, char **bufc, int oper, SEP *psep, SEP *posep ) { char **ptrs1 = NULL; try { ptrs1 = new char *[LBUF_SIZE]; } catch (...) { ; // Nothing. } if (NULL == ptrs1) { return; } char **ptrs2 = NULL; try { ptrs2 = new char *[LBUF_SIZE]; } catch (...) { ; // Nothing. } if (NULL == ptrs2) { delete [] ptrs1; return; } int val; char *list1 = alloc_lbuf("fun_setunion.1"); mux_strncpy(list1, fargs[0], LBUF_SIZE-1); int n1 = list2arr(ptrs1, LBUF_SIZE, list1, psep); do_asort(ptrs1, n1, ASCII_LIST); char *list2 = alloc_lbuf("fun_setunion.2"); mux_strncpy(list2, fargs[1], LBUF_SIZE-1); int n2 = list2arr(ptrs2, LBUF_SIZE, list2, psep); do_asort(ptrs2, n2, ASCII_LIST); int i1 = 0; int i2 = 0; char *oldp = NULL; bool bFirst = true; switch (oper) { case SET_UNION: // Copy elements common to both lists. // // Handle case of two identical single-element lists. // if ( n1 == 1 && n2 == 1 && strcmp(ptrs1[0], ptrs2[0]) == 0) { safe_str(ptrs1[0], buff, bufc); break; } // Process until one list is empty. // while ( i1 < n1 && i2 < n2) { // Skip over duplicates. // if ( i1 > 0 || i2 > 0) { while ( i1 < n1 && oldp && strcmp(ptrs1[i1], oldp) == 0) { i1++; } while ( i2 < n2 && oldp && strcmp(ptrs2[i2], oldp) == 0) { i2++; } } // Compare and copy. // if ( i1 < n1 && i2 < n2) { if (!bFirst) { print_sep(posep, buff, bufc); } bFirst = false; if (strcmp(ptrs1[i1], ptrs2[i2]) < 0) { oldp = ptrs1[i1]; safe_str(ptrs1[i1], buff, bufc); i1++; } else { oldp = ptrs2[i2]; safe_str(ptrs2[i2], buff, bufc); i2++; } } } // Copy rest of remaining list, stripping duplicates. // for (; i1 < n1; i1++) { if ( !oldp || strcmp(oldp, ptrs1[i1]) != 0) { if (!bFirst) { print_sep(posep, buff, bufc); } bFirst = false; oldp = ptrs1[i1]; safe_str(ptrs1[i1], buff, bufc); } } for (; i2 < n2; i2++) { if ( !oldp || strcmp(oldp, ptrs2[i2]) != 0) { if (!bFirst) { print_sep(posep, buff, bufc); } bFirst = false; oldp = ptrs2[i2]; safe_str(ptrs2[i2], buff, bufc); } } break; case SET_INTERSECT: // Copy elements not in both lists. // while ( i1 < n1 && i2 < n2) { val = strcmp(ptrs1[i1], ptrs2[i2]); if (!val) { // Got a match, copy it. // if (!bFirst) { print_sep(posep, buff, bufc); } bFirst = false; oldp = ptrs1[i1]; safe_str(ptrs1[i1], buff, bufc); i1++; i2++; while ( i1 < n1 && strcmp(ptrs1[i1], oldp) == 0) { i1++; } while ( i2 < n2 && strcmp(ptrs2[i2], oldp) == 0) { i2++; } } else if (val < 0) { i1++; } else { i2++; } } break; case SET_DIFF: // Copy elements unique to list1. // while ( i1 < n1 && i2 < n2) { val = strcmp(ptrs1[i1], ptrs2[i2]); if (!val) { // Got a match, increment pointers. // oldp = ptrs1[i1]; while ( i1 < n1 && strcmp(ptrs1[i1], oldp) == 0) { i1++; } while ( i2 < n2 && strcmp(ptrs2[i2], oldp) == 0) { i2++; } } else if (val < 0) { // Item in list1 not in list2, copy. // if (!bFirst) { print_sep(posep, buff, bufc); } bFirst = false; safe_str(ptrs1[i1], buff, bufc); oldp = ptrs1[i1]; i1++; while ( i1 < n1 && strcmp(ptrs1[i1], oldp) == 0) { i1++; } } else { // Item in list2 but not in list1, discard. // oldp = ptrs2[i2]; i2++; while ( i2 < n2 && strcmp(ptrs2[i2], oldp) == 0) { i2++; } } } // Copy remainder of list1. // while (i1 < n1) { if (!bFirst) { print_sep(posep, buff, bufc); } bFirst = false; safe_str(ptrs1[i1], buff, bufc); oldp = ptrs1[i1]; i1++; while ( i1 < n1 && strcmp(ptrs1[i1], oldp) == 0) { i1++; } } } free_lbuf(list1); free_lbuf(list2); delete [] ptrs1; delete [] ptrs2; } static FUNCTION(fun_setunion) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_INIT|DELIM_STRING)) { return; } handle_sets(fargs, buff, bufc, SET_UNION, &sep, &osep); } static FUNCTION(fun_setdiff) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_INIT|DELIM_STRING)) { return; } handle_sets(fargs, buff, bufc, SET_DIFF, &sep, &osep); } static FUNCTION(fun_setinter) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } SEP osep = sep; if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_INIT|DELIM_STRING)) { return; } handle_sets(fargs, buff, bufc, SET_INTERSECT, &sep, &osep); } /* --------------------------------------------------------------------------- * rjust, ljust, center: Justify or center text, specifying fill character. */ #define CJC_CENTER 0 #define CJC_LJUST 1 #define CJC_RJUST 2 static void centerjustcombo ( int iType, char *buff, char **bufc, char *fargs[], int nfargs ) { // Width must be a number. // if (!is_integer(fargs[1], NULL)) { return; } size_t width = mux_atol(fargs[1]); if (width <= 0 || LBUF_SIZE <= width) { safe_range(buff, bufc); return; } // Determine string to pad with. // size_t vwPad = 0; size_t nPad = 0; char aPad[SBUF_SIZE]; struct ANSI_In_Context aic; struct ANSI_Out_Context aoc; if (nfargs == 3 && *fargs[2]) { char *p = RemoveSetOfCharacters(fargs[2], "\r\n\t"); ANSI_String_In_Init(&aic, p, ANSI_ENDGOAL_NORMAL); ANSI_String_Out_Init(&aoc, aPad, sizeof(aPad), sizeof(aPad), ANSI_ENDGOAL_LEAK); ANSI_String_Copy(&aoc, &aic, sizeof(aPad)); nPad = ANSI_String_Finalize(&aoc, &vwPad); } if (0 == nPad) { aPad[0] = ' '; aPad[1] = '\0'; nPad = 1; vwPad = 1; } size_t vwStr; char aStr[LBUF_SIZE]; size_t nStr = ANSI_TruncateToField(fargs[0], sizeof(aStr), aStr, width, &vwStr, ANSI_ENDGOAL_NORMAL); // If the visual width of the text fits exactly into the field, // then we are done. ANSI_TruncateToField insures that it's // never larger. // if (vwStr == width) { safe_copy_buf(aStr, nStr, buff, bufc); return; } size_t vwLeading = 0; if (iType == CJC_CENTER) { vwLeading = (width - vwStr)/2; } else if (iType == CJC_RJUST) { vwLeading = width - vwStr; } size_t vwTrailing = width - vwLeading - vwStr; // Shortcut this function if nPad == 1 (i.e., the padding is a single // character). // if (nPad == 1 && vwPad == 1) { safe_fill(buff, bufc, aPad[0], vwLeading); safe_copy_buf(aStr, nStr, buff, bufc); safe_fill(buff, bufc, aPad[0], vwTrailing); return; } // Calculate the necessary info about the leading padding. // The origin on the padding is at byte 0 at beginning of the // field (this may cause mis-syncronization on the screen if // the same background padding string is used on several lines // with each idented from column 0 by a different amount. // There is nothing center() can do about this issue. You are // on your own. // // Padding is repeated nLeadFull times and then a partial string // of vwLeadPartial visual width is tacked onto the end. // // vwLeading == nLeadFull * vwPad + vwLeadPartial // size_t nLeadFull = 0; size_t vwLeadPartial = 0; if (vwLeading) { nLeadFull = vwLeading / vwPad; vwLeadPartial = vwLeading - nLeadFull * vwPad; } // Calculate the necessary info about the trailing padding. // // vwTrailing == vwTrailPartial0 + nTrailFull * vwPad // + vwTrailPartial1 // size_t vwTrailSkip0 = 0; size_t vwTrailPartial0 = 0; size_t nTrailFull = 0; size_t vwTrailPartial1 = 0; if (vwTrailing) { vwTrailSkip0 = (vwLeading + vwStr) % vwPad; if (vwTrailSkip0) { vwTrailPartial0 = vwPad - vwTrailSkip0; if (vwTrailing < vwTrailPartial0) { vwTrailPartial0 = vwTrailing; vwTrailing = 0; } else { vwTrailing -= vwTrailPartial0; } } nTrailFull = vwTrailing / vwPad; vwTrailPartial1 = vwTrailing - nTrailFull * vwPad; } size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; ANSI_String_Out_Init(&aoc, *bufc, nBufferAvailable, LBUF_SIZE-1, ANSI_ENDGOAL_NORMAL); size_t vwDone; // Output the runs of full leading padding. // size_t i; size_t n; for (i = 0; i < nLeadFull; i++) { ANSI_String_In_Init(&aic, aPad, ANSI_ENDGOAL_NORMAL); ANSI_String_Copy(&aoc, &aic, vwPad); } // Output the partial leading padding segment. // if (vwLeadPartial > 0) { ANSI_String_In_Init(&aic, aPad, ANSI_ENDGOAL_NORMAL); ANSI_String_Copy(&aoc, &aic, vwLeadPartial); } // Output the main string to be centered. // if (nStr > 0) { ANSI_String_In_Init(&aic, aStr, ANSI_ENDGOAL_NORMAL); ANSI_String_Copy(&aoc, &aic, LBUF_SIZE-1); } // Output the first partial trailing padding segment. // if (vwTrailPartial0 > 0) { ANSI_String_In_Init(&aic, aPad, ANSI_ENDGOAL_NORMAL); ANSI_String_Skip(&aic, vwTrailSkip0, &vwDone); ANSI_String_Copy(&aoc, &aic, vwTrailPartial0); } // Output the runs of full trailing padding. // for (i = 0; i < nTrailFull; i++) { ANSI_String_In_Init(&aic, aPad, ANSI_ENDGOAL_NORMAL); ANSI_String_Copy(&aoc, &aic, vwPad); } // Output the second partial trailing padding segment. // if (vwTrailPartial1 > 0) { ANSI_String_In_Init(&aic, aPad, ANSI_ENDGOAL_NORMAL); ANSI_String_Copy(&aoc, &aic, vwTrailPartial1); } n = ANSI_String_Finalize(&aoc, &vwDone); *bufc += n; } static FUNCTION(fun_ljust) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); centerjustcombo(CJC_LJUST, buff, bufc, fargs, nfargs); } static FUNCTION(fun_rjust) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); centerjustcombo(CJC_RJUST, buff, bufc, fargs, nfargs); } static FUNCTION(fun_center) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); centerjustcombo(CJC_CENTER, buff, bufc, fargs, nfargs); } /* --------------------------------------------------------------------------- * setq, setr, r: set and read global registers. */ static FUNCTION(fun_setq) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int regnum = mux_RegisterSet[(unsigned char)fargs[0][0]]; if ( regnum < 0 || regnum >= MAX_GLOBAL_REGS || fargs[0][1] != '\0') { safe_str("#-1 INVALID GLOBAL REGISTER", buff, bufc); } else { size_t n = strlen(fargs[1]); RegAssign(&mudstate.global_regs[regnum], n, fargs[1]); } } static FUNCTION(fun_setr) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int regnum = mux_RegisterSet[(unsigned char)fargs[0][0]]; if ( regnum < 0 || regnum >= MAX_GLOBAL_REGS || fargs[0][1] != '\0') { safe_str("#-1 INVALID GLOBAL REGISTER", buff, bufc); } else { size_t n = strlen(fargs[1]); RegAssign(&mudstate.global_regs[regnum], n, fargs[1]); safe_copy_buf(fargs[1], n, buff, bufc); } } static FUNCTION(fun_r) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int regnum = mux_RegisterSet[(unsigned char)fargs[0][0]]; if ( regnum < 0 || regnum >= MAX_GLOBAL_REGS || fargs[0][1] != '\0') { safe_str("#-1 INVALID GLOBAL REGISTER", buff, bufc); } else if (mudstate.global_regs[regnum]) { safe_copy_buf(mudstate.global_regs[regnum]->reg_ptr, mudstate.global_regs[regnum]->reg_len, buff, bufc); } } /* --------------------------------------------------------------------------- * isdbref: is the argument a valid dbref? */ static FUNCTION(fun_isdbref) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); bool bResult = false; if (nfargs >= 1) { char *p = fargs[0]; if (NUMBER_TOKEN == p[0]) { p++; dbref dbitem = parse_dbref(p); bResult = Good_obj(dbitem); } } safe_bool(bResult, buff, bufc); } /* --------------------------------------------------------------------------- * trim: trim off unwanted white space. */ static char* trim_fast_left(char* str, char delim) { // We assume delim is never '\0' // while (*str == delim) { str++; } return str; } static void trim_fast_right(char* str, char delim) { // We assume delim is never '\0' // char* last = NULL; while (*str) { if (*str != delim) { last = str; } str++; } if (last == NULL) { return; } *(last+1) = '\0'; } static char* trim_left(char* str, SEP* sep) { if (1 == sep->n) { return trim_fast_left(str, sep->str[0]); } size_t cycle = 0; size_t max = sep->n; char* base = str-1; for ( ; *str == sep->str[cycle]; str++) { if (max <= ++cycle) { cycle = 0; base = str; } } return base+1; } static void trim_right(char* str, SEP* sep) { if (1 == sep->n) { trim_fast_right(str,sep->str[0]); return; } int cycle = static_cast(sep->n - 1); size_t max = sep->n - 1; int n = static_cast(strlen(str)); size_t base = n; n--; for ( ; n >= 0 && str[n] == sep->str[cycle]; n--) { if (--cycle < 0) { cycle = max; base = n; } } *(str+base) = '\0'; } static FUNCTION(fun_trim) { SEP sep; if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING)) { return; } #define TRIM_LEFT 1 #define TRIM_RIGHT 2 int trim; if (nfargs >= 2) { switch (mux_tolower(*fargs[1])) { case 'l': trim = TRIM_LEFT; break; case 'r': trim = TRIM_RIGHT; break; default: trim = TRIM_LEFT|TRIM_RIGHT; break; } } else { trim = TRIM_LEFT|TRIM_RIGHT; } char* str; if (trim & TRIM_LEFT) { str = trim_left(fargs[0],&sep); } else { str = fargs[0]; } if (trim & TRIM_RIGHT) { trim_right(str,&sep); } safe_str(str,buff,bufc); } static FUNCTION(fun_config) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (nfargs == 1) { cf_display(executor, fargs[0], buff, bufc); } else { cf_list(executor, buff, bufc); } } // --------------------------------------------------------------------------- // fun_bittype adapted from RhostMUSH. Used with permission. // static int return_bit(dbref player) { if (God(player)) { return 7; } // 6 is Rhost Immortal. We don't have an equivalent (yet?). if (Wizard(player)) { return 5; } if (Royalty(player)) { return 4; } if (Staff(player) || Builder(player)) { return 3; } if (Head(player) || Immortal(player)) { return 2; } if (!(Uninspected(player) || Guest(player))) { return 1; } return 0; } static FUNCTION(fun_bittype) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref target; if (nfargs == 1) { target = match_thing(executor, fargs[0]); } else { target = executor; } if (!Good_obj(target)) { return; } safe_ltoa(return_bit(target), buff, bufc); } static FUNCTION(fun_error) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if ( Good_obj(mudconf.global_error_obj) && !Going(mudconf.global_error_obj)) { dbref aowner; int aflags; char *errtext = atr_get(mudconf.global_error_obj, A_VA, &aowner, &aflags); char *errbuff = alloc_lbuf("process_command.error_msg"); char *errbufc = errbuff; char *str = errtext; if (nfargs == 1) { char *arg = fargs[0]; mux_exec(errbuff, &errbufc, mudconf.global_error_obj, caller, enactor, AttrTrace(aflags, EV_TOP|EV_EVAL|EV_FCHECK|EV_STRIP_CURLY), &str, &arg, 1); *errbufc = '\0'; } else { mux_exec(errbuff, &errbufc, mudconf.global_error_obj, caller, enactor, AttrTrace(aflags, EV_TOP|EV_EVAL|EV_FCHECK|EV_STRIP_CURLY), &str, NULL, 0); *errbufc = '\0'; } safe_str(errbuff, buff, bufc); free_lbuf(errtext); free_lbuf(errbuff); } else { safe_str("Huh? (Type \"help\" for help.)", buff, bufc); } } static FUNCTION(fun_strip) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (fargs[0][0] == '\0') { return; } size_t n; char *p = strip_ansi(fargs[0], &n); if ( nfargs < 2 || fargs[1][0] == '\0') { safe_copy_buf(p, n, buff, bufc); return; } char *pInput = alloc_lbuf("fun_strip.1"); memcpy(pInput, p, n+1); p = strip_ansi(fargs[1], &n); safe_str(RemoveSetOfCharacters(pInput, p), buff, bufc); free_lbuf(pInput); } #define DEFAULT_WIDTH 78 static char *expand_tabs(const char *str) { static char tbuf1[LBUF_SIZE]; char *bp = tbuf1; if (str) { unsigned int n = 0; bool ansi = false; for (unsigned int i = 0; str[i]; i++) { switch (str[i]) { case '\t': safe_fill(tbuf1, &bp, ' ', 8 - n % 8); continue; case '\r': // FALL THROUGH case '\n': n = 0; break; case ESC_CHAR: ansi = true; break; case ANSI_ATTR_CMD: if (ansi) { ansi = false; } else { n++; } break; case BEEP_CHAR: break; default: if (!ansi) { n++; } } safe_chr(str[i], tbuf1, &bp); } } *bp = '\0'; return tbuf1; } static size_t wraplen(char *str, const size_t nWidth, bool &newline) { const size_t length = strlen(str); newline = false; if (length <= nWidth) { /* Find the first return char * so %r will not mess with any alignment * functions. */ for (size_t i = 0; i < length; i++) { if ( str[i] == '\n' || str[i] == '\r') { newline = true; return i+2; } } return length; } /* Find the first return char * so %r will not mess with any alignment * functions. */ for (size_t i = 0; i < nWidth; i++) { if ( str[i] == '\n' || str[i] == '\r') { newline = true; return i+2; } } /* No return char was found. Now * find the last space in str. */ size_t maxlen = nWidth; while (str[maxlen] != ' ' && maxlen > 0) { maxlen--; } if (str[maxlen] != ' ') { maxlen = nWidth; } return maxlen; } static FUNCTION(fun_wrap) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // ARG 2: Width. Default: 78. // int nWidth = DEFAULT_WIDTH; if ( nfargs >= 2 && fargs[1][0]) { nWidth = mux_atol(fargs[1]); if ( nWidth < 1 || nWidth >= LBUF_SIZE) { safe_range(buff, bufc); return; } } // ARG 3: Justification. Default: Left. // int iJustKey = CJC_LJUST; if ( nfargs >= 3 && fargs[2][0]) { char cJust = mux_toupper(fargs[2][0]); switch (cJust) { case 'L': iJustKey = CJC_LJUST; break; case 'R': iJustKey = CJC_RJUST; break; case 'C': iJustKey = CJC_CENTER; break; default: safe_str("#-1 INVALID JUSTIFICATION SPECIFIED", buff, bufc); return; } } // ARG 4: Left padding. Default: blank. // char *pLeft = NULL; if ( nfargs >= 4 && fargs[3][0]) { pLeft = fargs[3]; } // ARG 5: Right padding. Default: blank. // char *pRight = NULL; if ( nfargs >= 5 && fargs[4][0]) { pRight = fargs[4]; } // ARG 6: Hanging indent. Default: 0. // int nHanging = 0; if ( nfargs >= 6 && fargs[5][0]) { nHanging = mux_atol(fargs[5]); } // ARG 7: Output separator. Default: line break. // const char *pOSep = "\r\n"; if ( nfargs >= 7 && fargs[6][0]) { if (!strcmp(fargs[6], "@@")) { pOSep = NULL; } else { pOSep = fargs[6]; } } // ARG 8: First line width. Default: same as arg 2. int nFirstWidth = nWidth; if ( nfargs >= 8 && fargs[7][0]) { nFirstWidth = mux_atol(fargs[7]); if ( nFirstWidth < 1 || nFirstWidth >= LBUF_SIZE) { safe_range(buff, bufc); return; } } char *str = alloc_lbuf("fun_mywrap.str"); char *tstr = alloc_lbuf("fun_mywrap.str2"); mux_strncpy(tstr, expand_tabs(fargs[0]), LBUF_SIZE-1); mux_strncpy(str,strip_ansi(tstr), LBUF_SIZE-1); size_t nLength = 0; bool newline = false; char *jargs[2]; struct ANSI_In_Context aic; struct ANSI_Out_Context aoc; char *mbufc; char *mbuf = mbufc = alloc_lbuf("fun_mywrap.out"); size_t nBufferAvailable, nSize; size_t nDone; size_t i = 0; while (str[i]) { nLength = wraplen(str + i, i == 0 ? nFirstWidth : nWidth, newline); mbufc = mbuf; ANSI_String_In_Init(&aic, tstr, ANSI_ENDGOAL_NORMAL); ANSI_String_Skip(&aic, i, &nDone); if (nDone < i || nLength <= 0) { break; } if (i > 0) { safe_str(pOSep, buff, bufc); if (nHanging > 0) { safe_fill(buff, bufc, ' ', nHanging); } } nBufferAvailable = LBUF_SIZE - (mbufc - mbuf) - 1; ANSI_String_Out_Init(&aoc, mbufc, nBufferAvailable, nLength-(newline ? 2 : 0), ANSI_ENDGOAL_NORMAL); ANSI_String_Copy(&aoc, &aic, nLength-(newline ? 2 : 0)); nSize = ANSI_String_Finalize(&aoc, &nDone); mbufc += nSize; jargs[0] = mbuf; jargs[1] = mux_ltoa_t(i == 0 ? nFirstWidth : nWidth); safe_str(pLeft,buff,bufc); centerjustcombo(iJustKey, buff, bufc, jargs, 2); safe_str(pRight, buff, bufc); i += nLength; if (str[i] == ' ' && str[i+1] != ' ') { i++; } } free_lbuf(mbuf); free_lbuf(str); free_lbuf(tstr); } typedef struct { int iBase; char chLetter; int nName; const char *pName; } RADIX_ENTRY; #define N_RADIX_ENTRIES 7 static const RADIX_ENTRY reTable[N_RADIX_ENTRIES] = { { 31556926, 'y', 4, "year" }, // Average solar year. { 2629743, 'M', 5, "month" }, // Average month. { 604800, 'w', 4, "week" }, // 7 days. { 86400, 'd', 3, "day" }, { 3600, 'h', 4, "hour" }, { 60, 'm', 6, "minute" }, { 1, 's', 6, "second" } }; #define IYEARS 0 #define IMONTHS 1 #define IWEEKS 2 #define IDAYS 3 #define IHOURS 4 #define IMINUTES 5 #define ISECONDS 6 // This routine supports most of the time formats using the above // table. // static void GeneralTimeConversion ( char *Buffer, long Seconds, int iStartBase, int iEndBase, bool bSingleTerm, bool bNames ) { if (Seconds < 0) { Seconds = 0; } char *p = Buffer; int iValue; if ( iStartBase < 0 || N_RADIX_ENTRIES <= iStartBase || iEndBase < 0 || N_RADIX_ENTRIES <= iEndBase) { *p++ = '\0'; return; } for (int i = iStartBase; i <= iEndBase; i++) { if (reTable[i].iBase <= Seconds || i == iEndBase) { // Division and remainder. // iValue = Seconds/reTable[i].iBase; Seconds -= iValue * reTable[i].iBase; if (iValue != 0 || i == iEndBase) { if (p != Buffer) { *p++ = ' '; } p += mux_ltoa(iValue, p); if (bNames) { // Use the names with the correct pluralization. // *p++ = ' '; memcpy(p, reTable[i].pName, reTable[i].nName); p += reTable[i].nName; if (iValue != 1) { // More than one or zero. // *p++ = 's'; } } else { *p++ = reTable[i].chLetter; } } if (bSingleTerm) { break; } } } *p++ = '\0'; } // These buffers are used by: // // digit_format (23 bytes) uses TimeBuffer80, // time_format_1 (12 bytes) uses TimeBuffer80, // time_format_2 (17 bytes) uses TimeBuffer64, // expand_time (33 bytes) uses TimeBuffer64, // write_time (69 bytes) uses TimeBuffer80. // // time_format_1 and time_format_2 are called from within the same // printf, so they must use different buffers. // // We pick 64 as a round number. // static char TimeBuffer64[64]; static char TimeBuffer80[80]; // Show time in days, hours, and minutes // // 2^63/86400 is 1.07E14 which is at most 15 digits. // '(15)d (2):(2)\0' is at most 23 characters. // static const char *digit_format(int Seconds) { if (Seconds < 0) { Seconds = 0; } // We are showing the time in minutes. 59s --> 0m // // Divide the time down into days, hours, and minutes. // int Days = Seconds / 86400; Seconds -= Days * 86400; int Hours = Seconds / 3600; Seconds -= Hours * 3600; int Minutes = Seconds / 60; if (Days > 0) { mux_sprintf(TimeBuffer80, sizeof(TimeBuffer80), "%dd %02d:%02d", Days, Hours, Minutes); } else { mux_sprintf(TimeBuffer80, sizeof(TimeBuffer80), "%02d:%02d", Hours, Minutes); } return TimeBuffer80; } // Show time in one of the following formats limited by a width of 8, 9, 10, // or 11 places and depending on the value to display: // // Width:8 // Z9:99 0 to 86,399 // 9d 99:99 86,400 to 863,999 // ZZ9d 99h 864,000 to 86,396,459 // ZZZ9w 9d 86,396,460 to 6,047,913,659 // // Width:9 // Z9:99 0 to 86,399 // Z9d 99:99 86,400 to 8,639,999 // ZZZ9d 99h 8,640,000 to 863,996,459 // ZZZ9w 9d 863,996,460 to 6,047,913,659 // // Width:10 // Z9:99 0 to 86,399 // ZZ9d 99:99 86,400 to 86,399,999 // ZZZZ9d 99h 86,400,000 to 8,639,996,459 // // Width:11 // Z9:99 0 to 86,399 // ZZZ9d 99:99 86,400 to 863,999,999 // ZZZZZ9d 99h 864,000,000 to 86,399,996,459 // static int tf1_width_table[4][3] = { { 86399, 863999, 86396459, }, { 86399, 8639999, 863996459, }, { 86399, 86399999, INT_MAX, }, { 86399, 863999999, INT_MAX, } }; static struct { const char *specs[4]; int div[3]; } tf1_case_table[4] = { { { " %2d:%02d", " %2d:%02d", " %2d:%02d", " %2d:%02d" }, { 3600, 60, 1 } }, { { "%dd %02d:%02d", "%2dd %02d:%02d", "%3dd %02d:%02d", "%4dd %02d:%02d" }, { 86400, 3600, 60 } }, { { "%3dd %02dh", "%4dd %02dh", "%5dd %02dh", "%6dd %02dh" }, { 86400, 3600, 1 } }, { { "%4dw %d", "%4dw %d", "", "" }, { 604800, 86400, 1 } } }; const char *time_format_1(int Seconds, size_t maxWidth) { if (Seconds < 0) { Seconds = 0; } if ( maxWidth < 8 || 12 < maxWidth) { mux_strncpy(TimeBuffer80, "???", sizeof(TimeBuffer80)-1); return TimeBuffer80; } size_t iWidth = maxWidth - 8; int iCase = 0; while ( iCase < 3 && tf1_width_table[iWidth][iCase] < Seconds) { iCase++; } int i, n[3]; for (i = 0; i < 3; i++) { n[i] = Seconds / tf1_case_table[iCase].div[i]; Seconds -= n[i] *tf1_case_table[iCase].div[i]; } mux_sprintf(TimeBuffer80, sizeof(TimeBuffer80), tf1_case_table[iCase].specs[iWidth], n[0], n[1], n[2]); return TimeBuffer80; } // Show time in days, hours, minutes, or seconds. // const char *time_format_2(int Seconds) { // 2^63/86400 is 1.07E14 which is at most 15 digits. // '(15)d\0' is at most 17 characters. // GeneralTimeConversion(TimeBuffer64, Seconds, IYEARS, ISECONDS, true, false); return TimeBuffer64; } // Del's added functions for dooferMUX ! :) // D.Piper (del@doofer.org) 1997 & 2000 // // expand_time - Written (short) time format. // static const char *expand_time(int Seconds) { // 2^63/2592000 is 3558399705577 which is at most 13 digits. // '(13)M (1)w (1)d (2)h (2)m (2)s\0' is at most 33 characters. // GeneralTimeConversion(TimeBuffer64, Seconds, IMONTHS, ISECONDS, false, false); return TimeBuffer64; } // write_time - Written (long) time format. // static const char *write_time(int Seconds) { // 2^63/2592000 is 3558399705577 which is at most 13 digits. // '(13) months (1) weeks (1) days (2) hours (2) minutes (2) seconds\0' is // at most 69 characters. // GeneralTimeConversion(TimeBuffer80, Seconds, IMONTHS, ISECONDS, false, true); return TimeBuffer80; } // digittime - Digital format time ([(days)d]HH:MM) from given // seconds. D.Piper - May 1997 & April 2000 // static FUNCTION(fun_digittime) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int tt = mux_atol(fargs[0]); safe_str(digit_format(tt), buff, bufc); } // singletime - Single element time from given seconds. // D.Piper - May 1997 & April 2000 // static FUNCTION(fun_singletime) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int tt = mux_atol(fargs[0]); safe_str(time_format_2(tt), buff, bufc); } // exptime - Written (short) time from given seconds // D.Piper - May 1997 & April 2000 // static FUNCTION(fun_exptime) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int tt = mux_atol(fargs[0]); safe_str(expand_time(tt), buff, bufc); } // writetime - Written (long) time from given seconds // D.Piper - May 1997 & April 2000 // static FUNCTION(fun_writetime) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); int tt = mux_atol(fargs[0]); safe_str(write_time(tt), buff, bufc); } // cmds - Return player command count (Wizard_Who OR Self ONLY) // D.Piper - May 1997 // static FUNCTION(fun_cmds) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); long nCmds = -1; if (is_rational(fargs[0])) { SOCKET s = mux_atol(fargs[0]); bool bFound = false; DESC *d; DESC_ITER_CONN(d) { if (d->descriptor == s) { bFound = true; break; } } if ( bFound && ( d->player == executor || Wizard_Who(executor))) { nCmds = d->command_count; } } else { dbref target = lookup_player(executor, fargs[0], true); if ( Good_obj(target) && Connected(target) && ( Wizard_Who(executor) || Controls(executor, target))) { nCmds = fetch_cmds(target); } } safe_ltoa(nCmds, buff, bufc); } // startsecs - Time the MUX was started, in seconds // D.Piper - May 1997 & April 2000 // static FUNCTION(fun_startsecs) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(fargs); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); CLinearTimeAbsolute lta; lta = mudstate.start_time; lta.Local2UTC(); safe_str(lta.ReturnSecondsString(), buff, bufc); } // conntotal - Return player's total online time to the MUX // (including their current connection). D.Piper - May 1997 // static FUNCTION(fun_conntotal) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref target = lookup_player(executor, fargs[0], true); if (Good_obj(target)) { long TotalTime = fetch_totaltime(target); if (Connected(target)) { TotalTime += fetch_connect(target); } safe_ltoa(TotalTime, buff, bufc); } else { safe_str("#-1 PLAYER NOT FOUND", buff, bufc); } } // connmax - Return player's longest session to the MUX // (including the current one). D.Piper - May 1997 // static FUNCTION(fun_connmax) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref target = lookup_player(executor, fargs[0], true); if (Good_obj(target)) { long Longest = fetch_longestconnect(target); long Current = fetch_connect(target); if (Longest < Current) { Longest = Current; } safe_ltoa(Longest, buff, bufc); } else { safe_str("#-1 PLAYER NOT FOUND", buff, bufc); } } // connlast - Return player's last connection time to the MUX // D.Piper - May 1997 // static FUNCTION(fun_connlast) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref target = lookup_player(executor, fargs[0], true); if (Good_obj(target)) { safe_ltoa(fetch_lastconnect(target), buff, bufc); } else { safe_str("#-1 PLAYER NOT FOUND", buff, bufc); } } // connnum - Return the total number of sessions this player has had // to the MUX (including any current ones). D.Piper - May 1997 // static FUNCTION(fun_connnum) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref target = lookup_player(executor, fargs[0], true); if (Good_obj(target)) { long NumConnections = fetch_numconnections(target); if (Connected(target)) { NumConnections += fetch_session(target); } safe_ltoa(NumConnections, buff, bufc); } else { safe_str("#-1 PLAYER NOT FOUND", buff, bufc); } } // connleft - Return when a player last logged off the MUX as // UTC seconds. D.Piper - May 1997 // static FUNCTION(fun_connleft) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref target = lookup_player(executor, fargs[0], true); if (Good_obj(target)) { CLinearTimeAbsolute cl = fetch_logouttime(target); safe_str(cl.ReturnSecondsString(7), buff, bufc); } else { safe_str("#-1 PLAYER NOT FOUND", buff, bufc); } } // lattrcmds - Output a list of all attributes containing $ commands. // Altered from lattr(). D.Piper - May 1997 & April 2000 // static FUNCTION(fun_lattrcmds) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); // Check for wildcard matching. parse_attrib_wild checks for read // permission, so we don't have to. Have p_a_w assume the // slash-star if it is missing. // olist_push(); dbref thing; if (parse_attrib_wild(executor, fargs[0], &thing, false, false, true)) { bool isFirst = true; char *buf = alloc_lbuf("fun_lattrcmds"); for (int ca = olist_first(); ca != NOTHING; ca = olist_next()) { ATTR *pattr = atr_num(ca); if (pattr) { dbref aowner; int aflags; atr_get_str(buf, thing, pattr->number, &aowner, &aflags); if (buf[0] == '$') { if (!isFirst) { safe_chr(' ', buff, bufc); } isFirst = false; safe_str(pattr->name, buff, bufc); } } } free_lbuf(buf); } else { safe_nomatch(buff, bufc); } olist_pop(); } // lcmds - Output a list of all $ commands on an object. // Altered from MUX lattr(). D.Piper - May 1997 & April 2000 // Modified to handle spaced commands and ^-listens - July 2001 (Ash) // Applied patch and code reviewed - February 2002 (Stephen) // static FUNCTION(fun_lcmds) { SEP sep; if (!OPTIONAL_DELIM(2, sep, DELIM_NULL|DELIM_CRLF|DELIM_STRING)) { return; } // Check to see what type of command matching we will do. '$' commands // or '^' listens. We default with '$' commands. // char cmd_type = '$'; if ( nfargs == 3 && ( *fargs[2] == '$' || *fargs[2] == '^')) { cmd_type = *fargs[2]; } // Check for wildcard matching. parse_attrib_wild checks for read // permission, so we don't have to. Have p_a_w assume the // slash-star if it is missing. // olist_push(); dbref thing; if (parse_attrib_wild(executor, fargs[0], &thing, false, false, true)) { bool isFirst = true; char *buf = alloc_lbuf("fun_lattrcmds"); dbref aowner; int aflags; for (int ca = olist_first(); ca != NOTHING; ca = olist_next()) { ATTR *pattr = atr_num(ca); if (pattr) { atr_get_str(buf, thing, pattr->number, &aowner, &aflags); if (buf[0] == cmd_type) { bool isFound = false; char *c_ptr = buf+1; // If there is no characters between the '$' or '^' and the // ':' it's not a valid command, so skip it. // if (*c_ptr != ':') { int isEscaped = false; while (*c_ptr && !isFound) { // We need to check if the ':' in the command is // escaped. // if (*c_ptr == '\\') { isEscaped = !isEscaped; } else if (*c_ptr == ':' && !isEscaped) { isFound = true; *c_ptr = '\0'; } else if (*c_ptr != '\\' && isEscaped) { isEscaped = false; } c_ptr++; } } // We don't want to bother printing out the $command // if it doesn't have a matching ':'. It isn't a valid // command then. // if (isFound) { if (!isFirst) { print_sep(&sep, buff, bufc); } mux_strlwr(buf); safe_str(buf+1, buff, bufc); isFirst = false; } } } } free_lbuf(buf); } else { safe_nomatch(buff, bufc); } olist_pop(); } // lflags - List flags as names - (modified from 'flag_description()' and // MUX flags(). D.Piper - May 1997 & May 2000 // static FUNCTION(fun_lflags) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); dbref target; ATTR *pattr; if (parse_attrib(executor, fargs[0], &target, &pattr)) { if ( pattr && See_attr(executor, target, pattr)) { dbref aowner; int aflags; atr_pget_info(target, pattr->number, &aowner, &aflags); decode_attr_flag_names(aflags, buff, bufc); } } else { target = match_thing_quiet(executor, fargs[0]); if (!Good_obj(target)) { safe_match_result(target, buff, bufc); return; } bool bFirst = true; if ( mudconf.pub_flags || Examinable(executor, target)) { FLAGNAMEENT *fp; for (fp = gen_flag_names; fp->flagname; fp++) { if (!fp->bPositive) { continue; } FLAGBITENT *fbe = fp->fbe; if (db[target].fs.word[fbe->flagflag] & fbe->flagvalue) { if ( ( (fbe->listperm & CA_STAFF) && !Staff(executor)) || ( (fbe->listperm & CA_ADMIN) && !WizRoy(executor)) || ( (fbe->listperm & CA_WIZARD) && !Wizard(executor)) || ( (fbe->listperm & CA_GOD) && !God(executor))) { continue; } if ( isPlayer(target) && (fbe->flagvalue == CONNECTED) && (fbe->flagflag == FLAG_WORD2) && Hidden(target) && !See_Hidden(executor)) { continue; } if (!bFirst) { safe_chr(' ', buff, bufc); } bFirst = false; safe_str(fp->flagname, buff, bufc); } } } else { safe_noperm(buff, bufc); } } } // --------------------------------------------------------------------------- // fun_art: // // Accepts a single argument. Based on the rules specified in the config // parameters article_regexp and article_exception it determines whether the // word should use 'an' or 'a' as its article. // // By default if a word matches the regexp specified in article_regexp then // this function will return 'an', otherwise it will return 'a'. If, however // the word also matches one of the specified article_exception regexp's // will return the given article. // static FUNCTION(fun_art) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); const int ovecsize = 33; int ovec[ovecsize]; // Drop the input string into lower case. // mux_strlwr(fargs[0]); // Search for exceptions. // ArtRuleset *arRule = mudconf.art_rules; while (arRule != NULL) { pcre* reRuleRegexp = (pcre *) arRule->m_pRegexp; pcre_extra* reRuleStudy = (pcre_extra *) arRule->m_pRegexpStudy; if ( !MuxAlarm.bAlarmed && pcre_exec(reRuleRegexp, reRuleStudy, fargs[0], static_cast(strlen(fargs[0])), 0, 0, ovec, ovecsize) > 0) { safe_str(arRule->m_bUseAn ? "an" : "a", buff, bufc); return; } arRule = arRule->m_pNextRule; } // Default to 'a'. // safe_str( "a", buff, bufc); } // --------------------------------------------------------------------------- // fun_ord: // // Takes a single character and returns the corresponding ordinal of its // position in the character set. // static FUNCTION(fun_ord) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); size_t n; char *p = strip_ansi(fargs[0], &n); if (n == 1) { unsigned char ch = p[0]; safe_ltoa(ch, buff, bufc); } else { safe_str("#-1 FUNCTION EXPECTS ONE CHARACTER", buff, bufc); } } // --------------------------------------------------------------------------- // fun_chr: // // Takes an integer and returns the corresponding character from the character // set. // static FUNCTION(fun_chr) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); if (!is_integer(fargs[0], NULL)) { safe_str("#-1 ARGUMENT MUST BE A NUMBER", buff, bufc); return; } int ch = mux_atol(fargs[0]); if ( ch < 0 || (int) UCHAR_MAX < ch) { safe_str("#-1 THIS ISN'T UNICODE", buff, bufc); } else if (mux_isprint(ch)) { safe_chr(ch, buff, bufc); } else { safe_str("#-1 UNPRINTABLE CHARACTER", buff, bufc); } } // --------------------------------------------------------------------------- // fun_stripaccents: // static FUNCTION(fun_stripaccents) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); size_t nLen; char *p = strip_accents(fargs[0], &nLen); safe_copy_buf(p, nLen, buff, bufc); } // Base Letter: AaCcEeIiNnOoUuYy?!<>sPpD // static const unsigned char AccentCombo1[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0,18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,19, 0,20,17, // 3 0, 1, 0, 3,24, 5, 0, 0, 0, 7, 0, 0, 0, 0, 9,11, // 4 22, 0, 0, 0, 0,13, 0, 0, 0,15, 0, 0, 0, 0, 0, 0, // 5 0, 2, 0, 4, 0, 6, 0, 0, 0, 8, 0, 0, 0, 0,10,12, // 6 23, 0, 0,21, 0,14, 0, 0, 0,16, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; // Accent: `'^~:o,u"B|-&Ee // static const unsigned char AccentCombo2[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 0, 0, 9, 0, 0, 0,13, 2, 0, 0, 0, 0, 7,12, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, // 3 0, 0,10, 0, 0,14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, // 5 1, 0, 0, 0, 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, // 6 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,11, 0, 4, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; static const unsigned char AccentCombo3[24][16] = { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // ` ' ^ ~ : o , u " B | - & E e // { 0x00, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00 }, // 1 'A' { 0x00, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6 }, // 2 'a' { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 3 'C' { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 4 'c' { 0x00, 0xC8, 0xC9, 0xCA, 0x00, 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 5 'E' { 0x00, 0xE8, 0xE9, 0xEA, 0x00, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 6 'e' { 0x00, 0xCC, 0xCD, 0xCE, 0x00, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 7 'I' { 0x00, 0xEC, 0xED, 0xEE, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 8 'i' { 0x00, 0x00, 0x00, 0x00, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 9 'N' { 0x00, 0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 10 'n' { 0x00, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 11 'O' { 0x00, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00 }, // 12 'o' { 0x00, 0xD9, 0xDA, 0xDB, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 13 'U' { 0x00, 0xF9, 0xFA, 0xFB, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 14 'u' { 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 15 'Y' { 0x00, 0x00, 0xFD, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 16 'y' { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 17 '?' { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 18 '!' { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 19 '<' { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 20 '>' { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 21 's' { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0x00, 0x00, 0x00, 0x00 }, // 22 'P' { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00 }, // 23 'p' { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00 } // 24 'D' }; // --------------------------------------------------------------------------- // fun_accent: // static FUNCTION(fun_accent) { UNUSED_PARAMETER(executor); UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(nfargs); UNUSED_PARAMETER(cargs); UNUSED_PARAMETER(ncargs); size_t n = strlen(fargs[0]); if (n != strlen(fargs[1])) { safe_str("#-1 STRING LENGTHS MUST BE EQUAL", buff, bufc); return; } const unsigned char *p = (unsigned char *)fargs[0]; const unsigned char *q = (unsigned char *)fargs[1]; while (*p) { unsigned char ch = '\0'; unsigned char ch0 = AccentCombo1[(unsigned char)*p]; if (0 < ch0) { unsigned char ch1 = AccentCombo2[(unsigned char)*q]; if (0 < ch1) { ch = AccentCombo3[ch0-1][ch1]; } } if (!mux_isprint(ch)) { ch = *p; } safe_chr(ch, buff, bufc); p++; q++; } } // ---------------------------------------------------------------------------- // flist: List of existing functions in alphabetical order. // // Name Handler # of args min # max # flags permissions // to parse of args of args // static FUN builtin_function_list[] = { {"@@", fun_null, 1, 1, 1, FN_NOEVAL, CA_PUBLIC}, {"ABS", fun_abs, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ACCENT", fun_accent, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"ACOS", fun_acos, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"ADD", fun_add, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"AFTER", fun_after, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"ALPHAMAX", fun_alphamax, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"ALPHAMIN", fun_alphamin, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"AND", fun_and, MAX_ARG, 0, MAX_ARG, 0, CA_PUBLIC}, {"ANDBOOL", fun_andbool, MAX_ARG, 0, MAX_ARG, 0, CA_PUBLIC}, {"ANDFLAGS", fun_andflags, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"ANSI", fun_ansi, MAX_ARG, 2, MAX_ARG, 0, CA_PUBLIC}, {"APOSS", fun_aposs, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ART", fun_art, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ASIN", fun_asin, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"ATAN", fun_atan, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"ATTRCNT", fun_attrcnt, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"BAND", fun_band, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"BEEP", fun_beep, MAX_ARG, 0, 0, 0, CA_WIZARD}, {"BEFORE", fun_before, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"BITTYPE", fun_bittype, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"BNAND", fun_bnand, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"BOR", fun_bor, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"BXOR", fun_bxor, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"CAND", fun_cand, MAX_ARG, 0, MAX_ARG, FN_NOEVAL, CA_PUBLIC}, {"CANDBOOL", fun_candbool, MAX_ARG, 0, MAX_ARG, FN_NOEVAL, CA_PUBLIC}, #if defined(WOD_REALMS) || defined(REALITY_LVLS) {"CANSEE", fun_cansee, MAX_ARG, 2, 3, 0, CA_PUBLIC}, #endif {"CAPSTR", fun_capstr, 1, 1, 1, 0, CA_PUBLIC}, {"CASE", fun_case, MAX_ARG, 2, MAX_ARG, FN_NOEVAL, CA_PUBLIC}, {"CAT", fun_cat, MAX_ARG, 0, MAX_ARG, 0, CA_PUBLIC}, {"CEIL", fun_ceil, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"CEMIT", fun_cemit, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"CENTER", fun_center, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"CHANNELS", fun_channels, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"CHILDREN", fun_children, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"CHOOSE", fun_choose, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"CHR", fun_chr, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"CMDS", fun_cmds, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"COLUMNS", fun_columns, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"COMALIAS", fun_comalias, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"COMP", fun_comp, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"COMTITLE", fun_comtitle, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"CON", fun_con, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"CONFIG", fun_config, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"CONN", fun_conn, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"CONNLAST", fun_connlast, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"CONNLEFT", fun_connleft, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"CONNMAX", fun_connmax, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"CONNNUM", fun_connnum, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"CONNRECORD", fun_connrecord, MAX_ARG, 0, 0, 0, CA_PUBLIC}, {"CONNTOTAL", fun_conntotal, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"CONTROLS", fun_controls, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"CONVSECS", fun_convsecs, MAX_ARG, 1, 3, 0, CA_PUBLIC}, {"CONVTIME", fun_convtime, MAX_ARG, 1, 3, 0, CA_PUBLIC}, {"COR", fun_cor, MAX_ARG, 0, MAX_ARG, FN_NOEVAL, CA_PUBLIC}, {"CORBOOL", fun_corbool, MAX_ARG, 0, MAX_ARG, FN_NOEVAL, CA_PUBLIC}, {"COS", fun_cos, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"CRC32", fun_crc32, MAX_ARG, 0, MAX_ARG, 0, CA_PUBLIC}, {"CREATE", fun_create, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"CTIME", fun_ctime, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"CTU", fun_ctu, MAX_ARG, 3, 3, 0, CA_PUBLIC}, {"CWHO", fun_cwho, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"DEC", fun_dec, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"DECRYPT", fun_decrypt, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"DEFAULT", fun_default, MAX_ARG, 2, 2, FN_NOEVAL, CA_PUBLIC}, {"DELETE", fun_delete, MAX_ARG, 3, 3, 0, CA_PUBLIC}, {"DIE", fun_die, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"DIGITTIME", fun_digittime, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"DIST2D", fun_dist2d, MAX_ARG, 4, 4, 0, CA_PUBLIC}, {"DIST3D", fun_dist3d, MAX_ARG, 6, 6, 0, CA_PUBLIC}, {"DISTRIBUTE", fun_distribute, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"DOING", fun_doing, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"DUMPING", fun_dumping, MAX_ARG, 0, 0, 0, CA_PUBLIC}, {"E", fun_e, MAX_ARG, 0, 0, 0, CA_PUBLIC}, {"EDEFAULT", fun_edefault, MAX_ARG, 2, 2, FN_NOEVAL, CA_PUBLIC}, {"EDIT", fun_edit, MAX_ARG, 3, 3, 0, CA_PUBLIC}, {"ELEMENTS", fun_elements, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"ELOCK", fun_elock, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"EMIT", fun_emit, MAX_ARG, 1, 1, 0, CA_PUBLIC}, #ifdef DEPRECATED {"EMPTY", fun_empty, MAX_ARG, 0, 1, 0, CA_PUBLIC}, #endif // DEPRECATED {"ENCRYPT", fun_encrypt, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"ENTRANCES", fun_entrances, MAX_ARG, 0, 4, 0, CA_PUBLIC}, {"EQ", fun_eq, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"ERROR", fun_error, 1, 0, 1, 0, CA_PUBLIC}, {"ESCAPE", fun_escape, 1, 1, 1, 0, CA_PUBLIC}, {"ETIMEFMT", fun_etimefmt, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"EVAL", fun_eval, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"EXIT", fun_exit, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"EXP", fun_exp, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"EXPTIME", fun_exptime, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"EXTRACT", fun_extract, MAX_ARG, 3, 5, 0, CA_PUBLIC}, {"FCOUNT", fun_fcount, MAX_ARG, 0, 1, FN_NOEVAL, CA_PUBLIC}, {"FDEPTH", fun_fdepth, MAX_ARG, 0, 0, 0, CA_PUBLIC}, {"FDIV", fun_fdiv, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"FILTER", fun_filter, MAX_ARG, 2, 13, 0, CA_PUBLIC}, {"FILTERBOOL", fun_filterbool, MAX_ARG, 2, 13, 0, CA_PUBLIC}, {"FINDABLE", fun_findable, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"FIRST", fun_first, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"FLAGS", fun_flags, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"FLOOR", fun_floor, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"FLOORDIV", fun_floordiv, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"FMOD", fun_fmod, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"FOLD", fun_fold, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"FOREACH", fun_foreach, MAX_ARG, 2, 4, 0, CA_PUBLIC}, #if defined(FIRANMUX) {"FORMAT", fun_format, MAX_ARG, 4, 4, 0, CA_PUBLIC}, #endif // FIRANMUX {"FULLNAME", fun_fullname, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"GET", fun_get, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"GET_EVAL", fun_get_eval, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"GRAB", fun_grab, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"GRABALL", fun_graball, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"GREP", fun_grep, MAX_ARG, 3, 3, 0, CA_PUBLIC}, {"GREPI", fun_grepi, MAX_ARG, 3, 3, 0, CA_PUBLIC}, {"GT", fun_gt, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"GTE", fun_gte, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"HASATTR", fun_hasattr, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"HASATTRP", fun_hasattrp, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"HASFLAG", fun_hasflag, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"HASPOWER", fun_haspower, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"HASQUOTA", fun_hasquota, MAX_ARG, 2, 3, 0, CA_PUBLIC}, #ifdef REALITY_LVLS {"HASRXLEVEL", fun_hasrxlevel, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"HASTXLEVEL", fun_hastxlevel, MAX_ARG, 2, 2, 0, CA_PUBLIC}, #endif // REALITY_LVLS {"HASTYPE", fun_hastype, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"HEIGHT", fun_height, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"HOME", fun_home, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"HOST", fun_host, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"IABS", fun_iabs, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"IADD", fun_iadd, MAX_ARG, 0, MAX_ARG, 0, CA_PUBLIC}, {"IDIV", fun_idiv, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"IDLE", fun_idle, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"IF", fun_ifelse, MAX_ARG, 2, 3, FN_NOEVAL, CA_PUBLIC}, {"IFELSE", fun_ifelse, MAX_ARG, 3, 3, FN_NOEVAL, CA_PUBLIC}, {"ILEV", fun_ilev, MAX_ARG, 0, 0, 0, CA_PUBLIC}, {"IMUL", fun_imul, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"INC", fun_inc, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"INDEX", fun_index, MAX_ARG, 4, 4, 0, CA_PUBLIC}, {"INSERT", fun_insert, MAX_ARG, 3, 4, 0, CA_PUBLIC}, {"INUM", fun_inum, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"INZONE", fun_inzone, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ISDBREF", fun_isdbref, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"ISIGN", fun_isign, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ISINT", fun_isint, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ISNUM", fun_isnum, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ISRAT", fun_israt, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ISUB", fun_isub, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"ISWORD", fun_isword, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ITEMIZE", fun_itemize, MAX_ARG, 1, 4, 0, CA_PUBLIC}, #ifdef DEPRECATED {"ITEMS", fun_items, MAX_ARG, 0, 1, 0, CA_PUBLIC}, #endif // DEPRECATED {"ITER", fun_iter, MAX_ARG, 2, 4, FN_NOEVAL, CA_PUBLIC}, {"ITEXT", fun_itext, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"LADD", fun_ladd, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"LAND", fun_land, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"LAST", fun_last, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"LATTR", fun_lattr, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"LATTRCMDS", fun_lattrcmds, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"LATTRP", fun_lattrp, MAX_ARG, 1, 1, 0, CA_PUBLIC}, #ifdef REALITY_LVLS {"LISTRLEVELS", fun_listrlevels, MAX_ARG, 0, 0, 0, CA_PUBLIC}, #endif {"LCMDS", fun_lcmds, MAX_ARG, 1, 3, 0, CA_PUBLIC}, {"LCON", fun_lcon, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"LCSTR", fun_lcstr, 1, 1, 1, 0, CA_PUBLIC}, {"LDELETE", fun_ldelete, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"LEXITS", fun_lexits, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"LFLAGS", fun_lflags, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"LINK", fun_link, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"LIST", fun_list, MAX_ARG, 2, 3, FN_NOEVAL, CA_PUBLIC}, {"LIT", fun_lit, 1, 1, 1, FN_NOEVAL, CA_PUBLIC}, {"LJUST", fun_ljust, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"LN", fun_ln, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"LNUM", fun_lnum, MAX_ARG, 0, 4, 0, CA_PUBLIC}, {"LOC", fun_loc, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"LOCALIZE", fun_localize, MAX_ARG, 1, 1, FN_NOEVAL, CA_PUBLIC}, {"LOCATE", fun_locate, MAX_ARG, 3, 3, 0, CA_PUBLIC}, {"LOCK", fun_lock, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"LOG", fun_log, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"LOR", fun_lor, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"LPARENT", fun_lparent, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"LPORTS", fun_lports, MAX_ARG, 0, 0, 0, CA_WIZARD}, {"LPOS", fun_lpos, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"LRAND", fun_lrand, MAX_ARG, 3, 4, 0, CA_PUBLIC}, {"LROOMS", fun_lrooms, MAX_ARG, 1, 3, 0, CA_PUBLIC}, #ifdef DEPRECATED {"LSTACK", fun_lstack, MAX_ARG, 0, 1, 0, CA_PUBLIC}, #endif // DEPRECATED {"LT", fun_lt, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"LTE", fun_lte, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"LWHO", fun_lwho, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"MAIL", fun_mail, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"MAILFROM", fun_mailfrom, MAX_ARG, 1, 2, 0, CA_PUBLIC}, #if defined(FIRANMUX) {"MAILJ", fun_mailj, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"MAILSIZE", fun_mailsize, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"MAILSUBJ", fun_mailsubj, MAX_ARG, 1, 2, 0, CA_PUBLIC}, #endif // FIRANMUX {"MAP", fun_map, MAX_ARG, 2, 13, 0, CA_PUBLIC}, {"MATCH", fun_match, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"MATCHALL", fun_matchall, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"MAX", fun_max, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"MEMBER", fun_member, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"MERGE", fun_merge, MAX_ARG, 3, 3, 0, CA_PUBLIC}, {"MID", fun_mid, MAX_ARG, 3, 3, 0, CA_PUBLIC}, {"MIN", fun_min, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"MIX", fun_mix, MAX_ARG, 2, 12, 0, CA_PUBLIC}, {"MOD", fun_mod, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"MONEY", fun_money, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"MONIKER", fun_moniker, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"MOTD", fun_motd, MAX_ARG, 0, 0, 0, CA_PUBLIC}, {"MTIME", fun_mtime, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"MUDNAME", fun_mudname, MAX_ARG, 0, 0, 0, CA_PUBLIC}, {"MUL", fun_mul, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"MUNGE", fun_munge, MAX_ARG, 3, 4, 0, CA_PUBLIC}, {"NAME", fun_name, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"NEARBY", fun_nearby, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"NEQ", fun_neq, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"NEXT", fun_next, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"NOT", fun_not, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"NULL", fun_null, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"NUM", fun_num, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"OBJ", fun_obj, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"OBJEVAL", fun_objeval, MAX_ARG, 2, 2, FN_NOEVAL, CA_PUBLIC}, {"OBJMEM", fun_objmem, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"OEMIT", fun_oemit, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"OR", fun_or, MAX_ARG, 0, MAX_ARG, 0, CA_PUBLIC}, {"ORBOOL", fun_orbool, MAX_ARG, 0, MAX_ARG, 0, CA_PUBLIC}, {"ORD", fun_ord, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ORFLAGS", fun_orflags, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"OWNER", fun_owner, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"PACK", fun_pack, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"PARENT", fun_parent, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"PARSE", fun_iter, MAX_ARG, 2, 4, FN_NOEVAL, CA_PUBLIC}, #ifdef DEPRECATED {"PEEK", fun_peek, MAX_ARG, 0, 2, 0, CA_PUBLIC}, #endif // DEPRECATED {"PEMIT", fun_pemit, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"PFIND", fun_pfind, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"PI", fun_pi, MAX_ARG, 0, 0, 0, CA_PUBLIC}, {"PICKRAND", fun_pickrand, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"PLAYMEM", fun_playmem, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"PMATCH", fun_pmatch, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"POLL", fun_poll, MAX_ARG, 0, 0, 0, CA_PUBLIC}, #ifdef DEPRECATED {"POP", fun_pop, MAX_ARG, 0, 2, 0, CA_PUBLIC}, #endif // DEPRECATED {"PORTS", fun_ports, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"POS", fun_pos, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"POSS", fun_poss, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"POWER", fun_power, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"POWERS", fun_powers, MAX_ARG, 1, 1, 0, CA_PUBLIC}, #ifdef DEPRECATED {"PUSH", fun_push, MAX_ARG, 1, 2, 0, CA_PUBLIC}, #endif // DEPRECATED {"R", fun_r, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"RAND", fun_rand, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"REGMATCH", fun_regmatch, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"REGMATCHI", fun_regmatchi, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"REGRAB", fun_regrab, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"REGRABALL", fun_regraball, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"REGRABALLI", fun_regraballi, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"REGRABI", fun_regrabi, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"REMAINDER", fun_remainder, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"REMIT", fun_remit, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"REMOVE", fun_remove, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"REPEAT", fun_repeat, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"REPLACE", fun_replace, MAX_ARG, 3, 4, 0, CA_PUBLIC}, {"REST", fun_rest, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"REVERSE", fun_reverse, 1, 1, 1, 0, CA_PUBLIC}, {"REVWORDS", fun_revwords, MAX_ARG, 0, MAX_ARG, 0, CA_PUBLIC}, {"RIGHT", fun_right, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"RJUST", fun_rjust, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"RLOC", fun_rloc, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"ROMAN", fun_roman, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ROOM", fun_room, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ROUND", fun_round, MAX_ARG, 2, 2, 0, CA_PUBLIC}, #ifdef REALITY_LVLS {"RXLEVEL", fun_rxlevel, MAX_ARG, 1, 1, 0, CA_PUBLIC}, #endif // REALITY_LVLS {"S", fun_s, 1, 1, 1, 0, CA_PUBLIC}, {"SCRAMBLE", fun_scramble, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"SEARCH", fun_search, 1, 0, 1, 0, CA_PUBLIC}, {"SECS", fun_secs, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"SECURE", fun_secure, 1, 1, 1, 0, CA_PUBLIC}, {"SET", fun_set, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"SETDIFF", fun_setdiff, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"SETINTER", fun_setinter, MAX_ARG, 2, 4, 0, CA_PUBLIC}, #if defined(FIRANMUX) {"SETPARENT", fun_setparent, MAX_ARG, 2, 2, 0, CA_PUBLIC}, #endif // FIRANMUX {"SETQ", fun_setq, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"SETR", fun_setr, MAX_ARG, 2, 2, 0, CA_PUBLIC}, #if defined(FIRANMUX) {"SETNAME", fun_setname, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"TRIGGER", fun_trigger, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, #endif // FIRANMUX {"SETUNION", fun_setunion, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"SHA1", fun_sha1, 1, 0, 1, 0, CA_PUBLIC}, {"SHL", fun_shl, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"SHR", fun_shr, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"SHUFFLE", fun_shuffle, MAX_ARG, 1, 3, 0, CA_PUBLIC}, {"SIGN", fun_sign, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"SIN", fun_sin, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"SINGLETIME", fun_singletime, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"SITEINFO", fun_siteinfo, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"SORT", fun_sort, MAX_ARG, 1, 4, 0, CA_PUBLIC}, {"SORTBY", fun_sortby, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"SPACE", fun_space, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"SPELLNUM", fun_spellnum, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"SPLICE", fun_splice, MAX_ARG, 3, 5, 0, CA_PUBLIC}, #if defined(FIRANMUX) {"SQL", fun_sql, MAX_ARG, 1, 3, 0, CA_WIZARD}, #endif // FIRANMUX {"SQRT", fun_sqrt, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"SQUISH", fun_squish, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"STARTSECS", fun_startsecs, MAX_ARG, 0, 0, 0, CA_PUBLIC}, {"STARTTIME", fun_starttime, MAX_ARG, 0, 0, 0, CA_PUBLIC}, {"STATS", fun_stats, MAX_ARG, 0, 1, 0, CA_PUBLIC}, {"STEP", fun_step, MAX_ARG, 3, 5, 0, CA_PUBLIC}, {"STRCAT", fun_strcat, MAX_ARG, 0, MAX_ARG, 0, CA_PUBLIC}, {"STRIP", fun_strip, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"STRIPACCENTS",fun_stripaccents, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"STRIPANSI", fun_stripansi, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"STRLEN", fun_strlen, 1, 0, 1, 0, CA_PUBLIC}, {"STRMATCH", fun_strmatch, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"STRMEM", fun_strmem, 1, 0, 1, 0, CA_PUBLIC}, {"STRTRUNC", fun_strtrunc, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"SUB", fun_sub, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"SUBEVAL", fun_subeval, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"SUBJ", fun_subj, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"SUCCESSES", fun_successes, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"SWITCH", fun_switch, MAX_ARG, 2, MAX_ARG, FN_NOEVAL, CA_PUBLIC}, {"T", fun_t, 1, 0, 1, 0, CA_PUBLIC}, {"TABLE", fun_table, MAX_ARG, 1, 6, 0, CA_PUBLIC}, {"TAN", fun_tan, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"TEL", fun_tel, MAX_ARG, 2, 2, 0, CA_PUBLIC}, #if defined(FIRANMUX) {"TEXT", fun_text, MAX_ARG, 2, 2, 0, CA_PUBLIC}, #endif // FIRANMUX {"TEXTFILE", fun_textfile, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"TIME", fun_time, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"TIMEFMT", fun_timefmt, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"TRANSLATE", fun_translate, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"TRIM", fun_trim, MAX_ARG, 1, 3, 0, CA_PUBLIC}, {"TRUNC", fun_trunc, MAX_ARG, 1, 1, 0, CA_PUBLIC}, #ifdef REALITY_LVLS {"TXLEVEL", fun_txlevel, MAX_ARG, 1, 1, 0, CA_PUBLIC}, #endif // REALITY_LVLS {"TYPE", fun_type, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"U", fun_u, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"UCSTR", fun_ucstr, 1, 1, 1, 0, CA_PUBLIC}, {"UDEFAULT", fun_udefault, MAX_ARG, 2, MAX_ARG, FN_NOEVAL, CA_PUBLIC}, {"ULOCAL", fun_ulocal, MAX_ARG, 1, MAX_ARG, 0, CA_PUBLIC}, {"UNPACK", fun_unpack, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"V", fun_v, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"VADD", fun_vadd, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"VALID", fun_valid, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"VCROSS", fun_vcross, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"VDIM", fun_words, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"VDOT", fun_vdot, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"VERSION", fun_version, MAX_ARG, 0, 0, 0, CA_PUBLIC}, {"VISIBLE", fun_visible, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"VMAG", fun_vmag, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"VMUL", fun_vmul, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"VSUB", fun_vsub, MAX_ARG, 2, 4, 0, CA_PUBLIC}, {"VUNIT", fun_vunit, MAX_ARG, 1, 2, 0, CA_PUBLIC}, {"WHERE", fun_where, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"WIDTH", fun_width, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"WORDPOS", fun_wordpos, MAX_ARG, 2, 3, 0, CA_PUBLIC}, {"WORDS", fun_words, MAX_ARG, 0, 2, 0, CA_PUBLIC}, {"WRAP", fun_wrap, MAX_ARG, 1, 8, 0, CA_PUBLIC}, {"WRITETIME", fun_writetime, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"XGET", fun_xget, MAX_ARG, 2, 2, 0, CA_PUBLIC}, {"XOR", fun_xor, MAX_ARG, 0, MAX_ARG, 0, CA_PUBLIC}, {"ZFUN", fun_zfun, MAX_ARG, 2, 11, 0, CA_PUBLIC}, {"ZONE", fun_zone, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {"ZWHO", fun_zwho, MAX_ARG, 1, 1, 0, CA_PUBLIC}, {NULL, NULL, MAX_ARG, 0, 0, 0, 0} }; void function_add(FUN *fp) { char *buff = alloc_sbuf("init_functab"); char *bp = buff; safe_sb_str(fp->name, buff, &bp); *bp = '\0'; mux_strlwr(buff); hashaddLEN(buff, strlen(buff), fp, &mudstate.func_htab); free_sbuf(buff); } void functions_add(FUN funlist[]) { char *buff = alloc_sbuf("init_functab"); for (FUN *fp = funlist; fp->name; fp++) { char *bp = buff; safe_sb_str(fp->name, buff, &bp); *bp = '\0'; mux_strlwr(buff); hashaddLEN(buff, strlen(buff), fp, &mudstate.func_htab); } free_sbuf(buff); } void init_functab(void) { functions_add(builtin_function_list); ufun_head = NULL; } void do_function ( dbref executor, dbref caller, dbref enactor, int key, int nargs, char *fname, char *target ) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(nargs); UFUN *ufp, *ufp2; ATTR *ap; if ((key & FN_LIST) || !fname || *fname == '\0') { notify(executor, tprintf("%-28s %-8s %-30s Flgs", "Function Name", "DBref#", "Attribute")); notify(executor, tprintf("%28s %8s %30s %4s", "----------------------------", "--------", "------------------------------", " -- ")); int count = 0; for (ufp2 = ufun_head; ufp2; ufp2 = ufp2->next) { const char *pName = "(WARNING: Bad Attribute Number)"; ap = atr_num(ufp2->atr); if (ap) { pName = ap->name; } notify(executor, tprintf("%-28.28s #%-7d %-30.30s %c%c", ufp2->name, ufp2->obj, pName, ((ufp2->flags & FN_PRIV) ? 'W' : '-'), ((ufp2->flags & FN_PRES) ? 'p' : '-'))); count++; } notify(executor, tprintf("%28s %8s %30s %4s", "----------------------------", "--------", "------------------------------", " -- ")); notify(executor, tprintf("Total User-Defined Functions: %d", count)); return; } char *np, *bp; ATTR *pattr; dbref obj; // Make a local uppercase copy of the function name. // bp = np = alloc_sbuf("add_user_func"); safe_sb_str(fname, np, &bp); *bp = '\0'; mux_strlwr(np); // Verify that the function doesn't exist in the builtin table. // if (hashfindLEN(np, strlen(np), &mudstate.func_htab) != NULL) { notify_quiet(executor, "Function already defined in builtin function table."); free_sbuf(np); return; } // Make sure the target object exists. // if (!parse_attrib(executor, target, &obj, &pattr)) { notify_quiet(executor, NOMATCH_MESSAGE); free_sbuf(np); return; } // Make sure the attribute exists. // if (!pattr) { notify_quiet(executor, "No such attribute."); free_sbuf(np); return; } // Make sure attribute is readably by me. // if (!See_attr(executor, obj, pattr)) { notify_quiet(executor, NOPERM_MESSAGE); free_sbuf(np); return; } // Privileged functions require you control the obj. // if ((key & FN_PRIV) && !Controls(executor, obj)) { notify_quiet(executor, NOPERM_MESSAGE); free_sbuf(np); return; } // See if function already exists. If so, redefine it. // ufp = (UFUN *) hashfindLEN(np, strlen(np), &mudstate.ufunc_htab); if (!ufp) { ufp = NULL; try { ufp = new UFUN; } catch (...) { ; // Nothing. } if (NULL == ufp) { free_sbuf(np); return; } ufp->name = StringClone(np); mux_strupr(ufp->name); ufp->obj = obj; ufp->atr = pattr->number; ufp->perms = CA_PUBLIC; ufp->next = NULL; if (!ufun_head) { ufun_head = ufp; } else { for (ufp2 = ufun_head; ufp2->next; ufp2 = ufp2->next) { // Nothing ; } ufp2->next = ufp; } hashaddLEN(np, strlen(np), ufp, &mudstate.ufunc_htab); } ufp->obj = obj; ufp->atr = pattr->number; ufp->flags = key; free_sbuf(np); if (!Quiet(executor)) { notify_quiet(executor, tprintf("Function %s defined.", fname)); } } // --------------------------------------------------------------------------- // list_functable: List available functions. // void list_functable(dbref player) { char *buff = alloc_lbuf("list_functable"); char *bp = buff; safe_str("Functions:", buff, &bp); FUN *fp; for (fp = builtin_function_list; fp->name && bp < buff + (LBUF_SIZE-1); fp++) { if (check_access(player, fp->perms)) { safe_chr(' ', buff, &bp); safe_str(fp->name, buff, &bp); } } *bp = '\0'; notify(player, buff); bp = buff; safe_str("User-Functions:", buff, &bp); UFUN *ufp; for (ufp = ufun_head; ufp && bp < buff + (LBUF_SIZE-1); ufp = ufp->next) { if (check_access(player, ufp->perms)) { safe_chr(' ', buff, &bp); safe_str(ufp->name, buff, &bp); } } *bp = '\0'; notify(player, buff); free_lbuf(buff); } /* --------------------------------------------------------------------------- * cf_func_access: set access on functions */ CF_HAND(cf_func_access) { UNUSED_PARAMETER(vp); char *ap; for (ap = str; *ap && !mux_isspace(*ap); ap++) { *ap = mux_tolower(*ap); // Nothing. } size_t nstr = ap - str; if (*ap) { *ap++ = '\0'; } FUN *fp = (FUN *)hashfindLEN(str, nstr, &mudstate.func_htab); if (fp) { return cf_modify_bits(&fp->perms, ap, pExtra, nExtra, player, cmd); } UFUN *ufp = (UFUN *)hashfindLEN(str, nstr, &mudstate.ufunc_htab); if (ufp) { return cf_modify_bits(&ufp->perms, ap, pExtra, nExtra, player, cmd); } cf_log_notfound(player, cmd, "Function", str); return -1; } mux2.6/src/slave.cpp0000600000175000017500000001655711025753746014432 0ustar sdennissdennis// slave.cpp -- This slave does iptoname conversions, and identquery lookups. // // $Id: slave.cpp 8 2006-09-05 01:55:58Z brazilofmux $ // // The philosophy is to keep this program as simple/small as possible. It // routinely performs non-vfork forks()s, so the conventional wisdom is that // the smaller it is, the faster it goes. However, with modern memory // management support (including copy on reference paging), size is probably // not the issue it once was. // #include "autoconf.h" #include "config.h" #include #include #include #include #include #include #include "slave.h" #include #ifdef _SGI_SOURCE #define CAST_SIGNAL_FUNC (SIG_PF) #else #define CAST_SIGNAL_FUNC #endif pid_t parent_pid; #define MAX_STRING 1000 char *arg_for_errors; #ifndef INADDR_NONE #define INADDR_NONE ((in_addr_t)-1) #endif char *format_inet_addr(char *dest, long addr) { sprintf(dest, "%ld.%ld.%ld.%ld", (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, (addr & 0x0000FF00) >> 8, (addr & 0x000000FF)); return (dest + strlen(dest)); } // // copy a string, returning pointer to the null terminator of dest // char *stpcpy(char *dest, const char *src) { while ((*dest = *src)) { ++dest; ++src; } return (dest); } RETSIGTYPE child_timeout_signal(int iSig) { exit(1); } int query(char *ip, char *orig_arg) { char *comma; char *port_pair; struct hostent *hp; struct sockaddr_in sin; int s; FILE *f; char result[MAX_STRING]; char buf[MAX_STRING * 2]; char buf2[MAX_STRING * 2]; char buf3[MAX_STRING * 4]; char arg[MAX_STRING]; size_t len; char *p; in_addr_t addr; addr = inet_addr(ip); if (addr == INADDR_NONE) { return -1; } const char *pHName = ip; hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); if ( hp && strlen(hp->h_name) < MAX_STRING) { pHName = hp->h_name; } p = stpcpy(buf, ip); *p++ = ' '; p = stpcpy(p, pHName); *p++ = '\n'; *p++ = '\0'; arg_for_errors = orig_arg; strcpy(arg, orig_arg); comma = (char *)strrchr(arg, ','); if (comma == NULL) { return -1; } *comma = 0; port_pair = (char *)strrchr(arg, ','); if (port_pair == NULL) { return -1; } *port_pair++ = 0; *comma = ','; hp = gethostbyname(arg); if (hp == NULL) { static struct hostent def; static struct in_addr defaddr; static char *alist[1]; static char namebuf[MAX_STRING]; defaddr.s_addr = inet_addr(arg); if (defaddr.s_addr == INADDR_NONE) { return -1; } strcpy(namebuf, arg); def.h_name = namebuf; def.h_addr_list = alist; def.h_addr = (char *)&defaddr; def.h_length = sizeof(struct in_addr); def.h_addrtype = AF_INET; def.h_aliases = 0; hp = &def; } sin.sin_family = hp->h_addrtype; bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); sin.sin_port = htons(113); // ident port s = socket(hp->h_addrtype, SOCK_STREAM, 0); if (s < 0) { return -1; } if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { if ( errno != ECONNREFUSED && errno != ETIMEDOUT && errno != ENETUNREACH && errno != EHOSTUNREACH) { close(s); return -1; } buf2[0] = '\0'; } else { len = strlen(port_pair); if ((size_t)write(s, port_pair, len) != len) { close(s); return (-1); } if (write(s, "\r\n", 2) != 2) { close(s); return (-1); } f = fdopen(s, "r"); { int c; p = result; while ((c = fgetc(f)) != EOF) { if (c == '\n') { break; } if (0x20 <= c && c <= 0x7E) { *p++ = c; if (p - result == MAX_STRING - 1) { break; } } } *p = '\0'; } fclose(f); p = (char *)format_inet_addr(buf2, ntohl(sin.sin_addr.s_addr)); *p++ = ' '; p = stpcpy(p, result); *p++ = '\n'; *p++ = '\0'; } sprintf(buf3, "%s%s", buf, buf2); write(1, buf3, strlen(buf3)); return 0; } RETSIGTYPE alarm_signal(int iSig) { struct itimerval itime; struct timeval interval; if (getppid() != parent_pid) { exit(1); } signal(SIGALRM, CAST_SIGNAL_FUNC alarm_signal); interval.tv_sec = 120; // 2 minutes. interval.tv_usec = 0; itime.it_interval = interval; itime.it_value = interval; setitimer(ITIMER_REAL, &itime, 0); } #define MAX_CHILDREN 20 volatile int nChildrenStarted = 0; volatile int nChildrenEndedSIGCHLD = 0; volatile int nChildrenEndedMain = 0; RETSIGTYPE child_signal(int iSig) { // Collect the children. // while (waitpid(0, NULL, WNOHANG) > 0) { int nChildren = nChildrenStarted - nChildrenEndedSIGCHLD - nChildrenEndedMain; if (0 < nChildren) { nChildrenEndedSIGCHLD++; } } signal(SIGCHLD, CAST_SIGNAL_FUNC child_signal); } int main(int argc, char *argv[]) { char arg[MAX_STRING]; char *p; int len; pid_t child; parent_pid = getppid(); if (parent_pid == 1) { // Our real parent process is gone, and we have been inherited by the // init process. // exit(1); } alarm_signal(SIGALRM); signal(SIGCHLD, CAST_SIGNAL_FUNC child_signal); signal(SIGPIPE, SIG_DFL); for (;;) { len = read(0, arg, MAX_STRING - 1); if (len == 0) { break; } if (len < 0) { if (errno == EINTR) { errno = 0; continue; } break; } arg[len] = '\0'; p = strchr(arg, '\n'); if (p) { *p = '\0'; } child = fork(); switch (child) { case -1: exit(1); break; case 0: // child. { // We don't want to try this for more than 5 minutes. // struct itimerval itime; struct timeval interval; interval.tv_sec = 300; // 5 minutes. interval.tv_usec = 0; itime.it_interval = interval; itime.it_value = interval; signal(SIGALRM, CAST_SIGNAL_FUNC child_timeout_signal); setitimer(ITIMER_REAL, &itime, 0); } exit(query(arg, p + 1) != 0); break; } if (child > 0) { nChildrenStarted++; } int nChildren = nChildrenStarted - nChildrenEndedSIGCHLD - nChildrenEndedMain; // Collect the children. // while (waitpid(0, NULL, (nChildren < MAX_CHILDREN) ? WNOHANG : 0) > 0) { if (0 < nChildren) { nChildrenEndedMain++; } } } exit(0); } mux2.6/src/wild.cpp0000600000175000017500000002463411025753746014252 0ustar sdennissdennis// wild.cpp -- Wildcard routines. // // $Id: wild.cpp 8 2006-09-05 01:55:58Z brazilofmux $ // // Written by T. Alexander Popiel, 24 June 1993 // Last modified by T. Alexander Popiel, 19 August 1993 // // Thanks go to Andrew Molitor for debugging // Thanks also go to Rich $alz for code to benchmark against // // Copyright (c) 1993 by T. Alexander Popiel // This code is hereby placed under GNU copyleft, // see copyright.h for details. // #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #define EQUAL(a,b) (mux_tolower(a) == mux_tolower(b)) #define NOTEQUAL(a,b) (mux_tolower(a) != mux_tolower(b)) // Argument return space and size. // static char **arglist; static int numargs; // // --------------------------------------------------------------------------- // quick_wild: do a wildcard match, without remembering the wild data. // // This routine will cause crashes if fed NULLs instead of strings. // bool quick_wild(const char *tstr, const char *dstr) { if (mudstate.wild_invk_ctr >= mudconf.wild_invk_lim) { return false; } mudstate.wild_invk_ctr++; while (*tstr != '*') { switch (*tstr) { case '?': // Single character match. Return false if at end of data. // if (!*dstr) { return false; } break; case '\\': // Escape character. Move up, and force literal match of next // character. // tstr++; // FALL THROUGH default: // Literal character. Check for a match. If matching end of data, // return true. // if (NOTEQUAL(*dstr, *tstr)) { return false; } if (!*dstr) { return true; } } tstr++; dstr++; } // Skip over '*'. // tstr++; // Return true on trailing '*'. // if (!*tstr) { return true; } // Skip over wildcards. // while ( *tstr == '?' || *tstr == '*') { if (*tstr == '?') { if (!*dstr) { return false; } dstr++; } tstr++; } // Skip over a backslash in the pattern string if it is there. // if (*tstr == '\\') { tstr++; } // Return true on trailing '*'. // if (!*tstr) { return true; } // Scan for possible matches. // while (*dstr) { if ( EQUAL(*dstr, *tstr) && quick_wild(tstr + 1, dstr + 1)) { return true; } dstr++; } return false; } // --------------------------------------------------------------------------- // wild1: INTERNAL: do a wildcard match, remembering the wild data. // // DO NOT CALL THIS FUNCTION DIRECTLY - DOING SO MAY RESULT IN SERVER CRASHES // AND IMPROPER ARGUMENT RETURN. // // Side Effect: this routine modifies the 'arglist' static global variable. // static bool wild1(char *tstr, char *dstr, int arg) { if (mudstate.wild_invk_ctr >= mudconf.wild_invk_lim) { return false; } mudstate.wild_invk_ctr++; char *datapos; int argpos, numextra; while (*tstr != '*') { switch (*tstr) { case '?': // Single character match. Return false if at end of data. // if (!*dstr) { return false; } arglist[arg][0] = *dstr; arglist[arg][1] = '\0'; arg++; // Jump to the fast routine if we can. // if (arg >= numargs) { return quick_wild(tstr + 1, dstr + 1); } break; case '\\': // Escape character. Move up, and force literal match of next // character. // tstr++; // FALL THROUGH default: // Literal character. Check for a match. If matching end of data, // return true. // if (NOTEQUAL(*dstr, *tstr)) { return false; } if (!*dstr) { return true; } } tstr++; dstr++; } // If at end of pattern, slurp the rest, and leave. // if (!tstr[1]) { mux_strncpy(arglist[arg], dstr, LBUF_SIZE - 1); return true; } // Remember current position for filling in the '*' return. // datapos = dstr; argpos = arg; // Scan forward until we find a non-wildcard. // do { if (argpos < arg) { // Fill in arguments if someone put another '*' before a fixed // string. // arglist[argpos][0] = '\0'; argpos++; // Jump to the fast routine if we can. // if (argpos >= numargs) { return quick_wild(tstr, dstr); } // Fill in any intervening '?'s // while (argpos < arg) { arglist[argpos][0] = *datapos; arglist[argpos][1] = '\0'; datapos++; argpos++; // Jump to the fast routine if we can. // if (argpos >= numargs) { return quick_wild(tstr, dstr); } } } // Skip over the '*' for now... // tstr++; arg++; // Skip over '?'s for now... // numextra = 0; while (*tstr == '?') { if (!*dstr) { return false; } tstr++; dstr++; arg++; numextra++; } } while (*tstr == '*'); // Skip over a backslash in the pattern string if it is there. // if (*tstr == '\\') { tstr++; } // Check for possible matches. This loop terminates either at end of data // (resulting in failure), or at a successful match. // for (;;) { // Scan forward until first character matches. // if (*tstr) { while (NOTEQUAL(*dstr, *tstr)) { if (!*dstr) { return false; } dstr++; } } else { while (*dstr) { dstr++; } } // The first character matches, now. Check if the rest does, using // the fastest method, as usual. // if ( !*dstr || ((arg < numargs) ? wild1(tstr + 1, dstr + 1, arg) : quick_wild(tstr + 1, dstr + 1))) { // Found a match! Fill in all remaining arguments. First do the // '*'... // mux_strncpy(arglist[argpos], datapos, (dstr - datapos) - numextra); datapos = dstr - numextra; argpos++; // Fill in any trailing '?'s that are left. // while (numextra) { if (argpos >= numargs) { return true; } arglist[argpos][0] = *datapos; arglist[argpos][1] = '\0'; datapos++; argpos++; numextra--; } // It's done! // return true; } else { dstr++; } } } // --------------------------------------------------------------------------- // wild: do a wildcard match, remembering the wild data. // // This routine will cause crashes if fed NULLs instead of strings. // // Side Effect: this routine modifies the 'arglist' and 'numargs' static // global variables. // bool wild(char *tstr, char *dstr, char *args[], int nargs) { mudstate.wild_invk_ctr = 0; int i; char *scan; // Initialize the return array. // for (i = 0; i < nargs; i++) { args[i] = NULL; } // Do fast match. // while ( *tstr != '*' && *tstr != '?') { if (*tstr == '\\') { tstr++; } if (NOTEQUAL(*dstr, *tstr)) { return false; } if (!*dstr) { return true; } tstr++; dstr++; } // Allocate space for the return args. // i = 0; scan = tstr; while ( *scan && i < nargs) { switch (*scan) { case '?': args[i] = alloc_lbuf("wild.?"); i++; break; case '*': args[i] = alloc_lbuf("wild.*"); i++; } scan++; } // Put stuff in globals for quick recursion. // arglist = args; numargs = nargs; // Do the match. // bool value = nargs ? wild1(tstr, dstr, 0) : quick_wild(tstr, dstr); // Clean out any fake match data left by wild1. // for (i = 0; i < nargs; i++) { if ( args[i] != NULL && ( !*args[i] || !value)) { free_lbuf(args[i]); args[i] = NULL; } } return value; } // --------------------------------------------------------------------------- // wild_match: do either an order comparison or a wildcard match, remembering // the wild data, if wildcard match is done. // // This routine will cause crashes if fed NULLs instead of strings. // bool wild_match(char *tstr, const char *dstr) { switch (*tstr) { case '>': tstr++; if ( mux_isdigit(*tstr) || *tstr == '-') { long lt = mux_atol(tstr); long ld = mux_atol(dstr); return (lt < ld); } else { return (strcmp(tstr, dstr) < 0); } case '<': tstr++; if ( mux_isdigit(*tstr) || *tstr == '-') { long lt = mux_atol(tstr); long ld = mux_atol(dstr); return (lt > ld); } else { return (strcmp(tstr, dstr) > 0); } } mudstate.wild_invk_ctr = 0; return quick_wild(tstr, dstr); } mux2.6/game/0000700000175000017500000000000011025753746012716 5ustar sdennissdennismux2.6/game/netmux.conf0000700000175000017500000000243011025753746015107 0ustar sdennissdennis# netmux.conf - TinyMUX configuration file # # NOTE: GAMENAME, DATA, and TEXT in mux.config -must- agree with the # following settings. The ./Startmux, ./Backup, and _backupflat.sh # scripts depend on this assumption. # # Default filenames for the database # input_database data/netmux.db output_database data/netmux.db.new crash_database data/netmux.db.CRASH game_dir_file data/netmux.dir game_pag_file data/netmux.pag # # Mail, comsystem, and macro databases. # mail_database data/mail.db comsys_database data/comsys.db # # Configuration for art() article_rule an ^[aeiou] article_rule an ^he(ir|rb) article_rule an ^ho(mag|nest|no|ur) article_rule an ^un article_rule a ^unanim(ous|ity) article_rule a ^uni([acflopqtvx]|dim|dir|sex|son) article_rule a ^u[bcfhjkqrst][aeiou] article_rule a ^e[uw] article_rule a ^onc?e[-\ ]? article_rule a ^[aeiou][.-] article_rule an ^y[lt] # port 2860 mud_name AnonymousMUX # # Helpfile raw_helpfile help text/help raw_helpfile wizhelp text/wizhelp access wizhelp wizard # include alias.conf include compat.conf # # Configuration options needed for SGP master_room #2 access @function wizard access @function/privileged wizard helpfile +help text/plushelp helpfile +shelp text/staffhelp access +shelp staff # # Define local aliases/parameters/whatnot here. mux2.6/game/mux.config0000600000175000017500000000124211025753746014717 0ustar sdennissdennis# mux.config - constants for mux shell scripts # # Change these variables as appropriate # # NOTE: GAMENAME, DATA, and TEXT here -must- agree with the settings in # your $GAMENAME.conf file. The ./Startmux, ./Backup, and _backupflat.sh # scripts depend on this assumption. # BIN=./bin TEXT=./text DATA=./data GAMENAME=netmux OWNER=mux_admin@your_site.your_domain # # If you use compression, uncomment this and put the extension here. # #COMPRESSION=.gz # # You should never need to change these. # NEW_DB=$GAMENAME.db.new$COMPRESSION INPUT_DB=$GAMENAME.db$COMPRESSION GDBM_DB=$GAMENAME CRASH_DB=$GAMENAME.db.CRASH SAVE_DB=$GAMENAME.db.old$COMPRESSION PIDFILE=$GAMENAME.pid mux2.6/game/Backup0000700000175000017500000000326211025753746014054 0ustar sdennissdennis#!/bin/sh # # Standard MUSH backup script modified by bem@erisian.net to work with MUX # PATH=/bin:/usr/bin:/usr/local/bin:.; export PATH # . mux.config # # You'll want to use gzip if you have it. If you want really good # compression, try 'gzip --best'. If you don't have gzip, use 'compress'. ZIP=gzip # DBDATE=`date +%m%d-%H%M` # # files to tar up TEXT_FILES="$TEXT/badsite.txt $TEXT/connect.txt $TEXT/create_reg.txt $TEXT/down.txt $TEXT/full.txt $TEXT/guest.txt $TEXT/motd.txt $TEXT/news.txt $TEXT/newuser.txt $TEXT/plushelp.txt $TEXT/quit.txt $TEXT/register.txt $TEXT/wizmotd.txt $TEXT/wiznews.txt $TEXT/staffhelp.txt" CONFIG_FILES="mux.config $GAMENAME.conf" GAME_DB=$DATA/$GAMENAME.FLAT if [ -r $DATA/comsys.db ]; then COMM_DB=$DATA/comsys.db fi if [ -r $DATA/mail.db ]; then MAIL_DB=$DATA/mail.db fi if [ -r $DATA/$NEW_DB ]; then RECENT_DB=$DATA/$NEW_DB else if [ -r $DATA/$INPUT_DB ]; then echo "No recent checkpoint db. Using older db." RECENT_DB=$DATA/$INPUT_DB else if [ -r $DATA/$SAVE_DB ]; then echo "No input db. Using backup db." RECENT_DB=$DATA/$SAVE_DB else echo "No dbs. Backup attempt failed." exit fi fi fi VERSION_LINE=`head -n 1 $RECENT_DB` if [ $VERSION_LINE = "+X992001" -o $VERSION_LINE = "+X992002" ]; then cp $RECENT_DB $GAME_DB else if [ $VERSION_LINE = "+X1031937" -o $VERSION_LINE = "+X1031938" ]; then $BIN/dbconvert -d$DATA/$GDBM_DB -u -i$RECENT_DB -o$GAME_DB else echo "Unrecognized header in $RECENT_DB." exit fi fi tar cf - $GAME_DB $COMM_DB $MAIL_DB $CONFIG_FILES $TEXT_FILES | $ZIP -c > $GAMENAME.$DBDATE.tar.gz rm $GAME_DB mux2.6/game/Startmux0000700000175000017500000000226211025753746014475 0ustar sdennissdennis#!/bin/sh # # Startmux - Kick off the netmux process. # PATH=/usr/ucb:/bin:/usr/bin:.; export PATH # . mux.config # # Make sure there isn't already a MUX running. # if [ -r "$PIDFILE" ]; then oldpid=`cat $PIDFILE` if [ "$oldpid" -gt 1 ]; then nmux=`ps | grep $oldpid | grep netmux | wc -l` if [ "$nmux" -gt 0 ]; then echo "The MUX already seems to be running." exit 0 fi fi fi # # Save a copy of the previous input database. # if [ -r $DATA/$INPUT_DB ]; then mv -f $DATA/$INPUT_DB $DATA/$SAVE_DB fi # # If we have a good checkpoint database, make it the input database. # If not, use the backup of the input database. # if [ -r $DATA/$NEW_DB ]; then mv $DATA/$NEW_DB $DATA/$INPUT_DB elif [ -r $DATA/$SAVE_DB ]; then cp $DATA/$SAVE_DB $DATA/$INPUT_DB fi # # Remove the restart db if there is one. # if [ -r restart.db ]; then rm restart.db fi # # Refuse to start if CRASH databases are present. # if [ -r $DATA/$INPUT_DB.CRASH ]; then echo "There is a CRASH database present." echo "You should salvage what you can before continuing." exit 1 fi # # Kick off MUX # (nohup $BIN/netmux -c $GAMENAME.conf -p $PIDFILE >/dev/null 2>&1 &) mux2.6/game/bin/0000700000175000017500000000000011025753746013466 5ustar sdennissdennismux2.6/game/bin/.placeholder0000600000175000017500000000000011025753746015741 0ustar sdennissdennismux2.6/game/_backupflat.sh0000700000175000017500000000264511025753746015537 0ustar sdennissdennis#!/bin/sh # PATH=/bin:/usr/bin:/usr/local/bin:.; export PATH # . mux.config # # You'll want to use gzip if you have it. If you want really good # compression, try 'gzip --best'. If you don't have gzip, use 'compress'. # ZIP=gzip # DBDATE=`date +%m%d-%H%M` # if [ "$1" -a -r "$1" ]; then echo "Using flatfile from $1, renaming to $DATA/$GAMENAME.$DBDATE" mv $1 $DATA/$GAMENAME.$DBDATE elif [ -r $DATA/$NEW_DB ]; then $BIN/netmux -d$DATA/$GDBM_DB -i$DATA/$NEW_DB -o$DATA/$GAMENAME.$DBDATE -u elif [ -r $DATA/$INPUT_DB ]; then echo "No recent checkpoint db. Using older db." $BIN/netmux -d$DATA/$GDBM_DB -i$DATA/$INPUT_DB -o$DATA/$GAMENAME.$DBDATE -u elif [ -r $DATA/$SAVE_DB ]; then echo "No input db. Using backup db." $BIN/netmux -d$DATA/$GDBM_DB -i$DATA/$SAVE_DB -o$DATA/$GAMENAME.$DBDATE -u else echo "No dbs. Backup attempt failed." fi cd $DATA if [ -r $GAMENAME.$DBDATE ]; then FILES=$GAMENAME.$DBDATE else echo "No flatfile found. Aborting." exit fi if [ -r comsys.db ]; then cp comsys.db comsys.db.$DBDATE FILES="$FILES comsys.db.$DBDATE" else echo "Warning: no comsys.db found." fi if [ -r mail.db ]; then cp mail.db mail.db.$DBDATE FILES="$FILES mail.db.$DBDATE" else echo "Warning: no mail.db found." fi # FILES=$GAMENAME.$DBDATE comsys.db.$DBDATE mail.db.$DBDATE echo "Compressing and removing files: $FILES" tar czf dump.$DBDATE.tgz $FILES && rm -f $FILES & mux2.6/game/text/0000700000175000017500000000000011025753746013702 5ustar sdennissdennismux2.6/game/text/help.txt0000600000175000017500000152353511025753746015413 0ustar sdennissdennis& HELP HELP This is the TinyMUX online help facility. Notes on help descriptions: [text] - Text enclosed in []'s is optional. The []'s are never typed in as part of the command. - Information parameter for a command. The <>'s are never typed in as part of the command. - Syntax of help command: help [] - To get a list of TinyMUX topics: help topics - To get a list of Comsystem commands: help comsys - To get a list of TinyMUX Commands: help commands (or @list commands) Some of the configuration shown in the help.txt might not be the same as the configuration of this MUX. If you notice any errors, contact an admin. & " " COMMAND: " Says out loud to everyone in your current location (usually a room). Example: > "Where is the movie theater? You say, "Where is the movie theater?" Note that the closing double quote is automatically added. Related Topics: page, pose, say, :, ". & # # COMMAND: # Forces the object whose database number is to perform . Example: '#1033 move north' forces object #1033 to go north (assuming that you control it). The same restrictions that apply to @force also apply to this command. Related Topics: @force. & $-COMMANDS $-COMMANDS These commands are called arbitrary commands, user-defined commands, or $-commands (for how they are defined). See 'arbitrary commands' for the full description. Related Topics: arbitrary commands & & COMMAND: & [=] SYNONYM: @set = :[] Sets the attribute named on to . If is not a predefined attribute (like ofail or va), then it is created. Attributes so created are called user-named attributes. Attribute names may only contain letters, numbers, and the characters < -_.@#$^&*~?=+| >, and must start with a letter. The names of user-named attributes may not be abbreviated (an attempt to get the value of the attribute will fail, and an attempt to set will create a new attribute). The & command may be used to set predefined attributes (in this instance, '& =' is equivalent to '@ ='). Related Topics: @set. & : : COMMAND: : Displays to everyone in your current room, preceded by your name and a space. However, if starts with a space, no space is inserted between your name and the pose -- like the ';' command. Example: >:jumps for joy. Player jumps for joy. >: 's cat meows. Player's cat meows. Related Topics: page, pose, say, whisper, ;, ". & ; ; COMMAND: ; This command is much like the ':' command, except that no space is inserted between your name and the pose. However, can start with its own space -- a result similar to using the ':' command. Example: > ;'s watch beeps. Player's watch beeps. > ; meows. Player meows. Warning: This command does not work in command lists run from an attribute because the ';' is treated as the command separator. Use pose/nospace instead. Related Topics: page, pose, say, whisper, :, ". & @@ @@ COMMAND: @@ This command and everything after it (excluding the command-separator ';') is not evaluated by the parser. This is useful for adding comments in softcode or, more commonly, writing comment headers for softcode installers (such as /quotable text files). Note that @@ must be followed by a space or it will return an error message. Always be doubly sure that ()'s and {}'s in the (otherwise ignored) arguments are nested correctly, so that any semicolons used to separate it from subsequent code in the line are recognized by the parser. Example: > @va me=$foobar *:@fo #1234=%0;@@ This controls my foobar puppet. > foobar say Hello World! foobar says "Hello World!" > @@ --- Begin Code --- > @emit Hello World! > @@ --- End Code --- Hello World! Related Topics: think, @@(), null(). & @@() @@() FUNCTION: @@() The is not evaluated and returns nothing. Example: > think @@(pemit(me,Hello)) > think @@(abc) Related Topics: @@, null(). & @AAHEAR @AAHEAR COMMAND: @aahear = ATTRIBUTE: Aahear An Aahear on an object is activated whenever the listen pattern matches anything done/said by anything else in the room, including itself. (The Ahear ignores itself, helpful for keeping machines from triggering itself) Example: @aahear listener = "I heard someone (maybe me?) say the word! Related Topics: @ahear, @amhear, @listen. & @ACLONE @ACLONE COMMAND: @aclone = ATTRIBUTE: Aclone Sets the actions to be taken by a new object that has just been created as the result of a @clone command. The contents of the Aclone attribute are run by the new object and not by the old object. This attribute is only meaningful for things, and will never be automatically triggered on other object types. It is also possible to check the zone object/objects in the zone parent room for an @adisconnect. If one is found, it will be executed when a player disconnects in that zone. Example: @aclone Time bomb = @wait 600=@trig me/va;@wait 10=@trig me/vb @va time bomb = :EXPLODES with a thundering roar;@destroy me @vb time bomb = :ticks.; @wait 10=@trig me/vb Related Topics: @clone. & @ACONNECT @ACONNECT COMMAND: @aconnect = ATTRIBUTE: Aconnect Sets the actions to be taken by a player upon connecting to the MUX. The following steps occur in the following order whenever a player connects to the MUX. Parentage is observed. - Execute the connecting player's @aconnect. - Execute the master room's @aconnect. - Execute any @aconnect found on any of the master room's contents. - If the location that the player is connecting into belongs to a zone, then a) if the zone object is a thing, execute its @aconnect. b) if the zone object is a room, execute any @aconnect found on any of that room's contents. Example: > @aconnect me = check.my.mailbox Related Topics: @adisconnect. & @ADESCRIBE @ADESCRIBE COMMAND: @adescribe = ATTRIBUTE: Adescribe Sets the actions to be taken when is looked at. Example: @adesc kitten = :rubs against %n's legs affectionately. Related Topics: look, @desc, @idesc, @odesc, think & @ADFAIL @ADFAIL COMMAND: @adfail = ATTRIBUTE: Adfail Sets the action to be taken by an object when someone tries to drop it but fails because they didn't pass the object's drop lock. Example: @adfail sword = @name me=Cursed Sword;:laughs maniacally. Related Topics: drop, @dfail, @odfail, @lock. & @ADISCONNECT @ADISCONNECT COMMAND: @adisconnect = ATTRIBUTE: Adisconnect Sets the actions to be taken by a player upon disconnecting from the MUX. The following steps occur in the following order whenever a player connects to the MUX. Parentage is observed. - Execute the connecting player's @adisconnect. - Execute the master room's @adisconnect. - Execute any @adisconnect found on any of the master room's contents. - If the location that the player is connecting into belongs to a zone, then a) if the zone object is a thing, execute its @adisconnect. b) if the zone object is a room, execute any @adisconnect found on any of that room's contents. Example: > @adisconnect me = home Related Topics: @aconnect. & @ADROP @ADROP COMMAND: @adrop = ATTRIBUTE: Adrop Sets the action to be taken by an object when it is dropped, or by an exit when it is successfully used. Example: @adrop plastique = kill %n=100; @destroy me Related Topics: drop, @drop, @odrop, DROP-TO, EXITS. & @AEFAIL @AEFAIL COMMAND: @aefail = ATTRIBUTE: Aefail Sets the action to be taken by an object when someone tries to enter it but fails because the object is not ENTER_OK or the player fails the object's enter lock. The enter lock only affects the 'enter' command and its aliases (set via the @ealias command), it does not affect exits that lead to the object or teleporting in. This attribute is meaningful for players and things, and will never be automatically triggered on rooms or exits. Example: @aefail car = @emit ;'s alarm starts wailing when %n tries to break in. Related Topics: @aenter, @efail, @ealias, @enter, @oefail, @oenter, enter, ENTER_OK. & @AENTER @AENTER COMMAND: @aenter = ATTRIBUTE: Aenter Sets the action to be taken by an object or room when someone enters it, whether by using an exit, the enter or leave commands, or by teleporting. This attribute is meaningful for players, things, and rooms, and will never be automatically triggered on exits. Example: @aenter car = :starts its engine, eagerly awaiting a road trip.; "Beep Beep! Related Topics: enter, @enter, @oenter, ENTER_OK. & @AFAIL @AFAIL COMMAND: @afail = ATTRIBUTE: Afail Sets the commands to be performed by when one of these events occurs: - For exits: Someone tries to traverse the exit but cannot because they fail the exit's default lock or the exit is not linked. - For players and things: Someone tries to pick up the object but cannot because they fail the object's default lock. - For rooms, players, and things: Someone looks around inside the room, player, or thing and fails the object's default lock. Example: > @afail vase = :falls to the floor and smashes to pieces.;@destroy me Related Topics: @fail, @ofail, FAILURE. & @AGFAIL @AGFAIL COMMAND: @agfail = ATTRIBUTE: Agfail Sets the action to be taken by an object when someone tries to give it away but fails because they didn't pass the object's give lock. Example: @agfail sword = @name me=Cursed Sword;:laughs maniacally. Related Topics: give, @gfail, @ogfail, @lock. & @AHEAR @AHEAR COMMAND: @ahear = ATTRIBUTE: Ahear Sets the actions to be taken after the object hears a string that matches the pattern in the Listen attribute which was not produced by the object itself. Messages that are produced by the object itself are ignored. Example: @ahear clock = "The time is now [time()]. >> BONNNNGGGGG << Related Topics: @aahear, @amhear, @listen. & @AKILL @AKILL COMMAND: @akill = ATTRIBUTE: Akill Sets the actions to be taken by an object after it is killed and has returned to its home. This attribute is only meaningful for players and things, and will never be automatically triggered on other object types. Example: @akill lion = south; :leaps onto %n, roaring loudly.;kill %n=100 Related Topics: kill, @kill and @okill, BEING KILLED, IMMORTAL, WIZARD. & @ALEAD @ALEAD COMMAND: @alead = ATTRIBUTE: Alead Sets the executed when object is lead. This attribute is only available if FIRANMUX is enabled. Related Topics: @lead, @olead. & @ALEAVE @ALEAVE COMMAND: @aleave = ATTRIBUTE: Aleave Sets the action to be taken by an object or room when someone leaves it, whether by using an exit, the enter or leave commands, or by teleporting. This attribute is meaningful for players, things, and rooms, and will never be automatically triggered on exits. Example: @aleave car = :stops to let %n out.;:revs its engine, hoping another brave soul would like a ride. Related Topics: leave, @leave, @oleave. & @ALFAIL @ALFAIL COMMAND: @alfail = ATTRIBUTE: Alfail Sets the action to be taken by an object when someone tries to leave it but fails because the player fails the object's leave lock. The leave lock only affects the 'leave' command and its aliases (set via the @ealias command), it does not affect going home, using an exit in the location, or teleporting out. This attribute is meaningful for players and things, and will never be automatically triggered on rooms or exits. Example: @alfail box = :rattles around as %n tries to escape. Related Topics: @aleave, @lalias, @leave, @lfail, @oleave, @olfail, leave. & @ALIAS @ALIAS COMMAND: @alias = ATTRIBUTE: Alias Provides an alternate name by which the player is known. The alternate name is only used for players when referenced as '*' or by commands that only take playernames (such as page or @stats). You may not set an alias on any other object type. When setting an alias, the alias is checked to see that it is both a legal player name and not already in use. Only if both checks succeed is the alias set. Related Topics: @name. & @AMAIL @AMAIL COMMAND: @amail = ATTRIBUTE: Amail Sets the actions to be taken after a player receives @mail. This should *never* @mail another player, as this could cause an infinite loop. Example: @amail me=@mail/file [mail()]=2 This would place all incoming messages in folder #2. Related Topics: @mailsucc, @signature, @mail. & @AMHEAR @AMHEAR COMMAND: @amhear = ATTRIBUTE: Amhear Sets the actions to be taken after the object hears a string that matches the pattern in the Listen attribute which was produced by the object itself. Messages that are produced by anything other than the object itself are ignored. Example: @amhear listener = "Wait a minute. I said the trigger word! Related Topics: @aahear, @ahear, @listen. & @AMOVE @AMOVE COMMAND: @amove = ATTRIBUTE: Amove Sets the action to be taken by an object whenever it moves from one location to another, whether by using an exit, entering or leaving an object, teleporting, or going home. This attribute is meaningful for players, and things and will never be automatically triggered on other object types. Example: @amove car = @vz me=[extract(%vz,1,19)] [loc(me)] Related Topics: @move, @omove. & @APAY @APAY COMMAND: @apay = ATTRIBUTE: Apay Sets the actions to be taken after the object is given the number of coins specified in its Cost attribute. If the giver tries to give more than that number of coins, the excess is refunded, and if less than the necessary amount is given then it is all given back and a snide message is sent to the giver. This attribute is only meaningful for players and things, and will never be automatically triggered on other object types. Example: @apay Coke machine = @clone Can of Coke; :drops a can on the floor. Related Topics: give, @cost, @opay, @pay. & @ARFAIL @ARFAIL COMMAND: @arfail = ATTRIBUTE: Arfail Sets the action to be taken by an object when someone tries to give it something that fails its give lock. Example: @arfail merchant = "I don't buy such junk. Begone!; @tel %#=cheater_exit Related Topics: give, @agfail, @gfail, @ogfail, @orfail, @rfail, @lock. & @ASUCCESS @ASUCCESS COMMAND: @asuccess = ATTRIBUTE: Asucc Sets the actions to be taken by an object when someone successfully picks it up (because they passed the lock), by an exit when someone passes through it, or when someone looks at a room and passes the room's lock. Example: @asucc kitten = :climbs up your sleeve and nuzzles your face. Related Topics: @osucc, @success, SUCCESS. & @ATFAIL @ATFAIL COMMAND: @atfail = ATTRIBUTE: Atfail Sets the action to be taken by an object when someone tries to teleport there but fails. Example: @atfail here = @page [owner(me)]=%N tried to teleport here. Related Topics: @teleport, @tfail, @otfail, @lock. & @ATOFAIL @ATOFAIL COMMAND: @atofail = ATTRIBUTE: Atofail Sets the action to be taken by an object when someone tries to teleport out but fails. Example: @atofail here = @page [owner(me)]=%N tried to teleport out. Related Topics: @teleport, @tofail, @otofail, @lock. & @ATPORT @ATPORT COMMAND: @atport = ATTRIBUTE: Atport Sets the actions to be performed by object whenever it teleports. The actions are performed after the object moves to its new location. This attribute is only meaningful for players and things, and will never be automatically triggered on other object types. Example: @atport me = &TEL.COUNT me=add(v(TEL.COUNT),1) Related Topics: @otport, @oxtport, @tport, @teleport. & @AUFAIL @AUFAIL COMMAND: @aufail = ATTRIBUTE: Aufail Sets the list of commands to be run when someone 'use's the object but fails the object's use lock. Note that the other functions controlled by the use lock (paying, listening, and $-commands) do not trigger Aufail. Example: @aufail robot = "I _told_ you to leave me alone; kill %n=100 Related Topics: @oufail, @ufail, @use. & @AUSE @AUSE COMMAND: @ause = ATTRIBUTE: Ause Sets the actions to be taken when someone uses the object with the use command. This attribute is only meaningful for players and things, and will never be automatically triggered on other object types. Example: @ause grenade = :EXPLODES with a thundering roar; kill %n=100; @destroy me Related Topics: use, @ouse, @use. & @AWAY @AWAY COMMAND: @away = ATTRIBUTE: Away This attribute is sent as a message to anyone who tries to page you when you are not connected. This attribute is only meaningful for players, and will never be automatically referenced on other object types. Example: @away me = Hey, I'm not even connected. So why are you paging me? Related Topics: @idle, @idletimeout, @reject, page. & @BREAK @BREAK COMMAND: @break @break stops the execution of further commands in the current action list if its argument is a true value. It doesn't affect new queue entries made by previous commands in the action list. Very useful to people who don't like @switch. Examples: > @va obj=$testme *:@pemit %#=Before;@break %0;@pemit %#=After > testme 0 Before After > testme 1 Before > @force me={@switch 1=1,think 3rd;think 1st;@break 1;think 2nd} 1st 3rd In the last example, the @switch is run, which queues 'think 3rd', 'think 1st' is run, displaying '1st', command execution is broken (so we never 'think 2nd', and then the queued 'think 3rd' is run, displaying '3rd'. If you follow that, you have a very good understanding of the TinyMUX queue. :) Related Topics: BOOLEAN VALUES & @CBOOT @CBOOT COMMAND: @cboot[/quiet] = Only wizards or the owner of the channel can use this command. It forcefully removes an object from that channel. You may specify a player name as if you prefix it with an '*' (e.g., '*Player1'), otherwise should be a dbref or if you are in the same room, the name of an object or player. Example: > @cboot Public=Player1 [Public] Staff1 boots Player1 off the channel. [Public] Player1 has left this channel. Related Topics: comsys commands & @CCHARGE @CCHARGE COMMAND: @ccharge = This command imposes a charge of coins on transmitting over a channel. The default fee when a channel is created is 0. All proceeds benefit the channel owner. Example: > @ccharge Public=1 Set. Related Topics: comsys commands & @CCHOWN @CCHOWN COMMAND: @cchown = Changes ownership of to . If the player is not in the same room, you will need to add a '*' before the name (e.g., '*player1'). Example: >@cchown Public=Staff1 Set. Related Topics: @clist, @cwho. & @CCREATE @CCREATE COMMAND: @ccreate Only Wizards can create new channels. Creates a new channel with default settings. Once the channel is created, it can be associated with a object with the @cset command. That object can be used to set locks and descriptions on the channel. Example: > @ccreate Public Channel Public created. Related Topics: comsys, @cset, @cdestroy, @clist, @cchown. & @CDESTROY @CDESTROY COMMAND: @cdestroy Deletes permanently from the comsystem database. It does not destroy all aliases that exist for -- those are left to the owners of those aliases. Players are notified both at login when they own aliases for which a channel no longer exists and when they try to use them. Even if a Channel is destroyed and then recreated, the alias will still be non functioning. The alias must be removed with the 'delcom' command and added with the 'addcom' command. Example: > @cdestroy Staff Channel Staff destroyed. Related Topics: @clist, @ccreate, @cchown, addcom, delcom. & @CEMIT @CEMIT COMMAND: @cemit[/] = Sends over prefixed by the channel's name. You must own or control the channel to do this. The following switches are available: /noheader - Sends the message to everyone on without the channel's name prefixed. Example: > @cemit Public=This is a test! [Public] This is a test! > @cemit/noheader Public=This is a test! This is a test. Related Topics: comsys commands, alias, addcom, cemit() & @CHARGES @CHARGES COMMAND: @charges = ATTRIBUTE: Charges This attribute allows you to limit the number of times an object can be used. If there is a charges attribute it is decremented each time an action on the object is triggered. Once it reaches zero, normal triggering stops and the Runout attribute (if one is present) is run instead. Example: @charges Fireball wand = 5 Related Topics: @runout. & @CHOWN @CHOWN COMMAND: @chown[/nostrip] [=] @chown /[=] The first form changes the ownership of to . By default, this is yourself. Objects may be things, rooms or exits. To @chown things, you have to be carrying the thing. For rooms or exits, you have to be in the room. Objects must have the CHOWN_OK flag set before they may be @chowned. In a room, the command used must be @chown here=, and for an object, you must be very specific. Players can't be @chowned; they always own themselves. When an object is @chowned, all unlocked attributes on the object are automatically @chowned as well. Locked attributes remain owned by their original owners. Without the /nostrip switch, CHOWN_OK, all flags specified in the stripped_flags configuration option, and all @powers are stripped. Also, HALT is set. With /nostrip, ROYALTY and INHERIT are preserved (albeit with warnings). #1 can use /nostrip to further preserve WIZARD and @powers. By default, stripped_flags includes: BLIND, CONNECTED, GAGGED, HEAD_FLAG, IMMORTAL, INHERIT, ROYALTY, SLAVE, STAFF, SUSPECT, UNINSPECTED, and WIZARD. { 'help @chown2' for more } & @CHOWN2 @CHOWN (continued) The second form changes the ownership of the indicated attribute on to . The default is the owner of the object. You may only @chown unlocked attributes. You may @chown unlocked attributes on objects that you own to yourself, and you may also @chown attributes that you own on objects owned by others to the owner of the object. Related Topics: ATTRIBUTE OWNERSHIP, CHOWN_OK, @lock, stripped_flags, and @unlock. & @CHZONE @CHZONE COMMAND: @chzone =. Changes the zone of to . If is "none", the zone is reset to NOTHING. @chzone'ing a player does not automatically change the zone of their objects. Anyone may reset the zone of an object they own; must either be "none", or must be owned by them. Only wizards may @chzone an object to an arbitrary zone object. Players may @chzone themselves to an object they own; otherwise, only wizards may @chzone players. For non-player objects, @chzone'ing strips all flags in the stripped_flags. By default, stripped_flags includes: BLIND, CONNECTED, GAGGED, HEAD_FLAG, IMMORTAL, INHERIT, ROYALTY, SLAVE, STAFF, SUSPECT, UNINSPECTED, and WIZARD. Related Topics: stripped_flags, ZONE OBJECTS & @CLIST @CLIST COMMAND: @clist[/