Exemplo n.º 1
0
/* Massjoin support - really useful when trying to do things (like op/deop)
   to people after netjoins. It sends
   "massjoin #channel nick!user@host nick2!user@host ..." signals */
static void event_join(IRC_SERVER_REC *server, const char *data,
		       const char *nick, const char *address)
{
	char *params, *channel, *ptr;
	IRC_CHANNEL_REC *chanrec;
	NICK_REC *nickrec;
	GSList *nicks, *tmp;

	g_return_if_fail(data != NULL);

	if (g_strcasecmp(nick, server->nick) == 0) {
		/* You joined, no need to do anything here */
		return;
	}

	params = event_get_params(data, 1, &channel);
	ptr = strchr(channel, 7); /* ^G does something weird.. */
	if (ptr != NULL) *ptr = '\0';

	/* find channel */
	chanrec = irc_channel_find(server, channel);
	g_free(params);
	if (chanrec == NULL) return;

	/* check that the nick isn't already in nicklist. seems to happen
	   sometimes (server desyncs or something?) */
	nickrec = nicklist_find(CHANNEL(chanrec), nick);
	if (nickrec != NULL) {
		/* destroy the old record */
		nicklist_remove(CHANNEL(chanrec), nickrec);
	}

	/* add user to nicklist */
	nickrec = irc_nicklist_insert(chanrec, nick, FALSE, FALSE, FALSE, TRUE);
        nicklist_set_host(CHANNEL(chanrec), nickrec, address);

	if (chanrec->massjoins == 0) {
		/* no nicks waiting in massjoin queue */
		chanrec->massjoin_start = time(NULL);
		chanrec->last_massjoins = 0;
	}

	if (nickrec->realname == NULL) {
		/* Check if user is already in some other channel,
		   get the realname and other stuff from there */
		nicks = nicklist_get_same(SERVER(server), nick);
		for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
			NICK_REC *rec = tmp->next->data;

			if (rec->realname != NULL) {
				nickrec->last_check = rec->last_check;
				nickrec->realname = g_strdup(rec->realname);
				nickrec->gone = rec->gone;
				break;
			}
		}
		g_slist_free(nicks);
	}

	chanrec->massjoins++;
}
Exemplo n.º 2
0
/* SYNTAX: NAMES [-count | -ops -halfops -voices -normal] [<channels> | **] */
static void cmd_names(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
{
	CHANNEL_REC *chanrec;
	GHashTable *optlist;
        GString *unknowns;
	char *channel, **channels, **tmp;
        int flags;
	void *free_arg;

	g_return_if_fail(data != NULL);
	if (!IS_SERVER(server) || !server->connected)
		cmd_return_error(CMDERR_NOT_CONNECTED);

	if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
			    "names", &optlist, &channel))
		return;

	if (g_strcmp0(channel, "*") == 0 || *channel == '\0') {
		if (!IS_CHANNEL(item))
                        cmd_param_error(CMDERR_NOT_JOINED);

		channel = CHANNEL(item)->name;
	}

	flags = 0;
	if (g_hash_table_lookup(optlist, "ops") != NULL)
		flags |= CHANNEL_NICKLIST_FLAG_OPS;
	if (g_hash_table_lookup(optlist, "halfops") != NULL)
		flags |= CHANNEL_NICKLIST_FLAG_HALFOPS;
	if (g_hash_table_lookup(optlist, "voices") != NULL)
		flags |= CHANNEL_NICKLIST_FLAG_VOICES;
	if (g_hash_table_lookup(optlist, "normal") != NULL)
		flags |= CHANNEL_NICKLIST_FLAG_NORMAL;
	if (g_hash_table_lookup(optlist, "count") != NULL)
		flags |= CHANNEL_NICKLIST_FLAG_COUNT;

        if (flags == 0) flags = CHANNEL_NICKLIST_FLAG_ALL;

        unknowns = g_string_new(NULL);

	channels = g_strsplit(channel, ",", -1);
	for (tmp = channels; *tmp != NULL; tmp++) {
		chanrec = channel_find(server, *tmp);
		if (chanrec == NULL)
			g_string_append_printf(unknowns, "%s,", *tmp);
		else {
			fe_channels_nicklist(chanrec, flags);
			signal_stop();
		}
	}
	g_strfreev(channels);

	if (unknowns->len > 1)
                g_string_truncate(unknowns, unknowns->len-1);

	if (unknowns->len > 0 && g_strcmp0(channel, unknowns->str) != 0)
                signal_emit("command names", 3, unknowns->str, server, item);
        g_string_free(unknowns, TRUE);

	cmd_params_free(free_arg);
}
Exemplo n.º 3
0
/* modes of current channel, if any */
static char *expando_chanmode(SERVER_REC *server, void *item, int *free_ret)
{
	return !IS_CHANNEL(item) ? NULL : CHANNEL(item)->mode;
}
Exemplo n.º 4
0
/* if you are a channel operator in $C, expands to a '@' */
static char *expando_chanop(SERVER_REC *server, void *item, int *free_ret)
{
	return IS_CHANNEL(item) && CHANNEL(item)->chanop ? "@" : "";
}
Exemplo n.º 5
0
static void
et_setup(stpi_dither_t *d)
{
  int size = 2 * MAX_SPREAD + ((d->dst_width + 7) & ~7);
  static const int diff_factors[] = {1, 10, 16, 23, 32};
  eventone_t *et = stp_zalloc(sizeof(eventone_t));
  int xa, ya;
  int i;
  for (i = 0; i < CHANNEL_COUNT(d); i++) {
    CHANNEL(d, i).error_rows = 1;
    CHANNEL(d, i).errs = stp_zalloc(1 * sizeof(int *));
    CHANNEL(d, i).errs[0] = stp_zalloc(size * sizeof(int));
  }
  if (d->stpi_dither_type & D_UNITONE) {
    stpi_dither_channel_t *dc = stp_zalloc(sizeof(stpi_dither_channel_t));
    stp_dither_matrix_clone(&(d->dither_matrix), &(dc->dithermat), 0, 0);
    stp_dither_matrix_clone(&(d->transition_matrix), &(dc->pick), 0, 0);
    dc->error_rows = 1;
    dc->errs = stp_zalloc(1 * sizeof(int *));
    dc->errs[0] = stp_zalloc(size * sizeof(int));
    et->dummy_channel = dc;
  }

  xa = d->x_aspect / d->y_aspect;
  if (xa == 0)
    xa = 1;
  et->d_sq.dx = xa * xa;
  et->d2x = 2 * et->d_sq.dx;

  ya = d->y_aspect / d->x_aspect;
  if (ya == 0)
    ya = 1;
  et->d_sq.dy = ya * ya;
  et->d2y = 2 * et->d_sq.dy;

  et->aspect = EVEN_C2 / (xa * ya);
  et->unitone_aspect = UNITONE_C2 / (xa * ya);
  et->d_sq.r_sq = 0;

  for (i = 0; i < CHANNEL_COUNT(d); i++) {
    int x;
    shade_distance_t *shade = stp_zalloc(sizeof(shade_distance_t));
    shade->dis = et->d_sq;
    shade->et_dis = stp_malloc(sizeof(distance_t) * d->dst_width);
    if (CHANNEL(d, i).darkness > .1)
      shade->share_this_channel = 1;
    else
      shade->share_this_channel = 0;
    for (x = 0; x < d->dst_width; x++) {
      shade->et_dis[x] = et->d_sq;
    }
    CHANNEL(d, i).aux_data = shade;
  }
  if (et->dummy_channel) {
    int x;
    shade_distance_t *shade = stp_zalloc(sizeof(shade_distance_t));
    shade->dis = et->d_sq;
    shade->et_dis = stp_malloc(sizeof(distance_t) * d->dst_width);
    for (x = 0; x < d->dst_width; x++) {
      shade->et_dis[x] = et->d_sq;
    }
    et->dummy_channel->aux_data = shade;
  }

  et->physical_aspect = d->y_aspect / d->x_aspect;
  if (et->physical_aspect >= 4)
    et->physical_aspect = 4;
  else if (et->physical_aspect >= 2)
    et->physical_aspect = 2;
  else et->physical_aspect = 1;

  et->diff_factor = diff_factors[et->physical_aspect];

  d->aux_data = et;
  d->aux_freefunc = free_eventone_data;
}
Exemplo n.º 6
0
static void event_names_list(IRC_SERVER_REC *server, const char *data)
{
	IRC_CHANNEL_REC *chanrec;
	NICK_REC *rec;
	char *params, *type, *channel, *names, *ptr, *host;
        int op, halfop, voice;
	char prefixes[MAX_USER_PREFIXES+1];

	g_return_if_fail(data != NULL);

	params = event_get_params(data, 4, NULL, &type, &channel, &names);

	chanrec = irc_channel_find(server, channel);
	if (chanrec == NULL || chanrec->names_got) {
		/* unknown channel / names list already read */
		g_free(params);
		return;
	}

	/* type = '=' = public, '*' = private, '@' = secret.

	   This is actually pretty useless to check here, but at least we
	   get to know if the channel is +p or +s a few seconds before
	   we receive the MODE reply...

	   If the channel key is set, assume the channel is +k also until
           we know better, so parse_channel_modes() won't clear the key */
	if (*type == '*') {
		parse_channel_modes(chanrec, NULL,
				    chanrec->key ? "+kp" : "+p", FALSE);
	} else if (*type == '@') {
		parse_channel_modes(chanrec, NULL,
				    chanrec->key ? "+ks" : "+s", FALSE);
	}

	while (*names != '\0') {
		while (*names == ' ') names++;
		ptr = names;
		while (*names != '\0' && *names != ' ') names++;
		if (*names != '\0') *names++ = '\0';

		/* some servers show ".@nick", there's also been talk about
		   showing "@+nick" and since none of these chars are valid
		   nick chars, just check them until a non-nickflag char is
		   found. */
		op = halfop = voice = FALSE;
		prefixes[0] = '\0';
		while (isnickflag(server, *ptr)) {
			prefix_add(prefixes, *ptr, (SERVER_REC *) server);
			switch (*ptr) {
			case '@':
                                op = TRUE;
                                break;
			case '%':
                                halfop = TRUE;
                                break;
			case '+':
                                voice = TRUE;
                                break;
			}
                        ptr++;
		}

		host = strchr(ptr, '!');
		if (host != NULL)
			*host++ = '\0';

		if (nicklist_find((CHANNEL_REC *) chanrec, ptr) == NULL) {
			rec = irc_nicklist_insert(chanrec, ptr, op, halfop,
						  voice, FALSE, prefixes);
			if (host != NULL)
				nicklist_set_host(CHANNEL(chanrec), rec, host);
		}
	}

	g_free(params);
}
Exemplo n.º 7
0
void
stpi_dither_ut(stp_vars_t *v,
	       int row,
	       const unsigned short *raw,
	       int duplicate_line,
	       int zero_mask,
	       const unsigned char *mask)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  eventone_t *et;

  int		x,
	        length;
  unsigned char	bit;
  int		i;

  int		terminate;
  int		direction;
  int		xerror, xstep, xmod;
  int		channel_count = CHANNEL_COUNT(d);
  stpi_dither_channel_t *ddc;

  if (channel_count == 1) {
    stpi_dither_et(v, row, raw, duplicate_line, zero_mask, mask);
    return;
  }

  if (!et_initializer(d, duplicate_line, zero_mask))
    return;

  et = (eventone_t *) d->aux_data;
  ddc = et->dummy_channel;

  length = (d->dst_width + 7) / 8;

  if (row & 1) {
    direction = 1;
    x = 0;
    terminate = d->dst_width;
    d->ptr_offset = 0;
  } else {
    direction = -1;
    x = d->dst_width - 1;
    terminate = -1;
    d->ptr_offset = length - 1;
    raw += channel_count * (d->src_width - 1);
  }
  bit = 1 << (7 - (x & 7));
  xstep  = channel_count * (d->src_width / d->dst_width);
  xmod   = d->src_width % d->dst_width;
  xerror = (xmod * x) % d->dst_width;

  for (; x != terminate; x += direction) {

    shade_distance_t *ssp = (shade_distance_t *) ddc->aux_data;
    int point_error = 0;
    int total_error = 0;
    int channels_to_print = 0;
    int print_all_channels = 0;
    int maximum_value = 0;
    int comparison = 32768;
    stpi_dither_channel_t *best_channel = NULL;
    stpi_dither_channel_t *second_best_channel = NULL;
    int best_channel_value = INT_MIN;
    int second_best_channel_value = INT_MIN;
    int random_value = ditherpoint(d, &(d->dither_matrix), x);

    if (d->stpi_dither_type & D_ORDERED_BASE)
      comparison += (random_value / 16) - 2048;


    ddc->b = 0;
    advance_eventone_pre(ssp, et, x);

    for (i=0; i < channel_count; i++) {
      stpi_dither_channel_t *dc = &CHANNEL(d, i);
      if (dc->ptr) {
	shade_distance_t *sp = (shade_distance_t *) dc->aux_data;

	advance_eventone_pre(sp, et, x);

	/*
	 * Find which are the two candidate dot sizes.
	 * Rather than use the absolute value of the point to compute
	 * the error, we will use the relative value of the point within
	 * the range to find the two candidate dot sizes.
	 */
	dc->b = find_segment_and_ditherpoint(dc, raw[i],
					     &(sp->lower), &(sp->upper));
	if (sp->share_this_channel) {
	  if (dc->b > maximum_value)
	    maximum_value = dc->b;
	  ddc->b += dc->b;
	}
	/* Incorporate error data from previous line */
	dc->v += 2 * dc->b + (dc->errs[0][x + MAX_SPREAD] + 8) / 16;
	dc->o = unitone_adjust(dc, et, dc->v - dc->b, dc->b);
      }
    }

#if 0
    if ((2 * (ddc->b - maximum_value)) < (3 * maximum_value))
      print_all_channels = 1;
#endif

    if (ddc->b > 131070)
      print_all_channels = 1;
    else if (ddc->b > 65535) {
      ddc->b -= 65535;
      channels_to_print = 1;
    }

    if (ddc->b > 65535) {
      ddc->b = 65535;
    }
    
    ddc->v += 2 * ddc->b + (ddc->errs[0][x + MAX_SPREAD] + 8) / 16;
    total_error += eventone_adjust(ddc, et, ddc->v - ddc->b, ddc->b);
    if (total_error >= comparison) {
      channels_to_print += 1;
    }

    if (!print_all_channels) {
      for (i=0; i < channel_count; i++) {
	stpi_dither_channel_t *dc = &CHANNEL(d, i);
	shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
      
	if (dc->ptr) {

	  if (sp->share_this_channel) {
	    if (dc->o > best_channel_value) {
	      second_best_channel = best_channel;
	      best_channel = dc;
	      second_best_channel_value = best_channel_value;
	      if (dc->o >= 32768)
		best_channel_value = INT_MAX;
	      else
		best_channel_value = dc->o;
	    } else if (dc->o > second_best_channel_value) {
	      second_best_channel = dc;
	      if (dc->o >= 32768)
		second_best_channel_value = INT_MAX;
	      else
		second_best_channel_value = dc->o;
	    }
	  }
	}
      }
    }
    
    for (i=0; i < channel_count; i++) {
      stpi_dither_channel_t *dc = &CHANNEL(d, i);
      if (dc->ptr) {

	/* Determine whether to print the larger or smaller dot */
	shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
	stpi_ink_defn_t *inkp = &(sp->lower);

	if (dc->o < 0)
	  dc->o = 0;
	else if (dc->o > 65535)
	  dc->o = 65535;
	if (print_all_channels || !sp->share_this_channel) {
	  point_error += dc->o;
	  if (point_error >= comparison) {
	    point_error -= 65535;
	    inkp = &(sp->upper);
	    dc->v -= 131070;
	    sp->dis = et->d_sq;
	  }
	} else if ((channels_to_print >= 1 && best_channel == dc) ||
		   (channels_to_print >= 2 && second_best_channel == dc)) {
	  inkp = &(sp->upper);
	  dc->v -= 131070;
	  sp->dis = et->d_sq;
	}	  
	if (inkp->bits) {
	  if (!mask || (*(mask + d->ptr_offset) & bit)) {
	    set_row_ends(dc, x);

	    /* Do the printing */
	    print_ink(d, dc->ptr, inkp, bit, length);
	  }
	}
      }
    }
    if (total_error >= comparison) {
      ddc->v -= 131070;
      total_error -= 65535;
      ssp->dis = et->d_sq;
    }

    eventone_update(ddc, et, x, direction);
    diffuse_error(ddc, et, x, direction);
    for (i=0; i < channel_count; i++) {
      stpi_dither_channel_t *dc = &CHANNEL(d, i);
      if (dc->ptr) {

	/* Spread the error around to the adjacent dots */
	eventone_update(dc, et, x, direction);
	diffuse_error(dc, et, x, direction);
      }
    }


    if (direction == 1)
      ADVANCE_UNIDIRECTIONAL(d, bit, raw, channel_count, xerror, xstep, xmod);
    else
      ADVANCE_REVERSE(d, bit, raw, channel_count, xerror, xstep, xmod);
  }
  if (direction == -1)
    stpi_dither_reverse_row_ends(d);
}
Exemplo n.º 8
0
void
stpi_dither_et(stp_vars_t *v,
	       int row,
	       const unsigned short *raw,
	       int duplicate_line,
	       int zero_mask,
	       const unsigned char *mask)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  eventone_t *et;

  int		x,
	        length;
  unsigned char	bit;
  int		i;

  int		terminate;
  int		direction;
  int		xerror, xstep, xmod;
  int		channel_count = CHANNEL_COUNT(d);

  if (!et_initializer(d, duplicate_line, zero_mask))
    return;

  et = (eventone_t *) d->aux_data;

  length = (d->dst_width + 7) / 8;

  if (row & 1) {
    direction = 1;
    x = 0;
    terminate = d->dst_width;
    d->ptr_offset = 0;
  } else {
    direction = -1;
    x = d->dst_width - 1;
    terminate = -1;
    d->ptr_offset = length - 1;
    raw += channel_count * (d->src_width - 1);
  }
  bit = 1 << (7 - (x & 7));
  xstep  = channel_count * (d->src_width / d->dst_width);
  xmod   = d->src_width % d->dst_width;
  xerror = (xmod * x) % d->dst_width;

  for (; x != terminate; x += direction) {

    int point_error = 0;
    int comparison = 32768;

    if (d->stpi_dither_type & D_ORDERED_BASE)
      comparison += (ditherpoint(d, &(d->dither_matrix), x) / 16) - 2048;

    for (i=0; i < channel_count; i++) {
      if (CHANNEL(d, i).ptr)
	{
	  int inkspot;
	  int range_point;
	  stpi_dither_channel_t *dc = &CHANNEL(d, i);
	  shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
	  stpi_ink_defn_t *inkp;
	  stpi_ink_defn_t lower, upper;

	  advance_eventone_pre(sp, et, x);

	  /*
	   * Find which are the two candidate dot sizes.
	   * Rather than use the absolute value of the point to compute
	   * the error, we will use the relative value of the point within
	   * the range to find the two candidate dot sizes.
	   */
	  range_point =
	    find_segment_and_ditherpoint(dc, raw[i], &lower, &upper);

	  /* Incorporate error data from previous line */
	  dc->v += 2 * range_point + (dc->errs[0][x + MAX_SPREAD] + 8) / 16;
	  inkspot = dc->v - range_point;

	  point_error += eventone_adjust(dc, et, inkspot, range_point);

	  /* Determine whether to print the larger or smaller dot */
	  inkp = &lower;
	  if (point_error >= comparison) {
	    point_error -= 65535;
	    inkp = &upper;
	    dc->v -= 131070;
	    sp->dis = et->d_sq;
	  }

	  /* Adjust the error to reflect the dot choice */
	  if (inkp->bits) {
	    if (!mask || (*(mask + d->ptr_offset) & bit)) {
	      set_row_ends(dc, x);

	      /* Do the printing */
	      print_ink(d, dc->ptr, inkp, bit, length);
	    }
	  }

	  /* Spread the error around to the adjacent dots */
	  eventone_update(dc, et, x, direction);
	  diffuse_error(dc, et, x, direction);
	}
    }
    if (direction == 1)
      ADVANCE_UNIDIRECTIONAL(d, bit, raw, channel_count, xerror, xstep, xmod);
    else
      ADVANCE_REVERSE(d, bit, raw, channel_count, xerror, xstep, xmod);
  }
  if (direction == -1)
    stpi_dither_reverse_row_ends(d);
}
Exemplo n.º 9
0
/* convert _underlined_ and *bold* words (and phrases) to use real
   underlining or bolding */
char *expand_emphasis(WI_ITEM_REC *item, const char *text)
{
	GString *str;
	char *ret;
	int pos;

        g_return_val_if_fail(text != NULL, NULL);

	str = g_string_new(text);

	for (pos = 0; pos < str->len; pos++) {
		char type, *bgn, *end;

		bgn = str->str + pos;

		if (*bgn == '*') 
			type = 2; /* bold */
		else if (*bgn == '_') 
			type = 31; /* underlined */
		else
			continue;

		/* check that the beginning marker starts a word, and
		   that the matching end marker ends a word */
		if ((pos > 0 && !isspace(bgn[-1])) || !ishighalnum(bgn[1]))
			continue;
		if ((end = strchr(bgn+1, *bgn)) == NULL)
			continue;
		if (!ishighalnum(end[-1]) || ishighalnum(end[1]) ||
		    end[1] == type || end[1] == '*' || end[1] == '_')
			continue;

		if (IS_CHANNEL(item)) {
			/* check that this isn't a _nick_, we don't want to
			   use emphasis on them. */
			int found;
                        char c;

			c = end[1];
                        end[1] = '\0';
                        found = nicklist_find(CHANNEL(item), bgn) != NULL;
			end[1] = c;
			if (found) continue;
		}

		/* allow only *word* emphasis, not *multiple words* */
		if (!settings_get_bool("emphasis_multiword")) {
			char *c;
			for (c = bgn+1; c != end; c++) {
				if (!ishighalnum(*c))
					break;
			}
			if (c != end) continue;
		}

		if (settings_get_bool("emphasis_replace")) {
			*bgn = *end = type;
                        pos += (end-bgn);
		} else {
			g_string_insert_c(str, pos, type);
                        pos += (end - bgn) + 2;
			g_string_insert_c(str, pos++, type);
		}
	}

	ret = str->str;
	g_string_free(str, FALSE);
	return ret;
}
Exemplo n.º 10
0
Arquivo: main.cpp Projeto: Dewb/moody
strips.push_back(pStrip); \
pSupply->addFixture(pStrip); \
std::cout << "Added channel " << channel << " length: " << length << " X: " << start << " Y: " << ycoord << " flip: " << dir << "\n"; \
}

#define END_POWER_NODE }

#define DIRECTION_RIGHT false
#define DIRECTION_LEFT true


void createNetwork(const uint8_t* data, int dataWidth, int dataHeight)
{
    // Left outer
    BEGIN_POWER_NODE("10.32.0.05", 51, 50, DIRECTION_LEFT)
    CHANNEL(1, 0)
    CHANNEL(2, 2)
    END_POWER_NODE
    
    BEGIN_POWER_NODE("10.32.0.06", 51, 50, DIRECTION_LEFT)
    CHANNEL(1, 1)
    CHANNEL(2, 3)
    END_POWER_NODE
    
    // Left middle outer
    BEGIN_POWER_NODE("10.32.0.44", 51, 101, DIRECTION_LEFT)
    CHANNEL(1, 0)
    CHANNEL(2, 1)
    END_POWER_NODE
    
    BEGIN_POWER_NODE("10.32.0.17", 51, 101, DIRECTION_LEFT)
Exemplo n.º 11
0
static void
stpi_dither_set_ranges(stp_vars_t *v, int color, const stp_shade_t *shade,
		       double density, double darkness)
{
  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
  stpi_dither_channel_t *dc = &(CHANNEL(d, color));
  const stp_dotsize_t *ranges = shade->dot_sizes;
  int nlevels = shade->numsizes;
  int i;

  STP_SAFE_FREE(dc->ranges);
  STP_SAFE_FREE(dc->ink_list);

  dc->nlevels = nlevels > 1 ? nlevels + 1 : nlevels;
  dc->ranges = (stpi_dither_segment_t *)
    stp_zalloc(dc->nlevels * sizeof(stpi_dither_segment_t));
  dc->ink_list = (stpi_ink_defn_t *)
    stp_zalloc((dc->nlevels + 1) * sizeof(stpi_ink_defn_t));
  dc->bit_max = 0;
  dc->density = density * 65535;
  dc->darkness = darkness;
  stp_init_debug_messages(v);
  stp_dprintf(STP_DBG_INK, v,
	      "stpi_dither_set_ranges channel %d nlevels %d density %f darkness %f\n",
	      color, nlevels, density, darkness);
  for (i = 0; i < nlevels; i++)
    stp_dprintf(STP_DBG_INK, v,
		"  level %d value %f pattern %x\n", i,
		ranges[i].value, ranges[i].bit_pattern);
  dc->ranges[0].lower = &dc->ink_list[0];
  dc->ranges[0].upper = &dc->ink_list[1];
  dc->ink_list[0].range = 0;
  dc->ink_list[0].value = 0;
  dc->ink_list[0].bits = 0;
  if (nlevels == 1)
    dc->ink_list[1].range = 65535;
  else
    dc->ink_list[1].range = ranges[0].value * 65535.0 * density;
  if (dc->ink_list[1].range > 65535)
    dc->ink_list[1].range = 65535;
  dc->ink_list[1].value = ranges[0].value * 65535.0;
  if (dc->ink_list[1].value > 65535)
    dc->ink_list[1].value = 65535;
  dc->ink_list[1].bits = ranges[0].bit_pattern;
  if (ranges[0].bit_pattern > dc->bit_max)
    dc->bit_max = ranges[0].bit_pattern;
  dc->ranges[0].range_span = dc->ranges[0].upper->range;
  dc->ranges[0].value_span = dc->ranges[0].upper->value;
  if (dc->nlevels > 1)
    {
      for (i = 1; i < nlevels; i++)
	{
	  int l = i + 1;
	  dc->ranges[i].lower = &dc->ink_list[i];
	  dc->ranges[i].upper = &dc->ink_list[l];

	  dc->ink_list[l].range =
	    (ranges[i].value + ranges[i].value) * 32768.0 * density;
	  if (dc->ink_list[l].range > 65535)
	    dc->ink_list[l].range = 65535;
	  dc->ink_list[l].value = ranges[i].value * 65535.0;
	  if (dc->ink_list[l].value > 65535)
	    dc->ink_list[l].value = 65535;
	  dc->ink_list[l].bits = ranges[i].bit_pattern;
	  if (ranges[i].bit_pattern > dc->bit_max)
	    dc->bit_max = ranges[i].bit_pattern;
	  dc->ranges[i].range_span =
	    dc->ink_list[l].range - dc->ink_list[i].range;
	  dc->ranges[i].value_span =
	    dc->ink_list[l].value - dc->ink_list[i].value;
	}
      dc->ranges[i].lower = &dc->ink_list[i];
      dc->ranges[i].upper = &dc->ink_list[i+1];
      dc->ink_list[i+1] = dc->ink_list[i];
      dc->ink_list[i+1].range = 65535;
      dc->ranges[i].range_span =
	dc->ink_list[i+1].range - dc->ink_list[i].range;
      dc->ranges[i].value_span =
	dc->ink_list[i+1].value - dc->ink_list[i].value;
    }
  stpi_dither_finalize_ranges(v, dc);
  stp_flush_debug_messages(v);
}