1 // Selection list management functions
2 // Copyright (C) 2000 Core Technologies.
3 
4 // This file is part of e93.
5 //
6 // e93 is free software; you can redistribute it and/or modify
7 // it under the terms of the e93 LICENSE AGREEMENT.
8 //
9 // e93 is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // e93 LICENSE AGREEMENT for more details.
13 //
14 // You should have received a copy of the e93 LICENSE AGREEMENT
15 // along with e93; see the file "LICENSE.TXT".
16 
17 #include	"includes.h"
18 
19 typedef struct selectionElement
20 {
21 	SPARSE_ARRAY_HEADER
22 		saHeader;					// only need the header
23 } SELECTION_ELEMENT;
24 
25 typedef struct selectionUniverse
26 {
27 	UINT32
28 		cursorPosition;				// if there is no selection, this is the cursor's position
29 	SPARSE_ARRAY
30 		selectionArray;
31 } SELECTION_UNIVERSE;
32 
33 enum
34 {
35 	DUPLICATE_NAME
36 };
37 
38 static const char *errorDescriptions[]=
39 {
40 	"Duplicate mark names are not allowed"
41 };
42 
DeleteAllSelections(SELECTION_UNIVERSE * universe)43 void DeleteAllSelections(SELECTION_UNIVERSE *universe)
44 // Remove all selections from universe
45 {
46 	DeleteSARange(&universe->selectionArray,0,universe->selectionArray.totalElements);
47 }
48 
DeleteSelectionRange(SELECTION_UNIVERSE * universe,UINT32 startPosition,UINT32 numElements)49 void DeleteSelectionRange(SELECTION_UNIVERSE *universe,UINT32 startPosition,UINT32 numElements)
50 // Remove selection array elements from startPosition for numElements
51 // NOTE: this does not mind being called for positions outside of the current array
52 // This pulls the remaining array elements to the left.
53 {
54 	DeleteSARange(&universe->selectionArray,startPosition,numElements);
55 }
56 
InsertSelectionRange(SELECTION_UNIVERSE * universe,UINT32 startPosition,UINT32 numElements)57 bool InsertSelectionRange(SELECTION_UNIVERSE *universe,UINT32 startPosition,UINT32 numElements)
58 // insert numElements into the selection array at startPosition
59 // the elements inserted will be selected if the insertion was inside a current selection
60 // This pushes the existing array elements after startPosition to the right.
61 {
62 	return(InsertSARange(&universe->selectionArray,startPosition,numElements));
63 }
64 
ClearSelectionRange(SELECTION_UNIVERSE * universe,UINT32 startPosition,UINT32 numElements)65 bool ClearSelectionRange(SELECTION_UNIVERSE *universe,UINT32 startPosition,UINT32 numElements)
66 // clear selection at startPosition for numElements of universe
67 // if there is a problem, return false
68 {
69 	return(ClearSARange(&universe->selectionArray,startPosition,numElements));
70 }
71 
SetSelectionRange(SELECTION_UNIVERSE * universe,UINT32 startPosition,UINT32 numElements)72 bool SetSelectionRange(SELECTION_UNIVERSE *universe,UINT32 startPosition,UINT32 numElements)
73 // set selection at startPosition for numElements of universe
74 // if there is a problem, return false
75 // the selection will overwrite anything currently in the array at
76 // the given positions (no insertion (right shift) is performed)
77 {
78 	SELECTION_ELEMENT
79 		element;
80 
81 	return(SetSARange(&universe->selectionArray,startPosition,numElements,&element));
82 }
83 
GetSelectionAtOrAfterPosition(SELECTION_UNIVERSE * universe,UINT32 position,UINT32 * startPosition,UINT32 * numElements)84 bool GetSelectionAtOrAfterPosition(SELECTION_UNIVERSE *universe,UINT32 position,UINT32 *startPosition,UINT32 *numElements)
85 // Return the index of the selection which occupies position,
86 // or the first one after the position if the position is not occupied.
87 // If the passed position is past the end of the array, return false
88 // NOTE: this uses a cache so it is efficient to call
89 // repeatedly for positions which are nearby each other
90 {
91 	SELECTION_ELEMENT
92 		*element;
93 
94 	if(GetSARecordAtOrAfterPosition(&universe->selectionArray,position,startPosition,numElements,(void **)&element))
95 	{
96 		return(true);
97 	}
98 	return(false);
99 }
100 
GetSelectionAtOrBeforePosition(SELECTION_UNIVERSE * universe,UINT32 position,UINT32 * startPosition,UINT32 * numElements)101 bool GetSelectionAtOrBeforePosition(SELECTION_UNIVERSE *universe,UINT32 position,UINT32 *startPosition,UINT32 *numElements)
102 // Return the index of the selection which occupies position,
103 // or the first one before the position if the position is not occupied.
104 // If the passed position is before the first element of the array, return false.
105 // NOTE: this uses a cache so it is efficient to call
106 // repeatedly for positions which are nearby each other
107 {
108 	SELECTION_ELEMENT
109 		*element;
110 
111 	if(GetSARecordAtOrBeforePosition(&universe->selectionArray,position,startPosition,numElements,(void **)&element))
112 	{
113 		return(true);
114 	}
115 	return(false);
116 }
117 
GetSelectionRange(SELECTION_UNIVERSE * universe,UINT32 position,UINT32 * startPosition,UINT32 * numElements,bool * isActive)118 bool GetSelectionRange(SELECTION_UNIVERSE *universe,UINT32 position,UINT32 *startPosition,UINT32 *numElements,bool *isActive)
119 // return the range of positions in the array which include position
120 // and are selected (or not selected) the same as position
121 // NOTE: this uses a cache so it is efficient to call
122 // repeatedly for positions which are nearby each other
123 // NOTE: if position is off the end of the array, isActive will be returned as false,
124 // startPosition will contain the position where the array ended and
125 // this will return false (numElements will not be set)
126 {
127 	SELECTION_ELEMENT
128 		*element;
129 
130 	*isActive=false;
131 	if(GetSARecordForPosition(&universe->selectionArray,position,startPosition,numElements,(void **)&element))
132 	{
133 		if(element)
134 		{
135 			*isActive=true;
136 		}
137 		return(true);
138 	}
139 	return(false);
140 }
141 
GetSelectionAtPosition(SELECTION_UNIVERSE * universe,UINT32 position)142 bool GetSelectionAtPosition(SELECTION_UNIVERSE *universe,UINT32 position)
143 // call this to return the selection at the given position of
144 // the given selection universe.
145 // NOTE: if position is off the end of the array, this will return false.
146 // NOTE: this uses a cache so it is efficient to call
147 // repeatedly for positions which are nearby each other
148 {
149 	UINT32
150 		startPosition,
151 		numElements;
152 	bool
153 		selection;
154 
155 	GetSelectionRange(universe,position,&startPosition,&numElements,&selection);
156 	return(selection);
157 }
158 
IsSelectionEmpty(SELECTION_UNIVERSE * universe)159 bool IsSelectionEmpty(SELECTION_UNIVERSE *universe)
160 // return TRUE if universe contains no selection elements
161 {
162 	return(IsSAEmpty(&universe->selectionArray));
163 }
164 
GetSelectionEndPositions(SELECTION_UNIVERSE * universe,UINT32 * startPosition,UINT32 * endPosition)165 void GetSelectionEndPositions(SELECTION_UNIVERSE *universe,UINT32 *startPosition,UINT32 *endPosition)
166 // return the start and end absolute text positions of the passed selection universe
167 // if there are no selections, then the cursor position is returned as both the start and the end
168 {
169 	if(!GetSAElementEnds(&universe->selectionArray,startPosition,endPosition))
170 	{
171 		(*startPosition)=(*endPosition)=universe->cursorPosition;
172 	}
173 }
174 
GetSelectionCursorPosition(SELECTION_UNIVERSE * universe)175 UINT32 GetSelectionCursorPosition(SELECTION_UNIVERSE *universe)
176 // Get the cursor position for the passed selection universe
177 {
178 	return(universe->cursorPosition);
179 }
180 
SetSelectionCursorPosition(SELECTION_UNIVERSE * universe,UINT32 position)181 void SetSelectionCursorPosition(SELECTION_UNIVERSE *universe,UINT32 position)
182 // Set the cursor position for the passed selection universe
183 {
184 	universe->cursorPosition=position;
185 }
186 
AdjustSelectionsForChange(SELECTION_UNIVERSE * universe,UINT32 startOffset,UINT32 oldEndOffset,UINT32 newEndOffset)187 void AdjustSelectionsForChange(SELECTION_UNIVERSE *universe,UINT32 startOffset,UINT32 oldEndOffset,UINT32 newEndOffset)
188 // given a change at startOffset, run through the given selection list, and fix it up
189 // NOTE: this can cause all the selections to disappear
190 // If it does, then the cursor will be left at the end of the change
191 {
192 	UINT32
193 		startPosition,
194 		endPosition;
195 
196 	if(GetSAElementEnds(&universe->selectionArray,&startPosition,&endPosition))	// if there is some selection, then move the cursor to the start so if the selection goes away, the cursor is left in the correct spot
197 	{
198 		universe->cursorPosition=startPosition;			// push to the start
199 	}
200 
201 	DeleteSelectionRange(universe,startOffset,oldEndOffset-startOffset);
202 	InsertSelectionRange(universe,startOffset,newEndOffset-startOffset);
203 
204 	if(universe->cursorPosition>=startOffset)			// if cursor was before the change, then do not move it
205 	{
206 		if(universe->cursorPosition>oldEndOffset)		// see if cursor was past changed area (move it relatively)
207 		{
208 			universe->cursorPosition=(universe->cursorPosition+newEndOffset)-oldEndOffset;
209 		}
210 		else
211 		{
212 			universe->cursorPosition=newEndOffset;		// if cursor in middle of change, put it at the end
213 		}
214 	}
215 }
216 
CopySelectionUniverse(SELECTION_UNIVERSE * sourceUniverse,SELECTION_UNIVERSE * destUniverse)217 bool CopySelectionUniverse(SELECTION_UNIVERSE *sourceUniverse,SELECTION_UNIVERSE *destUniverse)
218 // copy sourceUniverse to destUniverse
219 // if there is a problem, SetError, and return false
220 // This may be called with sourceUniverse==destUniverse
221 {
222 	bool
223 		fail;
224 	UINT32
225 		startPosition,
226 		numElements;
227 
228 	fail=false;
229 	DeleteAllSelections(destUniverse);
230 	destUniverse->cursorPosition=sourceUniverse->cursorPosition;	// copy the cursor position
231 
232 	startPosition=0;
233 	while(!fail&&GetSelectionAtOrAfterPosition(sourceUniverse,startPosition,&startPosition,&numElements))
234 	{
235 		fail=!SetSelectionRange(destUniverse,startPosition,numElements);
236 		startPosition+=numElements;
237 	}
238 	return(!fail);
239 }
240 
OrSelectionUniverse(SELECTION_UNIVERSE * sourceUniverse,SELECTION_UNIVERSE * destUniverse)241 bool OrSelectionUniverse(SELECTION_UNIVERSE *sourceUniverse,SELECTION_UNIVERSE *destUniverse)
242 // Logical OR sourceUniverse to destUniverse
243 // if there is a problem, SetError, and return false
244 // NOTE: adjacent selection boundaries that are not shared
245 // will be coalesced in the result.
246 // This may be called with sourceUniverse==destUniverse
247 {
248 	bool
249 		fail;
250 	UINT32
251 		startPosition,
252 		numElements;
253 	UINT32
254 		destPosition,
255 		destElements;
256 
257 	fail=false;
258 
259 	startPosition=0;
260 	while(!fail&&GetSelectionAtOrAfterPosition(sourceUniverse,startPosition,&startPosition,&numElements))
261 	{
262 		if(GetSelectionAtOrAfterPosition(destUniverse,startPosition,&destPosition,&destElements))
263 		{
264 			if(destPosition<startPosition)					// if dest selection has a section that extends back from the start, coalesce it in
265 			{
266 				numElements+=startPosition-destPosition;
267 				startPosition=destPosition;
268 			}
269 			if(GetSelectionAtOrAfterPosition(destUniverse,startPosition+numElements,&destPosition,&destElements))
270 			{
271 				if(destPosition<startPosition+numElements)	// if dest selection has a section that extends beyond the end, coalesce it in
272 				{
273 					numElements=destPosition+destElements-startPosition;
274 				}
275 			}
276 		}
277 		fail=!SetSelectionRange(destUniverse,startPosition,numElements);
278 		startPosition+=numElements;
279 	}
280 	return(!fail);
281 }
282 
AndSelectionUniverse(SELECTION_UNIVERSE * sourceUniverse,SELECTION_UNIVERSE * destUniverse)283 bool AndSelectionUniverse(SELECTION_UNIVERSE *sourceUniverse,SELECTION_UNIVERSE *destUniverse)
284 // Logical AND sourceUniverse to destUniverse
285 // if there is a problem, SetError, and return false
286 // NOTE: all selections boundaries occuring in either selection will be
287 // present in the resulting selection.
288 // This may be called with sourceUniverse==destUniverse
289 {
290 	bool
291 		fail;
292 	UINT32
293 		clearPosition,
294 		startPosition,
295 		endPosition,
296 		numElements;
297 	UINT32
298 		destPosition,
299 		destElements;
300 
301 	fail=false;
302 
303 	clearPosition=startPosition=0;
304 	while(!fail&&GetSelectionAtOrAfterPosition(sourceUniverse,startPosition,&startPosition,&numElements))
305 	{
306 		fail=!ClearSelectionRange(destUniverse,clearPosition,startPosition-clearPosition);
307 		if(GetSelectionAtOrAfterPosition(destUniverse,startPosition+numElements,&destPosition,&destElements))
308 		{
309 			if(destPosition<startPosition+numElements)	// make sure to break dest at end of start if needed
310 			{
311 				fail=!SetSelectionRange(destUniverse,destPosition,startPosition+numElements-destPosition);
312 			}
313 		}
314 		startPosition+=numElements;
315 		clearPosition=startPosition;
316 	}
317 
318 	if(!fail&&GetSAElementEnds(&destUniverse->selectionArray,&startPosition,&endPosition))
319 	{
320 		if(endPosition>clearPosition)
321 		{
322 			fail=!ClearSelectionRange(destUniverse,clearPosition,endPosition-clearPosition);
323 		}
324 	}
325 	return(!fail);
326 }
327 
XorSelectionUniverse(SELECTION_UNIVERSE * sourceUniverse,SELECTION_UNIVERSE * destUniverse)328 bool XorSelectionUniverse(SELECTION_UNIVERSE *sourceUniverse,SELECTION_UNIVERSE *destUniverse)
329 // Logical XOR sourceUniverse to destUniverse
330 // if there is a problem, SetError, and return false
331 // NOTE: all selections boundaries occuring in either selection will be
332 // present in the resulting selection.
333 // This may be called with sourceUniverse==destUniverse
334 {
335 	bool
336 		fail;
337 	UINT32
338 		startPositionS,
339 		numElementsS,
340 		startPositionD,
341 		numElementsD,
342 		numToDo;
343 
344 	fail=false;
345 
346 	startPositionS=startPositionD=0;
347 	while(!fail&&GetSelectionAtOrAfterPosition(sourceUniverse,startPositionS,&startPositionS,&numElementsS))
348 	{
349 		while(!fail&&numElementsS)
350 		{
351 			if(GetSelectionAtOrAfterPosition(destUniverse,startPositionS,&startPositionD,&numElementsD))
352 			{
353 				if(startPositionS<startPositionD)
354 				{
355 					numToDo=startPositionD-startPositionS;
356 					if(numToDo>numElementsS)
357 					{
358 						numToDo=numElementsS;
359 					}
360 					fail=!SetSelectionRange(destUniverse,startPositionS,numToDo);
361 					numElementsS-=numToDo;
362 					startPositionS+=numToDo;
363 				}
364 				if(!fail&&numElementsS)		// still some to do?
365 				{
366 					numToDo=startPositionD+numElementsD-startPositionS;
367 					if(numToDo>numElementsS)
368 					{
369 						numToDo=numElementsS;
370 					}
371 					fail=!ClearSelectionRange(destUniverse,startPositionS,numToDo);
372 					numElementsS-=numToDo;
373 					startPositionS+=numToDo;
374 				}
375 			}
376 			else	// just copy S to D now
377 			{
378 				fail=!SetSelectionRange(destUniverse,startPositionS,numElementsS);
379 				startPositionS+=numElementsS;
380 				numElementsS=0;
381 			}
382 		}
383 	}
384 	return(!fail);
385 }
386 
CloseSelectionUniverse(SELECTION_UNIVERSE * universe)387 void CloseSelectionUniverse(SELECTION_UNIVERSE *universe)
388 // dispose of a selection universe
389 {
390 	UnInitSA(&(universe->selectionArray));
391 	MDisposePtr(universe);
392 }
393 
OpenSelectionUniverse()394 SELECTION_UNIVERSE *OpenSelectionUniverse()
395 // Open a selection universe (with no elements)
396 // If there is a problem, set the error, and return NULL
397 {
398 	SELECTION_UNIVERSE
399 		*universe;
400 
401 	if((universe=(SELECTION_UNIVERSE *)MNewPtr(sizeof(SELECTION_UNIVERSE))))
402 	{
403 		universe->cursorPosition=0;						// no cursor position yet, so just set it to 0
404 		if(InitSA(&(universe->selectionArray),sizeof(SELECTION_ELEMENT)))
405 		{
406 			return(universe);
407 		}
408 		MDisposePtr(universe);
409 	}
410 	return(NULL);
411 }
412 
413 // --------------------------------------------------------------------------------------------------------------------------
414 // Mark management
415 
UnlinkVisibilityFromMark(EDITOR_MARK * mark,MARK_VISIBILITY * visibility)416 static void UnlinkVisibilityFromMark(EDITOR_MARK *mark,MARK_VISIBILITY *visibility)
417 // unlink the visibility record from the mark's list
418 {
419 	if(visibility->prevView)
420 	{
421 		visibility->prevView->nextView=visibility->nextView;
422 	}
423 	else
424 	{
425 		mark->headVisibility=visibility->nextView;
426 	}
427 	if(visibility->nextView)
428 	{
429 		visibility->nextView->prevView=visibility->prevView;
430 	}
431 	else
432 	{
433 		mark->tailVisibility=visibility->prevView;
434 	}
435 }
436 
LinkVisibilityToMark(EDITOR_MARK * mark,MARK_VISIBILITY * visibility)437 static void LinkVisibilityToMark(EDITOR_MARK *mark,MARK_VISIBILITY *visibility)
438 // Link the visibility record to the list of views that this mark is visible in
439 {
440 	visibility->parentMark=mark;
441 
442 	visibility->nextView=NULL;
443 	if((visibility->prevView=mark->tailVisibility))
444 	{
445 		mark->tailVisibility->nextView=visibility;
446 	}
447 	else
448 	{
449 		mark->headVisibility=visibility;
450 	}
451 	mark->tailVisibility=visibility;
452 }
453 
UnlinkVisibilityFromView(EDITOR_VIEW * view,MARK_VISIBILITY * visibility)454 static void UnlinkVisibilityFromView(EDITOR_VIEW *view,MARK_VISIBILITY *visibility)
455 // unlink the visibility record from the view's list
456 {
457 	if(visibility->prevMark)
458 	{
459 		visibility->prevMark->nextMark=visibility->nextMark;
460 	}
461 	else
462 	{
463 		view->headVisibility=visibility->nextMark;
464 	}
465 	if(visibility->nextMark)
466 	{
467 		visibility->nextMark->prevMark=visibility->prevMark;
468 	}
469 	else
470 	{
471 		view->tailVisibility=visibility->prevMark;
472 	}
473 }
474 
LinkVisibilityToView(EDITOR_VIEW * view,MARK_VISIBILITY * visibility)475 static void LinkVisibilityToView(EDITOR_VIEW *view,MARK_VISIBILITY *visibility)
476 // Link the visibility record to the list of marks visible on the
477 // passed view
478 {
479 	visibility->parentView=view;
480 
481 	visibility->nextMark=NULL;
482 	if((visibility->prevMark=view->tailVisibility))
483 	{
484 		view->tailVisibility->nextMark=visibility;
485 	}
486 	else
487 	{
488 		view->headVisibility=visibility;
489 	}
490 	view->tailVisibility=visibility;
491 }
492 
LocateMarkVisibilityInView(EDITOR_VIEW * view,EDITOR_MARK * mark)493 MARK_VISIBILITY *LocateMarkVisibilityInView(EDITOR_VIEW *view,EDITOR_MARK *mark)
494 // hunt the passed view to see if mark is present in its visible
495 // mark list
496 {
497 	MARK_VISIBILITY
498 		*visibility;
499 
500 	visibility=view->headVisibility;
501 	while(visibility)
502 	{
503 		if(visibility->parentMark==mark)
504 		{
505 			return(visibility);
506 		}
507 		visibility=visibility->nextMark;
508 	}
509 	return(NULL);
510 }
511 
DisposeMarkVisible(MARK_VISIBILITY * visibility)512 static void DisposeMarkVisible(MARK_VISIBILITY *visibility)
513 // unlink and remove mark visibility record
514 {
515 	UnlinkVisibilityFromView(visibility->parentView,visibility);
516 	UnlinkVisibilityFromMark(visibility->parentMark,visibility);
517 	MDisposePtr(visibility);
518 }
519 
UnlinkVisibleMarksFromView(EDITOR_VIEW * view)520 void UnlinkVisibleMarksFromView(EDITOR_VIEW *view)
521 // Get rid of all visible marks attached to the passed view (usually done
522 // when closing the view)
523 {
524 	while(view->headVisibility)
525 	{
526 		DisposeMarkVisible(view->headVisibility);		// remove all visible marks
527 	}
528 }
529 
ClearEditorMarkVisible(EDITOR_MARK * mark,EDITOR_VIEW * view)530 void ClearEditorMarkVisible(EDITOR_MARK *mark,EDITOR_VIEW *view)
531 // Remove the mark from the list of those visible on the passed view
532 {
533 	MARK_VISIBILITY
534 		*visibility;
535 
536 	if((visibility=LocateMarkVisibilityInView(view,mark)))
537 	{
538 		ViewInvalidateMark(view,mark);					// invalidate it in the view so that it will disappear
539 		DisposeMarkVisible(visibility);
540 	}
541 }
542 
SetEditorMarkVisible(EDITOR_MARK * mark,EDITOR_VIEW * view,EDITOR_COLOR backgroundColor)543 bool SetEditorMarkVisible(EDITOR_MARK *mark,EDITOR_VIEW *view,EDITOR_COLOR backgroundColor)
544 // Make the passed mark visible in the passed view. If it is already visible, just
545 // update the colors
546 {
547 	MARK_VISIBILITY
548 		*visibility;
549 
550 	if(!(visibility=LocateMarkVisibilityInView(view,mark)))
551 	{
552 		if((visibility=(MARK_VISIBILITY *)MNewPtr(sizeof(MARK_VISIBILITY))))	// allocate a record, and link it to the view and mark
553 		{
554 			LinkVisibilityToMark(mark,visibility);
555 			LinkVisibilityToView(view,visibility);
556 		}
557 	}
558 	if(visibility)	// found or allocated record?
559 	{
560 		visibility->backgroundColor=backgroundColor;
561 		ViewInvalidateMark(view,mark);					// invalidate it in the view it just became visible in
562 		return(true);
563 	}
564 	return(false);
565 }
566 
LocateEditorMark(EDITOR_BUFFER * buffer,char * markName)567 EDITOR_MARK *LocateEditorMark(EDITOR_BUFFER *buffer,char *markName)
568 // attempt to locate a mark with the given name on buffer
569 // if one is found, return it, else, return NULL
570 {
571 	bool
572 		found;
573 	EDITOR_MARK
574 		*currentMark;
575 
576 	currentMark=buffer->marks;
577 	found=false;
578 	while(currentMark&&!found)
579 	{
580 		if(currentMark->markName&&(strcmp(currentMark->markName,markName)==0))
581 		{
582 			found=true;
583 		}
584 		else
585 		{
586 			currentMark=currentMark->nextMark;		// locate the mark to delete
587 		}
588 	}
589 	return(currentMark);
590 }
591 
UnlinkEditorMarkFromBuffer(EDITOR_BUFFER * buffer,EDITOR_MARK * mark)592 static void UnlinkEditorMarkFromBuffer(EDITOR_BUFFER *buffer,EDITOR_MARK *mark)
593 // unlink a mark from the buffer
594 {
595 	EDITOR_MARK
596 		*previousMark,
597 		*currentMark;
598 
599 	previousMark=NULL;
600 	currentMark=buffer->marks;
601 	while(currentMark&&(currentMark!=mark))
602 	{
603 		previousMark=currentMark;
604 		currentMark=currentMark->nextMark;			// locate the mark to delete
605 	}
606 	if(currentMark)									// make sure we located it
607 	{
608 		if(previousMark)							// see if it was at the top
609 		{
610 			previousMark->nextMark=currentMark->nextMark;	// link across
611 		}
612 		else
613 		{
614 			buffer->marks=currentMark->nextMark;	// set new top of list
615 		}
616 	}
617 }
618 
LinkEditorMarkToBuffer(EDITOR_BUFFER * buffer,EDITOR_MARK * mark)619 static void LinkEditorMarkToBuffer(EDITOR_BUFFER *buffer,EDITOR_MARK *mark)
620 // link a mark to the buffer
621 {
622 	mark->nextMark=buffer->marks;					// link onto start of list
623 	buffer->marks=mark;
624 }
625 
CloseEditorMark(EDITOR_BUFFER * buffer,EDITOR_MARK * mark)626 void CloseEditorMark(EDITOR_BUFFER *buffer,EDITOR_MARK *mark)
627 // Remove a mark from the buffer
628 {
629 	ViewsInvalidateMark(mark);						// invalidate it if it was visible in any view
630 	while(mark->headVisibility)
631 	{
632 		DisposeMarkVisible(mark->headVisibility);	// remove all visibility of this mark
633 	}
634 	UnlinkEditorMarkFromBuffer(buffer,mark);
635 	MDisposePtr(mark->markName);
636 	CloseSelectionUniverse(mark->selectionUniverse);	// close the selections
637 	MDisposePtr(mark);								// get rid of the mark
638 }
639 
NewEditorMark(EDITOR_BUFFER * buffer,char * markName)640 EDITOR_MARK *NewEditorMark(EDITOR_BUFFER *buffer,char *markName)
641 // Create a new empty mark on the buffer with markName
642 // If the name is already taken, return SetError, and return NULL
643 {
644 	EDITOR_MARK
645 		*mark;
646 
647 	if(!LocateEditorMark(buffer,markName))
648 	{
649 		if((mark=(EDITOR_MARK *)MNewPtr(sizeof(EDITOR_MARK))))
650 		{
651 			if((mark->selectionUniverse=OpenSelectionUniverse()))
652 			{
653 				if((mark->markName=(char *)MNewPtr(strlen(markName)+1)))
654 				{
655 					strcpy(mark->markName,markName);		// copy the name
656 					mark->headVisibility=NULL;				// this mark is not yet visible in any view
657 					mark->tailVisibility=NULL;
658 					LinkEditorMarkToBuffer(buffer,mark);	// link the mark to its buffer
659 					return(mark);
660 				}
661 				CloseSelectionUniverse(mark->selectionUniverse);
662 			}
663 			MDisposePtr(mark);
664 		}
665 	}
666 	else
667 	{
668 		SetError(errorDescriptions[DUPLICATE_NAME]);
669 	}
670 	return(NULL);
671 }
672