1 /************************************************************************/
2 /*									*/
3 /*  Buffer administration routines.					*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docBaseConfig.h"
8 
9 #   include	<string.h>
10 #   include	<ctype.h>
11 #   include	<stdlib.h>
12 #   include	<uniUtf8.h>
13 #   include	<ucdGeneralCategory.h>
14 
15 #   include	<appDebugon.h>
16 
17 #   include	"docDocumentField.h"
18 #   include	"docBookmarkField.h"
19 
20 /************************************************************************/
21 /*									*/
22 /*  Extract the name from a bookmark field.				*/
23 /*									*/
24 /*  Return the bookmark name.						*/
25 /*									*/
26 /************************************************************************/
27 
docFieldGetBookmark(const MemoryBuffer ** pMarkName,const DocumentField * df)28 int docFieldGetBookmark(	const MemoryBuffer **		pMarkName,
29 				const DocumentField *		df )
30     {
31     if  ( df->dfKind != DOCfkBOOKMARK			||
32 	  df->dfInstructions.fiComponentCount < 2	)
33 	{ return -1;	}
34 
35     *pMarkName= &(df->dfInstructions.fiComponents[1].icBuffer);
36 
37     if  ( df->dfInstructions.fiComponentCount > 2 )
38 	{ LDEB(df->dfInstructions.fiComponentCount);	}
39 
40     return 0;
41     }
42 
43 /************************************************************************/
44 /*									*/
45 /*  Is this field a Toc bookmark?					*/
46 /*									*/
47 /************************************************************************/
48 
docIsTocBookmark(long * pId,const DocumentField * df)49 int docIsTocBookmark(	long *				pId,
50 			const DocumentField *		df )
51     {
52     char *			past;
53     long			id;
54 
55     const char *		markName;
56     int				markSize;
57 
58     if  ( df->dfKind != DOCfkBOOKMARK			||
59 	  df->dfInstructions.fiComponentCount < 2	)
60 	{ return -1;	}
61 
62     markName= (const char *)df->dfInstructions.fiComponents[1].icBuffer.mbBytes;
63     markSize= df->dfInstructions.fiComponents[1].icBuffer.mbSize;
64 
65     if  ( strncmp( markName, "_Toc", 4 ) )
66 	{ return 0;	}
67 
68     id= strtod( markName+ 4, &past );
69     if  ( past == markName+ 4 )
70 	{ return 0;	}
71     if  ( past- markName < markSize )
72 	{ return 0;	}
73 
74     if  ( pId )
75 	{ *pId= id;	}
76 
77     return 1;
78     }
79 
docFieldMatchesBookmark(const DocumentField * df,const MemoryBuffer * markName)80 int docFieldMatchesBookmark(	const DocumentField *		df,
81 				const MemoryBuffer *		markName )
82     {
83     int				rval= 0;
84     const MemoryBuffer *	foundName;
85 
86     if  ( df->dfKind == DOCfkBOOKMARK )
87 	{
88 	if  ( ! docFieldGetBookmark( &foundName, df )		&&
89 	      ! utilMemoryCompareBuffers( foundName, markName )	)
90 	    { rval= 1;	}
91 	}
92 
93     return rval;
94     }
95 
docSetBookmarkField(FieldInstructions * fi,const MemoryBuffer * mb)96 int docSetBookmarkField(	FieldInstructions *	fi,
97 				const MemoryBuffer *	mb )
98     {
99     if  ( docStartFieldInstructions( fi, "BOOKMARK", 8 ) )
100 	{ LDEB(8); return -1;	}
101 
102     if  ( docFieldInstructionsAddComponent( fi, mb ) )
103 	{ LDEB(1); return -1;	}
104 
105     return 0;
106     }
107 
108 /************************************************************************/
109 
110 # define BKMK( sym ) ( ucdIsL( (sym) ) || ucdIsNd( (sym) ) || (sym) == '_' )
111 
docBookmarkNormalizeBytes(int * pChanged,char * to,const char * from,int left)112 static int docBookmarkNormalizeBytes(	int *			pChanged,
113 					char *			to,
114 					const char *		from,
115 					int			left )
116     {
117     int			done= 0;
118     int			past= 0;
119 
120     unsigned short	symbol;
121     int			step;
122 
123     *pChanged= 0;
124 
125     while( left > 0 )
126 	{
127 	step= uniGetUtf8( &symbol, from );
128 	if  ( step < 1 )
129 	    { LDEB(step); return -1;	}
130 
131 	if  ( BKMK( symbol ) )
132 	    { break;	}
133 
134 	from += step; left -= step;
135 	*pChanged= 1;
136 	}
137 
138     while( left > 0 )
139 	{
140 	while( left > 0 )
141 	    {
142 	    step= uniGetUtf8( &symbol, from );
143 	    if  ( step < 1 )
144 		{ LDEB(step); return -1;	}
145 
146 	    if  ( ! BKMK( symbol ) )
147 		{ break;	}
148 	    if  ( done+ step > DOCmaxBOOKMARK )
149 		{ goto ready;	}
150 
151 	    memcpy( to, from, step );
152 
153 	    to += step; done += step;
154 	    past= done;
155 	    from += step; left -= step;
156 	    }
157 
158 	if  ( left <= 0 || done+ 1 >= DOCmaxBOOKMARK )
159 	    { goto ready;	}
160 
161 	*(to++)= '_'; done++;
162 	from += step; left -= step;
163 	*pChanged= 1;
164 
165 	while( left > 0 )
166 	    {
167 	    step= uniGetUtf8( &symbol, from );
168 	    if  ( step < 1 )
169 		{ LDEB(step); return -1;	}
170 
171 	    if  ( BKMK( symbol ) )
172 		{ break;	}
173 
174 	    from += step; left -= step;
175 	    *pChanged= 1;
176 	    }
177 	}
178 
179   ready:
180 
181     if  ( left > 0 )
182 	{ *pChanged= 1;	}
183 
184     return past;
185     }
186 
187 /************************************************************************/
188 /*									*/
189 /*  Bring a bookmark in a generally accepted format.			*/
190 /*  I.E: Replace everything that is not isalnum() and truncate to	*/
191 /*  DOCmaxBOOKMARK.							*/
192 /*									*/
193 /************************************************************************/
194 
docAdaptBookmarkName(MemoryBuffer * markName)195 int docAdaptBookmarkName(	MemoryBuffer *		markName )
196     {
197     char *		buf= (char *)markName->mbBytes;
198     int			changed= 0;
199     int			done;
200 
201     done= docBookmarkNormalizeBytes( &changed, buf, buf, markName->mbSize );
202 
203     utilMemoryBufferSetSize( markName, done );
204     return changed;
205     }
206 
207 /************************************************************************/
208 /*									*/
209 /*  Derive a nice bookmark from the document text.			*/
210 /*									*/
211 /************************************************************************/
212 
docBookmarkFromText(MemoryBuffer * markName,const char * text,int len)213 int docBookmarkFromText(	MemoryBuffer *		markName,
214 				const char *		text,
215 				int			len )
216     {
217     char	scratch[DOCmaxBOOKMARK+ 1];
218     int		done;
219     int		changed= 0;
220 
221     done= docBookmarkNormalizeBytes( &changed, scratch, text, len );
222 
223     if  ( done < 4 )
224 	{ memcpy( scratch, "bkmk", 5 ); done= 4;	}
225 
226     if  ( utilMemoryBufferSetBytes( markName, (unsigned char *)scratch, done ) )
227 	{ LDEB(done); return -1;	}
228 
229     return 0;
230     }
231 
232 /************************************************************************/
233 /*									*/
234 /*  Return a suitable index for inserting a suffix to make the bookmark	*/
235 /*  unique.								*/
236 /*									*/
237 /*  We want to use 'wanted' bytes for the suffix.			*/
238 /*									*/
239 /*  1)  If the suffix fits after the bookmark, return the end of the	*/
240 /*	bookmark.							*/
241 /*  2)  Otherwise, look for the last position that leaves space.	*/
242 /*									*/
243 /************************************************************************/
244 
docBookmarkSuffixIndex(const MemoryBuffer * markName,int wanted)245 int docBookmarkSuffixIndex(		const MemoryBuffer *	markName,
246 					int			wanted )
247     {
248     const char *	buf= (char *)markName->mbBytes;
249     int			offset= 0;
250 
251     /*  1  */
252     if  ( markName->mbSize+ wanted < DOCmaxBOOKMARK )
253 	{ return markName->mbSize;	}
254 
255     while( offset < markName->mbSize )
256 	{
257 	unsigned short	symbol;
258 	int		step= uniGetUtf8( &symbol, buf );
259 
260 	if  ( step < 1 )
261 	    { LDEB(step); return offset;	}
262 	if  ( offset+ step+ wanted >= DOCmaxBOOKMARK )
263 	    { return offset;	}
264 
265 	offset += step; buf += step;
266 	}
267 
268     LLLDEB(markName->mbBytes,wanted,DOCmaxBOOKMARK);
269     return -1;
270     }
271