Exemple #1
0
void processLDFlags(const String& ldFlags, StringVec& libs) {
    // Tokenize flags
    StringVec ldFlagTokens;
    tokenize(ldFlags, ldFlagTokens, " \t", "", "\"'", "", "", true, false);

    // Expand -Wl, and -Xlinker tokens to make parsing easier
    StringVec ldFlagsFixed;
    replaceWlArgs(ldFlagTokens, ldFlagsFixed);

    String savedToken;
    for (auto opt : ldFlagsFixed) {
        if (savedToken.empty()) {
            opt = reduceLinkerToken(opt);
            if (opt == "-library" || opt == "-framework") {
                savedToken = opt;
            } else if (strBeginsWith(opt, "-l")) {
                String libName = strEndsWith(opt, ".o") ? opt.substr(2) : "lib" + opt.substr(2) + ".?";
                libs.push_back(libName);
            } else if (strEndsWith(opt, ".a") || strEndsWith(opt, ".dylib") || strEndsWith(opt, ".o")) {
                libs.push_back(opt);
            }
        } else {
            if (savedToken == "-library") {
                libs.push_back(opt);
            } else if (savedToken == "-framework") {
                std::string frameworkName = opt.substr(0, opt.find(',')) + ".framework";
                libs.push_back(frameworkName);
            }
            savedToken.clear();
        }
    }
}
Exemple #2
0
CMnemosynthDb::SEndpoint *CMnemosynthDb::GetOrAddEndpoint (const CString &sName, DWORD dwProcessID)

//	GetOrAddEndpoint
//
//	Returns an endpoint for the given name

	{
	CSmartLock Lock(m_cs);

	//	If we already have it, skip

	SEndpoint *pEndpoint = FindEndpoint(sName);
	if (pEndpoint != NULL)
		{
		//	If this is a new process ID, then it means that the module
		//	has been restarted, so we need to restart the sequence number.s

		if (dwProcessID != 0 && dwProcessID != pEndpoint->dwProcessID)
			{
#ifdef DEBUG_MODULE_RESTART
			printf("[%s] Resetting endpoint %s to process ID %x\n", (LPSTR)m_pProcess->GetModuleName(), (LPSTR)sName, dwProcessID);
#endif
			pEndpoint->dwProcessID = dwProcessID;
			pEndpoint->dwSeqRecv = 0;
			pEndpoint->dwSeqSent = 0;
			}

		return pEndpoint;
		}

	//	Add

	DWORD dwID = m_dwNextID++;
	pEndpoint = m_Endpoints.Insert(dwID);
	pEndpoint->dwID = dwID;
	pEndpoint->sName = sName;
	pEndpoint->pPort = NULL;
	pEndpoint->dwSeqRecv = 0;
	pEndpoint->dwSeqSent = 0;

	//	If the module name ends with CentralModule then this is
	//	a module with Exarch (responsible for cross-machine sync)

	pEndpoint->bCentralModule = strEndsWith(sName, STR_CENTRAL_MODULE);

	//	If the module starts with our machine name, then this is
	//	a local endpoint.

	pEndpoint->bLocalMachine = strStartsWith(sName, m_pProcess->GetMachineName());
	pEndpoint->dwProcessID = (pEndpoint->bLocalMachine ? dwProcessID : 0);

	//	This endpoint needs a full update of everything we've got

	pEndpoint->bFullUpdate = true;

	//	Done

	return pEndpoint;
	}
Exemple #3
0
END_TEST

START_TEST(test_strEndsWith)
{
    fail_unless(!strEndsWith("foo.bar", ".foo"), NULL);
    fail_unless(strEndsWith("foo.bar", ".bar"), NULL);
    fail_unless(!strEndsWith("foo.bar", "o"), NULL);
    fail_unless(strEndsWith("foo.bar", "r"), NULL);
    fail_unless(strEndsWith("foo.bar", "oo.bar"), NULL);
    fail_unless(strEndsWith("foo.bar", "foo.bar"), NULL);
    fail_unless(!strEndsWith("foo.bar", "xoo.bar"), NULL);
    fail_unless(!strEndsWith("fo", "foo"), NULL);
    fail_unless(!strEndsWith("", "foo"), NULL);
}
Exemple #4
0
List<Object *>::Iterator Object::findChild(const char *pattern,
        List<Object *>::Iterator first) const
{
    if(!pattern) return nullptr;

    List<Object *>::Iterator pos;
    CString r(pattern);

    auto wildcard_pos = r.find(WILDCARD_CHAR);

    if(wildcard_pos == r.end()) {
        pos = p.children.find([&r](Object *o) -> bool
        {
            return r == o->name().data();
        }, first);
    } else if(r.front() == WILDCARD_CHAR) {
        pos = p.children.find([&r](Object *o) -> bool
        {
            return strEndsWith(o->name().data(), r.data()+1, o->name().size(), r.size()-1);
        }, first);
    } else if(r.back() == WILDCARD_CHAR) {
        r.resize(r.size()-1);
        pos = p.children.find([&r](Object *o) -> bool
        {
            return strStartsWith(o->name().data(), r.data(), o->name().size(), r.size());
        }, first);
    } else {
        pos = p.children.find([&r, &wildcard_pos](Object *o) -> bool
        {
            size_t wildcard_idx = (&(*wildcard_pos))-r.data();
            bool ends = strEndsWith(o->name().data(), r.data()+wildcard_idx+1,
            o->name().size(), r.size()-wildcard_idx-1);

            CString s(r.data(), wildcard_idx);
            bool starts = strStartsWith(o->name().data(), s.data(), o->name().size(), s.size());

            return starts && ends;
        }, first);
    }

    return pos;
}
XCScheme::XCScheme(const String& absSchemePath, const PBXProject* owner)
: m_absPath(absSchemePath), m_parentProject(owner)
{
  // Record the scheme name
  m_name = sb_fname(sb_basename(m_absPath));

#if defined(_MSC_VER)
  // Disambiguate scheme names from different users
  String userDir = sb_basename(sb_dirname(sb_dirname(m_absPath)));
  if (strEndsWith(userDir, ".xcuserdatad"))
    m_name = m_name + " (" + sb_fname(userDir) + ")";
#endif
}
Exemple #6
0
char *convertDottedPathToSlashedPath (char *filename)
{
    char *result = g_strdup (filename);
    char *tmp;

    for (tmp = result; *tmp; tmp++)
        if (*tmp == '.')
            *tmp = '/';

    if (strEndsWith (result, "/balsa"))
        result[strlen (result) - 6] = '.';

    return result;
}
	std::string rangeFromOverflow(const std::string &prefix, const std::string &done){
		if (strContains(overflow, prefix)){
			if (strEndsWith(overflow, prefix)) return prefix;
			v1.clear();
			std::string tmp = overflow.substr(overflow.find(prefix) + prefix.length());
			auto pos = tmp.find(done);
			if (pos != std::string::npos){
				overflow = tmp.substr(pos);
				return prefix + tmp.substr(0,pos);
			}
			else return prefix + tmp;
		}
		return "";
	}
bool LEVELSELECT::addLevelListEntry(char* levelFileName)
{
    if (strlen(levelFileName)+1 > MAX_PATH)
    {
        error("LEVELSELECT::addLevelListEntry", "Parameter levelFileName too long. Max length is MAX_PATH (%d).", MAX_PATH);
        return false;
    }

    if (!strEndsWith(levelFileName, ".lvl"))
    {
        logger(true, "WARNING: Unknown file in level directory %s: %s", GetCurrent()->GetDirectory()->name, levelFileName);
        return false;
    }

    LEVELFILE *lastLevel = GetCurrent()->GetLevel();
    LEVELFILE *newLevel;

    //get last level
    if (lastLevel != NULL)
    {
        while (lastLevel->next != NULL)
        {
            lastLevel = lastLevel->next;
        }
    }

    newLevel = (LEVELFILE*)malloc(sizeof(LEVELFILE));
    newLevel->prev = lastLevel;
    newLevel->next = NULL;
    if (lastLevel != NULL)
    {
        lastLevel->next = newLevel;
        newLevel->index = lastLevel->index+1;
    }
    else
    {
        newLevel->index = 0;
    }

    strcpy(newLevel->name, levelFileName);
    newLevel->name[strlen(newLevel->name)-4] = '\0'; //cut off fileextension (to get levelname)
    newLevel->directory = GetCurrent()->currentDirectory;
    GetCurrent()->GetLevelPath(newLevel->path, newLevel);
    newLevel->score = HIGHSCORE(newLevel->name, newLevel->directory->name);
    newLevel->level = new LEVEL({(windX/2+160), 160}, 17, newLevel->path, true);

    if (GetCurrent()->GetLevel() == NULL)
        GetCurrent()->currentLevel = newLevel;
    return true;
}
Exemple #9
0
bool CArchonProcess::SendMessage (const CString &sAddress, const SArchonMessage &Msg)

//	SendMessage
//
//	Sends a message to the given address. If we fail, we reply as appropriate.

	{
	bool bSuccess;

	CMessagePort *pPort = Bind(sAddress);
	if (pPort)
		{
		bSuccess = pPort->SendMessage(Msg);
		}
	else
		{
		Log(MSG_LOG_ERROR, strPattern(ERR_CANT_BIND, sAddress));
		bSuccess = false;
		}

	//	If we failed to send the message, then we might want to reply to the 
	//	client.

	if (!bSuccess)
		{
		//	If this is a notification port then we ignore the error (it just
		//	means that no one is listening).

		if (!strEndsWith(sAddress, STR_NOTIFY_SUFFIX) 
				&& !strStartsWith(Msg.sMsg, MSG_ERROR_PREFIX))
			{
			//	Reply to client, if necessary

			if (!CMessagePort::IsNullAddr(Msg.sReplyAddr))
				SendMessageCommand(Msg.sReplyAddr, MSG_ERROR_UNABLE_TO_COMPLY, NULL_STR, Msg.dwTicket, CDatum(strPattern(ERR_CANT_SEND_TO, sAddress)));
			else
				Log(MSG_LOG_ERROR, strPattern("Failed sending message to: %s.", sAddress));
			}
		}

	//	Done

	return bSuccess;
	}
Exemple #10
0
static String expandRecursivePath(const String& path, const String& prefix, const VariableCollectionHierarchy& vch)
{
  // Check if recursive expansion is necessary
  if (!strEndsWith(path, "/**"))
    return addPrefixQuoted(path, prefix, vch);
  
  // Remove the pesky /** ending
  String fixedPath = path.substr(0, path.length() - 3);
  
  // Expand the path and get an absolute project path
  String expandedPath = vch.expand(fixedPath);
  String projectPath = vch.getValue("PROJECT_DIR");
  
  // Make an absolute path
  String absPath = joinPaths(projectPath, expandedPath);
  
  // Get a list of subdirectories to ignore
  StringVec ignoreList;
  vch.getValue("EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES", ignoreList);

  // Get recursive paths
  StringVec dirVec;
  getRecursiveDirList(absPath, dirVec, ignoreList);
  
  // Sort the paths such that they are in breadth-first, alphabetic order
  std::sort(dirVec.begin(), dirVec.end(), compare_nocase_breadth_first);

  // Substitute back the original form of the path (which likely contains variables)
  String ret;
  for (unsigned i = 0; i < dirVec.size(); i++) {
    dirVec[i].replace(0, absPath.length(), fixedPath);
    ret += addPrefixQuoted(dirVec[i], prefix, vch);
  }

  // Check that the recursive expansion succeeded
  if (dirVec.empty()) {
    SBLog::info() << "Failed recursive expansion of \"" << absPath << "\". Path does not exist." << std::endl;
    return "";
  } else { 
    return ret;
  }
}
Exemple #11
0
CDatum CUserInfoSession::CreateSanitizedUserRecord (CDatum dRecord)

//	CreateSanitizedUserRecord
//
//	Creates a user record suitable for returning to clients. In partincular,
//	we remove the authentication information.

	{
	int i;

	//	Create a destination

	CComplexStruct *pDest = new CComplexStruct;

	//	Copy all appropriate fields

	for (i = 0; i < dRecord.GetCount(); i++)
		{
		//	If this is an auth field, then skip it

		if (strEquals(dRecord.GetKey(i), FIELD_AUTH_DESC))
			;

		else if (strEndsWith(dRecord.GetKey(i), FIELD_AUTH_DESC_SUFFIX))
			;
		
		//	Otherwise, copy it

		else
			pDest->SetElement(dRecord.GetKey(i), dRecord.GetElement(i));
		}

	//	Done

	return CDatum(pDest);
	}
void SBFrameworksBuildPhase::writeVCProjectFiles(VCProject& proj) const
{
  // We don't support linking with frameworks when building bundles
  TargetProductType productType = m_parentTarget.getProductType();
  if (productType == TargetBundle) {
    if (!m_phase->getBuildFileList().empty()) {
      SBLog::warning() << "Ignoring all frameworkss in \"" << m_parentTarget.getName() << "\" bundle target." << std::endl;
    }
    return;
  }

  String linkTarget;
  if (productType == TargetApplication)
    linkTarget = "Link";
  else if (productType == TargetStaticLib)
    linkTarget = "Lib";

  // Get paths to all the build files (frameworks)
  StringVec buildFilePaths;
  if (m_phase) {
    const BuildFileList& buildFiles = m_phase->getBuildFileList();
    sbAssert(buildFiles.size() == m_buildFileTargets.size());
    for (size_t i = 0; i < buildFiles.size(); i++) {
      const PBXFile* file = buildFiles[i]->getFile();
      // Ignore any frameworks build from source (they will be added as project references)
      if (file && !m_buildFileTargets[i])
        buildFilePaths.push_back(file->getFullPath());
    }
  }

  for (auto bs : m_parentTarget.getBuildSettings()) {
    VCProjectConfiguration* config = proj.addConfiguration(bs.first);

    // Extrace libs/frameworks from OTHER_LDFLAGS
    StringVec buildFilePaths(buildFilePaths);
    processLDFlags(bs.second->getValue("OTHER_LDFLAGS"), buildFilePaths);

    // Construct a list of libraries to link against
    StringSet linkedLibs;
    linkedLibs.insert("%(AdditionalDependencies)");
    for (auto filePath : buildFilePaths) {
      if (productType == TargetStaticLib && !strEndsWith(filePath, ".a"))
        continue;

      String winLibName = sb_fname(sb_basename(filePath)) + ".lib";

      // If the library is blocked then add the replacement library to our additional dependencies 
      auto it = s_blockedLibraries.find(winLibName);
      while (it != s_blockedLibraries.end())
      {
          // get the replacement library.
          winLibName = it->second;

          // follow any transitive replacement.
          it = s_blockedLibraries.find(winLibName);
      }

      if (!winLibName.empty())
      {
          linkedLibs.insert(winLibName);
      }
    }

    // AdditionalDependencies
    String additionalDeps = joinStrings(linkedLibs, ";");
    if (!additionalDeps.empty()) {
      config->setItemDefinition(linkTarget, "AdditionalDependencies", additionalDeps);
    }
  }
}
Exemple #13
0
void CExarchEngine::MsgAddModule (const SArchonMessage &Msg, const CHexeSecurityCtx *pSecurityCtx)

//	MsgAddModule
//
//	Exarch.addModule [{machineName}] {filePath} [{debug}]

	{
	CSmartLock Lock(m_cs);
	CString sError;

	//	Must be admin service

	if (!ValidateSandboxAdmin(Msg, pSecurityCtx))
		return;

	//	Get parameters

	bool bHasMachineName = (Msg.dPayload.GetCount() >= 2 && !strEndsWith(strToLower(Msg.dPayload.GetElement(0)), STR_EXE_SUFFIX));
	int iArg = 0;
	CString sMachineName = (bHasMachineName ? Msg.dPayload.GetElement(iArg++) : NULL_STR);
	CString sModuleFilePath = Msg.dPayload.GetElement(iArg++);
	CDatum dDebug = Msg.dPayload.GetElement(iArg++);

	//	If we have a machine name, try to parse it in case the user gave us
	//	a partial name.

	if (bHasMachineName)
		{
		if (!ParseMachineName(sMachineName, &sMachineName))
			{
			SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, strPattern("Unknown machine: %s", sMachineName), Msg);
			return;
			}
		}

	//	If this is not for our machine, then we need to send a message to the
	//	other machine.

	if (!sMachineName.IsEmpty()
			&& !strEqualsNoCase(GetMachineName(), sMachineName))
		{
		CString sAddress = GenerateMachineAddress(sMachineName, ADDRESS_EXARCH_COMMAND);
		if (sAddress.IsEmpty())
			{
			SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, strPattern("Unable to generate address for: %s", sMachineName), Msg);
			return;
			}

		StartSession(Msg, new CAddModuleSession(this, sAddress, sModuleFilePath));
		}

	//	Otherwise, we add a local module

	else
		{
		//	Add the module

		CString sModuleName;
		if (!AddModule(sModuleFilePath, strEqualsNoCase(dDebug, FIELD_DEBUG), &sModuleName, &sError))
			{
			SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, sError, Msg);
			return;
			}

		//	Add it to our list of modules

		CComplexArray *pModuleList = new CComplexArray(m_dMachineConfig.GetElement(FIELD_MODULES));
		pModuleList->Append(CDatum(sModuleName));

		CComplexStruct *pConfig = new CComplexStruct(m_dMachineConfig);
		pConfig->SetElement(FIELD_MODULES, CDatum(pModuleList));
		m_dMachineConfig = CDatum(pConfig);

		//	Save it

		WriteConfig();

		//	Done

		SendMessageReply(MSG_OK, CDatum(), Msg);
		}
	}
Exemple #14
0
void RunFile (const CString &sFilespec, bool bNoLogo)
	{
	ALERROR error;
	CCodeChain &CC = g_pUniverse->GetCC();
	CCodeChainCtx Ctx;

	//	Verify the file

	CString sRunFile = sFilespec;
	if (!strEndsWith(sRunFile, CONSTLIT("."))
			&& pathGetExtension(sRunFile).IsBlank())
		sRunFile.Append(CONSTLIT(".tlisp"));

	//	Open the file

	CFileReadBlock InputFile(sRunFile);
	if (error = InputFile.Open())
		{
		printf("error : Unable to open file '%s'.\n", sRunFile.GetASCIIZPointer());
		return;
		}

	if (!bNoLogo)
		printf("%s\n", sRunFile.GetASCIIZPointer());

	//	Parse

	CString sInputFile(InputFile.GetPointer(0), InputFile.GetLength(), TRUE);
	CString sOutput;
	int iOffset = 0;

	while (true)
		{
		int iCharCount;
		ICCItem *pCode = Ctx.Link(sInputFile, iOffset, &iCharCount);
		if (pCode->IsNil())
			break;
		else if (pCode->IsError())
			{
			printf("error : %s\n", pCode->GetStringValue().GetASCIIZPointer());
			Ctx.Discard(pCode);
			return;
			}

		iOffset += iCharCount;

		//	Execute

		ICCItem *pResult = Ctx.Run(pCode);

		//	Compose output

		if (pResult->IsIdentifier())
			sOutput = pResult->Print(&CC, PRFLAG_NO_QUOTES | PRFLAG_ENCODE_FOR_DISPLAY);
		else
			sOutput = CC.Unlink(pResult);

		//	Free

		Ctx.Discard(pResult);
		Ctx.Discard(pCode);
		}

	//	Output result

	printf("%s\n", sOutput.GetASCIIZPointer());
	}
Exemple #15
0
int main(int argc, char* argv[])
{
	#if defined _DEBUG
	printf("+++ start\n");

	int argi=0;
	printf("+++ argc: %d\n", argc);
	for ( argi; argi<argc; argi++)
	{
		printf("+++ argv[%d]='%s'\n", argi, argv[argi]);
	}
	#endif

	if ( argc>1 )
	{
		if ( findParam(argv, argc, "-h")>0 ||
			findParam(argv, argc, "--help")>0
			)
		{
			help(argv[0]);
			return RET_SUCCES;
		}
	}
	else
	{
		printf("error: not enought params\n");
		help(argv[0]);
		return RET_ERR_PARAMS;
	}

	bfo=0;
	if ( findParam(argv, argc, "-d")>0 ||
		findParam(argv, argc, "--debug")>0
		)
	{
		bfo |= BFO_DEBUG;
		#if defined _DEBUG
		printf("+++ main: in debug BF mode: bfo: 0x%X\n", bfo);
		#endif
	}

	bf_mem=(UCHAR*)calloc(BF_MEMORY_SIZE, sizeof(char));
	if ( !bf_mem )
	{
		#if defined _DEBUG
		printf("--- main: bf_mem=NULL\n");
		#else
		printf("error: can't allocate memory for BF cells\n");
		#endif
		return RET_ERR_MEM;
	}

	FILE* bf_sc_fd;
	if ( argc>1 && strEndsWith(argv[argc-1], "bf") )
	{
		bf_sc_fd=fopen(argv[argc-1], "r");
		if ( bf_sc_fd )
		{
			bf_sc=(UCHAR*)calloc(BUFFER_SIZE, sizeof(char));
			int bf_sc_sz=0;
			int readb=0;
			while( !feof(bf_sc_fd) )
			{
				if ( bf_sc )
				{
					readb=fread(bf_sc+bf_sc_sz*BUFFER_SIZE*sizeof(char),
								BUFFER_SIZE*sizeof(char),
								1,
								bf_sc_fd);

// 					#if defined _DEBUG
// 					printf("bf_sc::fread #%d:\n%s (%d)\n", bf_sc_sz+1, bf_sc, readb);
// 					#endif

					if ( readb==1 )
					{
						bf_sc_sz+=1;
						bf_sc=(UCHAR*)realloc(bf_sc,
													  (bf_sc_sz+1)*BUFFER_SIZE*sizeof(char));
						memset(bf_sc+(BUFFER_SIZE*bf_sc_sz), 0, BUFFER_SIZE);
					}
				}
				else
				{
					#if defined _DEBUG
					printf("--- bf_sc=NULL\n");
					#endif
					return RET_ERR_MEM;
				}
			}
			close(bf_sc_fd);

			if ( bf_sc )
			{
				#if defined _DEBUG
				printf("bf_sc @ 0x%X (%d):\n'%s'\n", bf_sc,
					   BUFFER_SIZE*(bf_sc_sz+1)*sizeof(char),
					   bf_sc);
				#endif

				if ( strEndsWith(argv[argc-1], ".qbf") ||
					findParam(argv, argc, "-q")>0 ||
					findParam(argv, argc, "--quick")>0
					)
				{
					bfo |= BFO_QUICK;
					#if defined _DEBUG
					printf("+++ main: in quick BF mode: bfo: 0x%X\n", bfo);
					#endif
					
					#if defined _DEBUG
					printf("+++ main: prepare sc\n");
					#endif
					
					bf_sc=prepare(bf_sc);
					if ( bf_sc )
					{
						#if defined _DEBUG
						printf("bf_sc @ 0x%X (%d):\n'%s'\n", bf_sc,
							BUFFER_SIZE*(bf_sc_sz+1)*sizeof(char),
							bf_sc);
						#endif
					}
					else
					{
						#if defined _DEBUG
						printf("--- main: can't prepare SC\n");
						#endif
						return RET_ERR_SC;
					}
				}
			}

			if ( findParam(argv, argc, "-sc")>0 ||
				findParam(argv, argc, "--show-code")>0
				)
			{
				printf("Source code:\n'%s'\n", bf_sc);
			}

			if ( bf_sc )
			{
				int sz=strlen(bf_sc);
				#if defined _DEBUG
				printf("+++ bf_sc[%d]=0x%02X\n", sz-1, bf_sc[sz-1]);
				#endif

				// TODO: str replace ?
				if ( bf_sc[sz-1]==0x0a || bf_sc[sz-1]==0x0d )
					bf_sc[sz-1]=0;
				if ( bf_sc[sz-2]==0x0a || bf_sc[sz-2]==0x0a )
					bf_sc[sz-2]=0;

				if ( validate(bf_sc) )
				{
					bf_mp=bf_mem;
					execute(bf_sc);
					printf("\n");
					
					free(bf_sc);
					free(bf_mem);
				}
				else
				{
					printf("code is invalid\n");
				}
			}
		}
		else
		{
			printf("can't open '%s'\n", argv[argc-1]);
		}
	}
	else
	{
		printf("'%s' seems to be not a BF source\n", argv[argc-1]);
	}

	#if defined _DEBUG
	printf("+++ stop\n");
	#endif

	return RET_SUCCES;
};
Exemple #16
0
/***********************************************************************************************************************************
Test Run
***********************************************************************************************************************************/
void
testRun(void)
{
    FUNCTION_HARNESS_VOID();

    // *****************************************************************************************************************************
    if (testBegin("strNew(), strNewBuf(), strNewN(), strEmpty(), strPtr(), strSize(), and strFree()"))
    {
        // We don't want this struct to grow since there are generally a lot of strings, so make sure it doesn't grow without us
        // knowing about it
        TEST_RESULT_UINT(sizeof(StringConst), TEST_64BIT() ? 16 : 12, "check StringConst struct size");

        // Test the size macro
        TEST_RESULT_VOID(CHECK_SIZE(555), "valid size");
        TEST_ERROR(CHECK_SIZE(STRING_SIZE_MAX + 1), AssertError, "string size must be <= 1073741824 bytes");

        String *string = strNew("static string");
        TEST_RESULT_STR(strPtr(string), "static string", "new with static string");
        TEST_RESULT_INT(strSize(string), 13, "check size");
        TEST_RESULT_BOOL(strEmpty(string), false, "is not empty");
        TEST_RESULT_INT(strlen(strPtr(string)), 13, "check size with strlen()");
        TEST_RESULT_CHAR(strPtr(string)[2], 'a', "check character");

        TEST_RESULT_VOID(strFree(string), "free string");

        // -------------------------------------------------------------------------------------------------------------------------
        TEST_RESULT_STR(strPtr(strNewN("testmorestring", 4)), "test", "new string with size limit");

        // -------------------------------------------------------------------------------------------------------------------------
        Buffer *buffer = bufNew(8);
        memcpy(bufPtr(buffer), "12345678", 8);
        bufUsedSet(buffer, 8);

        TEST_RESULT_STR(strPtr(strNewBuf(buffer)), "12345678", "new string from buffer");

        // -------------------------------------------------------------------------------------------------------------------------
        string = strNewFmt("formatted %s %04d", "string", 1);
        TEST_RESULT_STR(strPtr(string), "formatted string 0001", "new with formatted string");
        TEST_RESULT_PTR(strPtr(NULL), NULL, "null string pointer");

        TEST_RESULT_VOID(strFree(string), "free string");
        TEST_RESULT_VOID(strFree(NULL), "free null string");
    }

    // *****************************************************************************************************************************
    if (testBegin("STRING_STATIC()"))
    {
        TEST_RESULT_STR(strPtr(TEST_STRING), "a very interesting string!", "check static string");
        TEST_RESULT_STR(strPtr(strSubN(TEST_STRING, 0, 6)), "a very", "read-only strSub() works");
    }

    // *****************************************************************************************************************************
    if (testBegin("strBase() and strPath()"))
    {
        TEST_RESULT_STR(strPtr(strBase(STRDEF(""))), "", "empty string");
        TEST_RESULT_STR(strPtr(strBase(STRDEF("/"))), "", "/ only");
        TEST_RESULT_STR(strPtr(strBase(STRDEF("/file"))), "file", "root file");
        TEST_RESULT_STR(strPtr(strBase(STRDEF("/dir1/dir2/file"))), "file", "subdirectory file");

        TEST_RESULT_STR(strPtr(strPath(STRDEF(""))), "", "empty string");
        TEST_RESULT_STR(strPtr(strPath(STRDEF("/"))), "/", "/ only");
        TEST_RESULT_STR(strPtr(strPath(STRDEF("/file"))), "/", "root path");
        TEST_RESULT_STR(strPtr(strPath(STRDEF("/dir1/dir2/file"))), "/dir1/dir2", "subdirectory file");
    }

    // *****************************************************************************************************************************
    if (testBegin("strCat(), strCatChr(), and strCatFmt()"))
    {
        String *string = strNew("XXXX");
        String *string2 = strNew("ZZZZ");

        TEST_RESULT_STR(strPtr(strCat(string, "YYYY")), "XXXXYYYY", "cat string");
        TEST_RESULT_SIZE(string->extra, 4, "check extra");
        TEST_RESULT_STR(strPtr(strCatFmt(string, "%05d", 777)), "XXXXYYYY00777", "cat formatted string");
        TEST_RESULT_SIZE(string->extra, 6, "check extra");
        TEST_RESULT_STR(strPtr(strCatChr(string, '!')), "XXXXYYYY00777!", "cat chr");
        TEST_RESULT_SIZE(string->extra, 5, "check extra");

        TEST_RESULT_STR(strPtr(string2), "ZZZZ", "check unaltered string");
    }

    // *****************************************************************************************************************************
    if (testBegin("strDup()"))
    {
        const String *string = STRDEF("duplicated string");
        String *stringDup = strDup(string);
        TEST_RESULT_STR(strPtr(stringDup), strPtr(string), "duplicated strings match");

        TEST_RESULT_PTR(strDup(NULL), NULL, "duplicate null string");
    }

    // *****************************************************************************************************************************
    if (testBegin("strBeginsWith() and strBeginsWithZ()"))
    {
        TEST_RESULT_BOOL(strBeginsWith(STRDEF(""), STRDEF("aaa")), false, "empty string");
        TEST_RESULT_BOOL(strBeginsWith(STRDEF("astring"), STRDEF("")), true, "empty begins with");
        TEST_RESULT_BOOL(strBeginsWithZ(STRDEF("astring"), "astr"), true, "partial begins with");
        TEST_RESULT_BOOL(strBeginsWithZ(STRDEF("astring"), "astring"), true, "equal strings");
    }

    // *****************************************************************************************************************************
    if (testBegin("strEndsWith() and strEndsWithZ()"))
    {
        TEST_RESULT_BOOL(strEndsWith(STRDEF(""), STRDEF(".doc")), false, "empty string");
        TEST_RESULT_BOOL(strEndsWith(STRDEF("astring"), STRDEF("")), true, "empty ends with");
        TEST_RESULT_BOOL(strEndsWithZ(STRDEF("astring"), "ing"), true, "partial ends with");
        TEST_RESULT_BOOL(strEndsWithZ(STRDEF("astring"), "astring"), true, "equal strings");
    }

    // *****************************************************************************************************************************
    if (testBegin("strEq(), strEqZ(), strCmp(), strCmpZ()"))
    {
        TEST_RESULT_BOOL(strEq(STRDEF("equalstring"), STRDEF("equalstring")), true, "strings equal");
        TEST_RESULT_BOOL(strEq(STRDEF("astring"), STRDEF("anotherstring")), false, "strings not equal");
        TEST_RESULT_BOOL(strEq(STRDEF("astring"), STRDEF("bstring")), false, "equal length strings not equal");

        TEST_RESULT_INT(strCmp(STRDEF("equalstring"), STRDEF("equalstring")), 0, "strings equal");
        TEST_RESULT_INT(strCmp(STRDEF("a"), STRDEF("b")), -1, "a < b");
        TEST_RESULT_INT(strCmp(STRDEF("b"), STRDEF("a")), 1, "b > a");

        TEST_RESULT_BOOL(strEqZ(STRDEF("equalstring"), "equalstring"), true, "strings equal");
        TEST_RESULT_BOOL(strEqZ(STRDEF("astring"), "anotherstring"), false, "strings not equal");
        TEST_RESULT_BOOL(strEqZ(STRDEF("astring"), "bstring"), false, "equal length strings not equal");

        TEST_RESULT_INT(strCmpZ(STRDEF("equalstring"), "equalstring"), 0, "strings equal");
        TEST_RESULT_INT(strCmpZ(STRDEF("a"), "b"), -1, "a < b");
        TEST_RESULT_INT(strCmpZ(STRDEF("b"), "a"), 1, "b > a");
    }

    // *****************************************************************************************************************************
    if (testBegin("strFirstUpper(), strFirstLower(), strUpper(), strLower()"))
    {
        TEST_RESULT_STR(strPtr(strFirstUpper(strNew(""))), "", "empty first upper");
        TEST_RESULT_STR(strPtr(strFirstUpper(strNew("aaa"))), "Aaa", "first upper");
        TEST_RESULT_STR(strPtr(strFirstUpper(strNew("Aaa"))), "Aaa", "first already upper");

        TEST_RESULT_STR(strPtr(strFirstLower(strNew(""))), "", "empty first lower");
        TEST_RESULT_STR(strPtr(strFirstLower(strNew("AAA"))), "aAA", "first lower");
        TEST_RESULT_STR(strPtr(strFirstLower(strNew("aAA"))), "aAA", "first already lower");

        TEST_RESULT_STR(strPtr(strLower(strNew("K123aBc"))), "k123abc", "all lower");
        TEST_RESULT_STR(strPtr(strLower(strNew("k123abc"))), "k123abc", "already lower");
        TEST_RESULT_STR(strPtr(strLower(strNew("C"))), "c", "char lower");
        TEST_RESULT_STR(strPtr(strLower(strNew(""))), "", "empty lower");

        TEST_RESULT_STR(strPtr(strUpper(strNew("K123aBc"))), "K123ABC", "all upper");
        TEST_RESULT_STR(strPtr(strUpper(strNew("K123ABC"))), "K123ABC", "already upper");
        TEST_RESULT_STR(strPtr(strUpper(strNew("c"))), "C", "char upper");
        TEST_RESULT_STR(strPtr(strUpper(strNew(""))), "", "empty upper");
    }

    // *****************************************************************************************************************************
    if (testBegin("strQuote()"))
    {
        TEST_RESULT_STR(strPtr(strQuote(STRDEF("abcd"), STRDEF("'"))), "'abcd'", "quote string");
    }

    // *****************************************************************************************************************************
    if (testBegin("strReplaceChr()"))
    {
        TEST_RESULT_STR(strPtr(strReplaceChr(strNew("ABCD"), 'B', 'R')), "ARCD", "replace chr");
    }

    // *****************************************************************************************************************************
    if (testBegin("strSub() and strSubN()"))
    {
        TEST_RESULT_STR(strPtr(strSub(STRDEF("ABCD"), 2)), "CD", "sub string");
        TEST_RESULT_STR(strPtr(strSubN(STRDEF("ABCD"), 1, 2)), "BC", "sub string with length");
    }

    // *****************************************************************************************************************************
    if (testBegin("strTrim()"))
    {
        TEST_RESULT_STR(strPtr(strTrim(strNew(""))), "", "trim empty");
        TEST_RESULT_STR(strPtr(strTrim(strNew("X"))), "X", "no trim (one char)");
        TEST_RESULT_STR(strPtr(strTrim(strNew("no-trim"))), "no-trim", "no trim (string)");
        TEST_RESULT_STR(strPtr(strTrim(strNew(" \t\r\n"))), "", "all whitespace");
        TEST_RESULT_STR(strPtr(strTrim(strNew(" \tbegin-only"))), "begin-only", "trim begin");
        TEST_RESULT_STR(strPtr(strTrim(strNew("end-only\t "))), "end-only", "trim end");
        TEST_RESULT_STR(strPtr(strTrim(strNew("\n\rboth\r\n"))), "both", "trim both");
        TEST_RESULT_STR(strPtr(strTrim(strNew("begin \r\n\tend"))), "begin \r\n\tend", "ignore whitespace in middle");
    }

    // *****************************************************************************************************************************
    if (testBegin("strChr() and strTrunc()"))
    {
        TEST_RESULT_INT(strChr(STRDEF("abcd"), 'c'), 2, "c found");
        TEST_RESULT_INT(strChr(STRDEF("abcd"), 'C'), -1, "capital C not found");
        TEST_RESULT_INT(strChr(STRDEF("abcd"), 'i'), -1, "i not found");
        TEST_RESULT_INT(strChr(STRDEF(""), 'x'), -1, "empty string - x not found");

        String *val = strNew("abcdef");
        TEST_ERROR(
            strTrunc(val, (int)(strSize(val) + 1)), AssertError,
            "assertion 'idx >= 0 && (size_t)idx <= this->size' failed");
        TEST_ERROR(strTrunc(val, -1), AssertError, "assertion 'idx >= 0 && (size_t)idx <= this->size' failed");

        TEST_RESULT_STR(strPtr(strTrunc(val, strChr(val, 'd'))), "abc", "simple string truncated");
        strCat(val, "\r\n to end");
        TEST_RESULT_STR(strPtr(strTrunc(val, strChr(val, 'n'))), "abc\r\n to e", "complex string truncated");
        TEST_RESULT_STR(strPtr(strTrunc(val, strChr(val, 'a'))), "", "complete string truncated - empty string");

        TEST_RESULT_INT(strSize(val), 0, "0 size");
        TEST_RESULT_STR(strPtr(strTrunc(val, 0)), "", "test coverage of empty string - no error thrown for index 0");
    }

    // *****************************************************************************************************************************
    if (testBegin("strToLog() and strObjToLog()"))
    {
        TEST_RESULT_STR(strPtr(strToLog(STRDEF("test"))), "{\"test\"}", "format string");
        TEST_RESULT_STR(strPtr(strToLog(NULL)), "null", "format null string");

        char buffer[256];
        TEST_RESULT_UINT(strObjToLog(NULL, (StrObjToLogFormat)strToLog, buffer, sizeof(buffer)), 4, "format null string");
        TEST_RESULT_STR(buffer, "null", "check null string");

        TEST_RESULT_UINT(strObjToLog(STRDEF("teststr"), (StrObjToLogFormat)strToLog, buffer, sizeof(buffer)), 11, "format string");
        TEST_RESULT_STR(buffer, "{\"teststr\"}", "check string");
    }

    // *****************************************************************************************************************************
    if (testBegin("strSizeFormat()"))
    {
        TEST_RESULT_STR(strPtr(strSizeFormat(0)), "0B", "zero bytes");
        TEST_RESULT_STR(strPtr(strSizeFormat(1023)), "1023B", "1023 bytes");
        TEST_RESULT_STR(strPtr(strSizeFormat(1024)), "1KB", "1 KB");
        TEST_RESULT_STR(strPtr(strSizeFormat(2200)), "2.1KB", "2.1 KB");
        TEST_RESULT_STR(strPtr(strSizeFormat(1048576)), "1MB", "1 MB");
        TEST_RESULT_STR(strPtr(strSizeFormat(20162900)), "19.2MB", "19.2 MB");
        TEST_RESULT_STR(strPtr(strSizeFormat(1073741824)), "1GB", "1 GB");
        TEST_RESULT_STR(strPtr(strSizeFormat(1073741824 + 107374183)), "1.1GB", "1.1 GB");
        TEST_RESULT_STR(strPtr(strSizeFormat(UINT64_MAX)), "17179869183GB", "uint64 max");
    }

    // *****************************************************************************************************************************
    if (testBegin("strLstNew(), strLstAdd*(), strLstGet(), strLstMove(), strLstSize(), and strLstFree()"))
    {
        // Add strings to the list
        // -------------------------------------------------------------------------------------------------------------------------
        StringList *list = NULL;

        MEM_CONTEXT_TEMP_BEGIN()
        {
            list = strLstNew();

            for (int listIdx = 0; listIdx <= LIST_INITIAL_SIZE; listIdx++)
            {
                if (listIdx == 0)
                {
                    TEST_RESULT_PTR(strLstAdd(list, NULL), list, "add null item");
                }
                else
                    TEST_RESULT_PTR(strLstAdd(list, strNewFmt("STR%02d", listIdx)), list, "add item %d", listIdx);
            }

            strLstMove(list, MEM_CONTEXT_OLD());
        }
        MEM_CONTEXT_TEMP_END();

        TEST_RESULT_INT(strLstSize(list), 9, "list size");

        // Read them back and check values
        // -------------------------------------------------------------------------------------------------------------------------
        for (unsigned int listIdx = 0; listIdx < strLstSize(list); listIdx++)
        {
            if (listIdx == 0)
            {
                TEST_RESULT_PTR(strLstGet(list, listIdx), NULL, "check null item");
            }
            else
                TEST_RESULT_STR(strPtr(strLstGet(list, listIdx)), strPtr(strNewFmt("STR%02u", listIdx)), "check item %u", listIdx);
        }

        TEST_RESULT_VOID(strLstFree(list), "free string list");
        TEST_RESULT_VOID(strLstFree(NULL), "free null string list");
    }
bool dmtcp::Util::strEndsWith(const dmtcp::string& str, const char *pattern)
{
  return strEndsWith(str.c_str(), pattern);
}