revert between 56095 -> 55830 in arch
[AROS.git] / workbench / tools / Edit / Memory.c
blob1c296ed5ee61c882cd94cbb2b8876405901c744d
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 **************************************************************/
7 #include "Memory.h"
8 #include "Project.h"
9 #include "Utility.h"
10 #include "Cursor.h"
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;
18 LINE *new;
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;
28 new->flags=0;
29 } else { FreeMem(new, sizeof(*new)); return NULL; }
31 return new;
34 /*** Simplified line creation ***/
35 LINE *new_line( LINE *prev )
37 LINE *new;
38 if(NULL != (new = (LINE *) AllocMem(sizeof(*new), MEMF_PUBLIC)))
40 new->max = 0;
41 new->flags = 0;
42 InsertAfter(prev, new);
44 return 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)))
56 ln->stream = new;
57 else
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 */
64 return size;
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)
77 register LINE *ln;
78 for(ln=next; ln; ln=next)
80 next=ln->next;
81 /* free_line(ln); */
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;
95 register ULONG oldsz;
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);
103 else return FALSE;
104 } else
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;
109 return TRUE;
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);
127 } else
128 return FALSE; /* Nothing change */
130 } else
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);
136 return TRUE;
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,
144 size = ln->size-pos;
145 LINE *ln2;
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);
155 } else {
156 free_line(ln2);
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);
163 } else return FALSE;
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)
172 ULONG i; STRPTR str;
173 for(str=string, i=0, buf[0]=pos, buf[1]=0; i<lg; str++, i++)
174 if(*str=='\n')
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! */
179 else return FALSE;
182 /* Some bytes left */
183 if(string < str) {
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;
189 return TRUE;
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;
196 pos = x2pos(ln,pos);
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;
201 if(ln->next) {
202 ln=ln->next; insln: lg = find_nbc(ln, pos);
203 if( !insert_str(jb, ln,lg,string,str-string) )
204 return FALSE;
205 if( isf )
207 buf[1]--;
208 isf=0;
210 buf[0]=lg+str-string;
211 } else {
212 /* Not enough lines, creates one */
213 LINE *new;
214 if(NULL != (new = create_line(string,buf[0]=str-string))) {
215 if( jb ) reg_add_chars(jb, new, 0, buf[0]+1);
216 InsertAfter(ln, new);
217 ln=new; buf[2]++;
219 else return FALSE;
221 string=str+1; buf[1]++;
224 /* Some bytes left (might not happen) */
225 if(string < str) { i=0; goto flush_ln; }
227 return TRUE;
230 /*** Modification of characters ***/
231 BOOL replace_char(LINE *ln, ULONG pos, UBYTE newchar)
233 ln->stream[pos] = newchar;
234 return TRUE;
237 /*** like previous, but with multiple replacement ***/
238 BOOL replace_chars(LINE *ln, ULONG s, ULONG e, UBYTE (*change)(UBYTE))
240 register UBYTE *buf;
241 for(buf=ln->stream+s; s < e; s++,buf++)
242 *buf = change(*buf);
243 return TRUE;
246 /*** Remove chars from pos s to e, including limits (s>=e) ***/
247 BOOL rem_chars(JBuf jb, LINE *ln, ULONG s, ULONG e)
249 ULONG size = ln->size-(e-s+1);
250 UBYTE *old = ln->stream;
252 if( jb ) reg_rem_chars(jb, ln, s, e);
253 /* Adjust the buffer to not be too much large */
254 if((ULONG) (ln->max-size) >= GRANULARITY)
255 /* Reduces its size, to keep minimal mem usage */
256 if(KERNEL_PANIC != (size = realloc_stream(ln, size)))
257 /* Copy beginning of line */
258 CopyMem(old, ln->stream, s);
259 else return FALSE;
260 else ln->size=size;
262 /* Copy end of line */
263 if(s < ln->size) CopyMem(old+e+1, ln->stream+s, ln->size-s);
264 /* Free reallocated chunk */
265 if(old != ln->stream && size>0) FreeMem(old, size);
266 return TRUE;
269 /*** Split line ln at specified position ***/
270 BOOL split_line(JBuf jb, LINE *ln, ULONG pos, ULONG *nbrwc, BYTE indent)
272 LINE *new;
273 LONG spc=0;
274 /* Count the blank chars starting the string */
275 if( indent )
277 register UBYTE *str;
278 for(str=ln->stream; spc<ln->size && (*str=='\t' || *str==' '); spc++, str++);
279 if(spc>pos) spc=pos;
281 if(NULL != (new = create_line(NULL, ln->size-pos+spc)))
283 if( jb ) {
284 if( spc ) reg_group_by( jb );
285 reg_add_chars(jb, ln, pos, 1);
286 if( spc ) reg_add_chars(jb, new, 0, spc), reg_group_by( jb );
288 /* Insert new line in buffer */
289 InsertAfter(ln, new);
290 /* Copy the buffer */
291 if(indent && spc) CopyMem(ln->stream, new->stream, spc);
292 if(pos < ln->size) CopyMem(ln->stream+pos, new->stream+spc, ln->size-pos);
293 ln->size = pos; *nbrwc = spc;
294 return TRUE;
296 return FALSE;
299 /*** Remove an entire line ***/
300 BOOL del_line(JBuf jb, LINE **first, LINE *del)
302 /* Don't delete the last line */
303 if( del->next == NULL )
305 if(del->size && jb) reg_rem_chars(jb, del, 0, del->size-1);
307 /* Keep a minimal edit buffer */
308 if(del->max > GRANULARITY)
310 STRPTR old = del->stream;
311 ULONG sz;
312 if( (sz = realloc_stream(del, 0)) && old!=del->stream )
313 FreeMem(old, sz);
315 else del->size=0;
316 /* Line wasn't entirely removed */
317 return FALSE;
318 } else {
319 /* Remove item from linked list and deallocate it */
320 Destroy(first, del);
321 if( jb ) reg_rem_line(jb, del);
322 else free_line( del );
323 return TRUE;
327 /*** Join two lines ***/
328 BOOL join_lines(JBuf jb, LINE *ln1, LINE *ln2)
330 ULONG size;
331 if( jb ) reg_join_lines(jb, ln1, ln2);
332 /* Is there enough place in ln1 to store ln2? */
333 if( (size = ln1->size + ln2->size) <= ln1->max)
335 /* Yes, just store ln2 after ln1 */
336 CopyMem(ln2->stream, ln1->stream+ln1->size, ln2->size);
337 ln1->size = size;
338 } else {
339 STRPTR old = ln1->stream;
340 ULONG nbc = ln1->size;
341 /* Need to realloc the stream */
342 if(KERNEL_PANIC != (size = realloc_stream(ln1, size)))
344 CopyMem(old, ln1->stream, nbc);
345 CopyMem(ln2->stream, ln1->stream+nbc, ln2->size);
346 if(size > 0) FreeMem(old, size);
347 } else return FALSE;
349 /* Remove the line ln2 (ln2 is never the first line) */
350 Destroy(NULL, ln2);
351 if(jb == NULL) free_line( ln2 );
352 return TRUE;
355 /*** Simple total lines and bytes count ***/
356 ULONG size_count( LINE *first, BYTE szEOL )
358 register ULONG i;
359 register LINE *ln;
360 for(i=0, ln=first; ln; i+=ln->size+szEOL, ln=ln->next);
361 return i-szEOL;