Example #1
0
void mark_object(object *pair) {
    object *obj;

    obj = pair;
    while (is_pair(obj)) {
        dump_object(obj);
        gc_set(obj);
        obj = obj_pn(obj);
    }
    if (is_atom(obj)) {
        dump_object(obj);
        gc_set(obj);
    }
}
Example #2
0
// Core function
void dump(sqlite3* db)
{
	int rv;
	unsigned long count;
	sqlite3_stmt* sqlcnt = NULL;
	sqlite3_stmt* sqlid = NULL;
	std::string commandcnt = "select count(id) from object;";
	std::string commandid =  "select id from object;";

	rv = sqlite3_prepare_v2(db, commandcnt.c_str(), -1, &sqlcnt, NULL);
	if (rv != SQLITE_OK)
	{
		fprintf(stderr, "can't count the object table: %d(%s)\n",
			rv, sqlite3_errmsg(db));
		sqlite3_finalize(sqlcnt);
		return;
	}
	while ((rv = sqlite3_step(sqlcnt)) == SQLITE_BUSY)
	{
		sched_yield();
	}
	if (rv != SQLITE_ROW)
	{
		fprintf(stderr, "can't count the object table: %d(%s)\n",
			rv, sqlite3_errmsg(db));
		sqlite3_finalize(sqlcnt);
		return;
	}
	count = sqlite3_column_int(sqlcnt, 0);
	sqlite3_finalize(sqlcnt);
	printf("%lu objects\n", count);

	rv = sqlite3_prepare_v2(db, commandid.c_str(), -1, &sqlid, NULL);
	if (rv != SQLITE_OK)
	{
		fprintf(stderr, "can't count the object table: %d(%s)\n",
			rv, sqlite3_errmsg(db));
		sqlite3_finalize(sqlid);
		return;
	}
	while (count-- > 0) {
		while ((rv = sqlite3_step(sqlid)) == SQLITE_BUSY)
		{
			sched_yield();
		}
		if (rv != SQLITE_ROW)
		{
			if (rv != SQLITE_DONE)
			{
				fprintf(stderr,
					"can't get next object id: %d(%s)\n",
					rv, sqlite3_errmsg(db));
			}
			sqlite3_finalize(sqlid);
			return;
		}
		long long oid = sqlite3_column_int64(sqlid, 0);
		dump_object(db, oid);
	}
}
Example #3
0
File: ar.c Project: meesokim/z88dk
/*-----------------------------------------------------------------------------
*	Dump library file
*----------------------------------------------------------------------------*/
void dump_library( FILE *fp, char *filename )
{
    long lib_start = ftell(fp) - 8;		/* before signature */
    long next_ptr = lib_start + 8;
    long obj_start, obj_len;
    enum file_type type;

    do
    {
        fseek( fp, next_ptr, SEEK_SET );	/* next block */
        obj_start = next_ptr + 8;

        next_ptr = xfread_long( fp, filename );
        obj_len = xfread_long( fp, filename );

        type = read_signature( fp, filename );
        if ( type != is_object )
            die("File %s: contains non-object file\n", filename );

        if ( obj_len == 0 )
            printf("  Deleted...\n");

        dump_object( fp, filename );

    } while ( next_ptr >= 0 );
}
Example #4
0
static PLI_INT32 vpi_tree_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
      vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
      vpiHandle argv = vpi_iterate(vpiArgument, callh);
      vpiHandle item;

      (void)name; /* Parameter is not used. */

      if (argv == 0) {
	    item = vpi_handle(vpiScope, callh);
	    dump_object(item);
	    return 0;
      }

      for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv))
	    dump_object(item);

      return 0;
}
Example #5
0
static void dump_object(vpiHandle item)
{
      PLI_INT32 item_type = vpi_get(vpiType, item);
      vpiHandle argv, cur;

      vpi_printf("%s: ", vpi_get_str(vpiFullName, item));
      vpi_printf("vpiType=%s (%d)\n", vpi_get_str(vpiType, item), item_type);

      switch (item_type) {

	      /* These types are themselves scopes and have objects within. */
	  case vpiModule:
	  case vpiGenScope:
	  case vpiFunction:
	  case vpiTask:
	  case vpiNamedBegin:
	  case vpiNamedFork:
	    argv = vpi_iterate(vpiScope, item);
	    for (cur = vpi_scan(argv) ; cur ; cur = vpi_scan(argv))
		  dump_object(cur);
	    break;
#if 0
	  case vpiRegArray:
	  case vpiNetArray:
	    vpi_printf("%s: ", vpi_get_str(vpiFullName, item));
	    vpi_printf("vpiType=%s (%d)\n", vpi_get_str(vpiType, item), item_type);
	    argv = vpi_iterate(vpiMember, item);
	    for (cur = vpi_scan(argv) ; cur ; cur = vpi_scan(argv))
		  dump_object(cur);
	    break;
#endif
	      /* vpiMemory contains words. */
	  case vpiMemory:
	    argv = vpi_iterate(vpiMemoryWord, item);
	    for (cur = vpi_scan(argv) ; cur ; cur = vpi_scan(argv))
		  dump_object(cur);

	    break;

	  default:
	    break;
      }
}
Example #6
0
void dump_active_list(void) {
    object *p = active_list;

    fprintf(stderr, "dumping active_list...\n");
    while (p != NULL) {
        dump_object(p);
        p = chain(p);
    }
    fprintf(stderr, "finished dumping active_list\n");
}
Example #7
0
void gc_sweep(void) {
    object *obj = active_list;
    object *next, *prev;

    fprintf(stderr, "sweeping objects...\n");
    dump_active_list();

    while (obj != NULL && obj == active_list) {
        next = chain(obj);
        if (gc_active(obj)) {
            gc_clear(obj);
        } else if (gc_free(obj)) {
            dump_object(obj);
            active_list = chain(obj);
            chain(obj) = free_list;
            free_list = obj;
        } else {
            error("illegal state while gc");
        }
        obj = next;
    }

    prev = active_list;
    while (obj != NULL) {
        next = chain(obj);
        if (gc_active(obj)) {
            gc_clear(obj);
            prev = obj;
        } else if (gc_free(obj)) {
            dump_object(obj);
            chain(prev) = next;
            chain(obj) = free_list;
            free_list = obj;
        } else {
            error("illegal state while gc");
        }
        obj = next;
    }

    dump_active_list();
    fprintf(stderr, "finished sweep\n");
}
Example #8
0
File: ar.c Project: meesokim/z88dk
/*-----------------------------------------------------------------------------
*	Main
*----------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
    char	*filename;
    FILE	*fp;
    int		flags = 0;
    int 	opt;

    while ((opt = getopt(argc,argv,"hleca")) != -1 )
    {
        switch (opt )
        {
        case 'l':
            opt_showlocal = 1;
            break;
        case 'e':
            opt_showexpr = 1;
            break;
        case 'c':
            opt_dump_code = 1;
            break;
        case 'a':
            opt_showlocal = opt_showexpr = opt_dump_code = 1;
            break;
        default:
            usage(argv[0]);
        }
    }

    if ( optind == argc )
        usage(argv[0]);

    while ( optind < argc )
    {
        filename = argv[optind++];
        fp = xfopen( filename, "rb" );
        switch ( read_signature( fp, filename ) )
        {
        case is_library:
            dump_library( fp, filename );
            break;

        case is_object:
            dump_object( fp, filename );
            break;

        default:
            assert(0);
        }
        fclose( fp );
    }
    return 0;
}
Example #9
0
/* test functions */
void f(void) {
    object *obj;
    object *list;

    gc_protect(&obj);

    obj = make_pair(100, NULL);
    obj = make_pair(200, obj);
    obj = make_pair(300, obj);
    obj = make_pair(400, obj);
    obj = make_pair(500, obj);

    obj = make_pair(600, obj); /* gc */

    /* triger gc, without protection*/
    list = eat_pool(5); /* result is broken */
    dump_object(list); /* print one object, this is implementation behavior */

    gc_abandon();
}
void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
		int hang)
{
	int i;
	uint32_t ptbase, ibbase, ibsize;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

	/* Reset the list of objects */
	objbufptr = 0;

	/* Get the physical address of the MMU pagetable */
	ptbase = kgsl_mmu_get_current_ptbase(device);

	/* Dump the ringbuffer */
	snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_RB,
		snapshot, remain, snapshot_rb, NULL);

	/*
	 * Make sure that the last IB1 that was being executed is dumped.
	 * Since this was the last IB1 that was processed, we should have
	 * already added it to the list during the ringbuffer parse but we
	 * want to be double plus sure.
	 */

	kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
	kgsl_regread(device, REG_CP_IB1_BUFSZ, &ibsize);

	/*
	 * The problem is that IB size from the register is the unprocessed size
	 * of the buffer not the original size, so if we didn't catch this
	 * buffer being directly used in the RB, then we might not be able to
	 * dump the whle thing. Print a warning message so we can try to
	 * figure how often this really happens.
	 */

	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ibbase, ptbase) && ibsize) {
		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
			ibbase, ibsize);
		KGSL_DRV_ERR(device, "CP_IB1_BASE not found in the ringbuffer. "
			"Dumping %x dwords of the buffer.\n", ibsize);
	}

	kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
	kgsl_regread(device, REG_CP_IB2_BUFSZ, &ibsize);

	/*
	 * Add the last parsed IB2 to the list. The IB2 should be found as we
	 * parse the objects below, but we try to add it to the list first, so
	 * it too can be parsed.  Don't print an error message in this case - if
	 * the IB2 is found during parsing, the list will be updated with the
	 * correct size.
	 */

	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ibbase, ptbase) && ibsize) {
		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
			ibbase, ibsize);
	}

	/*
	 * Go through the list of found objects and dump each one.  As the IBs
	 * are parsed, more objects might be found, and objbufptr will increase
	 */
	for (i = 0; i < objbufptr; i++)
		snapshot = dump_object(device, i, snapshot, remain);

	/*
	 * Only dump the istore on a hang - reading it on a running system
	 * has a non 0 chance of hanging the GPU
	 */

	if (hang) {
		snapshot = kgsl_snapshot_add_section(device,
			KGSL_SNAPSHOT_SECTION_ISTORE, snapshot, remain,
			snapshot_istore, NULL);
	}

	/* Add GPU specific sections - registers mainly, but other stuff too */
	if (adreno_dev->gpudev->snapshot)
		snapshot = adreno_dev->gpudev->snapshot(adreno_dev, snapshot,
			remain, hang);

	return snapshot;
}
Example #11
0
File: object.c Project: atrinik/dwc
/**
 * Player examines some object.
 * @param op Player.
 * @param tmp Object to examine. */
void examine(object *op, object *tmp)
{
	char buf[VERY_BIG_BUF], tmp_buf[64];
	int i;

	if (tmp == NULL || tmp->type == CLOSE_CON)
	{
		return;
	}

	strcpy(buf, "That is ");
	strncat(buf, long_desc(tmp, op), VERY_BIG_BUF - strlen(buf) - 1);
	buf[VERY_BIG_BUF - 1] = '\0';

	/* Only add this for usable items, not for objects like walls or
	 * floors for example. */
	if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED) && need_identify(tmp))
	{
		strncat(buf, " (unidentified)", VERY_BIG_BUF - strlen(buf) - 1);
	}

	buf[VERY_BIG_BUF - 1] = '\0';
	new_draw_info(NDI_UNIQUE, op, buf);
	buf[0] = '\0';

	if (QUERY_FLAG(tmp, FLAG_MONSTER) || tmp->type == PLAYER)
	{
		new_draw_info_format(NDI_UNIQUE, op, "%s.", describe_item(tmp->head ? tmp->head : tmp));
		examine_living(op, tmp);
	}
	/* We don't double use the item_xxx arch commands, so they are always valid */
	else if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
	{
		if (QUERY_FLAG(tmp, FLAG_IS_GOOD))
		{
			new_draw_info_format(NDI_UNIQUE, op, "It is good aligned.");
		}
		else if (QUERY_FLAG(tmp, FLAG_IS_EVIL))
		{
			new_draw_info_format(NDI_UNIQUE, op, "It is evil aligned.");
		}
		else if (QUERY_FLAG(tmp, FLAG_IS_NEUTRAL))
		{
			new_draw_info_format(NDI_UNIQUE, op, "It is neutral aligned.");
		}

		if (tmp->item_level)
		{
			if (tmp->item_skill)
			{
				new_draw_info_format(NDI_UNIQUE, op, "It needs a level of %d in %s to use.", tmp->item_level, find_skill_exp_skillname(tmp->item_skill));
			}
			else
			{
				new_draw_info_format(NDI_UNIQUE, op, "It needs a level of %d to use.", tmp->item_level);
			}
		}

		if (tmp->item_quality)
		{
			if (QUERY_FLAG(tmp, FLAG_INDESTRUCTIBLE))
			{
				new_draw_info_format(NDI_UNIQUE, op, "Qua: %d Con: Indestructible.", tmp->item_quality);
			}
			else
			{
				new_draw_info_format(NDI_UNIQUE, op, "Qua: %d Con: %d.", tmp->item_quality, tmp->item_condition);
			}
		}

		buf[0] = '\0';
	}

	switch (tmp->type)
	{
		case SPELLBOOK:
			if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) && tmp->stats.sp >= 0 && tmp->stats.sp <= NROFREALSPELLS)
			{
				if (tmp->sub_type == ST1_SPELLBOOK_CLERIC)
				{
					snprintf(buf, sizeof(buf), "%s is a %d level prayer.", spells[tmp->stats.sp].name, spells[tmp->stats.sp].level);
				}
				else
				{
					snprintf(buf, sizeof(buf), "%s is a %d level spell.", spells[tmp->stats.sp].name, spells[tmp->stats.sp].level);
				}
			}

			break;

		case BOOK:
			if (tmp->msg != NULL)
			{
				strcpy(buf, "Something is written in it.");
			}

			break;

		case CONTAINER:
			if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
			{
				if (tmp->race != NULL)
				{
					if (tmp->weight_limit)
					{
						snprintf(buf, sizeof(buf), "It can hold only %s and its weight limit is %.1f kg.", tmp->race, (float) tmp->weight_limit / 1000.0f);
					}
					else
					{
						snprintf(buf, sizeof(buf), "It can hold only %s.", tmp->race);
					}

					/* Has magic modifier? */
					if (tmp->weapon_speed != 1.0f)
					{
						new_draw_info(NDI_UNIQUE, op, buf);

						/* Bad */
						if (tmp->weapon_speed > 1.0f)
						{
							snprintf(buf, sizeof(buf), "It increases the weight of items inside by %.1f%%.", tmp->weapon_speed * 100.0f);
						}
						/* Good */
						else
						{
							snprintf(buf, sizeof(buf), "It decreases the weight of items inside by %.1f%%.", 100.0f - (tmp->weapon_speed * 100.0f));
						}
					}
				}
				else
				{
					if (tmp->weight_limit)
					{
						snprintf(buf, sizeof(buf), "Its weight limit is %.1f kg.", (float)tmp->weight_limit / 1000.0f);
					}

					/* Has magic modifier? */
					if (tmp->weapon_speed != 1.0f)
					{
						new_draw_info(NDI_UNIQUE, op, buf);

						/* Bad */
						if (tmp->weapon_speed > 1.0f)
						{
							snprintf(buf, sizeof(buf), "It increases the weight of items inside by %.1f%%.", tmp->weapon_speed * 100.0f);
						}
						/* Good */
						else
						{
							snprintf(buf, sizeof(buf), "It decreases the weight of items inside by %.1f%%.", 100.0f - (tmp->weapon_speed * 100.0f));
						}
					}
				}

				new_draw_info(NDI_UNIQUE, op, buf);

				if (tmp->weapon_speed == 1.0f)
				{
					snprintf(buf, sizeof(buf), "It contains %3.3f kg.", (float) tmp->carrying / 1000.0f);
				}
				else if (tmp->weapon_speed > 1.0f)
				{
					snprintf(buf, sizeof(buf), "It contains %3.3f kg, increased to %3.3f kg.", (float) tmp->damage_round_tag / 1000.0f, (float) tmp->carrying / 1000.0f);
				}
				else
				{
					snprintf(buf, sizeof(buf), "It contains %3.3f kg, decreased to %3.3f kg.", (float) tmp->damage_round_tag / 1000.0f, (float) tmp->carrying / 1000.0f);
				}
			}

			break;

		case WAND:
			if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
			{
				snprintf(buf, sizeof(buf), "It has %d charges left.", tmp->stats.food);
			}

			break;

		case POWER_CRYSTAL:
			/* Avoid division by zero... */
			if (tmp->stats.maxsp == 0)
			{
				snprintf(buf, sizeof(buf), "It has capacity of %d.", tmp->stats.maxsp);
			}
			else
			{
				int i;

				/* Higher capacity crystals */
				if (tmp->stats.maxsp > 1000)
				{
					i = (tmp->stats.maxsp % 1000) / 100;

					if (i)
					{
						snprintf(tmp_buf, sizeof(tmp_buf), "It has capacity of %d.%dk and is ", tmp->stats.maxsp / 1000, i);
					}
					else
					{
						snprintf(tmp_buf, sizeof(tmp_buf), "It has capacity of %dk and is ", tmp->stats.maxsp / 1000);
					}
				}
				else
				{
					snprintf(tmp_buf, sizeof(tmp_buf), "It has capacity of %d and is ", tmp->stats.maxsp);
				}

				strcat(buf, tmp_buf);
				i = (tmp->stats.sp * 10) / tmp->stats.maxsp;

				if (tmp->stats.sp == 0)
				{
					strcat(buf, "empty.");
				}
				else if (i == 0)
				{
					strcat(buf, "almost empty.");
				}
				else if (i < 3)
				{
					strcat(buf, "partially filled.");
				}
				else if (i < 6)
				{
					strcat(buf, "half full.");
				}
				else if (i < 9)
				{
					strcat(buf, "well charged.");
				}
				else if (tmp->stats.sp == tmp->stats.maxsp)
				{
					strcat(buf, "fully charged.");
				}
				else
				{
					strcat(buf, "almost full.");
				}
			}

			break;
	}

	if (buf[0] != '\0')
	{
		new_draw_info(NDI_UNIQUE, op, buf);
	}

	if (tmp->material && (need_identify(tmp) && QUERY_FLAG(tmp, FLAG_IDENTIFIED)))
	{
		strcpy(buf, "It is made of: ");

		for (i = 0; i < NROFMATERIALS; i++)
		{
			if (tmp->material & (1 << i))
			{
				strcat(buf, material[i].name);
				strcat(buf, " ");
			}
		}

		new_draw_info(NDI_UNIQUE, op, buf);
	}

	if (tmp->weight)
	{
		float weight = (float) (tmp->nrof ? tmp->weight * (int) tmp->nrof : tmp->weight) / 1000.0f;

		if (tmp->type == MONSTER)
		{
			new_draw_info_format(NDI_UNIQUE, op, "%s weighs %3.3f kg.", gender_subjective_upper[object_get_gender(tmp)], weight);
		}
		else if (tmp->type == PLAYER)
		{
			new_draw_info_format(NDI_UNIQUE, op, "%s weighs %3.3f kg and is carrying %3.3f kg.", gender_subjective_upper[object_get_gender(tmp)], weight, (float) tmp->carrying / 1000.0f);
		}
		else
		{
			new_draw_info_format(NDI_UNIQUE, op, tmp->nrof > 1 ? "They weigh %3.3f kg." : "It weighs %3.3f kg.", weight);
		}
	}

	if (QUERY_FLAG(tmp, FLAG_STARTEQUIP))
	{
		/* Unpaid clone shop item */
		if (QUERY_FLAG(tmp, FLAG_UNPAID))
		{
			new_draw_info_format(NDI_UNIQUE, op, "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", query_cost_string(tmp, op, F_BUY));
		}
		/* God-given item */
		else
		{
			new_draw_info_format(NDI_UNIQUE, op, "%s god-given item%s.", tmp->nrof > 1 ? "They are" : "It is a", tmp->nrof > 1 ? "s" : "");

			if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
			{
				if (tmp->value)
				{
					new_draw_info_format(NDI_UNIQUE, op, "But %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", query_cost_string(tmp, op, F_TRUE));
				}
				else
				{
					new_draw_info_format(NDI_UNIQUE, op, "%s worthless.", tmp->nrof > 1 ? "They are" : "It is");
				}
			}
		}
	}
	else if (tmp->value && !IS_LIVE(tmp))
	{
		if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
		{
			if (QUERY_FLAG(tmp, FLAG_UNPAID))
			{
				new_draw_info_format(NDI_UNIQUE, op, "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", query_cost_string(tmp, op, F_BUY));
			}
			else
			{
				new_draw_info_format(NDI_UNIQUE, op, "%s worth %s.", tmp->nrof > 1 ? "They are" : "It is", query_cost_string(tmp, op, F_TRUE));
				goto dirty_little_jump1;
			}
		}
		else
		{
			object *floor;
dirty_little_jump1:

			floor = GET_MAP_OB_LAYER(op->map, op->x, op->y, 0);

			if (floor && floor->type == SHOP_FLOOR && tmp->type != MONEY)
			{
				/* Used for SK_BARGAINING modification */
				int charisma = op->stats.Cha;

				/* This skill gives us a charisma boost */
				if (find_skill(op, SK_BARGAINING))
				{
					charisma += 4;

					if (charisma > MAX_STAT)
					{
						charisma = MAX_STAT;
					}
				}

				new_draw_info_format(NDI_UNIQUE, op, "This shop will pay you %s (%0.1f%%).", query_cost_string(tmp, op, F_SELL), 20.0f + 100.0f * cha_bonus[charisma]);
			}
		}
	}
	else if (!IS_LIVE(tmp))
	{
		if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
		{
			if (QUERY_FLAG(tmp, FLAG_UNPAID))
			{
				new_draw_info_format(NDI_UNIQUE, op, "%s would cost nothing.", tmp->nrof > 1 ? "They" : "It");
			}
			else
			{
				new_draw_info_format(NDI_UNIQUE, op, "%s worthless.", tmp->nrof > 1 ? "They are" : "It is");
			}
		}
	}

	/* Does the object have a message?  Don't show message for all object
	 * types - especially if the first entry is a match */
	if (tmp->msg && tmp->type != EXIT && tmp->type != BOOK && tmp->type != CORPSE && !QUERY_FLAG(tmp, FLAG_WALK_ON) && strncasecmp(tmp->msg, "@match", 7))
	{
		/* This is just a hack so when identifying the items, we print
		 * out the extra message */
		if (need_identify(tmp) && QUERY_FLAG(tmp, FLAG_IDENTIFIED))
		{
			new_draw_info(NDI_UNIQUE, op, "The object has a story:");
			new_draw_info(NDI_UNIQUE, op, tmp->msg);
		}
	}

	/* Blank line */
	new_draw_info(NDI_UNIQUE, op, " ");

	if (QUERY_FLAG(op, FLAG_WIZ))
	{
		StringBuffer *sb = stringbuffer_new();
		char *diff;

		stringbuffer_append_printf(sb, "count %d\n", tmp->count);
		dump_object(tmp, sb);
		diff = stringbuffer_finish(sb);
		new_draw_info(NDI_UNIQUE, op, diff);
		free(diff);
	}
}
Example #12
0
int
main (int argc, char *argv[])
{
  CK_RV err;
  CK_SLOT_ID_PTR slots;
  CK_ULONG slots_count;
  unsigned int i;

  (void) argc;
  (void) argv;

  if (argc > 1 && !strcmp ("--printable", argv[1]))
    printable = true;
    
  init_cryptoki ();

  err = C_GetSlotList (true, NULL, &slots_count);
  fail_if_err (err);

  if (slots_count == 0)
    {
      printf ("Skipping test because no token is present.\n");
      return 77;
    }

  printf ("Number of slots with tokens: %lu\n", slots_count);
  slots = malloc (sizeof (CK_SLOT_ID) * slots_count);
  if (!slots)
    fail_if_err (CKR_HOST_MEMORY);

  err = C_GetSlotList (true, slots, &slots_count);
  fail_if_err (err);

  for (i = 0; i < slots_count; i++)
    {
      CK_SESSION_HANDLE session;
      CK_OBJECT_HANDLE object;
      CK_ULONG count;

      printf ("%2i. Slot ID %lu\n", i, slots[i]);
      err = C_OpenSession (slots[i], CKF_SERIAL_SESSION, NULL, NULL,
			   &session);
      fail_if_err (err);
     
      printf ("    Session ID: %lu\n", session);

      err = C_FindObjectsInit (session, NULL, 0);
      fail_if_err (err);

      do
	{
	  err = C_FindObjects (session, &object, 1, &count);
	  fail_if_err (err);

	  if (count)
	    {
	      printf ("    Object Handle: %lu\n", object);

	      err = dump_object (session, object);
	      fail_if_err (err);
	    }
	}
      while (count);

      err = C_FindObjectsFinal (session);
      fail_if_err (err);

      err = C_CloseSession (session);
      fail_if_err (err);
    }

  return 0;
}