- Now puts cursor position in window title properly instead of overwriting
[tangerine.git] / workbench / tools / Edit / Memory.c
blob27f4b237e5ebbf3e22879ba9efdf287c97331025
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) ) return FALSE;
204 if( isf ) buf[1]--,isf=0; buf[0]=lg+str-string;
205 } else {
206 /* Not enough lines, creates one */
207 LINE *new;
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);
211 ln=new; buf[2]++;
213 else return FALSE;
215 string=str+1; buf[1]++;
218 /* Some bytes left (might not happen) */
219 if(string < str) { i=0; goto flush_ln; }
221 return TRUE;
224 /*** Modification of characters ***/
225 BOOL replace_char(LINE *ln, ULONG pos, UBYTE newchar)
227 ln->stream[pos] = newchar;
228 return TRUE;
231 /*** like previous, but with multiple replacement ***/
232 BOOL replace_chars(LINE *ln, ULONG s, ULONG e, UBYTE (*change)(UBYTE))
234 register UBYTE *buf;
235 for(buf=ln->stream+s; s < e; s++,buf++)
236 *buf = change(*buf);
237 return TRUE;
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);
253 else return FALSE;
254 else ln->size=size;
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);
260 return TRUE;
263 /*** Split line ln at specified position ***/
264 BOOL split_line(JBuf jb, LINE *ln, ULONG pos, ULONG *nbrwc, BYTE indent)
266 LINE *new;
267 LONG spc=0;
268 /* Count the blank chars starting the string */
269 if( indent )
271 register UBYTE *str;
272 for(str=ln->stream; spc<ln->size && (*str=='\t' || *str==' '); spc++, str++);
273 if(spc>pos) spc=pos;
275 if(NULL != (new = create_line(NULL, ln->size-pos+spc)))
277 if( jb ) {
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;
288 return TRUE;
290 return FALSE;
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;
305 ULONG sz;
306 if( (sz = realloc_stream(del, 0)) && old!=del->stream )
307 FreeMem(old, sz);
309 else del->size=0;
310 /* Line wasn't entirely removed */
311 return FALSE;
312 } else {
313 /* Remove item from linked list and deallocate it */
314 Destroy(first, del);
315 if( jb ) reg_rem_line(jb, del);
316 else free_line( del );
317 return TRUE;
321 /*** Join two lines ***/
322 BOOL join_lines(JBuf jb, LINE *ln1, LINE *ln2)
324 ULONG size;
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);
331 ln1->size = size;
332 } else {
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);
341 } else return FALSE;
343 /* Remove the line ln2 (ln2 is never the first line) */
344 Destroy(NULL, ln2);
345 if(jb == NULL) free_line( ln2 );
346 return TRUE;
349 /*** Simple total lines and bytes count ***/
350 ULONG size_count( LINE *first, BYTE szEOL )
352 register ULONG i;
353 register LINE *ln;
354 for(i=0, ln=first; ln; i+=ln->size+szEOL, ln=ln->next);
355 return i-szEOL;