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