1 /**************************************************************
2 **** memory.c: memory allocation of edited file. Critical! ****
3 **** Free software under GNU license, written in 15/2/2000 ****
4 **** © T.Pierron, C.Guillaume. ****
5 **************************************************************/
11 #include "ProtoTypes.h"
13 /*** Allocate a new line filled with "bytes" of "size" length ***/
14 LINE
*create_line(STRPTR bytes
, ULONG size
)
16 /* Round the size to the wanted granularity */
17 register ULONG rsize
= (size
& ~(GRANULARITY
-1)) + GRANULARITY
;
20 /* Allocate struct & buf */
21 if(NULL
!= (new = (LINE
*) AllocMem(sizeof(*new), MEMF_PUBLIC
)))
23 if(NULL
!= (new->stream
= (UBYTE
*) AllocMem(rsize
, MEMF_PUBLIC
)))
25 /* The line has been fully allocated! */
26 if(bytes
) CopyMem(bytes
, new->stream
, size
);
27 new->size
=size
; new->max
=rsize
;
29 } else { FreeMem(new, sizeof(*new)); return NULL
; }
34 /*** Simplified line creation ***/
35 LINE
*new_line( LINE
*prev
)
38 if(NULL
!= (new = (LINE
*) AllocMem(sizeof(*new), MEMF_PUBLIC
)))
42 InsertAfter(prev
, new);
47 /*** Try to resize the memory chunk of text, PRI-VA-TE! ***/
48 static ULONG
realloc_stream(LINE
*ln
, ULONG size
)
50 UBYTE
*new; ULONG rsize
;
51 /* Always adjust size to the granularity of mem */
52 rsize
= (size
& ~(GRANULARITY
-1)) + GRANULARITY
;
54 /* Don't free old stream, it's still needed */
55 if(NULL
!= (new = (UBYTE
*) AllocMem(rsize
, MEMF_PUBLIC
)))
58 /* Try to reduce disaster */
59 if( size
<= ln
->max
) rsize
=ln
->max
;
60 else return KERNEL_PANIC
;
62 ln
->size
=size
; size
=ln
->max
; ln
->max
=rsize
;
63 /* Return the size of old chunk that is going to be deallocated */
67 /*** Low-level deallocation function ***/
68 void free_line(LINE
*ln
)
70 if(ln
->max
) FreeMem(ln
->stream
, ln
->max
);
71 FreeMem(ln
, sizeof(*ln
));
74 /*** Free all allocated memory ***/
75 void trash_file(LINE
*next
)
78 for(ln
=next
; ln
; ln
=next
)
82 if(ln
->max
) FreeMem(ln
->stream
, ln
->max
);
83 FreeMem(ln
, sizeof(*ln
));
87 /*** Add a char in a line ***/
88 BOOL
add_char(JBuf jb
, LINE
*ln
, ULONG pos
, UBYTE newchar
)
90 /* Is there enough place to store the new char? */
91 if(ln
->size
>= ln
->max
)
93 /* A reallocation is needed */
94 register STRPTR oldbuf
= ln
->stream
;
97 if(KERNEL_PANIC
!= (oldsz
= realloc_stream(ln
, ln
->size
+1)))
99 if(pos
) CopyMem(oldbuf
, ln
->stream
, pos
);
100 CopyMem(oldbuf
+pos
, ln
->stream
+pos
+1, ln
->size
-pos
-1);
101 if(oldsz
> 0) FreeMem(oldbuf
, oldsz
);
105 MemMove(ln
->stream
+pos
,1,ln
->size
-pos
), ln
->size
++;
107 if( jb
) reg_add_chars(jb
, ln
, pos
, 1);
108 ln
->stream
[pos
] = newchar
;
112 /*** Like previous but a whole byte stream this time ***/
113 BOOL
insert_str(JBuf jb
, LINE
*ln
, ULONG pos
, STRPTR str
, ULONG lg
)
115 /* Is there enough place to store the string? */
116 if(ln
->size
+lg
>ln
->max
)
118 register STRPTR oldbuf
= ln
->stream
;
119 register ULONG oldsz
;
121 /* If realloc failed, don't change anything */
122 if(KERNEL_PANIC
!= (oldsz
= realloc_stream(ln
, ln
->size
+lg
)))
124 if(pos
) CopyMem(oldbuf
, ln
->stream
, pos
);
125 CopyMem(oldbuf
+pos
, ln
->stream
+pos
+lg
, ln
->size
-pos
-lg
);
126 if(oldsz
> 0) FreeMem(oldbuf
, oldsz
);
128 return FALSE
; /* Nothing change */
131 /* Just shifts the buffer */
132 MemMove(ln
->stream
+pos
,lg
,ln
->size
-pos
), ln
->size
+=lg
;
134 if( jb
) reg_add_chars(jb
, ln
, pos
, lg
);
135 CopyMem(str
,ln
->stream
+pos
,lg
);
139 /*** Like previous, but what's left after pos in ln is stored in a new line ***/
140 BOOL
break_line(JBuf jb
, LINE
*ln
, ULONG pos
, STRPTR str
, ULONG lg
)
142 STRPTR oldbuf
= ln
->stream
;
143 ULONG rsize
= ((pos
+lg
) & ~(GRANULARITY
-1)) + GRANULARITY
,
147 /* Add rest of line in a new string */
148 if(NULL
!= (ln2
= create_line(oldbuf
+ pos
, size
)))
150 if( rsize
!= ln
->max
)
151 /* If realloc failed, don't change anything */
152 if(KERNEL_PANIC
!= (rsize
= realloc_stream(ln
, pos
+lg
)))
154 if(pos
) CopyMem(oldbuf
, ln
->stream
, pos
);
157 return FALSE
; /* Nothing change */
159 else ln
->size
= pos
+ lg
;
160 InsertAfter(ln
, ln2
);
161 if( jb
) reg_add_chars(jb
, ln
, pos
, lg
+1);
162 CopyMem(str
, ln
->stream
+pos
, lg
);
165 if(oldbuf
!= ln
->stream
&& rsize
>0) FreeMem(oldbuf
, rsize
);
166 return (BOOL
)(str
!=NULL
);
169 /*** Add a whole string, taking care of newline ***/
170 BOOL
add_string(JBuf jb
, LINE
*ln
, ULONG pos
, STRPTR string
, ULONG lg
, LONG
*buf
)
173 for(str
=string
, i
=0, buf
[0]=pos
, buf
[1]=0; i
<lg
; str
++, i
++)
176 /* Add string at pos and copy rest of line to a new one */
177 if(break_line(jb
,ln
,pos
,string
,str
-string
)) string
=str
+1,pos
=0,ln
=ln
->next
,buf
[1]++;
178 /* Fucking memory failure! */
182 /* Some bytes left */
184 if( !insert_str(jb
, ln
,pos
,string
,str
-string
) ) return FALSE
;
185 else buf
[0] = str
-string
;
188 if( 0 == (buf
[2] = buf
[1]) ) buf
[0] += pos
;
192 /*** Add a block, taking care of newline ***/
193 BOOL
add_block(JBuf jb
, LINE
*ln
, ULONG pos
, STRPTR string
, ULONG lg
, LONG
*buf
)
195 ULONG i
; STRPTR str
; char isf
;
197 for(str
=string
, i
=lg
, buf
[1]=buf
[2]=0, isf
=1; i
--; str
++)
198 if(*str
=='\r') { flush_ln
:
199 /* First text insertion, must be done on current line */
200 if( isf
) goto insln
;
202 ln
=ln
->next
; insln
: lg
= find_nbc(ln
, pos
);
203 if( !insert_str(jb
, ln
,lg
,string
,str
-string
) ) return FALSE
;
204 if( isf
) buf
[1]--,isf
=0; buf
[0]=lg
+str
-string
;
206 /* Not enough lines, creates one */
208 if(NULL
!= (new = create_line(string
,buf
[0]=str
-string
))) {
209 if( jb
) reg_add_chars(jb
, new, 0, buf
[0]+1);
210 InsertAfter(ln
, new);
215 string
=str
+1; buf
[1]++;
218 /* Some bytes left (might not happen) */
219 if(string
< str
) { i
=0; goto flush_ln
; }
224 /*** Modification of characters ***/
225 BOOL
replace_char(LINE
*ln
, ULONG pos
, UBYTE newchar
)
227 ln
->stream
[pos
] = newchar
;
231 /*** like previous, but with multiple replacement ***/
232 BOOL
replace_chars(LINE
*ln
, ULONG s
, ULONG e
, UBYTE (*change
)(UBYTE
))
235 for(buf
=ln
->stream
+s
; s
< e
; s
++,buf
++)
240 /*** Remove chars from pos s to e, including limits (s>=e) ***/
241 BOOL
rem_chars(JBuf jb
, LINE
*ln
, ULONG s
, ULONG e
)
243 ULONG size
= ln
->size
-(e
-s
+1);
244 UBYTE
*old
= ln
->stream
;
246 if( jb
) reg_rem_chars(jb
, ln
, s
, e
);
247 /* Adjust the buffer to not be too much large */
248 if((ULONG
) (ln
->max
-size
) >= GRANULARITY
)
249 /* Reduces its size, to keep minimal mem usage */
250 if(KERNEL_PANIC
!= (size
= realloc_stream(ln
, size
)))
251 /* Copy beginning of line */
252 CopyMem(old
, ln
->stream
, s
);
256 /* Copy end of line */
257 if(s
< ln
->size
) CopyMem(old
+e
+1, ln
->stream
+s
, ln
->size
-s
);
258 /* Free reallocated chunk */
259 if(old
!= ln
->stream
&& size
>0) FreeMem(old
, size
);
263 /*** Split line ln at specified position ***/
264 BOOL
split_line(JBuf jb
, LINE
*ln
, ULONG pos
, ULONG
*nbrwc
, BYTE indent
)
268 /* Count the blank chars starting the string */
272 for(str
=ln
->stream
; spc
<ln
->size
&& (*str
=='\t' || *str
==' '); spc
++, str
++);
275 if(NULL
!= (new = create_line(NULL
, ln
->size
-pos
+spc
)))
278 if( spc
) reg_group_by( jb
);
279 reg_add_chars(jb
, ln
, pos
, 1);
280 if( spc
) reg_add_chars(jb
, new, 0, spc
), reg_group_by( jb
);
282 /* Insert new line in buffer */
283 InsertAfter(ln
, new);
284 /* Copy the buffer */
285 if(indent
&& spc
) CopyMem(ln
->stream
, new->stream
, spc
);
286 if(pos
< ln
->size
) CopyMem(ln
->stream
+pos
, new->stream
+spc
, ln
->size
-pos
);
287 ln
->size
= pos
; *nbrwc
= spc
;
293 /*** Remove an entire line ***/
294 BOOL
del_line(JBuf jb
, LINE
**first
, LINE
*del
)
296 /* Don't delete the last line */
297 if( del
->next
== NULL
)
299 if(del
->size
&& jb
) reg_rem_chars(jb
, del
, 0, del
->size
-1);
301 /* Keep a minimal edit buffer */
302 if(del
->max
> GRANULARITY
)
304 STRPTR old
= del
->stream
;
306 if( (sz
= realloc_stream(del
, 0)) && old
!=del
->stream
)
310 /* Line wasn't entirely removed */
313 /* Remove item from linked list and deallocate it */
315 if( jb
) reg_rem_line(jb
, del
);
316 else free_line( del
);
321 /*** Join two lines ***/
322 BOOL
join_lines(JBuf jb
, LINE
*ln1
, LINE
*ln2
)
325 if( jb
) reg_join_lines(jb
, ln1
, ln2
);
326 /* Is there enough place in ln1 to store ln2? */
327 if( (size
= ln1
->size
+ ln2
->size
) <= ln1
->max
)
329 /* Yes, just store ln2 after ln1 */
330 CopyMem(ln2
->stream
, ln1
->stream
+ln1
->size
, ln2
->size
);
333 STRPTR old
= ln1
->stream
;
334 ULONG nbc
= ln1
->size
;
335 /* Need to realloc the stream */
336 if(KERNEL_PANIC
!= (size
= realloc_stream(ln1
, size
)))
338 CopyMem(old
, ln1
->stream
, nbc
);
339 CopyMem(ln2
->stream
, ln1
->stream
+nbc
, ln2
->size
);
340 if(size
> 0) FreeMem(old
, size
);
343 /* Remove the line ln2 (ln2 is never the first line) */
345 if(jb
== NULL
) free_line( ln2
);
349 /*** Simple total lines and bytes count ***/
350 ULONG
size_count( LINE
*first
, BYTE szEOL
)
354 for(i
=0, ln
=first
; ln
; i
+=ln
->size
+szEOL
, ln
=ln
->next
);