From 5d562f15aaba0bb082e714e844995705f0ca1368 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Tue, 6 Aug 2024 17:59:52 +0300
Subject: [PATCH 4/5] Constify fields and parameters in spell.c

I started by marking VoidString as const, and fixing the fallout by
marking more fields and function arguments as const. It proliferated
quite a lot, but all within spell.c and spell.h.

A more narrow patch to get rid of the static VoidString buffer would
be to replace it with '#define VoidString ""', as C99 allows assigning
"" to a non-const pointer, even though you're not allowed to modify
it. But it seems like good hygiene to mark all these as const. In the
structs, the pointers can point to the constant VoidString, or a
buffer allocated with palloc(), or with compact_palloc(), so you
should not modify them.

Discussion: https://www.postgresql.org/message-id/7f86e06a-98c5-4ce3-8ec9-3885c8de0358@iki.fi
---
 src/backend/tsearch/spell.c       | 58 +++++++++++++++++--------------
 src/include/tsearch/dicts/spell.h | 16 ++++-----
 2 files changed, 39 insertions(+), 35 deletions(-)

diff --git a/src/backend/tsearch/spell.c b/src/backend/tsearch/spell.c
index 9b1441fa1a..1aef9ca1ef 100644
--- a/src/backend/tsearch/spell.c
+++ b/src/backend/tsearch/spell.c
@@ -191,7 +191,7 @@ lowerstr_ctx(IspellDict *Conf, const char *src)
 #define GETWCHAR(W,L,N,T) ( ((const uint8*)(W))[ ((T)==FF_PREFIX) ? (N) : ( (L) - 1 - (N) ) ] )
 #define GETCHAR(A,N,T)	  GETWCHAR( (A)->repl, (A)->replen, N, T )
 
-static char *VoidString = "";
+static const char *VoidString = "";
 
 static int
 cmpspell(const void *s1, const void *s2)
@@ -346,11 +346,11 @@ cmpaffix(const void *s1, const void *s2)
  * sflag: returns an affix flag from sflagset.
  */
 static void
-getNextFlagFromString(IspellDict *Conf, char **sflagset, char *sflag)
+getNextFlagFromString(IspellDict *Conf, const char **sflagset, char *sflag)
 {
 	int32		s;
-	char	   *next,
-			   *sbuf = *sflagset;
+	char	   *next;
+	const char *sbuf = *sflagset;
 	int			maxstep;
 	bool		stop = false;
 	bool		met_comma = false;
@@ -453,7 +453,7 @@ getNextFlagFromString(IspellDict *Conf, char **sflagset, char *sflag)
 static bool
 IsAffixFlagInUse(IspellDict *Conf, int affix, const char *affixflag)
 {
-	char	   *flagcur;
+	const char *flagcur;
 	char		flag[BUFSIZ];
 
 	if (*affixflag == 0)
@@ -1120,13 +1120,13 @@ addCompoundAffixFlagValue(IspellDict *Conf, char *s, uint32 val)
  * flags s.
  */
 static int
-getCompoundAffixFlagValue(IspellDict *Conf, char *s)
+getCompoundAffixFlagValue(IspellDict *Conf, const char *s)
 {
 	uint32		flag = 0;
 	CompoundAffixFlag *found,
 				key;
 	char		sflag[BUFSIZ];
-	char	   *flagcur;
+	const char *flagcur;
 
 	if (Conf->nCompoundAffixFlag == 0)
 		return 0;
@@ -1155,7 +1155,7 @@ getCompoundAffixFlagValue(IspellDict *Conf, char *s)
  * Conf->AffixData array and function returns its entry.
  * Else function returns the s parameter.
  */
-static char *
+static const char *
 getAffixFlagSet(IspellDict *Conf, char *s)
 {
 	if (Conf->useFlagAliases && *s != '\0')
@@ -1323,7 +1323,7 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename)
 				/* Also reserve place for empty flag set */
 				naffix++;
 
-				Conf->AffixData = (char **) palloc0(naffix * sizeof(char *));
+				Conf->AffixData = (const char **) palloc0(naffix * sizeof(char *));
 				Conf->lenAffixData = Conf->nAffixData = naffix;
 
 				/* Add empty flag set into AffixData */
@@ -1571,7 +1571,7 @@ isnewformat:
 static int
 MergeAffix(IspellDict *Conf, int a1, int a2)
 {
-	char	  **ptr;
+	const char **ptr;
 
 	Assert(a1 < Conf->nAffixData && a2 < Conf->nAffixData);
 
@@ -1585,24 +1585,28 @@ MergeAffix(IspellDict *Conf, int a1, int a2)
 	if (Conf->nAffixData + 1 >= Conf->lenAffixData)
 	{
 		Conf->lenAffixData *= 2;
-		Conf->AffixData = (char **) repalloc(Conf->AffixData,
-											 sizeof(char *) * Conf->lenAffixData);
+		Conf->AffixData = (const char **) repalloc(Conf->AffixData,
+												   sizeof(char *) * Conf->lenAffixData);
 	}
 
 	ptr = Conf->AffixData + Conf->nAffixData;
 	if (Conf->flagMode == FM_NUM)
 	{
-		*ptr = cpalloc(strlen(Conf->AffixData[a1]) +
-					   strlen(Conf->AffixData[a2]) +
-					   1 /* comma */ + 1 /* \0 */ );
-		sprintf(*ptr, "%s,%s", Conf->AffixData[a1], Conf->AffixData[a2]);
+		char	   *p = cpalloc(strlen(Conf->AffixData[a1]) +
+								strlen(Conf->AffixData[a2]) +
+								1 /* comma */ + 1 /* \0 */ );
+
+		sprintf(p, "%s,%s", Conf->AffixData[a1], Conf->AffixData[a2]);
+		*ptr = p;
 	}
 	else
 	{
-		*ptr = cpalloc(strlen(Conf->AffixData[a1]) +
-					   strlen(Conf->AffixData[a2]) +
-					   1 /* \0 */ );
-		sprintf(*ptr, "%s%s", Conf->AffixData[a1], Conf->AffixData[a2]);
+		char	   *p = cpalloc(strlen(Conf->AffixData[a1]) +
+								strlen(Conf->AffixData[a2]) +
+								1 /* \0 */ );
+
+		sprintf(p, "%s%s", Conf->AffixData[a1], Conf->AffixData[a2]);
+		*ptr = p;
 	}
 	ptr++;
 	*ptr = NULL;
@@ -1785,7 +1789,7 @@ NISortDictionary(IspellDict *Conf)
 		 * dictionary. Replace textual flag-field of Conf->Spell entries with
 		 * indexes into Conf->AffixData array.
 		 */
-		Conf->AffixData = (char **) palloc0(naffix * sizeof(char *));
+		Conf->AffixData = (const char **) palloc0(naffix * sizeof(const char *));
 
 		curaffix = -1;
 		for (i = 0; i < Conf->nspell; i++)
@@ -1954,7 +1958,7 @@ mkVoidAffix(IspellDict *Conf, bool issuffix, int startsuffix)
  * returns false.
  */
 static bool
-isAffixInUse(IspellDict *Conf, char *affixflag)
+isAffixInUse(IspellDict *Conf, const char *affixflag)
 {
 	int			i;
 
@@ -2169,7 +2173,7 @@ addToResult(char **forms, char **cur, char *word)
 }
 
 static char **
-NormalizeSubWord(IspellDict *Conf, char *word, int flag)
+NormalizeSubWord(IspellDict *Conf, const char *word, int flag)
 {
 	AffixNodeData *suffix = NULL,
 			   *prefix = NULL;
@@ -2255,7 +2259,7 @@ NormalizeSubWord(IspellDict *Conf, char *word, int flag)
 						if (CheckAffix(newword, swrdlen, prefix->aff[j], flag, pnewword, &baselen))
 						{
 							/* prefix success */
-							char	   *ff = (prefix->aff[j]->flagflags & suffix->aff[i]->flagflags & FF_CROSSPRODUCT) ?
+							const char *ff = (prefix->aff[j]->flagflags & suffix->aff[i]->flagflags & FF_CROSSPRODUCT) ?
 								VoidString : prefix->aff[j]->flag;
 
 							if (FindWord(Conf, pnewword, ff, flag))
@@ -2287,7 +2291,7 @@ typedef struct SplitVar
 } SplitVar;
 
 static int
-CheckCompoundAffixes(CMPDAffix **ptr, char *word, int len, bool CheckInPlace)
+CheckCompoundAffixes(CMPDAffix **ptr, const char *word, int len, bool CheckInPlace)
 {
 	bool		issuffix;
 
@@ -2367,7 +2371,7 @@ AddStem(SplitVar *v, char *word)
 }
 
 static SplitVar *
-SplitToVariants(IspellDict *Conf, SPNode *snode, SplitVar *orig, char *word, int wordlen, int startpos, int minpos)
+SplitToVariants(IspellDict *Conf, SPNode *snode, SplitVar *orig, const char *word, int wordlen, int startpos, int minpos)
 {
 	SplitVar   *var = NULL;
 	SPNodeData *StopLow,
@@ -2533,7 +2537,7 @@ addNorm(TSLexeme **lres, TSLexeme **lcur, char *word, int flags, uint16 NVariant
 }
 
 TSLexeme *
-NINormalizeWord(IspellDict *Conf, char *word)
+NINormalizeWord(IspellDict *Conf, const char *word)
 {
 	char	  **res;
 	TSLexeme   *lcur = NULL,
diff --git a/src/include/tsearch/dicts/spell.h b/src/include/tsearch/dicts/spell.h
index 10c05769ac..1b881b8320 100644
--- a/src/include/tsearch/dicts/spell.h
+++ b/src/include/tsearch/dicts/spell.h
@@ -66,7 +66,7 @@ typedef struct spell_struct
 		 * flag is filled in by NIImportDictionary(). After
 		 * NISortDictionary(), d is used instead of flag.
 		 */
-		char	   *flag;
+		const char *flag;
 		/* d is used in mkSPNode() */
 		struct
 		{
@@ -86,15 +86,15 @@ typedef struct spell_struct
  */
 typedef struct aff_struct
 {
-	char	   *flag;
+	const char *flag;
 	/* FF_SUFFIX or FF_PREFIX */
 	uint32		type:1,
 				flagflags:7,
 				issimple:1,
 				isregis:1,
 				replen:14;
-	char	   *find;
-	char	   *repl;
+	const char *find;
+	const char *repl;
 	union
 	{
 		/*
@@ -146,7 +146,7 @@ typedef struct AffixNode
 
 typedef struct
 {
-	char	   *affix;
+	const char *affix;
 	int			len;
 	bool		issuffix;
 } CMPDAffix;
@@ -170,7 +170,7 @@ typedef struct CompoundAffixFlag
 	union
 	{
 		/* Flag name if flagMode is FM_CHAR or FM_LONG */
-		char	   *s;
+		const char *s;
 		/* Flag name if flagMode is FM_NUM */
 		uint32		i;
 	}			flag;
@@ -192,7 +192,7 @@ typedef struct
 
 	SPNode	   *Dictionary;
 	/* Array of sets of affixes */
-	char	  **AffixData;
+	const char **AffixData;
 	int			lenAffixData;
 	int			nAffixData;
 	bool		useFlagAliases;
@@ -229,7 +229,7 @@ typedef struct
 	size_t		avail;			/* free space remaining at firstfree */
 } IspellDict;
 
-extern TSLexeme *NINormalizeWord(IspellDict *Conf, char *word);
+extern TSLexeme *NINormalizeWord(IspellDict *Conf, const char *word);
 
 extern void NIStartBuild(IspellDict *Conf);
 extern void NIImportAffixes(IspellDict *Conf, const char *filename);
-- 
2.39.2

