Example #1
0
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;
}
Example #2
0
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");
  }
}
Example #3
0
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;
}
Example #4
0
void sk_cleanup(void)
{
    Actual_Socket s;
    int i;

    if (sktree) {
	for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
	    close(s->s);
	}
    }
}
Example #5
0
File: x11fwd.c Project: rdebath/sgt
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));
	}
    }
Example #6
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);
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
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
}
Example #10
0
/*
 * 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;
	}
    }
}
Example #11
0
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);
    }
}
Example #12
0
/**
 * 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> &nbsp;&nbsp;pid=");
			strcat(_bb, int2str(jwl->workers[idx].pid, NULL));
			strcat(_bb, " &nbsp;&nbsp;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>&nbsp;&nbsp;&nbsp;");
				strcat(_bb, int2str(i, NULL));
				strcat(_bb, ".&nbsp;&nbsp;&nbsp;");
				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, "&nbsp;&nbsp;&nbsp;");
				strcat(_bb, int2str(p->hash, NULL));
				strcat(_bb, "&nbsp;&nbsp;&nbsp;");
				strncat(_bb, p->id->s, p->id->len);
			}
			lock_set_release(jwl->sems, idx);
		}
	}
	
	*_bl = strlen(_bb);

	return 0;
}
Example #13
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 = &bullet;
	    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);
	}
Example #14
0
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;
}
Example #15
0
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);
    }
}
Example #16
0
/*
 * 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);
}
Example #17
0
/*
 * 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;
	}
    }
}
Example #18
0
/*
 * 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;
}
Example #19
0
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();
}