Beispiel #1
0
void
hash_table_put (struct hash_table *ht, const void *key, const void *value)
{
  struct cell *c = find_cell (ht, key);
  if (CELL_OCCUPIED (c))
    {
      /* update existing item */
      c->key   = (void *)key; /* const? */
      c->value = (void *)value;
      return;
    }

  /* If adding the item would make the table exceed max. fullness,
     grow the table first.  */
  if (ht->count >= ht->resize_threshold)
    {
      grow_hash_table (ht);
      c = find_cell (ht, key);
    }

  /* add new item */
  ++ht->count;
  c->key   = (void *)key;       /* const? */
  c->value = (void *)value;
}
Beispiel #2
0
/*
 * Perform Tremaux algorithm until all 3 goal cells are visited
 *
 * Determine behavior of the robot in a cell according to its type
 * (path/dead end/junction)
 *
 * if path - go to the only possible direction
 * if dead end - rotate 180
 * if coming from a visited path - go to neighbour with least marks on a junction
 * if coming from a new path
 *  if junction is new - randomly choose direction
 *  if not - rotate 180
 */
void tremaux()
{

    move_forward();
    check_walls();
    determ_type(0);
    update_visited();

    int k, m, l;
    k = find_cell(goal1_x, goal1_y); //get goal cells
    m = find_cell(goal2_x, goal2_y);
    l = find_cell(goal3_x, goal3_y);

    while (cells[k].visited == 0 || cells[l].visited == 0 || cells[m].visited == 0) {

        int i = find_current_cell();

        if (cells[i].type == 'p')
        {
            choose_direction_p();
        }

        if (cells[i].type == 'd')
        {
            rotate_180();
            update_visited();

        }

        if (cells[i].type == 'j')
        {

            int p = find_prev_cell();

            if (cells[p].visited == 1)
            {
                if (cells[i].visited == 1)
                {
                    choose_direct_rand_j();
                }

                else
                {
                    rotate_180();
                }
            }

            else
            {
                with_least_marks();
            }
        }

        move();
    }
}
Beispiel #3
0
/*
 * Update the Cell struct representing the wall the robot is currently facing using the ping sensor. Additionally,
 * notify te neighbour about the absence of the w
 */
void ping_wall(int i)
{
    int temp_ping_dist = pingDistance();
    switch (direction) {
        case 'n' :
            if (temp_ping_dist < 30) {
                cells[i].north = 1;
            } else {
                cells[i].north = 0;
                int neighbour = find_cell(cells[i].x, cells[i].y + 1);
                if (neighbour != -1) cells[neighbour].south = 0;
            }
            north_weight = temp_ping_dist; //save distance from north wall
            break;

        case 'w' :
            if (temp_ping_dist < 30) {
                cells[i].west = 1;
            } else {
                cells[i].west = 0;
                int neighbour = find_cell(cells[i].x - 1, cells[i].y);
                if (neighbour != -1) cells[neighbour].east = 0;
            }
            west_weight = temp_ping_dist; //save distance from north wall
            break;

        case 's' :
            if (temp_ping_dist < 30) {
                cells[i].south = 1;
            } else {
                cells[i].south = 0;
                int neighbour = find_cell(cells[i].x, cells[i].y - 1);
                if (neighbour != -1) cells[neighbour].north = 0;
            }
            south_weight = temp_ping_dist; //save distance from north wall
            break;

        case 'e' :
            if (temp_ping_dist < 30) {
                cells[i].east = 1;
            } else {
                cells[i].east = 0;
                int neighbour = find_cell(cells[i].x + 1, cells[i].y);
                if (neighbour != -1) cells[neighbour].west = 0;
            }
            east_weight = temp_ping_dist; //save distance from north wall
            break;

    }
}
Beispiel #4
0
/*
 * Find a neighbour of a current cell that was visited the least number of times
 * Turns the robot towards it
 */
void with_least_marks()
{
    int min = 3;
    char min_dir = '\0';
    int i = find_current_cell();
    int j;


    if (cells[i].east == 0)
    {
        j = find_cell(current_x + 1, current_y);

        if (cells[j].visited < min) {
            min = cells[j].visited;
            min_dir = 'e';
        }
    }

    if (cells[i].north == 0) //if can enter cell on north
    {
        j = find_cell(current_x, current_y + 1);

        if (cells[j].visited < min) {
            min = cells[j].visited;
            min_dir = 'n';
        }
    }

    if (cells[i].west == 0) //if can enter cell on west
    {
        j = find_cell(current_x - 1, current_y);

        if (cells[j].visited < min) {
            min = cells[j].visited;
            min_dir = 'w';
        }
    }

    if (cells[i].south == 0) //if can enter cell on south
    {
        j = find_cell(current_x, current_y - 1);

        if (cells[j].visited < min) {
            min_dir = 's';
        }
    }

    swap_direction(min_dir);
}
Beispiel #5
0
// Draw a cell
void Fl_Table::_redraw_cell(TableContext context, int r, int c)
{
    if ( r < 0 || c < 0 ) return;
    int X,Y,W,H;
    find_cell(context, r, c, X, Y, W, H);	// find positions of cell
    draw_cell(context, r, c, X, Y, W, H);	// call users' function to draw it
}
Beispiel #6
0
/* 
 * Make an alias to a page in a source spd @ a source address to a
 * destination spd/addr
 */
vaddr_t mman_alias_page(spdid_t s_spd, vaddr_t s_addr, spdid_t d_spd, vaddr_t d_addr)
{
	int alias = -1, i;
	struct mem_cell *c;
	struct mapping_info *base;
	
	c = find_cell(s_spd, s_addr, &alias);
	if (-1 == alias) {printc("WTF\n");goto err;}
	assert(alias >= 0 && alias < MAX_ALIASES);
	base = c->map;
	for (i = 0 ; i < MAX_ALIASES ; i++) {
		if (alias == i || base[i].owner_spd != 0 || base[i].addr != 0) {
			continue;
		}

		if (cos_mmap_cntl(COS_MMAP_GRANT, 0, d_spd, d_addr, cell_index(c))) {
			printc("mm: could not alias page @ %x to spd %d from %x(%d)\n", 
			       (unsigned int)d_addr, (unsigned int)d_spd, (unsigned int)s_addr, (unsigned int)s_spd);
			goto err;
		}
		base[i].owner_spd = d_spd;
		base[i].addr = d_addr;
		base[i].parent = alias;
		c->naliases++;

		return d_addr;
	}
	/* no available alias slots! */
err:
	return 0;
}
Beispiel #7
0
void set_neighbor_references_for_cell(ih_box_system_t *system,
    ih_box_cell_t *cell)
{
  assert(system);
  assert(cell);
  ih_box_coordinate_t neighbor_coordinate;
  ih_box_coordinate_t relative_coordinate;
  ih_box_cell_t *neighbor;

  for (relative_coordinate.x = 0;
       relative_coordinate.x < 3;
       relative_coordinate.x++) {
    for (relative_coordinate.y = 0;
         relative_coordinate.y < 3;
         relative_coordinate.y++) {
      for (relative_coordinate.z = 0;
           relative_coordinate.z < 3;
           relative_coordinate.z++) {
        neighbor_coordinate.x = ih_core_wrap_index
          (cell->coordinate.x + (relative_coordinate.x - 1),
              system->dimension_coordinate.x);
        neighbor_coordinate.y = ih_core_wrap_index
          (cell->coordinate.y + (relative_coordinate.y - 1),
              system->dimension_coordinate.y);
        neighbor_coordinate.z = ih_core_wrap_index
          (cell->coordinate.z + (relative_coordinate.z - 1),
              system->dimension_coordinate.z);
        neighbor = find_cell(system, &neighbor_coordinate);
        cell->neighbors[relative_coordinate.x][relative_coordinate.y]
          [relative_coordinate.z] = neighbor;
      }
    }
  }
}
Beispiel #8
0
void dealloc(void *p)
{
    return;
    #ifdef PRINT_DEALLOC_CNT_EACH_TIME
        std::cout<<"DEALLOC CALLED"<<std::endl;
    #endif
    #ifdef NODEF
    if((size_t)p == 0x10)
        std::cout<<"ERR"<<std::endl;
    #endif
//    Buffer *buffer = _buffers;
    Node *cell = find_cell((size_t)p);
    mark_unused(cell);
/*    for(;buffer;buffer = buffer->next)
    {
        for(cell = buffer->cells; cell; cell = cell->next)
        {
            if(cell->offset + buffer->data == p)
            {
                mark_unused(cell);
                break;
            }
        }
    }*/
}
Beispiel #9
0
/* 
 * Make an alias to a page in a source spd @ a source address to a
 * destination spd/addr
 */
vaddr_t mman_alias_page(spdid_t s_spd, vaddr_t s_addr, spdid_t d_spd, vaddr_t d_addr, int flags)
{
	int alias = -1, i;
	struct mem_cell *c;
	struct mapping_info *base;
	
	c = find_cell(s_spd, s_addr, &alias);
	if (-1 == alias) goto err;
	assert(alias >= 0 && alias < MAX_ALIASES);
	base = c->map;
	for (i = alias+1 ; i < MAX_ALIASES ; i++) {
		if (base[i].owner_spd != 0 || base[i].addr != 0) continue;

		if (!parent_mman_alias_page(cos_spd_id(), (vaddr_t)c->local_addr, d_spd, d_addr)) {
			printc("mh: could not alias page @ %x to spd %d from %x(%d)\n", 
			       (unsigned int)d_addr, (unsigned int)d_spd, (unsigned int)s_addr, (unsigned int)s_spd);
			goto err;
		}
		base[i].owner_spd = d_spd;
		base[i].addr = d_addr;
		
		return d_addr;
	}
	/* no available alias slots! */
err:
	return 0;
}
Beispiel #10
0
/*
 * Call to give up a page of memory in an spd at an address.
 */
void mman_revoke_page(spdid_t spd, vaddr_t addr, int flags)
{
	int alias, i;
	struct mem_cell *mc;
	struct mapping_info *mi;

	mc = find_cell(spd, addr, &alias);
	if (!mc) {
		/* FIXME: add return codes to this call */
		return;
	}
	mi = mc->map;
	for (i = 0 ; i < MAX_ALIASES ; i++) {
		int idx;

		if (i == alias || !mi[i].owner_spd || 
		    !is_descendent(mi, alias, i)) continue;
		idx = cos_mmap_cntl(COS_MMAP_REVOKE, 0, mi[i].owner_spd, 
				    mi[i].addr, 0);
		assert(&cells[idx] == mc);
		/* mark page as removed */
		mi[i].addr = 0;
		mc->naliases--;
	}
	/* Go through and free all pages marked as removed */
	for (i = 0 ; i < MAX_ALIASES ; i++) {
		if (mi[i].addr == 0 && 
		    mi[i].owner_spd) {
			mi[i].owner_spd = 0;
			mi[i].parent = 0;
		}
	}

	return;
}
Beispiel #11
0
void WidgetTable::draw_cell(TableContext context,
	int R, int C, int X, int Y, int W, int H)
{
	switch (context)
	{
	case CONTEXT_STARTPAGE:
		fl_font(FL_HELVETICA, 12);		// font used by all headers
		col_width_all(50);				// sets the width of the columns
		break;

	case CONTEXT_RC_RESIZE:
	{
		int X, Y, W, H;
		int index = 0;
		for (int r = 0; r<rows(); r++)
		{
			for (int c = 0; c<cols(); c++)
			{
				if (index >= children()) break;
				find_cell(CONTEXT_TABLE, r, c, X, Y, W, H);
				child(index++)->resize(X, Y, W, H);
			}
		}
		init_sizes();			// tell group children resized
		return;
	}

	case CONTEXT_ROW_HEADER:
		fl_push_clip(X, Y, W, H);
		{
			static char s[40];
			sprintf(s, "Row %d", R);
			fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, row_header_color());
			fl_color(FL_BLACK);
			fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
		}
		fl_pop_clip();
		return;

	case CONTEXT_COL_HEADER:
		fl_push_clip(X, Y, W, H);
		{
			static char s[40];
			sprintf(s, "Column %d", C);
			fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, col_header_color());
			fl_color(FL_BLACK);
			fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
		}
		fl_pop_clip();
		return;

	case CONTEXT_CELL:
		return;		// fltk handles drawing the widgets

	default:
		return;
	}
}
Beispiel #12
0
void *
hash_table_get (const struct hash_table *ht, const void *key)
{
  struct cell *c = find_cell (ht, key);
  if (CELL_OCCUPIED (c))
    return c->value;
  else
    return NULL;
}
Beispiel #13
0
/**
Looks up the cell value.
@param[in]	_name Name of the header for indexing
@return Value of the cell
*/
std::string csv::Row::get_cell(string& _name)
{
	int cell_index = find_cell(_name);
	if (cell_index != -1)
	{
		return m_cells[cell_index];
	}
	throw Error::UNDEFINED_CELL;
}
Beispiel #14
0
void *cf_inferno_box_system_find(cf_inferno_box_system_t *system,
    cf_inferno_box_coordinate_t *coordinate)
{
  assert(system);
  assert(coordinate);
  assert(coordinate_in_range(system, coordinate));
  cf_inferno_box_cell_t *cell;

  cell = find_cell(system, coordinate);
  return cell->object;
}
Beispiel #15
0
void *ih_box_system_find(ih_box_system_t *system,
    ih_box_coordinate_t *coordinate)
{
  assert(system);
  assert(coordinate);
  assert(coordinate_in_range(system, coordinate));
  ih_box_cell_t *cell;

  cell = find_cell(system, coordinate);
  return cell->object;
}
Beispiel #16
0
/**
Sets the identified cell to the value.
@param[in]	_name Name of the header for indexing
@param[in]	_value Value to be assigned
*/
void csv::Row::set_cell(string& _name, string& _value)
{
	int cell_index = find_cell(_name);
	if (cell_index != -1)
	{
		m_cells[cell_index] = _value;
	}
	else
	{
		throw Error::UNDEFINED_CELL;
	}
}
bool cell_library::_parse_cell_item(string &s, size_t &pos) {
	string cell_name = string_utility::read_next_word(s, pos);
	cell *tar_cell = find_cell(cell_name);
	if (tar_cell == NULL) {
		cerr << "WARNING: Failed to find cell " << cell_name << ". (read_rw_operation)\n";
		return false;
	}
	while (string_utility::test_within(s, pos, "@")) {
		pos += 1;
		_parse_pin_item(s, pos, tar_cell->rw_op_collection);
	}
	return true;
}
Beispiel #18
0
void ih_box_system_add(ih_box_system_t *system,
    ih_box_coordinate_t *coordinate, void *object)
{
  assert(system);
  assert(coordinate);
  assert(coordinate_in_range(system, coordinate));
  assert(object);
  ih_box_cell_t *cell;

  cell = find_cell(system, coordinate);
  cell->object = object;
  system->set_cell(object, cell);
}
Beispiel #19
0
/*
 * Call to give up a page of memory in an spd at an address.
 */
int mman_release_page(spdid_t spd, vaddr_t addr, int flags)
{
	int alias;
	struct mem_cell *mc;

	mc = find_cell(spd, addr, &alias);
	if (!mc) return -1; /* FIXME: add return codes to this call */
	parent_mman_revoke_page(cos_spd_id(), (vaddr_t)mc->local_addr, flags);
	/* put the page back in the pool */
	mc->map[alias].owner_spd = 0;
	mc->map[alias].addr = 0;

	return 0;
}
Beispiel #20
0
// -----------------------------------------------------
// Insert key-value pair in symbol
// Ownership of the value object transfers to the symbab
void insert( symtab table, const char* key, void* value )
{
  int bn = hash( key, NBuckets );
  cell c = find_cell( table->bucket[ bn ], key );
  if ( c == NULL ) {		/* key not present */
    cell c = new_cell( key, value );
    c->next = table->bucket[ bn ];
    table->bucket[ bn ] = c;
  }
  else {			/* key found */
    free( c->value );
    c->value = value;
  }
}
Beispiel #21
0
optional<row>
row::pick(const vector<string> &names) const {
    row r(_database);
    bool got_values = false;
    for (const string &name : names) {
        if (const cell * const c = find_cell(name)) {
            r.add_cell(*c);
            got_values = true;
        }
        else
            r.add(boost::none);
    }
    return boost::make_optional(got_values, r);
}
bool cell_library::parse_cc_file(stringstream &ss) {
	string buff;
	cell* tar_cell;
	bool new_flag = false;
	std::regex e;
	std::smatch sm;

	while (getline(ss, buff)) {
		e = ("#(\\w+)");
		if (!std::regex_match(buff, sm, e))
			continue;

		tar_cell = find_cell(sm[1]);
		if (tar_cell == NULL) {
			new_flag = true;
			tar_cell = new cell;
		}

		if (new_flag)
			tar_cell->cell_name = sm[1];

		getline(ss, buff);
		if (new_flag) {
			_parse_inputs(buff, &tar_cell->input_pinlist, &tar_cell->map_input_pin, &tar_cell->input_num);
		}

		getline(ss, buff);
		if (new_flag) {
			_parse_output(buff, tar_cell->output_pin);
		}

		getline(ss, buff);
		_parse_01_vector(buff, tar_cell->cc1_array);

		getline(ss, buff);
		_parse_01_vector(buff, tar_cell->cc0_array);

		tar_cell->generate_truth_table();
		tar_cell->generate_backward_ref_table();
		tar_cell->generate_forward_ref_table();

		if (new_flag) {
			cell_list.push_back(tar_cell);
			map_cell[tar_cell->cell_name] = tar_cell;
		}
	}
	return true;
}
Beispiel #23
0
int
hash_table_get_pair (const struct hash_table *ht, const void *lookup_key,
                     void *orig_key, void *value)
{
  struct cell *c = find_cell (ht, lookup_key);
  if (CELL_OCCUPIED (c))
    {
      if (orig_key)
        *(void **)orig_key = c->key;
      if (value)
        *(void **)value = c->value;
      return 1;
    }
  else
    return 0;
}
Beispiel #24
0
void ih_box_system_remove(ih_box_system_t *system,
    ih_box_coordinate_t *coordinate)
{
  assert(system);
  assert(coordinate);
  ih_box_cell_t *cell;

  cell = find_cell(system, coordinate);
  if (cell->object) {
    system->set_cell(cell->object, NULL);
    if (system->destroy_object) {
      system->destroy_object(cell->object);
    }
    cell->object = NULL;
  }
}
bool cell_library::parse_co_file(stringstream &ss) {
	string buff;
	int j;
	cell* tar_cell;
	bool new_flag = false;
	std::regex e;
	std::smatch sm;
	bitset<MAX_CELL_INPUTS_X2> co_vector(0);

	while (getline(ss, buff)) {
		e = ("#(\\w+)");
		if (!std::regex_match(buff, sm, e))
			continue;
		tar_cell = find_cell(sm[1]);
		if (tar_cell == NULL) {
			new_flag = true;
			tar_cell = new cell;
		}

		if (new_flag)
			tar_cell->cell_name = sm[1];

		getline(ss, buff);
		if (new_flag) {
			_parse_inputs(buff, &tar_cell->input_pinlist, &tar_cell->map_input_pin, &tar_cell->input_num);
		}

		tar_cell->co_array.resize(tar_cell->input_num);

		getline(ss, buff);
		if (new_flag) {
			_parse_output(buff, tar_cell->output_pin);
		}

		for (j = 0; j < tar_cell->input_num; j++) {
			getline(ss, buff);
			_parse_01_vector(buff, tar_cell->co_array[j]);
		}

		if (new_flag) {
			cell_list.push_back(tar_cell);
			map_cell[tar_cell->cell_name] = tar_cell;
		}
	}
	return true;
}
Beispiel #26
0
//below fills the table with objects:
void WidgetTable::SetSize(int newrows, int newcols, WidgetTable * mytable)
{
	rows(newrows);
	cols(newcols);
	begin();		// start adding widgets to group
	{
		for (int r = 0; r<newrows; r++)
		{
			for (int c = 0; c<newcols; c++)
			{
				int X, Y, W, H;
				find_cell(CONTEXT_TABLE, r, c, X, Y, W, H);
				char s[40];
				//below decides what is put into table:
				//r is row and c is col
				if (c != 0 && c != 1 && c != 2 && c != 3) //this used to be ( c & 1) -bitwise comparison				
				{
					// Create the input widgets
					//sprintf(s, "%d.%d", r, c);
					Fl_Input *in = new Fl_Input(X, Y, W, H);
					//in->value(s);
				}
				else 
				{
					// Create the light buttons
					sprintf(s, "%d/%d ", r, c);
					My_fl_button *butt = new My_fl_button(X, Y, W, H, strdup(s));
					//Fl_Light_Button *butt = new Fl_Light_Button(X, Y, W, H, strdup(s));
					butt->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
					butt->callback(button_cb, (void*)mytable);
					//butt->value(((r + c * 2) & 4) ? 1 : 0);	//this sets the light on or off for Fl_Light_Button
					if (c == 0) butt->label("B LMT");
					if (c == 1) butt->label("B STP");
					if (c == 2) butt->label("S LMT");
					if (c == 3) butt->label("S STP");
					butt->x_pos = c;
					butt->y_pos = r;
				}

			}
		}
	}
	end();

}
Beispiel #27
0
void ih_box_system_move_absolute(ih_box_system_t *system, void *object,
    ih_box_coordinate_t *destination_coordinate)
{
  assert(system);
  assert(object);
  assert(destination_coordinate);
  ih_box_cell_t *source_cell;
  ih_box_cell_t *destination_cell;

  source_cell = system->get_cell(object);
  destination_cell = find_cell(system, destination_coordinate);

  if (source_cell != destination_cell) {
    ih_box_system_remove(system, destination_coordinate);
    ih_box_system_add(system, destination_coordinate, object);
    source_cell->object = NULL;
  }
}
Beispiel #28
0
int
hash_table_remove (struct hash_table *ht, const void *key)
{
  struct cell *c = find_cell (ht, key);
  if (!CELL_OCCUPIED (c))
    return 0;
  else
    {
      int size = ht->size;
      struct cell *cells = ht->cells;
      hashfun_t hasher = ht->hash_function;

      CLEAR_CELL (c);
      --ht->count;

      /* Rehash all the entries following C.  The alternative
         approach is to mark the entry as deleted, i.e. create a
         "tombstone".  That speeds up removal, but leaves a lot of
         garbage and slows down hash_table_get and hash_table_put.  */

      c = NEXT_CELL (c, cells, size);
      FOREACH_OCCUPIED_ADJACENT (c, cells, size)
        {
          const void *key2 = c->key;
          struct cell *c_new;

          /* Find the new location for the key. */
          c_new = cells + HASH_POSITION (key2, hasher, size);
          FOREACH_OCCUPIED_ADJACENT (c_new, cells, size)
            if (key2 == c_new->key)
              /* The cell C (key2) is already where we want it (in
                 C_NEW's "chain" of keys.)  */
              goto next_rehash;

          *c_new = *c;
          CLEAR_CELL (c);

        next_rehash:
          ;
        }
      return 1;
    }
}
Beispiel #29
0
/* 
 * FIXME: change interface to include the component making the call to
 * make sure that it owns the page it is trying to unmap (and the one
 * it is unmapping is a descendent.
 */
void mman_release_page(spdid_t spd, vaddr_t addr, int flags)
{
	int alias;
	long idx;
	struct mem_cell *mc;
	struct mapping_info *mi;

	mman_revoke_page(spd, addr, flags);
	mc = find_cell(spd, addr, &alias);
	if (!mc) {
		/* FIXME: add return codes to this call */
		return;
	}
	mi = mc->map;
	idx = cos_mmap_cntl(COS_MMAP_REVOKE, 0, mi[alias].owner_spd, 
			    mi[alias].addr, 0);
	assert(&cells[idx] == mc);
	mi[alias].addr = 0;
	mi[alias].owner_spd = 0;
	mi[alias].parent = 0;
	mc->naliases--;

	return;
}
Beispiel #30
0
void
copy_values_region (struct rng *fm, struct rng *to)
{
  CELLREF rf, rt, cf, ct;
  union vals dummy;
  CELL *cpf;

  if (set_to_region (fm, to) < 1)
    return;

  for (rf = fm->lr, rt = to->lr; rt <= to->hr; rt++, rf++)
    {
      for (cf = fm->lc, ct = to->lc; ct <= to->hc; ct++, cf++)
	{
	  cpf = find_cell (rf, cf);
	  set_new_value (rt, ct, cpf ? GET_TYP (cpf) : 0, cpf ? &(cpf->c_z) : &dummy);

	  if (cf == fm->hc)
	    cf = fm->lc - 1;
	}
      if (rf == fm->hr)
	rf = fm->lr - 1;
    }
}