home *** CD-ROM | disk | FTP | other *** search
/ AMOS PD CD / amospdcd.iso / 351-375 / apd372 / jason_banks / list_procs.amos / list_procs.amosSourceCode
AMOS Source Code  |  1991-06-13  |  10KB  |  218 lines

  1. '
  2. ' List Routines
  3. '
  4. ' (c) 12/91 Jason Banks - Routines used to manipulate a double-linked list 
  5. '
  6. ' Notes - See _DOCS procedure for instructions 
  7. '
  8. LISTBASE=0
  9. ' Normally this could be defined as a global variable
  10. ' BUT we will need more than one listbase, and this way we can avoid 
  11. ' writing multiple routines to do the same job for each list-type  
  12. '
  13. _NEXT=0 : _PREV=4 : Rem add in other data-pointers here. 
  14. '
  15. Global _NEXT,_PREV
  16. '
  17. Procedure _ADDLIST[LISTBASE,ITEM]
  18. ' TAKES THE LOCATION OF A PRE-DEFINED DATA ELEMENT, AND ADDS IT INTO THE LIST
  19. ' usage is :: _ADDLIST[listbase,itemptr] : listbase=param
  20. '
  21.    NEWLISTBASE=ITEM
  22.    Loke ITEM+_PREV,0
  23.    If LISTBASE=0
  24.       Loke ITEM+_NEXT,0
  25.    Else 
  26.       Loke ITEM+_NEXT,LISTBASE
  27.       TEMPITEM=LISTBASE
  28.       Loke TEMPITEM+_PREV,ITEM
  29.    End If 
  30. End Proc[NEWLISTBASE]
  31. Procedure _INSERT[LISTBASE,ITEMPTR,ITEM]
  32. ' Inserts a data element in the list, before the itemptr passed as a pointer 
  33. ' usage is :: _INSERT[Listbase,insertposition,itemptr] : listbase=param  
  34. '
  35.    If Leek(ITEMPTR+_PREV)=0
  36.    ' at start of list!
  37.       _ADDLIST[LISTBASE,ITEM] : LISTBASE=Param
  38.    Else 
  39.       PPTR=Leek(ITEMPTR+_PREV)
  40.       Loke PPTR+_NEXT,ITEM : Loke ITEMPTR+_PREV,ITEM
  41.       Loke ITEM+_NEXT,ITEMPTR : Loke ITEM+_PREV,PPTR
  42.    End If 
  43. End Proc[LISTBASE]
  44. Procedure _GETNEXT[ITEM]
  45. ' Returns the address of the next item in the list 
  46. ' usage is :: _Getnext[item] : itemnext=param  
  47.    If ITEM=0
  48.       NITEM=0
  49.    Else 
  50.       NITEM=Leek(ITEM+_NEXT)
  51.    End If 
  52. End Proc[NITEM]
  53. Procedure _GETPREV[ITEM]
  54. ' Returns the address of the previous item in the list 
  55. ' usage is :: _GetPrev[item]: itemprev=param 
  56.    If ITEM=0
  57.       PITEM=0
  58.    Else 
  59.       PITEM=Leek(ITEM+_PREV)
  60.    End If 
  61. End Proc[PITEM]
  62. Procedure _GETFIRST[ITEM]
  63. ' This can be used to find the start of a list, when the LISTBASE has been lost, or is unknown.
  64. ' a problem that can occur here, is that in a circular-linked list (one that does not have a start or end) 
  65. ' this can possibly cause an infinite loop.
  66. ' usage _getfirst[item] : strt=param 
  67. '
  68.    _GETNEXT[ITEM] : STP=Param
  69.    While(Leek(ITEM+_PREV)<>0) and(ITEM<>STP)
  70.       ITEM=Leek(ITEM+_PREV)
  71.    Wend 
  72. End Proc
  73. Procedure _GETLAST[ITEM]
  74. ' This can be used to find the end item of a lst.
  75. ' usage _getlast[item] : finish=param  
  76. '
  77.    _GETPREV[ITEM] : STP=Param
  78.    While(Leek(ITEM+_NEXT)<>0) and(ITEM<>STP)
  79.       ITEM=Leek(ITEM+_NEXT)
  80.    Wend 
  81. End Proc
  82. Procedure _REMOVE[LISTBASE,ITEM,SIZE]
  83. ' can be used to delete a record from the list. Note that it is essential that you get all of the parameters 
  84. ' correct - it always is, but this can crash the computer VERY VERY easily.
  85. ' Usage :: _Remove[Listbase,Itemptr,SizeofItem]
  86. '
  87.    NITEM=Leek(ITEM+_NEXT) : PITEM=Leek(ITEM+_PREV)
  88.    _FREEMEM[ITEM,SIZE]
  89.    If NITEM<>0 Then Loke NITEM+_PREV,PITEM
  90.    If PITEM<>0 Then Loke PITEM+_NEXT,NITEM
  91.    If PITEM=0 Then LISTBASE=NITEM
  92. End Proc[LISTBASE]
  93. Procedure _GETMEM[SIZE]
  94.    Dreg(0)=SIZE : Dreg(1)=$10001 : PTR=Execall(-198)
  95. End Proc[PTR]
  96. Procedure _FREEMEM[PTR,SIZE]
  97.    Dreg(0)=SIZE : Areg(1)=PTR : DUMMY=Execall(-210)
  98. End Proc
  99. Procedure _KILLLIST[LISTBASE,SIZE]
  100. ' This procedure kills an entire list, and thus free's the memory consumed by it.
  101. ' USAGE :: _KIlllist[listbase,sizeofitem]
  102. '
  103.    ITEM=LISTBASE
  104.    While ITEM<>0
  105.       NITEM=Leek(ITEM+_NEXT) : _FREEMEM[ITEM,SIZE] : ITEM=NITEM
  106.       ' note that we are not using the _REMOVE procedure.
  107.       ' this is because we do not need to use a "Safe" procedure,
  108.       ' as we don't care what happens to the list once we've deleted it! 
  109.    Wend 
  110. End Proc
  111. Procedure _DOCS
  112. '               List Procs  - Jason Banks - 15th December 1991 
  113. '
  114. '     This is a set of routines that should help you to create and 
  115. ' manipulate a working double-linked list. A linked list, is a series
  116. ' of memory groups, that contain pointers to one another - the idea is 
  117. ' that once you know the pointer to the START item, then you can follow
  118. ' the chain of pointers to the item that you require. This is quite simple 
  119. ' to do in languages such as Pascal, C and Assembly code, as this is the 
  120. ' only way that these languages can perform some data-intensive tasks. Amos
  121. ' and most other basics that I know of (I'm unsure about GFA Basic), do not
  122. ' allow you to use anything like this - there is not normally a need for it, 
  123. ' that's why you're programming Basic and not in one of the other languages! 
  124. '  
  125. '     However, there are some very important advantages to using a linked list,
  126. ' the main one being that, unlike an array (the nearest Basic Equivalent), you 
  127. ' only use as much memory as you have in data, while the array has to define and 
  128. ' often waste large amount of memory - a list is a more "Pay as you go" type 
  129. ' system. Other advantages are that there are some fairly advanced search techniques 
  130. ' such as Binary-Trees which are much easier to implement when using a linked list.
  131. ' [B-Tree's are commonly used as indexes, especially in data-bases. The PC DBase 
  132. ' and Fox-Base programs use what is called a BTree++, which combines the best features 
  133. ' of both list techniques].
  134. '
  135. '     To implement a List, what we need to do is define a structure for it - write down
  136. ' what all of the data items will be, and what FORM of data they will take :-
  137. ' AMOS will allow us to use Byte, Word, Long Word, and a limited form of strings for a 
  138. ' linked list. We must however, add two extra records to what ever else we define our
  139. ' data structure to look like - the LIST POINTERS. It's probally easier to explain with
  140. ' an example, so here goes for a (very) simple linked list design:-
  141. '
  142. ' We Want to keep a list of files in memory, with the name of the file, and some simple
  143. ' data about each file. Therefore the initial data structure looks like:-
  144. '
  145. ' Filename            -      String of 108 bytes 
  146. ' Size                -      longword
  147. '  
  148. ' We then also need to add in the control data, giving us a final data structure of:-  
  149. '  
  150. ' Pointer to Next Record     - Longword
  151. ' Pointer to previous record - Longword
  152. ' Filename                   - 108 bytes 
  153. ' Size                       - Longword  
  154. '
  155. ' To initialise this item, we use the EXEC library call ALLOCMEM to reserve some memory
  156. ' and then we can initialise the record. If the record is the first (as in this case it is)
  157. ' then we need to set both of the record pointers to 0. So that we keep track of the item, 
  158. ' we place it's address in the LISTBASE variable. Later, on once we have more than one 
  159. ' record, we place the value of LISTBASE into next record pointer, and a 0 into the previous 
  160. ' record pointer - we then update the previous record pointer OF THE NEXT ITEM IN THE LIST,
  161. ' to point backward to the new item, and thus maintain the links of the chain. 
  162. '
  163. '      Items also, however, contain data. We Need some way of getting the data into the list.
  164. '      Here are some of the methods used in different languages. 
  165. '  
  166. ' PASCAL :-        ListItem^.Data := Value;
  167. '
  168. ' C      :-        ListItem->Data = Value; 
  169. '
  170. ' 68000  :-        lea     ListItem,a0 
  171. '                  move.l  #Value, Data(a0)' 
  172. '
  173. ' The Amos Equivalent, is to use a Poke, Doke or Loke command to copy the data from 'Value' to the List
  174. '  
  175. ' Amos   :-        Loke    ListItem+Data,Value 
  176. '
  177. '      This leaves us with a rather blunt method of copying data into list items, unlike the pascal or C variants
  178. ' where the ListItem is split into several subvariables. Unfortunately, while the C and Pascal version is a rather 
  179. ' graceful method, we are left with a much less refined method - and one that has much less in the way of error
  180. ' checking built in - pascal will not allow you to store a string variable where a number should be, where the amos
  181. ' version will, and possibly more to the point, the pascal version has a great deal more meaning than the normal equivalent
  182. ' of loke windowptr+62,gdget (Store the pointer to a gadget in a window structure) as compared with  
  183. ' windowptr^.FirstGadget := gdget; . This tells us that we need to improve the readability of our code, by defining a set of 
  184. ' pre-defined pointer values. Therefore, taking the example of the filelist, our pointers would look like:-
  185. '
  186. ' _NextPtr = 0  (this is the first item in the list) 
  187. ' _PrevPtr = 4  (0 + 4 (size in bytes of a longword) = 4)
  188. ' _nameptr = 8  (4 + 4 = 8)
  189. ' _sizeptr = 116 (8+108 = 116) 
  190. ' The final size of the structure = 116 + 4 (size of final record) = 120 bytes.
  191. '
  192. '      So, what do we do now? Well, to make the program run a little more smoothly, we're going to create a few
  193. ' global variables, to use a pointers within the procedures. These are ListBase [*]- the pointer to the first item in the list 
  194. ' (* - you may need to create several LISTBASE type variables if you wish to have more than one list in use at a time) 
  195. ' and the pointers to all of the items within the data structure. We shall also create some procedures which will manipulate all of this data
  196. ' These being:-
  197. '
  198. ' AddItem -Add Item To List  
  199. ' Insert - Add Item Into List [Add an item at a given position]
  200. ' GetNext - obtains the location of the next item
  201. ' GetPrev - obtains the location of the previous item
  202. ' GetFirst - obtains the location of the first item
  203. ' GetLast - obtains the location of the last item
  204. ' RemoveItem - removes an item from the list, and rebuilds the list about it 
  205. ' Killlist - removes an entire list from memory
  206. '
  207. '
  208. '
  209. ' Some Final Notes. Unfortunately, the way AMOS works, if you are not careful with your
  210. ' lists, you can find your programs gaining in size, as AMOS tags your data structures along with your actual program code.
  211. ' There are two methods to remedy this, which are:-
  212. '
  213. ' 1) - Prevention is better than cure - make sure that every block of memory you reserve is freed after use. 
  214. ' 2) - Removing the extra passengers - To get rid of such hangers on, you need to save your program as an ascii file.
  215. '      If you opt for this method, make sure that all of your procedures are opened, and be prepared for a bit of a wait 
  216. '      while AMOS translates your Ascii code back into a conventional (and hopefully smaller!) program format. 
  217. '
  218. End Proc