|
|
1.1 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 Microsoft Corporation. ! 5: * All rights reserved. ! 6: * This source code is only intended as a supplement to ! 7: * Microsoft Development Tools and/or WinHelp documentation. ! 8: * See these sources for detailed information regarding the ! 9: * Microsoft samples programs. ! 10: \******************************************************************************/ ! 11: ! 12: /* ! 13: * LIST.H ! 14: */ ! 15: /*------------------------------------------------------------------------ ! 16: | Abstract data type LIST OF (*untyped*) object. ! 17: | Different lists can have different types of object in them ! 18: | Different items in a list can have different types of object in them. ! 19: | The price of this lack of typing is that you have a slightly more ! 20: | awkward syntax and you get no help from the compiler if you try to ! 21: | put the wrong type of data into the list. ! 22: | ! 23: | The list is implemented as a collection of items. Within the item ! 24: | somewhere is the object. ! 25: | ! 26: | Objects are stored UNALIGNED within items. ! 27: | ! 28: | Use: ! 29: | ! 30: | #include <list.h> ! 31: | . . . ! 32: | LIST MyList; (* or LIST liMyList for Hungarians *) ! 33: | . . . ! 34: | MyList = List_Create(); ! 35: | List_AddLast(MyList,&MyObject,sizeof(OBJECT)); ! 36: | ! 37: | In the abstract a LIST is a list of objects. The representation ! 38: | is a linked collection of items. The manner of the linking is ! 39: | implementation dependent (as I write this it's linear but when you ! 40: | read it it might be a tree (See Knuth for why a tree)). ! 41: | ! 42: | A LIST is a "handle" for a list which may be thought of as a POINTER ! 43: | (whether it is really a pointer or not is implementation dependent) ! 44: | so that it can be copied at the risk of creating an alias. e.g. ! 45: | ! 46: | L = List_Create(); ! 47: | L1 = L; (* L and L1 are both healthy and empty *) ! 48: | List_AddFirst(L, &elem, sizeof(elem)); ! 49: | (* L1 may also appear to have one object, there again it may be sick *) ! 50: | L1 = L; (* Now they both surely see the one element *) ! 51: | List_Destroy(&L1); (* L is almost certainly sick now too *) ! 52: | L1 = List_Create(); (* All bets off as to what L is like now ! 53: | but L1 is empty and healthy ! 54: | *) ! 55: | ! 56: | If two handles compare equal then the lists must be equal, but ! 57: | unequal handles could address two similar lists i.e. the same list ! 58: | of objects held in two different LISTs of items (like pointers). ! 59: | ! 60: | A LIST can be transferred from one variable to another like this: ! 61: | ! 62: | NewList = OldList; (* copy the handle *) ! 63: | OldList = List_Create(); (* kill the old alias *) ! 64: | ! 65: | and the Create statement can be omitted if OldList is never touched again. ! 66: | ! 67: | Items are identified by Cursors. A cursor is the address of an object ! 68: | within an item in the list. i.e. it is the address of the piece of your ! 69: | data that you had inserted. (It is probably NOT the address of the item). ! 70: | It is typed as pointer to void here, but you should declare it as a pointer ! 71: | to whatever sort of object you are putting in the LIST. ! 72: | ! 73: | The operations AddFirst, AddLast, AddAfter and AddBefore ! 74: | all copy elements by direct assignment. If an element is itself ! 75: | a complex structure (say a tree) then this will only copy a pointer ! 76: | or an anchor block or whatever and give all the usual problems of ! 77: | aliases. Clear will make the list empty, but will only free the ! 78: | storage that it can "see" directly. SplitBefore or Split After may ! 79: | also perform a Clear operation. To deal with fancy data structures ! 80: | use New rather than Add calls and copy the data yourself ! 81: | e.g. P = List_NewLast(MyList, sizeof(MyArray[14])*(23-14+1)); ! 82: | CopyArraySlice(P, MyArray, 14, 23); ! 83: | ! 84: | The operations NewFirst, NewLast, NewAfter, NewBefore, First and Last ! 85: | all return pointers to elements and thus allow you to do any copying. ! 86: | This is how you might copy a whole list of fancy structures: ! 87: | ! 88: | void CopyFancyList(LIST * To, LIST From) ! 89: | (* Assumes that To has been Created and is empty *) ! 90: | { PELEMENT Cursor; ! 91: | PELEMENT P; ! 92: | ! 93: | List_TRAVERSE(From, Cursor); ! 94: | { P = List_NewLast(To, sizeof(element) ); ! 95: | FancyCopy(P, Cursor); (* Copy so that *Cursor==*P afterwords *) ! 96: | } ! 97: | } ! 98: --------------------------------------------------------------------*/ ! 99: ! 100: typedef struct item_tag FAR * LIST; ! 101: typedef LIST FAR * PLIST; ! 102: ! 103: void APIENTRY List_Init(void); ! 104: /* MUST BE CALLED BEFORE ANY OF THE OTHER FUNCTIONS. */ ! 105: ! 106: void APIENTRY List_Dump(LPSTR Header, LIST lst); ! 107: /* Dump the internals to current output stream -- debug only */ ! 108: ! 109: void APIENTRY List_Show(LIST lst); ! 110: /* Dump hex representation of handle to current out stream -- debug only */ ! 111: ! 112: LIST APIENTRY List_Create(void); ! 113: /* Create a list. It will be initially empty */ ! 114: ! 115: void APIENTRY List_Destroy(PLIST plst); ! 116: /* Destroy *plst. It does not need to be empty first. ! 117: | All storage directly in the list wil be freed. ! 118: */ ! 119: ! 120: void APIENTRY List_AddFirst(LIST lst, LPVOID pObject, UINT uLen); ! 121: /* Add an item holding Object to the beginning of * plst */ ! 122: ! 123: LPVOID APIENTRY List_NewFirst(LIST lst, UINT uLen); ! 124: /* Return the address of the place for Len bytes of data in a new ! 125: | item at the start of *plst ! 126: */ ! 127: ! 128: void APIENTRY List_DeleteFirst(LIST lst); ! 129: /* Delete the first item in lst. Error if lst is empty */ ! 130: ! 131: void APIENTRY List_AddLast(LIST lst, LPVOID pObject, UINT uLen); ! 132: /* Add an item holding Object to the end of lst */ ! 133: ! 134: LPVOID APIENTRY List_NewLast(LIST lst, UINT uLen); ! 135: /* Return the address of the place for uLen bytes of data in a new ! 136: | item at the end of lst ! 137: */ ! 138: ! 139: void APIENTRY List_DeleteLast(LIST lst); ! 140: /* Delete the last item in lst. Error if lst is empty */ ! 141: ! 142: void APIENTRY List_AddAfter( LIST lst ! 143: , LPVOID Curs ! 144: , LPVOID pObject ! 145: , UINT uLen ! 146: ); ! 147: /*-------------------------------------------------------------------- ! 148: | Add an item holding *pObject to lst immediately after Curs. ! 149: | List_AddAfter(lst, NULL, pObject, Len) adds it to the start of the lst ! 150: ---------------------------------------------------------------------*/ ! 151: ! 152: LPVOID APIENTRY List_NewAfter(LIST lst, LPVOID Curs, UINT uLen); ! 153: /*-------------------------------------------------------------------- ! 154: | Return the address of the place for uLen bytes of data in a new ! 155: | item immediately after Curs. ! 156: | List_NewAfter(Lst, NULL, uLen) returns a pointer ! 157: | to space for uLen bytes in a new first element. ! 158: ---------------------------------------------------------------------*/ ! 159: ! 160: void APIENTRY List_AddBefore( LIST lst ! 161: , LPVOID Curs ! 162: , LPVOID pObject ! 163: , UINT uLen ! 164: ); ! 165: /*-------------------------------------------------------------------- ! 166: | Add an item holding Object to lst immediately before Curs. ! 167: | List_AddBefore(Lst, NULL, Object, uLen) adds it to the end of the list ! 168: ---------------------------------------------------------------------*/ ! 169: ! 170: LPVOID APIENTRY List_NewBefore(LIST lst, LPVOID Curs, UINT uLen ); ! 171: /*-------------------------------------------------------------------- ! 172: | Return the address of the place for uLen bytes of data in a new ! 173: | item immediately before Curs. ! 174: | List_NewBefore(Lst, NULL, uLen) returns a pointer ! 175: | to space for uLen bytes in a new last element. ! 176: ---------------------------------------------------------------------*/ ! 177: ! 178: void APIENTRY List_Delete(LPVOID Curs); ! 179: /*------------------------------------------------------------------ ! 180: | Delete the item that Curs identifies. ! 181: | This will be only a few (maybe as little as 3) machine instructions ! 182: | quicker than DeleteAndNext or DeleteAndPrev but leaves Curs dangling. ! 183: | It is therefore NOT usually to be preferred. ! 184: | It may be useful when you have a function which returns an LPVOID ! 185: | since the argument does not need to be a variable. ! 186: | Trivial example: List_Delete(List_First(L)); ! 187: -------------------------------------------------------------------*/ ! 188: ! 189: int APIENTRY List_ItemLength(LPVOID Curs); ! 190: /* Return the length of the object identified by the cursor Curs */ ! 191: ! 192: /*------------------------------------------------------------------ ! 193: | TRAVERSING THE ULIST ! 194: | ! 195: | LIST lst; ! 196: | object * Curs; ! 197: | . . . ! 198: | Curs = List_First(lst); ! 199: | while (Curs!=NULL) ! 200: | { DoSomething(*Curs); (* Curs points to YOUR data not to chain ptrs *) ! 201: | Curs = List_Next(Curs); ! 202: | } ! 203: | ! 204: | This is identically equal to ! 205: | List_TRAVERSE(lst, Curs) // note NO SEMI COLON! ! 206: | { DoSomething(*Curs); } ! 207: -------------------------------------------------------------------*/ ! 208: ! 209: #define List_TRAVERSE(lst, curs) for( curs=List_First(lst) \ ! 210: ; curs!=NULL \ ! 211: ; curs = List_Next((LPVOID)curs) \ ! 212: ) ! 213: ! 214: LPVOID APIENTRY List_First(LIST lst); ! 215: /*------------------------------------------------------------------ ! 216: | Return the address of the first object in lst ! 217: | If lst is empty then Return NULL. ! 218: --------------------------------------------------------------------*/ ! 219: ! 220: LPVOID APIENTRY List_Last(LIST lst); ! 221: /*------------------------------------------------------------------ ! 222: | Return the address of the last object in lst ! 223: | If lst is empty then return NULL. ! 224: --------------------------------------------------------------------*/ ! 225: ! 226: LPVOID APIENTRY List_Next(LPVOID Curs); ! 227: /*------------------------------------------------------------------ ! 228: | Return the address of the object after Curs^. ! 229: | List_Next(List_Last(lst)) == NULL; List_Next(NULL) is an error. ! 230: | List_Next(List_Prev(curs)) is illegal if curs identifies first el ! 231: --------------------------------------------------------------------*/ ! 232: ! 233: LPVOID APIENTRY List_Prev(LPVOID Curs); ! 234: /*------------------------------------------------------------------ ! 235: | Return the address of the object after Curs^. ! 236: | List_Prev(List_First(L)) == NULL; List_Prev(NULL) is an error. ! 237: | List_Prev(List_Next(curs)) is illegal if curs identifies last el ! 238: --------------------------------------------------------------------*/ ! 239: ! 240: /*------------------------------------------------------------------ ! 241: | Whole list operations ! 242: -----------------------------------------------------------------*/ ! 243: void APIENTRY List_Clear(LIST lst); ! 244: /* arrange that lst is empty after this */ ! 245: ! 246: BOOL APIENTRY List_IsEmpty(LIST lst); ! 247: /* Return TRUE if and only if lst is empty */ ! 248: ! 249: void APIENTRY List_Join(LIST l1, LIST l2); ! 250: /*----------------------------------------------------------------------- ! 251: | l1 := l1||l2; l2 := empty ! 252: | The elements themselves are not moved, so pointers to them remain valid. ! 253: | ! 254: | l1 gets all the elements of l1 in their original order followed by ! 255: | all the elements of l2 in the order they were in in l2. ! 256: | l2 becomes empty. ! 257: ------------------------------------------------------------------------*/ ! 258: ! 259: void APIENTRY List_InsertListAfter(LIST l1, LIST l2, LPVOID Curs); ! 260: /*----------------------------------------------------------------------- ! 261: | l1 := l1[...Curs] || l2 || l1[Curs+1...]; l2 := empty ! 262: | Curs=NULL means insert l2 at the start of l1 ! 263: | The elements themselves are not moved, so pointers to them remain valid. ! 264: | ! 265: | l1 gets the elements of l1 from the start up to and including the element ! 266: | that Curs points at, in their original order, ! 267: | followed by all the elements that were in l2, in their original order, ! 268: | followed by the rest of l1 ! 269: ------------------------------------------------------------------------*/ ! 270: ! 271: void APIENTRY List_InsertListBefore(LIST l1, LIST l2, LPVOID Curs); ! 272: /*----------------------------------------------------------------------- ! 273: | l1 := l1[...Curs-1] || l2 || l1[Curs...]; l2 := empty ! 274: | Curs=NULL means insert l2 at the end of l1 ! 275: | The elements themselves are not moved, so pointers to them remain valid. ! 276: | ! 277: | l1 gets the elements of l1 from the start up to but not including the ! 278: | element that Curs points at, in their original order, ! 279: | followed by all the elements that were in l2, in their original order, ! 280: | followed by the rest of l1. ! 281: ------------------------------------------------------------------------*/ ! 282: ! 283: void APIENTRY List_SplitAfter(LIST l1, LIST l2, LPVOID Curs); ! 284: /*----------------------------------------------------------------------- ! 285: | Let l1 be l1 and l2 be l2 ! 286: | Split l2 off from the front of l1: final l2,l1 = original l1 ! 287: | ! 288: | Split l1 into l2: objects of l1 up to and including Curs object ! 289: | l1: objects of l1 after Curs ! 290: | Any original contents of l2 are freed. ! 291: | List_Spilt(l1, l2, NULL) splits l1 before the first object so l1 gets all. ! 292: | The elements themselves are not moved. ! 293: ------------------------------------------------------------------------*/ ! 294: ! 295: void APIENTRY List_SplitBefore(LIST l1, LIST l2, LPVOID Curs); ! 296: /*---------------------------------------------------------------------- ! 297: | Split l2 off from the back of l1: final l1,l2 = original l1 ! 298: | ! 299: | Split l1 into l1: objects of l1 up to but not including Curs object ! 300: | l2: objects of l1 from Curs onwards ! 301: | Any original contants of l2 are freed. ! 302: | List_Spilt(l1, l2, NULL) splits l1 after the last object so l1 gets all. ! 303: | The elements themselves are not moved. ! 304: -----------------------------------------------------------------------*/ ! 305: ! 306: int APIENTRY List_Card(LIST lst); ! 307: /* Return the number of items in L */ ! 308: ! 309: /*------------------------------------------------------------------ ! 310: | Error handling. ! 311: | ! 312: | Each list has within it a flag which indicates whether any illegal ! 313: | operation has been detected (e.g. DeleteFirst when empty). ! 314: | Rather than have a flag on every operation, there is a flag held ! 315: | within the list that can be queried when convenient. Many operations ! 316: | do not have enough redundancy to allow any meaningful check. This ! 317: | is a design compromise (for instance to allow P = List_Next(P); ! 318: | rather than P = List_Next(L, P); which is more awkward, especially ! 319: | if L is actually a lengthy phrase). ! 320: | ! 321: | List_IsOK tests this flag (so is a very simple, quick operation). ! 322: | MakeOK sets the flag to TRUE, in other words to accept the current ! 323: | state of the list. ! 324: | ! 325: | It is possible for a list to be damaged (whether or not the flag ! 326: | says OK) for instance by the storage being overwritten. ! 327: | ! 328: | List_Check attempts to verify that the list is sound (for instance where ! 329: | there are both forward and backward pointers they should agree). ! 330: | ! 331: | List_Recover attempts to make a sound list out of whatever debris is left. ! 332: | If the list is damaged, Recover may trap (e.g. address error) but ! 333: | if the list was damaged then ANY operation on it may trap. ! 334: | If Check succeeds without trapping then so will Recover. ! 335: -----------------------------------------------------------------*/ ! 336: ! 337: BOOL APIENTRY List_IsOK(LIST lst); ! 338: /* Check return code */ ! 339: ! 340: void APIENTRY List_MakeOK(LIST lst); ! 341: /* Set return code to good */ ! 342: ! 343: BOOL APIENTRY List_Check(LIST lst); ! 344: /* Attempt to validate the chains */ ! 345: ! 346: void APIENTRY List_Recover(PLIST plst); ! 347: /* Desperate stuff. Attempt to reconstruct something */ ! 348: ! 349: /*------------------------------------------------------------------ ! 350: | It is designed to be as easy to USE as possible, consistent ! 351: | only with being an opaque type. ! 352: | ! 353: | In particular, the decision to use the address of an object a list cursor ! 354: | means that there is a small amount of extra arithmetic (in the ! 355: | IMPLEMENTATION) in cursor operations (e.g. Next and Prev). ! 356: | and spurious arguments are avoided whenever possible, even though ! 357: | it would allow greater error checking. ! 358: | ! 359: | Of the "whole list" operations, Clear is given because it seems to be ! 360: | a common operation, even though the caller can implement it with almost ! 361: | the same efficiency as the List implementation module. ! 362: | Join, Split and InsertListXxx cannot be implemented efficiently without ! 363: | knowing the representation. ! 364: --------------------------------------------------------------------*/
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.