1 1.30 andvar /* $NetBSD: init.c,v 1.30 2021/09/19 11:37:01 andvar Exp $ */ 2 1.9 jdolecek 3 1.9 jdolecek /*- 4 1.9 jdolecek * Copyright (c) 2000-2003 The NetBSD Foundation, Inc. 5 1.9 jdolecek * All rights reserved. 6 1.9 jdolecek * 7 1.9 jdolecek * This code is derived from software contributed to The NetBSD Foundation 8 1.9 jdolecek * by Ben Harris and Jaromir Dolecek. 9 1.9 jdolecek * 10 1.9 jdolecek * Redistribution and use in source and binary forms, with or without 11 1.9 jdolecek * modification, are permitted provided that the following conditions 12 1.9 jdolecek * are met: 13 1.9 jdolecek * 1. Redistributions of source code must retain the above copyright 14 1.9 jdolecek * notice, this list of conditions and the following disclaimer. 15 1.9 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 16 1.9 jdolecek * notice, this list of conditions and the following disclaimer in the 17 1.9 jdolecek * documentation and/or other materials provided with the distribution. 18 1.9 jdolecek * 19 1.9 jdolecek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.9 jdolecek * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.9 jdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.9 jdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.9 jdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.9 jdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.9 jdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.9 jdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.9 jdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.9 jdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.9 jdolecek * POSSIBILITY OF SUCH DAMAGE. 30 1.9 jdolecek */ 31 1.2 bjh21 32 1.1 bjh21 /*- 33 1.1 bjh21 * Copyright (c) 1993 34 1.1 bjh21 * The Regents of the University of California. All rights reserved. 35 1.1 bjh21 * 36 1.1 bjh21 * This code is derived from software contributed to Berkeley by 37 1.1 bjh21 * Peter McIlroy. 38 1.1 bjh21 * 39 1.1 bjh21 * Redistribution and use in source and binary forms, with or without 40 1.1 bjh21 * modification, are permitted provided that the following conditions 41 1.1 bjh21 * are met: 42 1.1 bjh21 * 1. Redistributions of source code must retain the above copyright 43 1.1 bjh21 * notice, this list of conditions and the following disclaimer. 44 1.1 bjh21 * 2. Redistributions in binary form must reproduce the above copyright 45 1.1 bjh21 * notice, this list of conditions and the following disclaimer in the 46 1.1 bjh21 * documentation and/or other materials provided with the distribution. 47 1.8 agc * 3. Neither the name of the University nor the names of its contributors 48 1.1 bjh21 * may be used to endorse or promote products derived from this software 49 1.1 bjh21 * without specific prior written permission. 50 1.1 bjh21 * 51 1.1 bjh21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 1.1 bjh21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 1.1 bjh21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 1.1 bjh21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 1.1 bjh21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 1.1 bjh21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 1.1 bjh21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 1.1 bjh21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 1.1 bjh21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 1.1 bjh21 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 1.1 bjh21 * SUCH DAMAGE. 62 1.1 bjh21 */ 63 1.1 bjh21 64 1.2 bjh21 #include "sort.h" 65 1.2 bjh21 66 1.30 andvar __RCSID("$NetBSD: init.c,v 1.30 2021/09/19 11:37:01 andvar Exp $"); 67 1.1 bjh21 68 1.1 bjh21 #include <ctype.h> 69 1.1 bjh21 #include <string.h> 70 1.1 bjh21 71 1.19 dsl static void insertcol(struct field *); 72 1.23 dsl static const char *setcolumn(const char *, struct field *); 73 1.2 bjh21 74 1.1 bjh21 /* 75 1.20 dsl * masks of ignored characters. 76 1.4 jdolecek */ 77 1.20 dsl static u_char dtable[NBINS], itable[NBINS]; 78 1.4 jdolecek 79 1.4 jdolecek /* 80 1.12 jdolecek * parsed key options 81 1.12 jdolecek */ 82 1.13 itojun struct coldesc *clist = NULL; 83 1.12 jdolecek int ncols = 0; 84 1.12 jdolecek 85 1.12 jdolecek /* 86 1.1 bjh21 * clist (list of columns which correspond to one or more icol or tcol) 87 1.1 bjh21 * is in increasing order of columns. 88 1.1 bjh21 * Fields are kept in increasing order of fields. 89 1.1 bjh21 */ 90 1.1 bjh21 91 1.1 bjh21 /* 92 1.1 bjh21 * keep clist in order--inserts a column in a sorted array 93 1.1 bjh21 */ 94 1.1 bjh21 static void 95 1.19 dsl insertcol(struct field *field) 96 1.1 bjh21 { 97 1.1 bjh21 int i; 98 1.13 itojun struct coldesc *p; 99 1.12 jdolecek 100 1.12 jdolecek /* Make space for new item */ 101 1.15 jdolecek p = realloc(clist, (ncols + 2) * sizeof(*clist)); 102 1.13 itojun if (!p) 103 1.13 itojun err(1, "realloc"); 104 1.13 itojun clist = p; 105 1.13 itojun memset(&clist[ncols], 0, sizeof(clist[ncols])); 106 1.12 jdolecek 107 1.1 bjh21 for (i = 0; i < ncols; i++) 108 1.1 bjh21 if (field->icol.num <= clist[i].num) 109 1.1 bjh21 break; 110 1.1 bjh21 if (field->icol.num != clist[i].num) { 111 1.1 bjh21 memmove(clist+i+1, clist+i, sizeof(COLDESC)*(ncols-i)); 112 1.1 bjh21 clist[i].num = field->icol.num; 113 1.1 bjh21 ncols++; 114 1.1 bjh21 } 115 1.1 bjh21 if (field->tcol.num && field->tcol.num != field->icol.num) { 116 1.1 bjh21 for (i = 0; i < ncols; i++) 117 1.1 bjh21 if (field->tcol.num <= clist[i].num) 118 1.1 bjh21 break; 119 1.1 bjh21 if (field->tcol.num != clist[i].num) { 120 1.1 bjh21 memmove(clist+i+1, clist+i,sizeof(COLDESC)*(ncols-i)); 121 1.1 bjh21 clist[i].num = field->tcol.num; 122 1.1 bjh21 ncols++; 123 1.1 bjh21 } 124 1.1 bjh21 } 125 1.1 bjh21 } 126 1.1 bjh21 127 1.1 bjh21 /* 128 1.1 bjh21 * matches fields with the appropriate columns--n^2 but who cares? 129 1.1 bjh21 */ 130 1.1 bjh21 void 131 1.19 dsl fldreset(struct field *fldtab) 132 1.1 bjh21 { 133 1.1 bjh21 int i; 134 1.13 itojun 135 1.13 itojun fldtab[0].tcol.p = clist + ncols - 1; 136 1.1 bjh21 for (++fldtab; fldtab->icol.num; ++fldtab) { 137 1.5 jdolecek for (i = 0; fldtab->icol.num != clist[i].num; i++) 138 1.5 jdolecek ; 139 1.1 bjh21 fldtab->icol.p = clist + i; 140 1.1 bjh21 if (!fldtab->tcol.num) 141 1.1 bjh21 continue; 142 1.5 jdolecek for (i = 0; fldtab->tcol.num != clist[i].num; i++) 143 1.5 jdolecek ; 144 1.1 bjh21 fldtab->tcol.p = clist + i; 145 1.1 bjh21 } 146 1.1 bjh21 } 147 1.1 bjh21 148 1.1 bjh21 /* 149 1.1 bjh21 * interprets a column in a -k field 150 1.1 bjh21 */ 151 1.3 jdolecek static const char * 152 1.23 dsl setcolumn(const char *pos, struct field *cur_fld) 153 1.1 bjh21 { 154 1.1 bjh21 struct column *col; 155 1.10 jdolecek char *npos; 156 1.1 bjh21 int tmp; 157 1.10 jdolecek col = cur_fld->icol.num ? (&cur_fld->tcol) : (&cur_fld->icol); 158 1.10 jdolecek col->num = (int) strtol(pos, &npos, 10); 159 1.10 jdolecek pos = npos; 160 1.1 bjh21 if (col->num <= 0 && !(col->num == 0 && col == &(cur_fld->tcol))) 161 1.1 bjh21 errx(2, "field numbers must be positive"); 162 1.1 bjh21 if (*pos == '.') { 163 1.1 bjh21 if (!col->num) 164 1.1 bjh21 errx(2, "cannot indent end of line"); 165 1.6 thorpej ++pos; 166 1.10 jdolecek col->indent = (int) strtol(pos, &npos, 10); 167 1.10 jdolecek pos = npos; 168 1.1 bjh21 if (&cur_fld->icol == col) 169 1.1 bjh21 col->indent--; 170 1.1 bjh21 if (col->indent < 0) 171 1.1 bjh21 errx(2, "illegal offset"); 172 1.1 bjh21 } 173 1.10 jdolecek for(; (tmp = optval(*pos, cur_fld->tcol.num)); pos++) 174 1.10 jdolecek cur_fld->flags |= tmp; 175 1.1 bjh21 if (cur_fld->icol.num == 0) 176 1.1 bjh21 cur_fld->icol.num = 1; 177 1.1 bjh21 return (pos); 178 1.1 bjh21 } 179 1.1 bjh21 180 1.1 bjh21 int 181 1.19 dsl setfield(const char *pos, struct field *cur_fld, int gflag) 182 1.1 bjh21 { 183 1.20 dsl cur_fld->mask = NULL; 184 1.4 jdolecek 185 1.23 dsl pos = setcolumn(pos, cur_fld); 186 1.1 bjh21 if (*pos == '\0') /* key extends to EOL. */ 187 1.1 bjh21 cur_fld->tcol.num = 0; 188 1.1 bjh21 else { 189 1.1 bjh21 if (*pos != ',') 190 1.1 bjh21 errx(2, "illegal field descriptor"); 191 1.23 dsl setcolumn((++pos), cur_fld); 192 1.1 bjh21 } 193 1.1 bjh21 if (!cur_fld->flags) 194 1.1 bjh21 cur_fld->flags = gflag; 195 1.23 dsl if (REVERSE) 196 1.23 dsl /* A local 'r' doesn't invert the global one */ 197 1.23 dsl cur_fld->flags &= ~R; 198 1.1 bjh21 199 1.20 dsl /* Assign appropriate mask table and weight table. */ 200 1.23 dsl cur_fld->weights = weight_tables[cur_fld->flags & (R | F)]; 201 1.23 dsl if (cur_fld->flags & I) 202 1.1 bjh21 cur_fld->mask = itable; 203 1.23 dsl else if (cur_fld->flags & D) 204 1.1 bjh21 cur_fld->mask = dtable; 205 1.4 jdolecek 206 1.1 bjh21 cur_fld->flags |= (gflag & (BI | BT)); 207 1.1 bjh21 if (!cur_fld->tcol.indent) /* BT has no meaning at end of field */ 208 1.4 jdolecek cur_fld->flags &= ~BT; 209 1.4 jdolecek 210 1.22 dsl if (cur_fld->tcol.num 211 1.22 dsl && !(!(cur_fld->flags & BI) && cur_fld->flags & BT) 212 1.22 dsl && (cur_fld->tcol.num <= cur_fld->icol.num 213 1.22 dsl /* indent if 0 -> end of field, i.e. okay */ 214 1.22 dsl && cur_fld->tcol.indent != 0 215 1.22 dsl && cur_fld->tcol.indent < cur_fld->icol.indent)) 216 1.1 bjh21 errx(2, "fields out of order"); 217 1.23 dsl 218 1.1 bjh21 insertcol(cur_fld); 219 1.1 bjh21 return (cur_fld->tcol.num); 220 1.1 bjh21 } 221 1.1 bjh21 222 1.1 bjh21 int 223 1.19 dsl optval(int desc, int tcolflag) 224 1.1 bjh21 { 225 1.1 bjh21 switch(desc) { 226 1.28 christos case 'b': 227 1.28 christos if (!tcolflag) 228 1.28 christos return BI; 229 1.28 christos else 230 1.28 christos return BT; 231 1.28 christos case 'd': return D; 232 1.28 christos case 'f': return F; 233 1.28 christos case 'i': return I; 234 1.28 christos case 'l': return L; 235 1.28 christos case 'n': return N; 236 1.28 christos case 'r': return R; 237 1.28 christos default: return 0; 238 1.1 bjh21 } 239 1.1 bjh21 } 240 1.1 bjh21 241 1.11 jdolecek /* 242 1.26 dholland * Return true if the options found in ARG, according to the getopt 243 1.26 dholland * spec in OPTS, require an additional argv word as an option 244 1.26 dholland * argument. 245 1.26 dholland */ 246 1.26 dholland static int 247 1.26 dholland options_need_argument(const char *arg, const char *opts) 248 1.26 dholland { 249 1.26 dholland size_t pos; 250 1.26 dholland const char *s; 251 1.26 dholland 252 1.26 dholland /*assert(arg[0] == '-');*/ 253 1.26 dholland 254 1.26 dholland pos = 1; 255 1.26 dholland while (arg[pos]) { 256 1.26 dholland s = strchr(opts, arg[pos]); 257 1.26 dholland if (s == NULL) { 258 1.26 dholland /* invalid option */ 259 1.26 dholland return 0; 260 1.26 dholland } 261 1.26 dholland if (s[1] == ':') { 262 1.26 dholland /* option requires argument */ 263 1.26 dholland if (arg[pos+1] == '\0') { 264 1.26 dholland /* no argument in this arg */ 265 1.26 dholland return 1; 266 1.26 dholland } 267 1.26 dholland else { 268 1.26 dholland /* argument is in this arg; no more options */ 269 1.26 dholland return 0; 270 1.26 dholland } 271 1.26 dholland } 272 1.26 dholland pos++; 273 1.26 dholland } 274 1.26 dholland return 0; 275 1.26 dholland } 276 1.26 dholland 277 1.26 dholland /* 278 1.11 jdolecek * Replace historic +SPEC arguments with appropriate -kSPEC. 279 1.26 dholland * 280 1.26 dholland * The form can be either a single +SPEC or a pair +SPEC -SPEC. 281 1.27 wiz * The following -SPEC is not recognized unless it follows 282 1.26 dholland * immediately. 283 1.11 jdolecek */ 284 1.1 bjh21 void 285 1.26 dholland fixit(int *argc, char **argv, const char *opts) 286 1.1 bjh21 { 287 1.26 dholland int i, j, sawplus; 288 1.11 jdolecek char *vpos, *tpos, spec[20]; 289 1.11 jdolecek int col, indent; 290 1.1 bjh21 291 1.26 dholland sawplus = 0; 292 1.1 bjh21 for (i = 1; i < *argc; i++) { 293 1.25 dholland /* 294 1.26 dholland * This loop must stop exactly where getopt will stop. 295 1.26 dholland * Otherwise it turns e.g. "sort x +3" into "sort x 296 1.26 dholland * -k4.1", which will croak if +3 was in fact really a 297 1.26 dholland * file name. In order to do this reliably we need to 298 1.26 dholland * be able to identify argv words that are option 299 1.26 dholland * arguments. 300 1.25 dholland */ 301 1.26 dholland 302 1.26 dholland if (!strcmp(argv[i], "--")) { 303 1.26 dholland /* End of options; stop. */ 304 1.25 dholland break; 305 1.26 dholland } 306 1.25 dholland 307 1.26 dholland if (argv[i][0] == '+') { 308 1.26 dholland /* +POS argument */ 309 1.26 dholland sawplus = 1; 310 1.26 dholland } else if (argv[i][0] == '-' && sawplus && 311 1.26 dholland isdigit((unsigned char)argv[i][1])) { 312 1.26 dholland /* -POS argument */ 313 1.26 dholland sawplus = 0; 314 1.26 dholland } else if (argv[i][0] == '-') { 315 1.26 dholland /* other option */ 316 1.26 dholland sawplus = 0; 317 1.26 dholland if (options_need_argument(argv[i], opts)) { 318 1.26 dholland /* skip over the argument */ 319 1.26 dholland i++; 320 1.26 dholland } 321 1.11 jdolecek continue; 322 1.26 dholland } else { 323 1.26 dholland /* not an option at all; stop */ 324 1.26 dholland sawplus = 0; 325 1.26 dholland break; 326 1.11 jdolecek } 327 1.11 jdolecek 328 1.26 dholland /* 329 1.26 dholland * At this point argv[i] is an old-style spec. The 330 1.26 dholland * sawplus flag used by the above loop logic also 331 1.26 dholland * tells us if it's a +SPEC or -SPEC. 332 1.26 dholland */ 333 1.26 dholland 334 1.11 jdolecek /* parse spec */ 335 1.11 jdolecek tpos = argv[i]+1; 336 1.11 jdolecek col = (int)strtol(tpos, &tpos, 10); 337 1.11 jdolecek if (*tpos == '.') { 338 1.11 jdolecek ++tpos; 339 1.11 jdolecek indent = (int) strtol(tpos, &tpos, 10); 340 1.11 jdolecek } else 341 1.11 jdolecek indent = 0; 342 1.26 dholland /* tpos now points to the optional flags */ 343 1.11 jdolecek 344 1.11 jdolecek /* 345 1.26 dholland * In the traditional form, x.0 means beginning of line; 346 1.26 dholland * in the new form, x.0 means end of line. Adjust the 347 1.26 dholland * value of INDENT accordingly. 348 1.11 jdolecek */ 349 1.26 dholland if (sawplus) { 350 1.11 jdolecek /* +POS */ 351 1.11 jdolecek col += 1; 352 1.11 jdolecek indent += 1; 353 1.11 jdolecek } else { 354 1.11 jdolecek /* -POS */ 355 1.11 jdolecek if (indent > 0) 356 1.11 jdolecek col += 1; 357 1.11 jdolecek } 358 1.11 jdolecek 359 1.26 dholland /* make the new style spec */ 360 1.29 christos (void)snprintf(spec, sizeof(spec), "%d.%d%s", col, indent, 361 1.11 jdolecek tpos); 362 1.11 jdolecek 363 1.26 dholland if (sawplus) { 364 1.11 jdolecek /* Replace the +POS argument with new-style -kSPEC */ 365 1.11 jdolecek asprintf(&vpos, "-k%s", spec); 366 1.1 bjh21 argv[i] = vpos; 367 1.11 jdolecek } else { 368 1.11 jdolecek /* 369 1.26 dholland * Append the spec to the one from the 370 1.26 dholland * preceding +POS argument, and remove the 371 1.26 dholland * current argv element entirely. 372 1.11 jdolecek */ 373 1.11 jdolecek asprintf(&vpos, "%s,%s", argv[i-1], spec); 374 1.11 jdolecek free(argv[i-1]); 375 1.11 jdolecek argv[i-1] = vpos; 376 1.11 jdolecek for (j=i; j < *argc; j++) 377 1.11 jdolecek argv[j] = argv[j+1]; 378 1.11 jdolecek *argc -= 1; 379 1.14 jdolecek i--; 380 1.1 bjh21 } 381 1.1 bjh21 } 382 1.1 bjh21 } 383 1.1 bjh21 384 1.1 bjh21 /* 385 1.1 bjh21 * ascii, Rascii, Ftable, and RFtable map 386 1.20 dsl * 387 1.20 dsl * Sorting 'weight' tables. 388 1.20 dsl * Convert 'ascii' characters into their sort order. 389 1.20 dsl * The 'F' variants fold lower case to upper equivalent 390 1.20 dsl * The 'R' variants are for reverse sorting. 391 1.23 dsl * 392 1.23 dsl * The record separator (REC_D) never needs a weight, this frees one 393 1.23 dsl * byte value as an 'end of key' marker. This must be 0 for normal 394 1.23 dsl * weight tables, and 0xff for reverse weight tables - and is used 395 1.23 dsl * to terminate keys so that short keys sort before (after if reverse) 396 1.23 dsl * longer keys. 397 1.23 dsl * 398 1.23 dsl * The field separator has a normal weight - although it cannot occur 399 1.23 dsl * within a key unless it is the default (space+tab). 400 1.23 dsl * 401 1.20 dsl * All other bytes map to the appropriate value for the sort order. 402 1.20 dsl * Numeric sorts don't need any tables, they are reversed by negation. 403 1.20 dsl * 404 1.23 dsl * Global reverse sorts are done by writing the sorted keys in reverse 405 1.30 andvar * order - the sort itself is still forwards. 406 1.23 dsl * This means that weights are only ever used when generating keys, any 407 1.23 dsl * sort of the original data bytes is always forwards and unweighted. 408 1.23 dsl * 409 1.1 bjh21 * Note: this is only good for ASCII sorting. For different LC 's, 410 1.20 dsl * all bets are off. 411 1.20 dsl * 412 1.20 dsl * itable[] and dtable[] are the masks for -i (ignore non-printables) 413 1.20 dsl * and -d (only sort blank and alphanumerics). 414 1.1 bjh21 */ 415 1.1 bjh21 void 416 1.22 dsl settables(void) 417 1.1 bjh21 { 418 1.20 dsl int i; 419 1.23 dsl int next_weight = 1; 420 1.23 dsl int rev_weight = 254; 421 1.23 dsl 422 1.23 dsl ascii[REC_D] = 0; 423 1.23 dsl Rascii[REC_D] = 255; 424 1.23 dsl Ftable[REC_D] = 0; 425 1.23 dsl RFtable[REC_D] = 255; 426 1.20 dsl 427 1.20 dsl for (i = 0; i < 256; i++) { 428 1.23 dsl if (i == REC_D) 429 1.20 dsl continue; 430 1.20 dsl ascii[i] = next_weight; 431 1.20 dsl Rascii[i] = rev_weight; 432 1.20 dsl if (Ftable[i] == 0) { 433 1.20 dsl Ftable[i] = next_weight; 434 1.20 dsl RFtable[i] = rev_weight; 435 1.20 dsl Ftable[tolower(i)] = next_weight; 436 1.20 dsl RFtable[tolower(i)] = rev_weight; 437 1.1 bjh21 } 438 1.20 dsl next_weight++; 439 1.20 dsl rev_weight--; 440 1.4 jdolecek 441 1.1 bjh21 if (i == '\n' || isprint(i)) 442 1.1 bjh21 itable[i] = 1; 443 1.4 jdolecek 444 1.1 bjh21 if (i == '\n' || i == '\t' || i == ' ' || isalnum(i)) 445 1.1 bjh21 dtable[i] = 1; 446 1.1 bjh21 } 447 1.1 bjh21 } 448