1/* 2 * ------------------------------------------------------------------------ 3 * PACKAGE: [incr Tk] 4 * DESCRIPTION: Building mega-widgets with [incr Tcl] 5 * 6 * [incr Tk] provides a framework for building composite "mega-widgets" 7 * using [incr Tcl] classes. It defines a set of base classes that are 8 * specialized to create all other widgets. 9 * 10 * This part defines some utility procedures that are useful for 11 * [incr Tk]. 12 * 13 * ======================================================================== 14 * AUTHOR: Michael J. McLennan 15 * Bell Labs Innovations for Lucent Technologies 16 * mmclennan@lucent.com 17 * http://www.tcltk.com/itcl 18 * 19 * RCS: $Id: itk_util.c,v 1.1 1998/07/27 18:45:25 stanton Exp $ 20 * ======================================================================== 21 * Copyright (c) 1993-1998 Lucent Technologies, Inc. 22 * ------------------------------------------------------------------------ 23 * See the file "license.terms" for information on usage and redistribution 24 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 25 */ 26#include "itk.h" 27 28 29/* 30 * ------------------------------------------------------------------------ 31 * Itk_OptListInit() 32 * 33 * Initializes an ordered option list, allocating a certain amount of 34 * memory for an initial option list. 35 * ------------------------------------------------------------------------ 36 */ 37void 38Itk_OptListInit(olist, options) 39 ItkOptList *olist; /* list to be initialized */ 40 Tcl_HashTable *options; /* table containing the real option entries */ 41{ 42 olist->options = options; 43 olist->len = 0; 44 olist->max = 10; 45 olist->list = (Tcl_HashEntry**)ckalloc( 46 (unsigned)(olist->max*sizeof(Tcl_HashEntry*)) 47 ); 48} 49 50 51/* 52 * ------------------------------------------------------------------------ 53 * Itk_OptListFree() 54 * 55 * Frees an ordered option list created by Itk_OptListInit(). 56 * This only frees the memory associated with the list, not the 57 * list itself. 58 * ------------------------------------------------------------------------ 59 */ 60void 61Itk_OptListFree(olist) 62 ItkOptList *olist; /* list to be freed */ 63{ 64 ckfree((char*)olist->list); 65 olist->len = olist->max = 0; 66} 67 68 69/* 70 * ------------------------------------------------------------------------ 71 * Itk_OptListAdd() 72 * 73 * Adds the hash table entry for an option like '-background' to an 74 * ordered list of options. The list is kept in alphabetical order, 75 * so that it can be searched quickly and printed out in order. 76 * ------------------------------------------------------------------------ 77 */ 78void 79Itk_OptListAdd(olist, entry) 80 ItkOptList *olist; /* ordered list */ 81 Tcl_HashEntry *entry; /* entry to be added to the list */ 82{ 83 int i, first, last, cmp, pos, size; 84 Tcl_HashEntry** newOrder; 85 char *swname, *optname; 86 87 /* 88 * Make sure that the option list is big enough. Resize 89 * if needed. 90 */ 91 if (olist->len >= olist->max) { 92 size = olist->max*sizeof(Tcl_HashEntry*); 93 newOrder = (Tcl_HashEntry**)ckalloc((unsigned)2*size); 94 memcpy((VOID*)newOrder, (VOID*)olist->list, (size_t)size); 95 ckfree((char*)olist->list); 96 97 olist->list = newOrder; 98 olist->max *= 2; 99 } 100 101 /* 102 * Perform a binary search to find the option switch quickly. 103 */ 104 first = 0; 105 last = olist->len-1; 106 swname = Tcl_GetHashKey(olist->options, entry) + 1; 107 108 while (last >= first) { 109 pos = (first+last)/2; 110 optname = Tcl_GetHashKey(olist->options, olist->list[pos]) + 1; 111 if (*swname == *optname) { 112 cmp = strcmp(swname, optname); 113 if (cmp == 0) { 114 break; /* found it! */ 115 } 116 } 117 else if (*swname < *optname) { 118 cmp = -1; 119 } 120 else { 121 cmp = 1; 122 } 123 124 if (cmp > 0) 125 first = pos+1; 126 else 127 last = pos-1; 128 } 129 130 /* 131 * If a matching entry was not found, then insert one. 132 */ 133 if (last < first) { 134 pos = first; 135 136 for (i=olist->len; i > pos; i--) { 137 olist->list[i] = olist->list[i-1]; 138 } 139 olist->list[pos] = entry; 140 olist->len++; 141 } 142} 143 144 145/* 146 * ------------------------------------------------------------------------ 147 * Itk_OptListRemove() 148 * 149 * Removes a hash table entry from an ordered list of options. 150 * This negates the action of Itk_OptionListAdd(), and is usually 151 * called when an option is completely removed from a mega-widget. 152 * This should be called before the entry is removed from the 153 * real option table. 154 * ------------------------------------------------------------------------ 155 */ 156void 157Itk_OptListRemove(olist, entry) 158 ItkOptList *olist; /* ordered list */ 159 Tcl_HashEntry *entry; /* entry to be removed from the list */ 160{ 161 int pos = 0; 162 int i, first, last, cmp; 163 char *swname, *optname; 164 165 first = 0; 166 last = olist->len-1; 167 swname = Tcl_GetHashKey(olist->options, entry) + 1; 168 169 while (last >= first) { 170 pos = (first+last)/2; 171 optname = Tcl_GetHashKey(olist->options, olist->list[pos]) + 1; 172 if (*swname == *optname) { 173 cmp = strcmp(swname, optname); 174 if (cmp == 0) { 175 break; /* found it! */ 176 } 177 } 178 else if (*swname < *optname) { 179 cmp = -1; 180 } 181 else { 182 cmp = 1; 183 } 184 185 if (cmp > 0) 186 first = pos+1; 187 else 188 last = pos-1; 189 } 190 191 /* 192 * If a matching entry was found, then remove it. 193 */ 194 if (last >= first) { 195 olist->len--; 196 for (i=pos; i < olist->len; i++) { 197 olist->list[i] = olist->list[i+1]; 198 } 199 } 200} 201