[GDCC]IHMLO,IS! - Free Text Wrapping Function To Good Home

Archive of the old editing forum
Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. This forum is archived - please use this set of forums to ask new questions.
Locked
User avatar
Sarah
Posts: 551
Joined: Wed Sep 06, 2006 12:36 pm
Preferred Pronouns: She/Her
Operating System Version (Optional): Debian 11 (bullseye), Windows 10
Location: Middle of Nowheresville Il.
Contact:

[GDCC]IHMLO,IS! - Free Text Wrapping Function To Good Home

Post by Sarah »

What has become of "I'm Hunting Memory Leaks Officer, I Swear!":

Well, Z-Windows takeover of SetHudClipRect's inadequate (for what zWin does/demands) text wrapping is plugged up and leak free and a long way to being complete. And because I know it's bad practice to blank a post, I thought I'd offer a little present to those who might find it useful; I want to blank the post in some way and remove my Z-Windows code you see. The function below is a rewritten version of my text wrapping function to remove the Z-Windows from it and make it more friendly to general usage by the GDCC crowd. ACS users might get something useful out of it, but you'll suffer most without manual memory management. Anyway, all yours!


IMPORTANT UPDATE 17-11-2016:
Testing of the regular wrapping portion has shown it doesn't work right; my fault too, I just slapped the space tracker from the hyphenation part in to eliminate the backtracking. What you'll find is that hyphenation works fine, but un-hyphenated strings lose everything after that first new-line character insertion. This is due to incorrect array writing, the indices get off track; curloop needs set to -1 and an extra offset needs added. I was able to eliminate offsetting, which eliminated index complexity, in the hyphenation portion, at the cost of higher code complexity, but it's solid. Non-hyphenation also does some odd things with the changes; so for the meantime I'm not updating this until I get the function behaving correctly. I recommend you don't use this function for the time being, unless you want to fix it yourself.

Code: Select all

/*
*	You agree by using this file to abide by the rights and restrictions
*	placed on you by the license agreement contained below.
*
*	You agree that this source code file is open source and free to be
*	distributed in any form, physical or electronic, or otherwise, so
*	long as this agreement and disclaimer remain intact with the code.
*	You agree that you have the right to use this code in any way that
*	you see fit; you may, without limitation, edit, build upon, and/or
*	utilize this source code in any project, non-profit or commercial,
*	so long as you openly credit the code author (Saicannasha), and make
*	this source code, with license and disclaimer intact, when requested.
*	You do not need permission from the code author (Saicannasha) to
*	exercise the rights listed above, so long as this source code file,
*	along with license and disclaimer, remain openly available upon
*	request.
*
*	Disclaimer: This source code is provided as-is with no guarantee of its
*	functionality.  The code author (Saicannasha) is excempt from any and 
*	all damages to persons or property that results from the usage of this code.
*
*	This agreement will be enforced where applicable.
*
*/

#include "stdio.h"
#include "stdbool.h"
#include "stdlib.h"
#include "string.h"
#include "ctype.h"

#define DEFHYPH_LENGTH 5     // Default number of chars that must be between the last space and the cutoff point before function will hyphenate

/*
*	Prototype	: char * GetHorizontalWrap (char *, bool, unsigned int, unsigned int)
*
*	Name		: Horizontal Wrapping Adjustment
*
*	Description	: Reformats a string and inserts newline, "\n", characters into the string
*				  based on the size of the font it uses and the specified wrapping width,
*				  the calcluation for which is determined by the string wrapping message.
*
*	Arguments	: 1 - char pointer to c-string to be processed
*			  2 - boolean, hyphenation control; true to enable, false otherwise
*			  3 - unsigned int, wrapping width - in pixels
*			  4 - unsigned int, character width - average for fonts that aren't fixed with
*
*	Return		: char pointer to newly processed string
*
*	Notes		: none
*
*/
char * GetHorizontalWrap(char * in_string, bool bhyph, unsigned int wrp_wdth, unsigned int char_wdth)
{
	bool rememchk;

	unsigned int ctowrp,
		pstloop = 0,
		spcedex = 0;

	char * nstmp = NULL,
		nswip = NULL,
		nsprcs = NULL;

	size_t uflen = strlen(in_string) + 1;	// size of string plus null terminator
	ctowrp = wrpwdth / char_wdth;

	if (bhyph)	// String needs hyphenated - have to add extra chars
	{
		for (int curloop = 0; curloop < ctowrp + 1; curloop++)
		{
			if (curloop + pstloop == uflen - 1)
				break;

			if (nstmp == NULL && nswip == NULL)
				nstmp = (char *)calloc(ctowrp + 2, sizeof(char));	// Length must be +2 for both the \n and \0

			if (nstmp != NULL || nswip != NULL)
			{
				// Memory check of nstmp
				if (nstmp != NULL)
				{
					nswip = nstmp;
					nstmp = NULL;
				}

				// Space tracker - records last known ' ' index for hyphenation comparison (TY to TheJerm13 for idea this makes function linear) 
				if ((curloop + pstloop < uflen) && (isspace((int)in_string[curloop + pstloop])))
					spcedex = curloop + pstloop;

				// String finalization - determine if hyphenation or space overwriting is to be used
				if (curloop == ctowrp - 1)
				{
					if ((curloop + pstloop) - spcedex >= DEFHYPH_LENGTH)
					{	// Hyphenation - last two indices are manually filled
						nswip[curloop] = '-';
						nswip[curloop + 1] = '\n';
					}
					else
					{	// Space overwriting - last index is possibly open so something may be copied over
						nswip[spcedex - pstloop] = '\n';
						if (curloop + pstloop < uflen && spcedex - pstloop != curloop)
							nswip[curloop] = in_string[curloop + pstloop];

						curloop++;
					}

					// Get memory for nsprcs and copy over nswip
					if (nsprcs == NULL)
						nstmp = (char *)calloc(strlen(nswip) + 1, sizeof(char));
					else
					{
						nstmp = (char *)realloc(nsprcs, (strlen(nsprcs) + strlen(nswip) + 1) * sizeof(char));
						rememchk = true;
					}

					if (nstmp != NULL)
					{
						nsprcs = nstmp;
						nstmp = NULL;

						if (pstloop == 0)
							strcpy(nsprcs, nswip);
						else
							strcat(nsprcs, nswip);

						free(nswip);
						nswip = NULL;
						rememchk = false;
					}
					else
					{
						if (rememchk)
							free(nsprcs);
						return NULL;
					}

					pstloop += curloop;
					curloop = -1;
				}
				// Normal string copying - overreading copies NULL terminator
				else
				{
					if (curloop + pstloop < uflen)
						nswip[curloop] = in_string[curloop + pstloop];
				}
			}
			else
				return NULL;
		}

		if (nswip != NULL) // Should still be string left to copy over
		{
			// Get memory for nsprcs and copy over nswip
			if (nsprcs == NULL)
				nstmp = (char *)calloc(strlen(nswip) + 1, sizeof(char));
			else
			{
				nstmp = (char *)realloc(nsprcs, (strlen(nsprcs) + strlen(nswip) + 1) * sizeof(char));
				rememchk = true;
			}

			if (nstmp != NULL)
			{
				nsprcs = nstmp;
				nstmp = NULL;

				if (pstloop == 0)
					strcpy(nsprcs, nswip);
				else
					strcat(nsprcs, nswip);

				free(nswip);
				return nsprcs;
			}
			else
			{
				if (rememchk)
					free(nsprcs);
				return NULL;
			}
		}
	}
	else	// String gets wrapped, without cutting off words, and without hyphenation - don't have to add chars, just overwrite
	{
		if (nsprcs == NULL)	// Get some memory if we don't have some already
			nstmp = (char *)calloc(uflen, sizeof(char));

		if (nstmp != NULL) // Check that memory got allocated
		{
			nsprcs = nstmp;
			nstmp = NULL;

			for (int curloop = 0; curloop < ctowrp + 2; curloop++)
			{
				// overread check - i is reset to 0, j is what tracks string position
				if (curloop + pstloop == uflen - 1) // Null term not included - need enough memory for it
					break;

				// Space tracker - records last known ' ' index for hyphenation comparison (TY to TheJerm13 for idea this makes function linear) 
				if ((curloop + pstloop < uflen) && (isspace((int)in_string[curloop + pstloop])))
					spcedex = curloop + pstloop;

				// String finalizing and normal writing
				if (curloop > ctowrp)
				{
					nsprcs[spcedex] = '\n';
					pstloop += curloop;
					curloop = 0;
				}
				else
					nsprcs[curloop + pstloop] = in_string[curloop + pstloop];
			}
		}
		else
			return NULL;

		return nsprcs;
	}
}
Spoiler: Old Post Info
Locked

Return to “Editing (Archive)”