HANDLE *handle_get_events(int *nevents) { HANDLE *ret; struct handle *h; int i, n, size; /* * Go through our tree counting the handle objects currently * engaged in useful activity. */ ret = NULL; n = size = 0; if (handles_by_evtomain) { for (i = 0; (h = index234(handles_by_evtomain, i)) != NULL; i++) { if (h->u.g.busy) { if (n >= size) { size += 32; ret = sresize(ret, size, HANDLE); } ret[n++] = h->u.g.ev_to_main; } } } *nevents = n; return ret; }
static void dbg_prtkws(keywordlist * kws) { /* * Output keywords in debugging format. */ int i; keyword *kw; for (i = 0; (kw = index234(kws->keys, i)) != NULL; i++) { wchar_t *wp; printf("keyword "); wp = kw->key; while (*wp) { putchar('\"'); for (; *wp; wp++) putchar(*wp); putchar('\"'); if (*++wp) printf(", "); } printf(" {\n"); dbg_prtwordlist(1, kw->text); printf("}\n"); } }
int next_fd(int *state, int *rwx) { struct fd *fd; fd = index234(fds, (*state)++); if (fd) { *rwx = fd->rwx; return fd->fd; } else return -1; }
void sk_cleanup(void) { Actual_Socket s; int i; if (sktree) { for (i = 0; (s = index234(sktree, i)) != NULL; i++) { close(s->s); } } }
static char *x11_verify(unsigned long peer_ip, int peer_port, struct X11Auth *auth, char *proto, unsigned char *data, int dlen) { if (strcmp(proto, x11_authnames[auth->fakeproto]) != 0) return "wrong authentication protocol attempted"; if (auth->fakeproto == X11_MIT) { if (dlen != auth->fakelen) return "MIT-MAGIC-COOKIE-1 data was wrong length"; if (memcmp(auth->fakedata, data, dlen) != 0) return "MIT-MAGIC-COOKIE-1 data did not match"; } if (auth->fakeproto == X11_XDM) { unsigned long t; time_t tim; int i; struct XDMSeen *seen, *ret; if (dlen != 24) return "XDM-AUTHORIZATION-1 data was wrong length"; if (peer_port == -1) return "cannot do XDM-AUTHORIZATION-1 without remote address data"; des_decrypt_xdmauth(auth->fakedata+9, data, 24); if (memcmp(auth->fakedata, data, 8) != 0) return "XDM-AUTHORIZATION-1 data failed check"; /* cookie wrong */ if (GET_32BIT_MSB_FIRST(data+8) != peer_ip) return "XDM-AUTHORIZATION-1 data failed check"; /* IP wrong */ if ((int)GET_16BIT_MSB_FIRST(data+12) != peer_port) return "XDM-AUTHORIZATION-1 data failed check"; /* port wrong */ t = GET_32BIT_MSB_FIRST(data+14); for (i = 18; i < 24; i++) if (data[i] != 0) /* zero padding wrong */ return "XDM-AUTHORIZATION-1 data failed check"; tim = time(NULL); if (abs(t - tim) > XDM_MAXSKEW) return "XDM-AUTHORIZATION-1 time stamp was too far out"; seen = snew(struct XDMSeen); seen->time = t; memcpy(seen->clientid, data+8, 6); assert(auth->xdmseen != NULL); ret = add234(auth->xdmseen, seen); if (ret != seen) { sfree(seen); return "XDM-AUTHORIZATION-1 data replayed"; } /* While we're here, purge entries too old to be replayed. */ for (;;) { seen = index234(auth->xdmseen, 0); assert(seen != NULL); if (t - seen->time <= XDM_MAXSKEW) break; sfree(delpos234(auth->xdmseen, 0)); } }
static void macrocleanup(tree234 * macros) { int ti; macro *m; for (ti = 0; (m = (macro *) index234(macros, ti)) != NULL; ti++) { sfree(m->name); sfree(m->text); sfree(m); } freetree234(macros); }
static struct sftp_request *sftp_alloc_request(void) { unsigned low, high, mid; int tsize; struct sftp_request *r; if (sftp_requests == NULL) sftp_requests = newtree234(sftp_reqcmp); /* * First-fit allocation of request IDs: always pick the lowest * unused one. To do this, binary-search using the counted * B-tree to find the largest ID which is in a contiguous * sequence from the beginning. (Precisely everything in that * sequence must have ID equal to its tree index plus * REQUEST_ID_OFFSET.) */ tsize = count234(sftp_requests); low = -1; high = tsize; while (high - low > 1) { mid = (high + low) / 2; r = index234(sftp_requests, mid); if (r->id == mid + REQUEST_ID_OFFSET) low = mid; /* this one is fine */ else high = mid; /* this one is past it */ } /* * Now low points to either -1, or the tree index of the * largest ID in the initial sequence. */ { unsigned i = low + 1 + REQUEST_ID_OFFSET; assert(NULL == find234(sftp_requests, &i, sftp_reqfind)); } /* * So the request ID we need to create is * low + 1 + REQUEST_ID_OFFSET. */ r = snew(struct sftp_request); r->id = low + 1 + REQUEST_ID_OFFSET; r->registered = false; r->userdata = NULL; add234(sftp_requests, r); return r; }
long schedule_timer(int ticks, timer_fn_t fn, void *ctx) { long when; struct timer *t, *first; init_timers(); now = GETTICKCOUNT(); when = ticks + now; /* * Just in case our various defences against timing skew fail * us: if we try to schedule a timer that's already in the * past, we instead schedule it for the immediate future. */ if (when - now <= 0) when = now + 1; t = snew(struct timer); t->fn = fn; t->ctx = ctx; t->now = when; t->when_set = now; if (t != add234(timers, t)) { sfree(t); /* identical timer already exists */ } else { add234(timer_contexts, t->ctx);/* don't care if this fails */ } first = (struct timer *)index234(timers, 0); if (first == t) { /* * This timer is the very first on the list, so we must * notify the front end. */ timer_change_notify(first->now); } return when; }
void sk_cleanup(void) { Actual_Socket s; int i; if (sktree) { for (i = 0; (s = index234(sktree, i)) != NULL; i++) { p_closesocket(s->s); } freetree234(sktree); sktree = NULL; } p_WSACleanup(); if (winsock_module) FreeLibrary(winsock_module); #ifndef NO_IPV6 if (wship6_module) FreeLibrary(wship6_module); #endif }
/* * Call to run any timers whose time has reached the present. * Returns the time (in ticks) expected until the next timer after * that triggers. */ int run_timers(long anow, long *next) { struct timer *first; init_timers(); now = GETTICKCOUNT(); while (1) { first = (struct timer *)index234(timers, 0); if (!first) return FALSE; /* no timers remaining */ if (find234(timer_contexts, first->ctx, NULL) == NULL) { /* * This timer belongs to a context that has been * expired. Delete it without running. */ delpos234(timers, 0); sfree(first); } else if (first->now - now <= 0 || now - (first->when_set - 10) < 0) { /* * This timer is active and has reached its running * time. Run it. */ delpos234(timers, 0); first->fn(first->ctx, first->now); sfree(first); } else { /* * This is the first still-active timer that is in the * future. Return how long it has yet to go. */ *next = first->now; return TRUE; } } }
void verify(void) { chkctx ctx; int i; void *p; ctx.treedepth = -1; /* depth unknown yet */ ctx.elemcount = 0; /* no elements seen yet */ /* * Verify validity of tree properties. */ if (tree->root) { if (tree->root->parent != NULL) error("root->parent is %p should be null", tree->root->parent); chknode(&ctx, 0, tree->root, NULL, NULL); } printf("tree depth: %d\n", ctx.treedepth); /* * Enumerate the tree and ensure it matches up to the array. */ for (i = 0; NULL != (p = index234(tree, i)); i++) { if (i >= arraylen) error("tree contains more than %d elements", arraylen); if (array[i] != p) error("enum at position %d: array says %s, tree says %s", i, array[i], p); } if (ctx.elemcount != i) { error("tree really contains %d elements, enum gave %d", ctx.elemcount, i); } if (i < arraylen) { error("enum gave only %d elements, array has %d", i, arraylen); } i = count234(tree); if (ctx.elemcount != i) { error("tree really contains %d elements, count234 gave %d", ctx.elemcount, i); } }
/** * SER2Jab connection management - function to use with iHttp module * - be aware of who is able to use the ihttp because he can close any * open connection between SER and Jabber server */ int xjab_connections(ih_req_p _irp, void *_p, char *_bb, int *_bl, char *_hb, int *_hl) { t_xj_jkey jkey, *p; str _u; ih_param_p _ipp = NULL; int idx, i, maxcount; char *cp; if(!_irp || !_bb || !_bl || *_bl <= 0 || !_hb || !_hl || *_hl <= 0) return -1; *_hl = 0; *_hb = 0; idx = -1; strcpy(_bb, "<h4>Active XMPP connections</h4>"); if(_irp->params) { strcat(_bb, "<br><b>Close action is alpha release!</b><br>"); _ipp = _irp->params; i = 0; while(_ipp) { switch(_ipp->name[0]) { case 'w': idx = 0; cp = _ipp->value; while(*cp && *cp>='0' && *cp<='9') { idx = idx*10 + *cp-'0'; cp++; } i++; break; case 'u': _u.s = _ipp->value; _u.len = strlen(_ipp->value); jkey.id = &_u; i++; break; case 'i': jkey.hash = 0; cp = _ipp->value; while(*cp && *cp>='0' && *cp<='9') { jkey.hash = jkey.hash*10 + *cp-'0'; cp++; } i++; break; } _ipp = _ipp->next; } if(i!=3 || idx < 0 || idx >= jwl->len) { strcat(_bb, "<br><b><i>Bad parameters!</i></b>\n"); } else { strcat(_bb, "<br><b><i>The connection of ["); strcat(_bb, _u.s); if(xj_wlist_set_flag(jwl, &jkey, XJ_FLAG_CLOSE) < 0) strcat(_bb, "] does not exist!</i></b>\n"); else strcat(_bb, "] was scheduled for closing!</i></b>\n"); } *_bl = strlen(_bb); return 0; } if(jwl!=NULL && jwl->len > 0 && jwl->workers!=NULL) { for(idx=0; idx<jwl->len; idx++) { strcat(_bb, "<br><b><i>Worker["); strcat(_bb, int2str(idx, NULL)); strcat(_bb, "]</i></b> pid="); strcat(_bb, int2str(jwl->workers[idx].pid, NULL)); strcat(_bb, " nr of jobs="); strcat(_bb, int2str(jwl->workers[idx].nr, NULL)); if(!jwl->workers[idx].sip_ids) continue; lock_set_get(jwl->sems, idx); maxcount = count234(jwl->workers[idx].sip_ids); for (i = 0; i < maxcount; i++) { p = (xj_jkey)index234(jwl->workers[idx].sip_ids, i); if(p == NULL) continue; strcat(_bb, "<br> "); strcat(_bb, int2str(i, NULL)); strcat(_bb, ". "); strcat(_bb, "<a href=\"xjabc?w="); strcat(_bb, int2str(idx, NULL)); strcat(_bb, "&i="); strcat(_bb, int2str(p->hash, NULL)); strcat(_bb, "&u="); strncat(_bb, p->id->s, p->id->len); strcat(_bb, "\">close</a>"); strcat(_bb, " "); strcat(_bb, int2str(p->hash, NULL)); strcat(_bb, " "); strncat(_bb, p->id->s, p->id->len); } lock_set_release(jwl->sems, idx); } } *_bl = strlen(_bb); return 0; }
void info_backend(paragraph *sourceform, keywordlist *keywords, indexdata *idx, void *unused) { paragraph *p; infoconfig conf; word *prefix, *body, *wp; word spaceword; wchar_t *prefixextra; int nesting, nestindent; int indentb, indenta; int filepos; int has_index; info_data intro_text = EMPTY_INFO_DATA; node *topnode, *currnode; word bullet; FILE *fp; IGNORE(unused); conf = info_configure(sourceform); /* * Go through and create a node for each section. */ topnode = info_node_new("Top", conf.charset); currnode = topnode; for (p = sourceform; p; p = p->next) switch (p->type) { /* * Chapter titles. */ case para_Chapter: case para_Appendix: case para_UnnumberedChapter: case para_Heading: case para_Subsect: { node *newnode, *upnode; char *nodename; nodename = info_node_name_for_para(p, &conf); newnode = info_node_new(nodename, conf.charset); sfree(nodename); p->private_data = newnode; if (p->parent) upnode = (node *)p->parent->private_data; else upnode = topnode; assert(upnode); newnode->up = upnode; currnode->next = newnode; newnode->prev = currnode; currnode->listnext = newnode; currnode = newnode; } break; default: p->private_data = NULL; break; } /* * Set up the display form of each index entry. */ { int i; indexentry *entry; for (i = 0; (entry = index234(idx->entries, i)) != NULL; i++) { info_idx *ii = snew(info_idx); info_data id = EMPTY_INFO_DATA; id.charset = conf.charset; ii->nnodes = ii->nodesize = 0; ii->nodes = NULL; ii->length = info_rdaddwc(&id, entry->text, NULL, FALSE, &conf); ii->text = id.output.text; entry->backend_data = ii; } } /* * An Info file begins with a piece of introductory text which * is apparently never shown anywhere. This seems to me to be a * good place to put the copyright notice and the version IDs. * Also, Info directory entries are expected to go here. */ intro_text.charset = conf.charset; info_rdaddsc(&intro_text, "This Info file generated by Halibut, "); info_rdaddsc(&intro_text, version); info_rdaddsc(&intro_text, "\n\n"); for (p = sourceform; p; p = p->next) if (p->type == para_Config && !ustricmp(p->keyword, L"info-dir-entry")) { wchar_t *section, *shortname, *longname, *kw; char *s; section = uadv(p->keyword); shortname = *section ? uadv(section) : L""; longname = *shortname ? uadv(shortname) : L""; kw = *longname ? uadv(longname) : L""; if (!*longname) { error(err_cfginsufarg, &p->fpos, p->origkeyword, 3); continue; } info_rdaddsc(&intro_text, "INFO-DIR-SECTION "); info_rdadds(&intro_text, section); info_rdaddsc(&intro_text, "\nSTART-INFO-DIR-ENTRY\n* "); info_rdadds(&intro_text, shortname); info_rdaddsc(&intro_text, ": ("); s = dupstr(conf.filename); if (strlen(s) > 5 && !strcmp(s+strlen(s)-5, ".info")) s[strlen(s)-5] = '\0'; info_rdaddsc(&intro_text, s); sfree(s); info_rdaddsc(&intro_text, ")"); if (*kw) { keyword *kwl = kw_lookup(keywords, kw); if (kwl && kwl->para->private_data) { node *n = (node *)kwl->para->private_data; info_rdaddsc(&intro_text, n->name); } } info_rdaddsc(&intro_text, ". "); info_rdadds(&intro_text, longname); info_rdaddsc(&intro_text, "\nEND-INFO-DIR-ENTRY\n\n"); } for (p = sourceform; p; p = p->next) if (p->type == para_Copyright) info_para(&intro_text, NULL, NULL, p->words, keywords, 0, 0, conf.width, &conf); for (p = sourceform; p; p = p->next) if (p->type == para_VersionID) info_versionid(&intro_text, p->words, &conf); if (intro_text.output.text[intro_text.output.pos-1] != '\n') info_rdaddc(&intro_text, '\n'); /* Do the title */ for (p = sourceform; p; p = p->next) if (p->type == para_Title) info_heading(&topnode->text, NULL, p->words, conf.width, &conf); nestindent = conf.listindentbefore + conf.listindentafter; nesting = 0; currnode = topnode; /* Do the main document */ for (p = sourceform; p; p = p->next) switch (p->type) { case para_QuotePush: nesting += 2; break; case para_QuotePop: nesting -= 2; assert(nesting >= 0); break; case para_LcontPush: nesting += nestindent; break; case para_LcontPop: nesting -= nestindent; assert(nesting >= 0); break; /* * Things we ignore because we've already processed them or * aren't going to touch them in this pass. */ case para_IM: case para_BR: case para_Biblio: /* only touch BiblioCited */ case para_VersionID: case para_NoCite: case para_Title: break; /* * Chapter titles. */ case para_Chapter: case para_Appendix: case para_UnnumberedChapter: case para_Heading: case para_Subsect: currnode = p->private_data; assert(currnode); assert(currnode->up); if (!currnode->up->started_menu) { info_rdaddsc(&currnode->up->text, "* Menu:\n\n"); currnode->up->started_menu = TRUE; } info_menu_item(&currnode->up->text, currnode, p, &conf); has_index |= info_check_index(p->words, currnode, idx); info_heading(&currnode->text, p->kwtext, p->words, conf.width, &conf); nesting = 0; break; case para_Rule: info_rule(&currnode->text, nesting, conf.width - nesting, &conf); break; case para_Normal: case para_Copyright: case para_DescribedThing: case para_Description: case para_BiblioCited: case para_Bullet: case para_NumberedList: has_index |= info_check_index(p->words, currnode, idx); if (p->type == para_Bullet) { bullet.next = NULL; bullet.alt = NULL; bullet.type = word_Normal; bullet.text = conf.bullet; prefix = • prefixextra = NULL; indentb = conf.listindentbefore; indenta = conf.listindentafter; } else if (p->type == para_NumberedList) { prefix = p->kwtext; prefixextra = conf.listsuffix; indentb = conf.listindentbefore; indenta = conf.listindentafter; } else if (p->type == para_Description) { prefix = NULL; prefixextra = NULL; indentb = conf.listindentbefore; indenta = conf.listindentafter; } else { prefix = NULL; prefixextra = NULL; indentb = indenta = 0; } if (p->type == para_BiblioCited) { body = dup_word_list(p->kwtext); for (wp = body; wp->next; wp = wp->next); wp->next = &spaceword; spaceword.next = p->words; spaceword.alt = NULL; spaceword.type = word_WhiteSpace; spaceword.text = NULL; } else { wp = NULL; body = p->words; } info_para(&currnode->text, prefix, prefixextra, body, keywords, nesting + indentb, indenta, conf.width - nesting - indentb - indenta, &conf); if (wp) { wp->next = NULL; free_word_list(body); } break; case para_Code: info_codepara(&currnode->text, p->words, nesting + conf.indent_code, conf.width - nesting - 2 * conf.indent_code); break; } /* * Create an index node if required. */ if (has_index) { node *newnode; int i, j, k; indexentry *entry; char *nodename; nodename = info_node_name_for_text(conf.index_text, &conf); newnode = info_node_new(nodename, conf.charset); sfree(nodename); newnode->up = topnode; currnode->next = newnode; newnode->prev = currnode; currnode->listnext = newnode; k = info_rdadds(&newnode->text, conf.index_text); info_rdaddsc(&newnode->text, "\n"); while (k > 0) { info_rdadds(&newnode->text, conf.underline); k -= ustrwid(conf.underline, conf.charset); } info_rdaddsc(&newnode->text, "\n\n"); info_menu_item(&topnode->text, newnode, NULL, &conf); for (i = 0; (entry = index234(idx->entries, i)) != NULL; i++) { info_idx *ii = (info_idx *)entry->backend_data; for (j = 0; j < ii->nnodes; j++) { /* * When we have multiple references for a single * index term, we only display the actual term on * the first line, to make it clear that the terms * really are the same. */ if (j == 0) info_rdaddsc(&newnode->text, ii->text); for (k = (j ? 0 : ii->length); k < conf.index_width-2; k++) info_rdaddc(&newnode->text, ' '); info_rdaddsc(&newnode->text, " *Note "); info_rdaddsc(&newnode->text, ii->nodes[j]->name); info_rdaddsc(&newnode->text, "::\n"); } } } /* * Finalise the text of each node, by adding the ^_ delimiter * and the node line at the top. */ for (currnode = topnode; currnode; currnode = currnode->listnext) { char *origtext = currnode->text.output.text; currnode->text = empty_info_data; currnode->text.charset = conf.charset; info_rdaddsc(&currnode->text, "\037\nFile: "); info_rdaddsc(&currnode->text, conf.filename); info_rdaddsc(&currnode->text, ", Node: "); info_rdaddsc(&currnode->text, currnode->name); if (currnode->prev) { info_rdaddsc(&currnode->text, ", Prev: "); info_rdaddsc(&currnode->text, currnode->prev->name); } info_rdaddsc(&currnode->text, ", Up: "); info_rdaddsc(&currnode->text, (currnode->up ? currnode->up->name : "(dir)")); if (currnode->next) { info_rdaddsc(&currnode->text, ", Next: "); info_rdaddsc(&currnode->text, currnode->next->name); } info_rdaddsc(&currnode->text, "\n\n"); info_rdaddsc(&currnode->text, origtext); /* * Just make _absolutely_ sure we end with a newline. */ if (currnode->text.output.text[currnode->text.output.pos-1] != '\n') info_rdaddc(&currnode->text, '\n'); sfree(origtext); } /* * Compute the offsets for the tag table. */ filepos = intro_text.output.pos; for (currnode = topnode; currnode; currnode = currnode->listnext) { currnode->pos = filepos; filepos += currnode->text.output.pos; } /* * Split into sub-files. */ if (conf.maxfilesize > 0) { int currfilesize = intro_text.output.pos, currfilenum = 1; for (currnode = topnode; currnode; currnode = currnode->listnext) { if (currfilesize > intro_text.output.pos && currfilesize + currnode->text.output.pos > conf.maxfilesize) { currfilenum++; currfilesize = intro_text.output.pos; } currnode->filenum = currfilenum; currfilesize += currnode->text.output.pos; } } /* * Write the primary output file. */ fp = fopen(conf.filename, "w"); if (!fp) { error(err_cantopenw, conf.filename); return; } fputs(intro_text.output.text, fp); if (conf.maxfilesize == 0) { for (currnode = topnode; currnode; currnode = currnode->listnext) fputs(currnode->text.output.text, fp); } else { int filenum = 0; fprintf(fp, "\037\nIndirect:\n"); for (currnode = topnode; currnode; currnode = currnode->listnext) if (filenum != currnode->filenum) { filenum = currnode->filenum; fprintf(fp, "%s-%d: %d\n", conf.filename, filenum, currnode->pos); } } fprintf(fp, "\037\nTag Table:\n"); if (conf.maxfilesize > 0) fprintf(fp, "(Indirect)\n"); for (currnode = topnode; currnode; currnode = currnode->listnext) fprintf(fp, "Node: %s\177%d\n", currnode->name, currnode->pos); fprintf(fp, "\037\nEnd Tag Table\n"); fclose(fp); /* * Write the subfiles. */ if (conf.maxfilesize > 0) { int filenum = 0; fp = NULL; for (currnode = topnode; currnode; currnode = currnode->listnext) { if (filenum != currnode->filenum) { char *fname; filenum = currnode->filenum; if (fp) fclose(fp); fname = snewn(strlen(conf.filename) + 40, char); sprintf(fname, "%s-%d", conf.filename, filenum); fp = fopen(fname, "w"); if (!fp) { error(err_cantopenw, fname); return; } sfree(fname); fputs(intro_text.output.text, fp); } fputs(currnode->text.output.text, fp); }
void *findrelpos234(tree234 *t, void *e, cmpfn234 cmp, int relation, int *index) { node234 *n; void *ret; int c; int idx, ecount, kcount, cmpret; if (t->root == NULL) return NULL; if (cmp == NULL) cmp = t->cmp; n = t->root; idx = 0; ecount = -1; cmpret = 0; if (e == NULL) { assert(relation == REL234_LT || relation == REL234_GT); if (relation == REL234_LT) cmpret = +1; else if (relation == REL234_GT) cmpret = -1; } while (1) { for (kcount = 0; kcount < 4; kcount++) { if (kcount >= 3 || n->elems[kcount] == NULL || (c = cmpret ? cmpret : cmp(e, n->elems[kcount])) < 0) { break; } if (n->kids[kcount]) idx += n->counts[kcount]; if (c == 0) { ecount = kcount; break; } idx++; } if (ecount >= 0) break; if (n->kids[kcount]) n = n->kids[kcount]; else break; } if (ecount >= 0) { if (relation != REL234_LT && relation != REL234_GT) { if (index) *index = idx; return n->elems[ecount]; } if (relation == REL234_LT) idx--; else idx++; } else { if (relation == REL234_EQ) return NULL; if (relation == REL234_LT || relation == REL234_LE) { idx--; } } ret = index234(t, idx); if (ret && index) *index = idx; return ret; }
int findtest(void) { const static int rels[] = { REL234_EQ, REL234_GE, REL234_LE, REL234_LT, REL234_GT }; const static char *const relnames[] = { "EQ", "GE", "LE", "LT", "GT" }; int i, j, rel, index; char *p, *ret, *realret, *realret2; int lo, hi, mid, c; for (i = 0; i < NSTR; i++) { p = strings[i]; for (j = 0; j < sizeof(rels)/sizeof(*rels); j++) { rel = rels[j]; lo = 0; hi = arraylen-1; while (lo <= hi) { mid = (lo + hi) / 2; c = strcmp(p, array[mid]); if (c < 0) hi = mid-1; else if (c > 0) lo = mid+1; else break; } if (c == 0) { if (rel == REL234_LT) ret = (mid > 0 ? array[--mid] : NULL); else if (rel == REL234_GT) ret = (mid < arraylen-1 ? array[++mid] : NULL); else ret = array[mid]; } else { assert(lo == hi+1); if (rel == REL234_LT || rel == REL234_LE) { mid = hi; ret = (hi >= 0 ? array[hi] : NULL); } else if (rel == REL234_GT || rel == REL234_GE) { mid = lo; ret = (lo < arraylen ? array[lo] : NULL); } else ret = NULL; } realret = findrelpos234(tree, p, NULL, rel, &index); if (realret != ret) { error("find(\"%s\",%s) gave %s should be %s", p, relnames[j], realret, ret); } if (realret && index != mid) { error("find(\"%s\",%s) gave %d should be %d", p, relnames[j], index, mid); } if (realret && rel == REL234_EQ) { realret2 = index234(tree, index); if (realret2 != realret) { error("find(\"%s\",%s) gave %s(%d) but %d -> %s", p, relnames[j], realret, index, index, realret2); } } #if 0 printf("find(\"%s\",%s) gave %s(%d)\n", p, relnames[j], realret, index); #endif } } realret = findrelpos234(tree, NULL, NULL, REL234_GT, &index); if (arraylen && (realret != array[0] || index != 0)) { error("find(NULL,GT) gave %s(%d) should be %s(0)", realret, index, array[0]); } else if (!arraylen && (realret != NULL)) { error("find(NULL,GT) gave %s(%d) should be NULL", realret, index); } realret = findrelpos234(tree, NULL, NULL, REL234_LT, &index); if (arraylen && (realret != array[arraylen-1] || index != arraylen-1)) { error("find(NULL,LT) gave %s(%d) should be %s(0)", realret, index, array[arraylen-1]); } else if (!arraylen && (realret != NULL)) { error("find(NULL,LT) gave %s(%d) should be NULL", realret, index); } }
/* * Generate a new complete random closed loop for the given grid. * * The method is to generate a WHITE/BLACK colouring of all the faces, * such that the WHITE faces will define the inside of the path, and the * BLACK faces define the outside. * To do this, we initially colour all faces GREY. The infinite space outside * the grid is coloured BLACK, and we choose a random face to colour WHITE. * Then we gradually grow the BLACK and the WHITE regions, eliminating GREY * faces, until the grid is filled with BLACK/WHITE. As we grow the regions, * we avoid creating loops of a single colour, to preserve the topological * shape of the WHITE and BLACK regions. * We also try to make the boundary as loopy and twisty as possible, to avoid * generating paths that are uninteresting. * The algorithm works by choosing a BLACK/WHITE colour, then choosing a GREY * face that can be coloured with that colour (without violating the * topological shape of that region). It's not obvious, but I think this * algorithm is guaranteed to terminate without leaving any GREY faces behind. * Indeed, if there are any GREY faces at all, both the WHITE and BLACK * regions can be grown. * This is checked using assert()ions, and I haven't seen any failures yet. * * Hand-wavy proof: imagine what can go wrong... * * Could the white faces get completely cut off by the black faces, and still * leave some grey faces remaining? * No, because then the black faces would form a loop around both the white * faces and the grey faces, which is disallowed because we continually * maintain the correct topological shape of the black region. * Similarly, the black faces can never get cut off by the white faces. That * means both the WHITE and BLACK regions always have some room to grow into * the GREY regions. * Could it be that we can't colour some GREY face, because there are too many * WHITE/BLACK transitions as we walk round the face? (see the * can_colour_face() function for details) * No. Imagine otherwise, and we see WHITE/BLACK/WHITE/BLACK as we walk * around the face. The two WHITE faces would be connected by a WHITE path, * and the BLACK faces would be connected by a BLACK path. These paths would * have to cross, which is impossible. * Another thing that could go wrong: perhaps we can't find any GREY face to * colour WHITE, because it would create a loop-violation or a corner-violation * with the other WHITE faces? * This is a little bit tricky to prove impossible. Imagine you have such a * GREY face (that is, if you coloured it WHITE, you would create a WHITE loop * or corner violation). * That would cut all the non-white area into two blobs. One of those blobs * must be free of BLACK faces (because the BLACK stuff is a connected blob). * So we have a connected GREY area, completely surrounded by WHITE * (including the GREY face we've tentatively coloured WHITE). * A well-known result in graph theory says that you can always find a GREY * face whose removal leaves the remaining GREY area connected. And it says * there are at least two such faces, so we can always choose the one that * isn't the "tentative" GREY face. Colouring that face WHITE leaves * everything nice and connected, including that "tentative" GREY face which * acts as a gateway to the rest of the non-WHITE grid. */ void generate_loop(grid *g, char *board, random_state *rs, loopgen_bias_fn_t bias, void *biasctx) { int i, j; int num_faces = g->num_faces; struct face_score *face_scores; /* Array of face_score objects */ struct face_score *fs; /* Points somewhere in the above list */ struct grid_face *cur_face; tree234 *lightable_faces_sorted; tree234 *darkable_faces_sorted; int *face_list; int do_random_pass; /* Make a board */ memset(board, FACE_GREY, num_faces); /* Create and initialise the list of face_scores */ face_scores = snewn(num_faces, struct face_score); for (i = 0; i < num_faces; i++) { face_scores[i].random = random_bits(rs, 31); face_scores[i].black_score = face_scores[i].white_score = 0; } /* Colour a random, finite face white. The infinite face is implicitly * coloured black. Together, they will seed the random growth process * for the black and white areas. */ i = random_upto(rs, num_faces); board[i] = FACE_WHITE; /* We need a way of favouring faces that will increase our loopiness. * We do this by maintaining a list of all candidate faces sorted by * their score and choose randomly from that with appropriate skew. * In order to avoid consistently biasing towards particular faces, we * need the sort order _within_ each group of scores to be completely * random. But it would be abusing the hospitality of the tree234 data * structure if our comparison function were nondeterministic :-). So with * each face we associate a random number that does not change during a * particular run of the generator, and use that as a secondary sort key. * Yes, this means we will be biased towards particular random faces in * any one run but that doesn't actually matter. */ lightable_faces_sorted = newtree234(white_sort_cmpfn); darkable_faces_sorted = newtree234(black_sort_cmpfn); /* Initialise the lists of lightable and darkable faces. This is * slightly different from the code inside the while-loop, because we need * to check every face of the board (the grid structure does not keep a * list of the infinite face's neighbours). */ for (i = 0; i < num_faces; i++) { grid_face *f = g->faces + i; struct face_score *fs = face_scores + i; if (board[i] != FACE_GREY) continue; /* We need the full colourability check here, it's not enough simply * to check neighbourhood. On some grids, a neighbour of the infinite * face is not necessarily darkable. */ if (can_colour_face(g, board, i, FACE_BLACK)) { fs->black_score = face_score(g, board, f, FACE_BLACK); add234(darkable_faces_sorted, fs); } if (can_colour_face(g, board, i, FACE_WHITE)) { fs->white_score = face_score(g, board, f, FACE_WHITE); add234(lightable_faces_sorted, fs); } } /* Colour faces one at a time until no more faces are colourable. */ while (TRUE) { enum face_colour colour; tree234 *faces_to_pick; int c_lightable = count234(lightable_faces_sorted); int c_darkable = count234(darkable_faces_sorted); if (c_lightable == 0 && c_darkable == 0) { /* No more faces we can use at all. */ break; } assert(c_lightable != 0 && c_darkable != 0); /* Choose a colour, and colour the best available face * with that colour. */ colour = random_upto(rs, 2) ? FACE_WHITE : FACE_BLACK; if (colour == FACE_WHITE) faces_to_pick = lightable_faces_sorted; else faces_to_pick = darkable_faces_sorted; if (bias) { /* * Go through all the candidate faces and pick the one the * bias function likes best, breaking ties using the * ordering in our tree234 (which is why we replace only * if score > bestscore, not >=). */ int j, k; struct face_score *best = NULL; int score, bestscore = 0; for (j = 0; (fs = (struct face_score *)index234(faces_to_pick, j))!=NULL; j++) { assert(fs); k = fs - face_scores; assert(board[k] == FACE_GREY); board[k] = colour; score = bias(biasctx, board, k); board[k] = FACE_GREY; bias(biasctx, board, k); /* let bias know we put it back */ if (!best || score > bestscore) { bestscore = score; best = fs; } } fs = best; } else { fs = (struct face_score *)index234(faces_to_pick, 0); } assert(fs); i = fs - face_scores; assert(board[i] == FACE_GREY); board[i] = colour; if (bias) bias(biasctx, board, i); /* notify bias function of the change */ /* Remove this newly-coloured face from the lists. These lists should * only contain grey faces. */ del234(lightable_faces_sorted, fs); del234(darkable_faces_sorted, fs); /* Remember which face we've just coloured */ cur_face = g->faces + i; /* The face we've just coloured potentially affects the colourability * and the scores of any neighbouring faces (touching at a corner or * edge). So the search needs to be conducted around all faces * touching the one we've just lit. Iterate over its corners, then * over each corner's faces. For each such face, we remove it from * the lists, recalculate any scores, then add it back to the lists * (depending on whether it is lightable, darkable or both). */ for (i = 0; i < cur_face->order; i++) { grid_dot *d = cur_face->dots[i]; for (j = 0; j < d->order; j++) { grid_face *f = d->faces[j]; int fi; /* face index of f */ if (f == NULL) continue; if (f == cur_face) continue; /* If the face is already coloured, it won't be on our * lightable/darkable lists anyway, so we can skip it without * bothering with the removal step. */ if (FACE_COLOUR(f) != FACE_GREY) continue; /* Find the face index and face_score* corresponding to f */ fi = f - g->faces; fs = face_scores + fi; /* Remove from lightable list if it's in there. We do this, * even if it is still lightable, because the score might * be different, and we need to remove-then-add to maintain * correct sort order. */ del234(lightable_faces_sorted, fs); if (can_colour_face(g, board, fi, FACE_WHITE)) { fs->white_score = face_score(g, board, f, FACE_WHITE); add234(lightable_faces_sorted, fs); } /* Do the same for darkable list. */ del234(darkable_faces_sorted, fs); if (can_colour_face(g, board, fi, FACE_BLACK)) { fs->black_score = face_score(g, board, f, FACE_BLACK); add234(darkable_faces_sorted, fs); } } } } /* Clean up */ freetree234(lightable_faces_sorted); freetree234(darkable_faces_sorted); sfree(face_scores); /* The next step requires a shuffled list of all faces */ face_list = snewn(num_faces, int); for (i = 0; i < num_faces; ++i) { face_list[i] = i; } shuffle(face_list, num_faces, sizeof(int), rs); /* The above loop-generation algorithm can often leave large clumps * of faces of one colour. In extreme cases, the resulting path can be * degenerate and not very satisfying to solve. * This next step alleviates this problem: * Go through the shuffled list, and flip the colour of any face we can * legally flip, and which is adjacent to only one face of the opposite * colour - this tends to grow 'tendrils' into any clumps. * Repeat until we can find no more faces to flip. This will * eventually terminate, because each flip increases the loop's * perimeter, which cannot increase for ever. * The resulting path will have maximal loopiness (in the sense that it * cannot be improved "locally". Unfortunately, this allows a player to * make some illicit deductions. To combat this (and make the path more * interesting), we do one final pass making random flips. */ /* Set to TRUE for final pass */ do_random_pass = FALSE; while (TRUE) { /* Remember whether a flip occurred during this pass */ int flipped = FALSE; for (i = 0; i < num_faces; ++i) { int j = face_list[i]; enum face_colour opp = (board[j] == FACE_WHITE) ? FACE_BLACK : FACE_WHITE; if (can_colour_face(g, board, j, opp)) { grid_face *face = g->faces +j; if (do_random_pass) { /* final random pass */ if (!random_upto(rs, 10)) board[j] = opp; } else { /* normal pass - flip when neighbour count is 1 */ if (face_num_neighbours(g, board, face, opp) == 1) { board[j] = opp; flipped = TRUE; } } } } if (do_random_pass) break; if (!flipped) do_random_pass = TRUE; } sfree(face_list); }
/* * Call to run any timers whose time has reached the present. * Returns the time (in ticks) expected until the next timer after * that triggers. */ int run_timers(long anow, long *next) { struct timer *first; init_timers(); #ifdef TIMING_SYNC /* * In this ifdef I put some code which deals with the * possibility that `anow' disagrees with GETTICKCOUNT by a * significant margin. Our strategy for dealing with it differs * depending on platform, because on some platforms * GETTICKCOUNT is more likely to be right whereas on others * `anow' is a better gold standard. */ { long tnow = GETTICKCOUNT(); if (tnow + TICKSPERSEC/50 - anow < 0 || anow + TICKSPERSEC/50 - tnow < 0 ) { #if defined TIMING_SYNC_ANOW /* * If anow is accurate and the tick count is wrong, * this is likely to be because the tick count is * derived from the system clock which has changed (as * can occur on Unix). Therefore, we resolve this by * inventing an offset which is used to adjust all * future output from GETTICKCOUNT. * * A platform which defines TIMING_SYNC_ANOW is * expected to have also defined this offset variable * in (its platform-specific adjunct to) putty.h. * Therefore we can simply reference it here and assume * that it will exist. */ tickcount_offset += anow - tnow; #elif defined TIMING_SYNC_TICKCOUNT /* * If the tick count is more likely to be accurate, we * simply use that as our time value, which may mean we * run no timers in this call (because we got called * early), or alternatively it may mean we run lots of * timers in a hurry because we were called late. */ anow = tnow; #else /* * Any platform which defines TIMING_SYNC must also define one of the two * auxiliary symbols TIMING_SYNC_ANOW and TIMING_SYNC_TICKCOUNT, to * indicate which measurement to trust when the two disagree. */ #error TIMING_SYNC definition incomplete #endif } } #endif now = anow; while (1) { first = (struct timer *)index234(timers, 0); if (!first) return FALSE; /* no timers remaining */ if (find234(timer_contexts, first->ctx, NULL) == NULL) { /* * This timer belongs to a context that has been * expired. Delete it without running. */ delpos234(timers, 0); sfree(first); } else if (first->now - now <= 0) { /* * This timer is active and has reached its running * time. Run it. */ delpos234(timers, 0); first->fn(first->ctx, first->now); sfree(first); } else { /* * This is the first still-active timer that is in the * future. Return how long it has yet to go. */ *next = first->now; return TRUE; } } }
/* * Find an element e in a sorted 2-3-4 tree t. Returns NULL if not * found. e is always passed as the first argument to cmp, so cmp * can be an asymmetric function if desired. cmp can also be passed * as NULL, in which case the compare function from the tree proper * will be used. */ void *findrelpos234(tree234 * t, void *e, cmpfn234 cmp, int relation, int *index) { node234 *n; void *ret; int c; int idx, ecount, kcount, cmpret; if (t->root == NULL) return NULL; if (cmp == NULL) cmp = t->cmp; n = t->root; /* * Attempt to find the element itself. */ idx = 0; ecount = -1; /* * Prepare a fake `cmp' result if e is NULL. */ cmpret = 0; if (e == NULL) { assert(relation == REL234_LT || relation == REL234_GT); if (relation == REL234_LT) cmpret = +1; /* e is a max: always greater */ else if (relation == REL234_GT) cmpret = -1; /* e is a min: always smaller */ } while (1) { for (kcount = 0; kcount < 4; kcount++) { if (kcount >= 3 || n->elems[kcount] == NULL || (c = cmpret ? cmpret : cmp(e, n->elems[kcount])) < 0) { break; } if (n->kids[kcount]) idx += n->counts[kcount]; if (c == 0) { ecount = kcount; break; } idx++; } if (ecount >= 0) break; if (n->kids[kcount]) n = n->kids[kcount]; else break; } if (ecount >= 0) { /* * We have found the element we're looking for. It's * n->elems[ecount], at tree index idx. If our search * relation is EQ, LE or GE we can now go home. */ if (relation != REL234_LT && relation != REL234_GT) { if (index) *index = idx; return n->elems[ecount]; } /* * Otherwise, we'll do an indexed lookup for the previous * or next element. (It would be perfectly possible to * implement these search types in a non-counted tree by * going back up from where we are, but far more fiddly.) */ if (relation == REL234_LT) idx--; else idx++; } else { /* * We've found our way to the bottom of the tree and we * know where we would insert this node if we wanted to: * we'd put it in in place of the (empty) subtree * n->kids[kcount], and it would have index idx * * But the actual element isn't there. So if our search * relation is EQ, we're doomed. */ if (relation == REL234_EQ) return NULL; /* * Otherwise, we must do an index lookup for index idx-1 * (if we're going left - LE or LT) or index idx (if we're * going right - GE or GT). */ if (relation == REL234_LT || relation == REL234_LE) { idx--; } } /* * We know the index of the element we want; just call index234 * to do the rest. This will return NULL if the index is out of * bounds, which is exactly what we want. */ ret = index234(t, idx); if (ret && index) *index = idx; return ret; }
void GuiFindToolBar::on_findDown() { termline *line; tree234 *whichtree; unsigned long tchar; GuiTerminalWindow *gterm = mainWnd->getCurrentTerminal(); Terminal *term; QScrollBar *scrollbar; QString str = ""; int tempStartPosition = 0; int tempCol, tempRow; if (!gterm) return; term = gterm->term; scrollbar = gterm->verticalScrollBar(); findTextFlag = true; if(getSearchedText() == "") { findTextFlag = false; gterm->viewport()->repaint(); return; } tempCol = currentCol; tempRow = currentRow; currentCol = currentCol + currentSearchedText.length(); if(getSearchedText().compare(currentSearchedText, Qt::CaseInsensitive)) { pageStartPosition = scrollbar->value(); currentSearchedText = getSearchedText(); if(currentCol < 0) currentCol = 0; whichtree = NULL; } if(currentRow < 0) currentRow = scrollbar->value(); while(1) { str = ""; if(currentRow >= scrollbar->maximum()+term->rows) { currentRow = 0; } if(count234(term->scrollback) > currentRow) { whichtree = term->scrollback; unsigned char *cline = (unsigned char*)index234(whichtree, currentRow); line = (termline*) decompressline(cline, NULL); } else { whichtree = term->screen; line = (termline*)index234(whichtree, abs(currentRow - count234(term->scrollback))); } for(int i = 0; line && i < line->size; i++) { //qDebug() << line->chars[i].chr; tchar = line->chars[i].chr; switch (tchar & CSET_MASK) { case CSET_ASCII: tchar = term->ucsdata->unitab_line[tchar & 0xFF]; break; case CSET_LINEDRW: tchar = term->ucsdata->unitab_xterm[tchar & 0xFF]; break; case CSET_SCOACS: tchar = term->ucsdata->unitab_scoacs[tchar&0xFF]; break; } str.append((char)tchar); } if(currentCol < term->cols && (currentCol = str.indexOf(currentSearchedText, currentCol, Qt::CaseInsensitive)) >= 0) { if(pageStartPosition != scrollbar->value()) gterm->setScrollBar(scrollbar->maximum()+term->rows, pageStartPosition, term->rows); else { if(currentRow < scrollbar->value() || currentRow >= (scrollbar->value() + term->rows)) { gterm->setScrollBar(scrollbar->maximum()+term->rows, currentRow, term->rows); pageStartPosition = scrollbar->value(); } } currentSearchedText = str.mid(currentCol, currentSearchedText.length()); tempStartPosition = pageStartPosition; break; } tempStartPosition++; if(tempStartPosition > (scrollbar->maximum()+term->rows)) { findTextFlag = false; currentCol = tempCol; currentRow = tempRow; gterm->viewport()->repaint(); return; } currentRow++; currentCol = 0; } gterm->viewport()->repaint(); }