1 /* HTHist.c
2 ** NAVIGATION MANAGER
3 **
4 ** (c) COPYRIGHT MIT 1995.
5 ** Please first read the full copyright statement in the file COPYRIGH.
6 ** @(#) $Id$
7 **
8 ** The history manager for the Library. This module is not called any
9 ** where in the Library so if the application does not call it, it is
10 ** not linked in at all.
11 */
12
13 /* Library include files */
14 #include "wwwsys.h"
15 #include "HTUtils.h"
16 #include "HTAnchor.h"
17 #include "HTHist.h" /* Implemented here */
18
19 struct _HTHistory {
20 HTList * alist; /* List of anchors */
21 int pos; /* Current position in list. 1 is home anchor */
22 };
23
24 /* ------------------------------------------------------------------------- */
25
26 /* Create a new History List
27 ** -------------------------
28 ** Creates a new history list and returns a handle to it. There can be
29 ** multiple history lists - for example one for each open window in
30 ** an application.
31 ** Returns HTHistory object if OK, else NULL
32 */
HTHistory_new(void)33 PUBLIC HTHistory *HTHistory_new (void)
34 {
35 HTHistory *element;
36 if ((element = (HTHistory *) HT_CALLOC(1, (sizeof(HTHistory)))) == NULL)
37 HT_OUTOFMEM("HTHistory_new");
38 element->alist = HTList_new();
39 return element;
40 }
41
42 /* Delete a History list
43 ** ---------------------
44 ** Deletes the history list.
45 ** Returns YES if OK, else NO
46 */
HTHistory_delete(HTHistory * hist)47 PUBLIC BOOL HTHistory_delete (HTHistory * hist)
48 {
49 if (hist) {
50 HTList_delete(hist->alist);
51 HT_FREE(hist);
52 return YES;
53 }
54 return NO;
55 }
56
57 /* Record an entry in a list
58 ** -------------------------
59 ** Registers the object in the linear list. The first entry is the
60 ** home page. No check is done for duplicates.
61 ** Returns YES if ok, else NO
62 */
HTHistory_record(HTHistory * hist,HTAnchor * cur)63 PUBLIC BOOL HTHistory_record (HTHistory * hist, HTAnchor * cur)
64 {
65 return (hist && cur && HTList_addObject(hist->alist, cur) && hist->pos++);
66 }
67
68 /* Replace list with new element
69 ** -----------------------------
70 ** Inserts the new element at the current position and removes all any
71 ** old list from current position. For example if c is cur pos
72 ** before: a b c d e
73 ** after : a b f
74 ** Returns YES if ok, else NO
75 */
HTHistory_replace(HTHistory * hist,HTAnchor * cur)76 PUBLIC BOOL HTHistory_replace (HTHistory * hist, HTAnchor * cur)
77 {
78 if (hist && cur) {
79 HTHistory_removeFrom(hist, hist->pos);
80 HTHistory_record(hist, cur);
81 }
82 return NO;
83 }
84
85 /* Delete last entry in a list
86 ** ---------------------------
87 ** Deletes the last object from the list
88 ** Returns YES if OK, else NO
89 */
HTHistory_removeLast(HTHistory * hist)90 PUBLIC BOOL HTHistory_removeLast (HTHistory * hist)
91 {
92 return (hist && HTList_removeLastObject(hist->alist) && hist->pos--);
93 }
94
95 /* Remove the History list from position
96 ** ------------------------------------
97 ** Deletes the history list FROM the entry at position 'cur' (excluded).
98 ** Home page has position 1.
99 ** Returns YES if OK, else NO
100 */
HTHistory_removeFrom(HTHistory * hist,int pos)101 PUBLIC BOOL HTHistory_removeFrom (HTHistory * hist, int pos)
102 {
103 if (hist && pos>=0) {
104 int cnt = HTList_count(hist->alist) - pos;
105 while (cnt-->0 && HTList_removeLastObject(hist->alist));
106 if (hist->pos > pos)
107 hist->pos = pos;
108 return YES;
109 }
110 return NO;
111 }
112
113 /* Number of elements stored
114 ** -------------------------
115 ** Returns the size of the history list or -1 if none.
116 */
HTHistory_count(HTHistory * hist)117 PUBLIC int HTHistory_count (HTHistory * hist)
118 {
119 return (hist ? HTList_count(hist->alist) : -1);
120 }
121
122 /* Current Location
123 ** ----------------
124 ** Returns the current position or -1
125 */
HTHistory_position(HTHistory * hist)126 PUBLIC int HTHistory_position (HTHistory * hist)
127 {
128 return (hist ? hist->pos : -1);
129 }
130
131 /* ------------------------------------------------------------------------- */
132 /* NAVIGATION */
133 /* ------------------------------------------------------------------------- */
134
135 /* Find and re-register visited anchor
136 ** -----------------------------------
137 ** Finds already registered anchor at given position and registers it
138 ** again EXCEPT if last entry. This allows for `circular' history lists
139 ** with duplicate entries. Position 1 is the home anchor.
140 */
HTHistory_recall(HTHistory * hist,int pos)141 PUBLIC HTAnchor * HTHistory_recall (HTHistory * hist, int pos)
142 {
143 HTAnchor *cur = NULL;
144 if (hist && pos > 0) {
145 int len = HTList_count(hist->alist);
146 if ((cur = (HTAnchor *) HTList_objectAt(hist->alist, len-pos))) {
147 if (cur != HTList_lastObject (hist->alist)) {
148 HTHistory_record(hist, cur);
149 } else
150 hist->pos = pos;
151 }
152 }
153 return cur;
154 }
155
156 /* Find Entry at position
157 ** ----------------------
158 ** Entry with the given index in the list (1 is the home page). Like
159 ** HTHistory_recall but without re-registration. Current position is
160 ** updated.
161 */
HTHistory_find(HTHistory * hist,int pos)162 PUBLIC HTAnchor * HTHistory_find (HTHistory * hist, int pos)
163 {
164 HTAnchor *cur = NULL;
165 if (hist && pos > 0) {
166 if ((cur = (HTAnchor *)
167 (HTList_objectAt(hist->alist, HTList_count(hist->alist)-pos))))
168 hist->pos = pos;
169 }
170 return cur;
171 }
172
173 /* List Entry at position
174 ** ----------------------
175 ** Entry with the given index in the list (1 is the home page). Like
176 ** HTHistory_find but current position is NOT updated.
177 */
HTHistory_list(HTHistory * hist,int pos)178 PUBLIC HTAnchor * HTHistory_list (HTHistory * hist, int pos)
179 {
180 return (hist ? (HTAnchor *)
181 (HTList_objectAt(hist->alist, HTList_count(hist->alist)-pos)) :
182 NULL);
183 }
184
185 /* Can we back in history
186 ** ----------------------
187 ** Returns YES if the current anchor is not the first entry (home page)
188 */
HTHistory_canBacktrack(HTHistory * hist)189 PUBLIC BOOL HTHistory_canBacktrack (HTHistory * hist)
190 {
191 return ((hist && hist->pos > 1) ? YES : NO);
192 }
193
194 /*
195 ** Backtrack with deletion
196 ** -----------------------
197 ** Returns the previous object and erases the last object. This does not
198 ** allow for 'forward' as we are always at the end of the list. If no
199 ** previous object exists, NULL is returned so that the application knows
200 ** that no previous object was found. See also HTHistory_back().
201 */
HTHistory_backtrack(HTHistory * hist)202 PUBLIC HTAnchor * HTHistory_backtrack (HTHistory * hist)
203 {
204 if (HTHistory_canBacktrack(hist)) {
205 HTHistory_removeLast(hist);
206 return (HTAnchor *) HTList_lastObject(hist->alist);
207 }
208 return NULL;
209 }
210
211 /*
212 ** Backtrack without deletion
213 ** --------------------------
214 ** Returns the previos object but does not erase the last object. This
215 ** does not allow for 'forward'. If no previous object exists, NULL is
216 ** returned so that the application knows that no previous object was
217 ** found. See also HTHistory_backtrack()
218 */
HTHistory_back(HTHistory * hist)219 PUBLIC HTAnchor * HTHistory_back (HTHistory * hist)
220 {
221 if (HTHistory_canBacktrack(hist)) {
222 int pos = HTList_count(hist->alist) - (--hist->pos);
223 return ((HTAnchor *) HTList_objectAt(hist->alist, pos));
224 }
225 return NULL;
226 }
227
228 /* Can we go forward
229 ** -----------------
230 ** Returns YES if the current anchor is not the last entry
231 */
HTHistory_canForward(HTHistory * hist)232 PUBLIC BOOL HTHistory_canForward (HTHistory * hist)
233 {
234 return ((hist && hist->pos < HTList_count(hist->alist)) ? YES : NO);
235 }
236
237 /*
238 ** Forward
239 ** -------
240 ** Return the next object in the list or NULL if none
241 */
HTHistory_forward(HTHistory * hist)242 PUBLIC HTAnchor * HTHistory_forward (HTHistory * hist)
243 {
244 if (HTHistory_canForward(hist)) {
245 int pos = HTList_count(hist->alist) - (++hist->pos);
246 return ((HTAnchor *) HTList_objectAt(hist->alist, pos));
247 }
248 return NULL;
249 }
250