1 /************************************************************************/
2 /*									*/
3 /*  Get/Move/Set Selections in paragraphs.				*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docBufConfig.h"
8 
9 #   include	<appDebugon.h>
10 
11 #   include	"docBuf.h"
12 #   include	"docDebug.h"
13 #   include	"docParaParticules.h"
14 #   include	"docParaString.h"
15 #   include	"docNodeTree.h"
16 
17 #   define DOCisADMINISTRATIVE(k) \
18 	    ( (k) == DOCkindFIELDHEAD || (k) == DOCkindFIELDTAIL )
19 
20 /*  Navigate to the next valid document position.			*/
21 
22 /************************************************************************/
23 /*									*/
24 /*  Return the next selectable string offset in the document.		*/
25 /*									*/
26 /*  Positions inside an UTF-8 sequence and positions between		*/
27 /*  administrative particules are invalid.				*/
28 /*  This means that hopping over an administrative particule is not a	*/
29 /*  step that counts.							*/
30 /*									*/
31 /************************************************************************/
32 
docGotoNextPosition(DocumentPosition * dp)33 int docGotoNextPosition(	DocumentPosition *	dp )
34     {
35     BufferItem *	paraNode= dp->dpNode;
36     int			stroff= dp->dpStroff;
37     int			tail= docParaLastStroff( paraNode );
38 
39     if  ( stroff >= tail )
40 	{ stroff= -1;	}
41 
42     while( stroff >= 0 && stroff < tail )
43 	{
44 	DocumentPosition	dpNext;
45 	int			part;
46 
47 	stroff= docParaNextStroff( paraNode, stroff );
48 	if  ( stroff < 0 )
49 	    { break;	}
50 
51 	docSetDocumentPosition( &dpNext, (BufferItem *)paraNode, stroff );
52 	if  ( docFindParticuleOfPosition( &part, (int *)0,
53 						    &dpNext, PARAfindFIRST ) )
54 	    { LDEB(1); return -1;	}
55 
56 	if  ( ! DOCisADMINISTRATIVE( paraNode->biParaParticules[part].tpKind ) )
57 	    { break;	}
58 	}
59 
60     while( paraNode )
61 	{
62 	if  ( stroff >= 0 && stroff <= tail )
63 	    {
64 	    docSetDocumentPosition( dp, paraNode, stroff );
65 	    return 0;
66 	    }
67 
68 	paraNode= docNextParagraph( paraNode );
69 	if  ( ! paraNode )
70 	    { break;	}
71 
72 	stroff= docParaFirstStroff( paraNode );
73 	tail= docParaLastStroff( paraNode );
74 
75 	if  ( docParaStrlen( paraNode ) == 0 )
76 	    {
77 	    docSetDocumentPosition( dp, paraNode, stroff );
78 	    return 0;
79 	    }
80 	}
81 
82     return -1;
83     }
84 
docNextPosition(DocumentPosition * dp)85 int docNextPosition(	DocumentPosition *	dp )
86     {
87     BufferItem *	paraNode= dp->dpNode;
88     int			stroff= dp->dpStroff;
89     int			tail= docParaLastStroff( paraNode );
90 
91     if  ( stroff >= tail )
92 	{ stroff= -1;	}
93 
94     if  ( stroff >= 0 && stroff < tail )
95 	{ stroff= docParaNextStroff( paraNode, stroff );	}
96 
97     while( paraNode )
98 	{
99 	if  ( stroff >= 0 && stroff <= tail )
100 	    {
101 	    docSetDocumentPosition( dp, paraNode, stroff );
102 	    return 0;
103 	    }
104 
105 	paraNode= docNextParagraph( paraNode );
106 	if  ( ! paraNode )
107 	    { break;	}
108 
109 	stroff= 0;
110 	tail= docParaStrlen( paraNode );
111 
112 	if  ( docParaStrlen( paraNode ) == 0 )
113 	    {
114 	    docSetDocumentPosition( dp, paraNode, stroff );
115 	    return 0;
116 	    }
117 	}
118 
119     return -1;
120     }
121 
122 /************************************************************************/
123 /*									*/
124 /*  Return the previous valid string offset in the paragraph.		*/
125 /*									*/
126 /*  Positions inside an UTF-8 sequence and positions between		*/
127 /*  administrative particules are invalid.				*/
128 /*  This means that hopping over an administrative particule is not a	*/
129 /*  step that counts.							*/
130 /*									*/
131 /************************************************************************/
132 
docGotoPrevPosition(DocumentPosition * dp)133 int docGotoPrevPosition(	DocumentPosition *	dp )
134     {
135     BufferItem *	paraNode= dp->dpNode;
136     int			stroff= dp->dpStroff;
137 
138     int			head= docParaFirstStroff( paraNode );
139 
140     if  ( stroff <= head )
141 	{ stroff= -1;	}
142 
143     while( stroff > head )
144 	{
145 	DocumentPosition	dpPrev;
146 	int			part;
147 
148 	stroff= docParaPrevStroff( paraNode, stroff );
149 	if  ( stroff < 0 )
150 	    { break;	}
151 
152 	docSetDocumentPosition( &dpPrev, (BufferItem *)paraNode, stroff );
153 	if  ( docFindParticuleOfPosition( &part, (int *)0,
154 						    &dpPrev, PARAfindLAST ) )
155 	    { LDEB(1); return -1;	}
156 
157 	if  ( ! DOCisADMINISTRATIVE( paraNode->biParaParticules[part].tpKind ) )
158 	    { break;	}
159 	}
160 
161     while( paraNode )
162 	{
163 	if  ( stroff >= head )
164 	    {
165 	    docSetDocumentPosition( dp, paraNode, stroff );
166 	    return 0;
167 	    }
168 
169 	paraNode= docPrevParagraph( paraNode );
170 	if  ( paraNode )
171 	    {
172 	    stroff= docParaLastStroff( paraNode );
173 	    head= docParaFirstStroff( paraNode );
174 	    }
175 	}
176 
177     return -1;
178     }
179 
docPrevPosition(DocumentPosition * dp)180 int docPrevPosition(	DocumentPosition *	dp )
181     {
182     BufferItem *	paraNode= dp->dpNode;
183     int			stroff= dp->dpStroff;
184 
185     const int		head= 0;
186 
187     if  ( stroff <= head )
188 	{ stroff= -1;	}
189 
190     if  ( stroff >= head )
191 	{
192 	stroff= docParaPrevStroff( paraNode, stroff );
193 	}
194 
195     while( paraNode )
196 	{
197 	if  ( stroff >= head )
198 	    {
199 	    docSetDocumentPosition( dp, paraNode, stroff );
200 	    return 0;
201 	    }
202 
203 	paraNode= docPrevParagraph( paraNode );
204 	if  ( paraNode )
205 	    { stroff= docParaStrlen( paraNode ); }
206 	}
207 
208     return -1;
209     }
210 
211 /************************************************************************/
212 /*									*/
213 /*  Return the first selectable string offset in the paragraph.		*/
214 /*									*/
215 /*  Return 0, or the position after a series of administrative		*/
216 /*  particules.								*/
217 /*									*/
218 /************************************************************************/
219 
docParaFirstStroff(const BufferItem * paraNode)220 int docParaFirstStroff(	const BufferItem *	paraNode )
221     {
222     int		stroff= 0;
223     int		part= 0;
224 
225     while( part < paraNode->biParaParticuleCount				&&
226 	   DOCisADMINISTRATIVE(paraNode->biParaParticules[part].tpKind)	)
227 	{
228 	stroff= paraNode->biParaParticules[part].tpStroff+
229 				    paraNode->biParaParticules[part].tpStrlen;
230 	part++;
231 	}
232 
233     return stroff;
234     }
235 
236 /************************************************************************/
237 /*									*/
238 /*  Return the last selectable string offset in the paragraph.		*/
239 /*									*/
240 /*  Return the last position in the paragraph or the position before	*/
241 /*  a series of administrative particules.				*/
242 /*									*/
243 /************************************************************************/
244 
docParaLastStroff(const BufferItem * paraNode)245 int docParaLastStroff(	const BufferItem *	paraNode )
246     {
247     int		stroff= docParaStrlen( paraNode );
248     int		part= paraNode->biParaParticuleCount- 1;
249 
250     if  ( part < 0 )
251 	{ LDEB(part); docListNode(0,paraNode,0); return -1;	}
252 
253     while( part >= 0							&&
254 	   DOCisADMINISTRATIVE(paraNode->biParaParticules[part].tpKind)	)
255 	{
256 	stroff= paraNode->biParaParticules[part].tpStroff;
257 	part--;
258 	}
259 
260     return stroff;
261     }
262 
263