mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-23 04:42:32 +00:00
nuke the string hash api as it's been obsoleted
This commit is contained in:
parent
a9fb183d19
commit
13fd0b8533
11 changed files with 107 additions and 567 deletions
|
@ -69,6 +69,4 @@ void QFS_Progs_Init (struct progs_s *pr);
|
||||||
|
|
||||||
void String_Progs_Init (struct progs_s *pr);
|
void String_Progs_Init (struct progs_s *pr);
|
||||||
|
|
||||||
void StringHash_Progs_Init (struct progs_s *pr);
|
|
||||||
|
|
||||||
#endif//__QF_csqc_h
|
#endif//__QF_csqc_h
|
||||||
|
|
|
@ -453,7 +453,6 @@ Menu_Init (void)
|
||||||
PR_Cmds_Init (&menu_pr_state);
|
PR_Cmds_Init (&menu_pr_state);
|
||||||
R_Progs_Init (&menu_pr_state);
|
R_Progs_Init (&menu_pr_state);
|
||||||
String_Progs_Init (&menu_pr_state);
|
String_Progs_Init (&menu_pr_state);
|
||||||
StringHash_Progs_Init (&menu_pr_state);
|
|
||||||
|
|
||||||
confirm_quit = Cvar_Get ("confirm_quit", "1", CVAR_ARCHIVE, NULL,
|
confirm_quit = Cvar_Get ("confirm_quit", "1", CVAR_ARCHIVE, NULL,
|
||||||
"confirm quit command");
|
"confirm quit command");
|
||||||
|
|
|
@ -12,4 +12,4 @@ libQFcsqc_la_LDFLAGS= -version-info 1:0:0
|
||||||
libQFcsqc_la_SOURCES=\
|
libQFcsqc_la_SOURCES=\
|
||||||
bi_cbuf.c bi_cmd.c bi_cvar.c bi_file.c bi_hash.c bi_init.c \
|
bi_cbuf.c bi_cmd.c bi_cvar.c bi_file.c bi_hash.c bi_init.c \
|
||||||
bi_inputline.c bi_plist.c \
|
bi_inputline.c bi_plist.c \
|
||||||
bi_qfile.c bi_qfs.c bi_string.c bi_strhash.c
|
bi_qfile.c bi_qfs.c bi_string.c
|
||||||
|
|
|
@ -44,7 +44,6 @@ static void (*const plist_progs_init)(progs_t *) = Plist_Progs_Init;
|
||||||
static void (*const qfile_progs_init)(progs_t *, int) = QFile_Progs_Init;
|
static void (*const qfile_progs_init)(progs_t *, int) = QFile_Progs_Init;
|
||||||
static void (*const qfs_progs_init)(progs_t *) = QFS_Progs_Init;
|
static void (*const qfs_progs_init)(progs_t *) = QFS_Progs_Init;
|
||||||
static void (*const string_progs_init)(progs_t *) = String_Progs_Init;
|
static void (*const string_progs_init)(progs_t *) = String_Progs_Init;
|
||||||
static void (*const stringhashe_progs_init)(progs_t *) = StringHash_Progs_Init;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BI_Init ()
|
BI_Init ()
|
||||||
|
|
|
@ -1,458 +0,0 @@
|
||||||
/*
|
|
||||||
bi_inputline.c
|
|
||||||
|
|
||||||
CSQC string hashes builtins
|
|
||||||
|
|
||||||
Copyright (C) 2002 Robin Redeker <elmex@x-paste.de>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License
|
|
||||||
as published by the Free Software Foundation; either version 2
|
|
||||||
of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
|
|
||||||
See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to:
|
|
||||||
|
|
||||||
Free Software Foundation, Inc.
|
|
||||||
59 Temple Place - Suite 330
|
|
||||||
Boston, MA 02111-1307, USA
|
|
||||||
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static __attribute__ ((unused)) const char rcsid[] =
|
|
||||||
"$Id$";
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#ifdef HAVE_STRING_H
|
|
||||||
# include <string.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STRINGS_H
|
|
||||||
# include <strings.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "QF/csqc.h"
|
|
||||||
#include "QF/console.h"
|
|
||||||
#include "QF/draw.h"
|
|
||||||
#include "QF/progs.h"
|
|
||||||
#include "QF/zone.h"
|
|
||||||
|
|
||||||
#define MAX_SH_VALUES 16
|
|
||||||
|
|
||||||
/*
|
|
||||||
DESIGN NOTE (by elmex):
|
|
||||||
|
|
||||||
This file contains code for QuakeC hashes.
|
|
||||||
The hases are designed to have around 10 sub-values for
|
|
||||||
one key.
|
|
||||||
Hashes are stored as hash-ids in the QC-environment.
|
|
||||||
|
|
||||||
The key->value pairs in the hashes are stored in the
|
|
||||||
order they are set. So its easy to make array-hashes.
|
|
||||||
The function which gets the Lenght of a hash is specialy
|
|
||||||
made for array purposes.
|
|
||||||
|
|
||||||
TODO: Check the FIXME's below in the code.
|
|
||||||
(please taniwha ;)
|
|
||||||
(about memory leaks)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// a hash element
|
|
||||||
typedef struct {
|
|
||||||
char * key;
|
|
||||||
char * values[MAX_SH_VALUES];
|
|
||||||
} str_hash_elem;
|
|
||||||
|
|
||||||
// a structure of a hash
|
|
||||||
typedef struct {
|
|
||||||
str_hash_elem **elements;
|
|
||||||
int cnt_elements;
|
|
||||||
} str_hash;
|
|
||||||
|
|
||||||
// a list structure of hashes
|
|
||||||
typedef struct {
|
|
||||||
str_hash **hashes;
|
|
||||||
int cnt_hashes;
|
|
||||||
} strh_resources_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
bi_StringHash_Create
|
|
||||||
|
|
||||||
Creates a hash structure and gives back the hash-id to the
|
|
||||||
QC-environment
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
bi_StringHash_Create (progs_t *pr)
|
|
||||||
{
|
|
||||||
strh_resources_t *res = PR_Resources_Find (pr, "StringHash");
|
|
||||||
int i;
|
|
||||||
int hash_id=-1;
|
|
||||||
|
|
||||||
// check if there is a empty hash in the array
|
|
||||||
for(i = 0; i < res->cnt_hashes; i++) {
|
|
||||||
if(res->hashes[i]->cnt_elements == 0) {
|
|
||||||
// we found a empty already allocated hash
|
|
||||||
hash_id = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(hash_id == -1) {
|
|
||||||
/* allocate a new hash struct, if
|
|
||||||
there is no old one */
|
|
||||||
if(res->hashes == NULL) { // allocate a new list of hashes
|
|
||||||
res->hashes = (str_hash **) malloc(
|
|
||||||
sizeof(str_hash*) * (res->cnt_hashes + 1));
|
|
||||||
} else { // reallocate the list of hashes
|
|
||||||
res->hashes = (str_hash **) realloc(res->hashes,
|
|
||||||
sizeof(str_hash*) * (res->cnt_hashes + 1));
|
|
||||||
}
|
|
||||||
hash_id = res->cnt_hashes;
|
|
||||||
|
|
||||||
res->hashes[hash_id] =
|
|
||||||
(str_hash*) malloc(sizeof(str_hash));
|
|
||||||
// dont forge to clean the hash
|
|
||||||
memset(res->hashes[hash_id],0,sizeof(str_hash));
|
|
||||||
|
|
||||||
res->cnt_hashes++; // increase cnt of allocated hashes
|
|
||||||
}
|
|
||||||
R_INT (pr) = hash_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
bi_StringHash_Destroy
|
|
||||||
|
|
||||||
Destroys a hash
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
bi_StringHash_Destroy (progs_t *pr)
|
|
||||||
{
|
|
||||||
strh_resources_t* res = PR_Resources_Find (pr, "StringHash");
|
|
||||||
int hash_id = P_INT (pr, 0);
|
|
||||||
str_hash *sh = NULL;
|
|
||||||
int i,d;
|
|
||||||
|
|
||||||
if(hash_id >= res->cnt_hashes || hash_id < 0) {
|
|
||||||
R_INT (pr) = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sh = res->hashes[hash_id];
|
|
||||||
|
|
||||||
/* we dont really destroy the allocated hash,
|
|
||||||
but we free the elements of the hash
|
|
||||||
and mark it for reuseing */
|
|
||||||
|
|
||||||
for(i = 0; i < sh->cnt_elements; i++) {
|
|
||||||
if(sh->elements[i] != NULL) {
|
|
||||||
/* they should never be NULL,
|
|
||||||
buy, who knows? */
|
|
||||||
PR_Error(pr, "NULL hash-element found -> not supposed!");
|
|
||||||
} else {
|
|
||||||
for(d=0;d<MAX_SH_VALUES;d++) {
|
|
||||||
// free key
|
|
||||||
free(sh->elements[i]->key);
|
|
||||||
// free values
|
|
||||||
if(sh->elements[i]->values[d] != NULL) {
|
|
||||||
free(sh->elements[i]->values[d]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(sh->elements[i]); // free str_hash_elem structs
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
FIXME: HELP: taniwha??? do i have to FREE
|
|
||||||
the strings ??
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
free(sh->elements); // free the list pointer
|
|
||||||
sh->elements = NULL;
|
|
||||||
sh->cnt_elements = 0;
|
|
||||||
R_INT (pr) = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
bi_StringHash_Set
|
|
||||||
|
|
||||||
Sets a the key-value (with a special id) in a hash
|
|
||||||
to a value.
|
|
||||||
If a non existing key is given a element if generated for it.
|
|
||||||
FIXME: look if this functions does mem-leak
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
bi_StringHash_Set (progs_t *pr)
|
|
||||||
{
|
|
||||||
strh_resources_t* res = PR_Resources_Find (pr, "StringHash");
|
|
||||||
int hash_id = P_INT (pr, 0);
|
|
||||||
const char *key = P_STRING (pr, 1);
|
|
||||||
const char *val = P_STRING (pr, 2);
|
|
||||||
int val_id = P_INT (pr, 3);
|
|
||||||
str_hash *sh = NULL;
|
|
||||||
int i,found_fl=0;
|
|
||||||
|
|
||||||
// validate the hash ID
|
|
||||||
if(res->hashes == NULL ||
|
|
||||||
(hash_id >= res->cnt_hashes || hash_id < 0) ||
|
|
||||||
(val_id < 0 || val_id >= MAX_SH_VALUES))
|
|
||||||
{
|
|
||||||
R_INT (pr) = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sh = res->hashes[hash_id];
|
|
||||||
|
|
||||||
// first search for existing key
|
|
||||||
for(i = 0; i < sh->cnt_elements; i++) {
|
|
||||||
if(strcmp(sh->elements[i]->key, key) == 0) {
|
|
||||||
// found already a element with that key
|
|
||||||
if(sh->elements[i]->values[val_id] == NULL) { // empty val
|
|
||||||
// strdup() because strings can dissappear
|
|
||||||
sh->elements[i]->values[val_id] = strdup(val);
|
|
||||||
} else {
|
|
||||||
// when using strdup(), we have to free the stuff properly
|
|
||||||
free(sh->elements[i]->values[val_id]);
|
|
||||||
sh->elements[i]->values[val_id] = strdup(val);
|
|
||||||
}
|
|
||||||
found_fl = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!found_fl) { // add a new element
|
|
||||||
if(sh->elements == NULL) { // alloc new elements list pointer
|
|
||||||
sh->elements = (str_hash_elem**) malloc(sizeof(str_hash_elem*));
|
|
||||||
sh->cnt_elements = 0; // 0 because usage as index here
|
|
||||||
} else {
|
|
||||||
sh->elements = (str_hash_elem**) realloc(sh->elements,
|
|
||||||
sizeof(str_hash_elem*) * (sh->cnt_elements+1));
|
|
||||||
}
|
|
||||||
sh->elements[sh->cnt_elements] = malloc(sizeof(str_hash_elem));
|
|
||||||
memset(sh->elements[sh->cnt_elements],0,sizeof(str_hash_elem));
|
|
||||||
|
|
||||||
sh->elements[sh->cnt_elements]->key = strdup(key);
|
|
||||||
sh->elements[sh->cnt_elements]->values[val_id] = strdup(val);
|
|
||||||
|
|
||||||
sh->cnt_elements++;
|
|
||||||
}
|
|
||||||
R_INT (pr) = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
bi_StringHash_SetIdx
|
|
||||||
|
|
||||||
Sets a the key-value (with a special id) in a hash
|
|
||||||
to a value. This function works by index of the element.
|
|
||||||
A element in hash is NOT generated automatically.
|
|
||||||
FIXME: look if this functions does mem-leak
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
bi_StringHash_SetIdx (progs_t *pr)
|
|
||||||
{
|
|
||||||
strh_resources_t* res = PR_Resources_Find (pr, "StringHash");
|
|
||||||
int hash_id = P_INT (pr, 0);
|
|
||||||
int idx = P_INT (pr, 1);
|
|
||||||
const char *val = P_STRING (pr, 2);
|
|
||||||
int val_id = P_INT (pr, 3);
|
|
||||||
str_hash *sh = NULL;
|
|
||||||
|
|
||||||
// validate the hash ID
|
|
||||||
if(res->hashes == NULL ||
|
|
||||||
(hash_id >= res->cnt_hashes || hash_id < 0) ||
|
|
||||||
(val_id < 0 || val_id >= MAX_SH_VALUES))
|
|
||||||
{
|
|
||||||
R_INT (pr) = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sh = res->hashes[hash_id];
|
|
||||||
|
|
||||||
if(idx < 0 || idx >= sh->cnt_elements || sh->elements[idx] == NULL) {
|
|
||||||
if(sh->elements[idx] == NULL)
|
|
||||||
PR_Error(pr, "NULL hash-element found -> not supposed!");
|
|
||||||
|
|
||||||
R_INT (pr) = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sh->elements[idx]->values[val_id] != NULL) {
|
|
||||||
free(sh->elements[idx]->values[val_id]);
|
|
||||||
}
|
|
||||||
sh->elements[idx]->values[val_id] = strdup(val);
|
|
||||||
|
|
||||||
|
|
||||||
R_INT (pr) = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
bi_StringHash_Get
|
|
||||||
|
|
||||||
Gets the value of a key and its id in a hash
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
bi_StringHash_Get (progs_t *pr)
|
|
||||||
{
|
|
||||||
strh_resources_t* res = PR_Resources_Find (pr, "StringHash");
|
|
||||||
int hash_id = P_INT (pr, 0);
|
|
||||||
const char *key = P_STRING (pr, 1);
|
|
||||||
int val_id = P_INT (pr, 2);
|
|
||||||
str_hash *sh = NULL;
|
|
||||||
int i,found_fl=0;
|
|
||||||
const char *retstr = NULL;
|
|
||||||
|
|
||||||
// validate the hash ID
|
|
||||||
if(res->hashes == NULL || hash_id >= res->cnt_hashes || hash_id < 0 ||
|
|
||||||
val_id >= MAX_SH_VALUES)
|
|
||||||
{
|
|
||||||
retstr = "";
|
|
||||||
RETURN_STRING(pr, retstr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sh = res->hashes[hash_id];
|
|
||||||
|
|
||||||
// first search for existing key
|
|
||||||
for(i = 0; i < sh->cnt_elements; i++) {
|
|
||||||
if(strcmp(sh->elements[i]->key, key) == 0) {
|
|
||||||
if(sh->elements[i]->values[val_id] != NULL) {
|
|
||||||
retstr = sh->elements[i]->values[val_id];
|
|
||||||
} else {
|
|
||||||
retstr = "";
|
|
||||||
}
|
|
||||||
found_fl = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!found_fl) {
|
|
||||||
retstr = "";
|
|
||||||
}
|
|
||||||
RETURN_STRING(pr, retstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
bi_StringHash_Length
|
|
||||||
|
|
||||||
Gets the count of the elements in a hash
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
bi_StringHash_Length (progs_t *pr)
|
|
||||||
{
|
|
||||||
strh_resources_t* res = PR_Resources_Find (pr, "StringHash");
|
|
||||||
int hash_id = P_INT (pr, 0);
|
|
||||||
str_hash *sh = NULL;
|
|
||||||
|
|
||||||
// validate the hash ID
|
|
||||||
if(res->hashes == NULL || hash_id >= res->cnt_hashes || hash_id < 0) {
|
|
||||||
R_INT (pr) = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sh = res->hashes[hash_id];
|
|
||||||
|
|
||||||
R_INT (pr) = sh->cnt_elements;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
bi_StringHash_GetIdx
|
|
||||||
|
|
||||||
Gets a hash elment by its index
|
|
||||||
special: if the val_id is -1 the key of the element will
|
|
||||||
be returned
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
bi_StringHash_GetIdx (progs_t *pr)
|
|
||||||
{
|
|
||||||
strh_resources_t* res = PR_Resources_Find (pr, "StringHash");
|
|
||||||
int hash_id = P_INT (pr, 0);
|
|
||||||
int idx = P_INT (pr, 1);
|
|
||||||
int val_id = P_INT (pr, 2);
|
|
||||||
str_hash *sh = NULL;
|
|
||||||
const char *retstr = NULL;
|
|
||||||
|
|
||||||
// validate the hash ID
|
|
||||||
if(res->hashes == NULL || hash_id >= res->cnt_hashes || hash_id < 0) {
|
|
||||||
retstr = NULL;
|
|
||||||
}
|
|
||||||
sh = res->hashes[hash_id];
|
|
||||||
|
|
||||||
if(idx < 0 || idx >= sh->cnt_elements ||
|
|
||||||
(val_id < -1 || val_id >= MAX_SH_VALUES))
|
|
||||||
{
|
|
||||||
retstr = NULL;
|
|
||||||
} else {
|
|
||||||
if(val_id == -1) {
|
|
||||||
retstr = sh->elements[idx]->key;
|
|
||||||
} else {
|
|
||||||
retstr = sh->elements[idx]->values[val_id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(retstr == NULL) { retstr = ""; }
|
|
||||||
|
|
||||||
RETURN_STRING(pr, retstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
bi_strh_clear
|
|
||||||
|
|
||||||
Free the dynamic allocated memory
|
|
||||||
XXX: taniwha: i dont know what to free
|
|
||||||
exactly, could you validate this code?
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
bi_strh_clear (progs_t *pr, void *data)
|
|
||||||
{
|
|
||||||
strh_resources_t *res = (strh_resources_t *)data;
|
|
||||||
int i,d,n;
|
|
||||||
|
|
||||||
for (i = 0; i < res->cnt_hashes; i++) {
|
|
||||||
if (res->hashes[i]) {
|
|
||||||
for(d = 0; d < res->hashes[i]->cnt_elements; d++) {
|
|
||||||
free(res->hashes[i]->elements[d]->key); // Free the key
|
|
||||||
for (n = 0; n < MAX_SH_VALUES; n++) // Free all values
|
|
||||||
if (res->hashes[i]->elements[d]->values[n])
|
|
||||||
free(res->hashes[i]->elements[d]->values[n]);
|
|
||||||
free(res->hashes[i]->elements[d]); // Free the element itself
|
|
||||||
}
|
|
||||||
free(res->hashes[i]->elements);
|
|
||||||
free(res->hashes[i]);
|
|
||||||
res->hashes[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free (res->hashes);
|
|
||||||
res->hashes = 0;
|
|
||||||
res->cnt_hashes = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
StringHash_Progs_Init
|
|
||||||
|
|
||||||
Inits the Progs-system with StringHash resources and
|
|
||||||
functions.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
StringHash_Progs_Init (progs_t *pr)
|
|
||||||
{
|
|
||||||
strh_resources_t *res = malloc (sizeof (strh_resources_t));
|
|
||||||
res->cnt_hashes = 0;
|
|
||||||
res->hashes = NULL;
|
|
||||||
|
|
||||||
PR_Resources_Register (pr, "StringHash", res, bi_strh_clear);
|
|
||||||
PR_AddBuiltin (pr, "StringHash_Create", bi_StringHash_Create, -1);
|
|
||||||
PR_AddBuiltin (pr, "StringHash_Destroy", bi_StringHash_Destroy, -1);
|
|
||||||
PR_AddBuiltin (pr, "StringHash_Set", bi_StringHash_Set, -1);
|
|
||||||
PR_AddBuiltin (pr, "StringHash_Get", bi_StringHash_Get, -1);
|
|
||||||
PR_AddBuiltin (pr, "StringHash_Length", bi_StringHash_Length, -1);
|
|
||||||
PR_AddBuiltin (pr, "StringHash_SetIdx", bi_StringHash_SetIdx, -1);
|
|
||||||
PR_AddBuiltin (pr, "StringHash_GetIdx", bi_StringHash_GetIdx, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
XXX NOTE by elmex:
|
|
||||||
A file, decripted like this is what
|
|
||||||
i want to see everywhere in qf-cvs =)
|
|
||||||
No excuse for undocumented code and design without
|
|
||||||
a reason for it.
|
|
||||||
We/I want to know why something was designed how it is.
|
|
||||||
*/
|
|
|
@ -31,7 +31,7 @@ EXTRA_DATA= $(menu_data)
|
||||||
menu_src= \
|
menu_src= \
|
||||||
client_menu.qc controls_o.qc \
|
client_menu.qc controls_o.qc \
|
||||||
inputline_util.qc menu.r options.qc \
|
inputline_util.qc menu.r options.qc \
|
||||||
options_util.qc servlist.qc string.r stringh.r
|
options_util.qc servlist.qc string.r
|
||||||
|
|
||||||
%.qfo: %.r
|
%.qfo: %.r
|
||||||
$(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $<
|
$(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $<
|
||||||
|
@ -48,5 +48,5 @@ menu.dat$(GZ): $(menu_obj) $(QFCC_DEP) ../lib/libgui.a ../lib/libcsqc.a ../lib/l
|
||||||
EXTRA_DIST= $(menu_src) \
|
EXTRA_DIST= $(menu_src) \
|
||||||
client_menu.h controls_o.h \
|
client_menu.h controls_o.h \
|
||||||
menu.h options.h \
|
menu.h options.h \
|
||||||
options_util.h servlist.h string.h stringh.h
|
options_util.h servlist.h string.h
|
||||||
CLEANFILES= *.dat *.sym *.gz *.qfo
|
CLEANFILES= *.dat *.sym *.gz *.qfo
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
Boston, MA 02111-1307, USA
|
Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Array.h"
|
||||||
|
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
#include "stringh.h"
|
#include "stringh.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
@ -37,9 +39,63 @@
|
||||||
integer set_key_flag; // holds flag for the key-setting
|
integer set_key_flag; // holds flag for the key-setting
|
||||||
|
|
||||||
// three global hashes for the main binding groups
|
// three global hashes for the main binding groups
|
||||||
integer movement_binding_hash;
|
Array movement_binding_hash;
|
||||||
integer misc_binding_hash;
|
Array misc_binding_hash;
|
||||||
integer weapon_binding_hash;
|
Array weapon_binding_hash;
|
||||||
|
|
||||||
|
struct binding_t = {
|
||||||
|
string text;
|
||||||
|
string command;
|
||||||
|
string keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
binding_t [16] movement_binding_list = {
|
||||||
|
{"Jump/Swin up", "+jump"},
|
||||||
|
{"Walk forward", "+forward"},
|
||||||
|
{"Backpedal", "+back"},
|
||||||
|
{"Turn left", "+left"},
|
||||||
|
{"Turn right", "+right"},
|
||||||
|
{"Run", "+speed"},
|
||||||
|
{"Step left", "+moveleft"},
|
||||||
|
{"Step right", "+moveright"},
|
||||||
|
{"Sidestep", "+strafe"},
|
||||||
|
{"Look up", "+lookup"},
|
||||||
|
{"Look down", "+lookdown"},
|
||||||
|
{"Center view", "centerview"},
|
||||||
|
{"Mouse look", "+mlook"},
|
||||||
|
{"Keyboard look", "+klook"},
|
||||||
|
{"Swim up", "+moveup"},
|
||||||
|
{"Swim down", "+movedown"},
|
||||||
|
};
|
||||||
|
|
||||||
|
binding_t [4] misc_binding_list = {
|
||||||
|
{"Pause game", "pause"},
|
||||||
|
{"Tog. m.-grab", "toggle in_grab"},
|
||||||
|
{"Messagemode", "messagemode"},
|
||||||
|
{"Screenshot", "screenshot"},
|
||||||
|
};
|
||||||
|
|
||||||
|
binding_t [10] weapon_binding_list = {
|
||||||
|
{"Attack", "+attack"},
|
||||||
|
{"Next weapon", "impulse 10"},
|
||||||
|
{"Axe", "impulse 1"},
|
||||||
|
{"Shotgun", "impulse 2"},
|
||||||
|
{"Super Shotgun", "impulse 3"},
|
||||||
|
{"Nailgun", "impulse 4"},
|
||||||
|
{"Super Nailgun", "impulse 5"},
|
||||||
|
{"Grenade L. ", "impulse 6"},
|
||||||
|
{"Rocket L. ", "impulse 7"},
|
||||||
|
{"Thunderbolt", "impulse 8"},
|
||||||
|
};
|
||||||
|
|
||||||
|
(binding_t []) (binding_t binding)
|
||||||
|
new_binding =
|
||||||
|
{
|
||||||
|
local binding_t []newb = obj_malloc (@sizeof (binding_t));
|
||||||
|
|
||||||
|
newb[0] = binding;
|
||||||
|
return newb;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
init_binding_hash
|
init_binding_hash
|
||||||
|
@ -49,55 +105,18 @@ integer weapon_binding_hash;
|
||||||
void ()
|
void ()
|
||||||
init_binding_hash =
|
init_binding_hash =
|
||||||
{
|
{
|
||||||
/*
|
local integer i;
|
||||||
DESIGN NOTES for the Menu:
|
|
||||||
|
|
||||||
binding config is loaded into hashes.
|
movement_binding_hash = [[Array alloc] init];
|
||||||
the key of the hash is the string, which will be displayed as binding
|
for (i = 0; i < @sizeof (movement_binding_list); i++)
|
||||||
description.
|
[movement_binding_hash addItem: new_binding (movement_binding_list[i])];
|
||||||
The first value of the key is the command, which is bound.
|
misc_binding_hash = [[Array alloc] init];
|
||||||
The second value (loaded later) of the hash will be the keyname.
|
for (i = 0; i < @sizeof (misc_binding_list); i++)
|
||||||
(see get_hash_keys())
|
[misc_binding_hash addItem: new_binding (misc_binding_list[i])];
|
||||||
*/
|
weapon_binding_hash = [[Array alloc] init];
|
||||||
|
for (i = 0; i < @sizeof (weapon_binding_list); i++)
|
||||||
|
[weapon_binding_hash addItem: new_binding (weapon_binding_list[i])];
|
||||||
|
|
||||||
// Movement keys
|
|
||||||
movement_binding_hash = StringHash_Create ();
|
|
||||||
StringHash_Set (movement_binding_hash, "Jump/Swin up", "+jump", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Walk forward", "+forward", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Backpedal", "+back", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Turn left", "+left", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Turn right", "+right", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Run", "+speed", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Step left", "+moveleft", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Step right", "+moveright", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Sidestep", "+strafe", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Look up", "+lookup", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Look down", "+lookdown", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Center view", "centerview", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Mouse look", "+mlook", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Keyboard look", "+klook", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Swim up", "+moveup", 0);
|
|
||||||
StringHash_Set (movement_binding_hash, "Swim down", "+movedown", 0);
|
|
||||||
|
|
||||||
// Misc keys
|
|
||||||
misc_binding_hash = StringHash_Create ();
|
|
||||||
StringHash_Set (misc_binding_hash, "Pause game", "pause", 0);
|
|
||||||
StringHash_Set (misc_binding_hash, "Tog. m.-grab", "toggle in_grab", 0);
|
|
||||||
StringHash_Set (misc_binding_hash, "Messagemode", "messagemode", 0);
|
|
||||||
StringHash_Set (misc_binding_hash, "Screenshot", "screenshot", 0);
|
|
||||||
|
|
||||||
// Weapon keys
|
|
||||||
weapon_binding_hash = StringHash_Create ();
|
|
||||||
StringHash_Set (weapon_binding_hash, "Attack", "+attack", 0);
|
|
||||||
StringHash_Set (weapon_binding_hash, "Next weapon", "impulse 10", 0);
|
|
||||||
StringHash_Set (weapon_binding_hash, "Axe", "impulse 1", 0);
|
|
||||||
StringHash_Set (weapon_binding_hash, "Shotgun", "impulse 2", 0);
|
|
||||||
StringHash_Set (weapon_binding_hash, "Super Shotgun", "impulse 3", 0);
|
|
||||||
StringHash_Set (weapon_binding_hash, "Nailgun", "impulse 4", 0);
|
|
||||||
StringHash_Set (weapon_binding_hash, "Super Nailgun", "impulse 5", 0);
|
|
||||||
StringHash_Set (weapon_binding_hash, "Grenade L. ", "impulse 6", 0);
|
|
||||||
StringHash_Set (weapon_binding_hash, "Rocket L. ", "impulse 7", 0);
|
|
||||||
StringHash_Set (weapon_binding_hash, "Thunderbolt", "impulse 8", 0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -130,22 +149,23 @@ get_keyname =
|
||||||
|
|
||||||
gets the keys for a keybinding-hash
|
gets the keys for a keybinding-hash
|
||||||
*/
|
*/
|
||||||
void (integer hash_id)
|
void (Array list)
|
||||||
get_hash_keys =
|
get_hash_keys =
|
||||||
{
|
{
|
||||||
local integer i,hlen;
|
local integer i,hlen;
|
||||||
local string binding, desc1 = "", desc2 = "";
|
local binding_t [] binding;
|
||||||
|
local string desc1 = "", desc2 = "";
|
||||||
|
|
||||||
hlen = StringHash_Length(hash_id);
|
hlen = [list count];
|
||||||
for(i = 0; i < hlen; i++) {
|
for(i = 0; i < hlen; i++) {
|
||||||
binding = StringHash_GetIdx(hash_id, i, 0);
|
binding = [list getItemAt: i];
|
||||||
desc1 = get_keyname (binding, 1); // first key bound to
|
desc1 = get_keyname (binding.command, 1); // first key bound to
|
||||||
desc2 = get_keyname (binding, 2); // second key bound to
|
desc2 = get_keyname (binding.command, 2); // second key bound to
|
||||||
|
|
||||||
if (desc2 != "") {
|
if (desc2 != "") {
|
||||||
desc1 += ", " + desc2;
|
desc1 += ", " + desc2;
|
||||||
}
|
}
|
||||||
StringHash_SetIdx (hash_id, i, desc1, 1);
|
binding.keys = desc1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -183,22 +203,22 @@ load_keybindings =
|
||||||
It takes the binding as argument.
|
It takes the binding as argument.
|
||||||
This function is called by the real callbacks.
|
This function is called by the real callbacks.
|
||||||
*/
|
*/
|
||||||
integer (string binding, integer key)
|
integer (binding_t [] binding, integer key)
|
||||||
CB_MAIN_control_binding =
|
CB_MAIN_control_binding =
|
||||||
{
|
{
|
||||||
local integer retval = 0, bindcnt = 0;
|
local integer retval = 0, bindcnt = 0;
|
||||||
|
|
||||||
if(set_key_flag) {
|
if(set_key_flag) {
|
||||||
bindcnt = Key_CountBinding(IMT_0, binding);
|
bindcnt = Key_CountBinding(IMT_0, binding.command);
|
||||||
/* we are not binding keys for more than one command
|
/* we are not binding keys for more than one command
|
||||||
by the menu (maybe extended later) */
|
by the menu (maybe extended later) */
|
||||||
if(bindcnt < 2) {
|
if(bindcnt < 2) {
|
||||||
Key_SetBinding (IMT_0, key, binding);
|
Key_SetBinding (IMT_0, key, binding.command);
|
||||||
} else {
|
} else {
|
||||||
// else, remove a binding and assign a new one
|
// else, remove a binding and assign a new one
|
||||||
dprint ("FOO\n");
|
dprint ("FOO\n");
|
||||||
Key_SetBinding (IMT_0, Key_LookupBinding(IMT_0, 1, binding), "");
|
Key_SetBinding (IMT_0, Key_LookupBinding(IMT_0, 1, binding.command), "");
|
||||||
Key_SetBinding (IMT_0, key, binding);
|
Key_SetBinding (IMT_0, key, binding.command);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_key_flag = 0;
|
set_key_flag = 0;
|
||||||
|
@ -208,7 +228,7 @@ CB_MAIN_control_binding =
|
||||||
set_key_flag = 1;
|
set_key_flag = 1;
|
||||||
retval = 1;
|
retval = 1;
|
||||||
} else if(key == QFK_BACKSPACE || key == QFK_DELETE) {
|
} else if(key == QFK_BACKSPACE || key == QFK_DELETE) {
|
||||||
Key_SetBinding (IMT_0, Key_LookupBinding(IMT_0, 1, binding), "");
|
Key_SetBinding (IMT_0, Key_LookupBinding(IMT_0, 1, binding.command), "");
|
||||||
|
|
||||||
retval = 1;
|
retval = 1;
|
||||||
}
|
}
|
||||||
|
@ -225,8 +245,7 @@ CB_MAIN_control_binding =
|
||||||
integer (string text, integer key)
|
integer (string text, integer key)
|
||||||
CB_basic_control_binding =
|
CB_basic_control_binding =
|
||||||
{
|
{
|
||||||
local string binding = StringHash_GetIdx (movement_binding_hash,
|
local binding_t [] binding = [movement_binding_hash getItemAt: stoi (text)];
|
||||||
stoi (text), 0);
|
|
||||||
local integer ret = CB_MAIN_control_binding (binding, key);
|
local integer ret = CB_MAIN_control_binding (binding, key);
|
||||||
|
|
||||||
// fetch all keynames (possible to optimize.. but not very neccessary)
|
// fetch all keynames (possible to optimize.. but not very neccessary)
|
||||||
|
@ -261,11 +280,11 @@ DRAW_basic_control_binding =
|
||||||
Draw_String (20, 20, "Enter: New binding");
|
Draw_String (20, 20, "Enter: New binding");
|
||||||
|
|
||||||
|
|
||||||
hl = StringHash_Length (movement_binding_hash);
|
hl = [movement_binding_hash count];
|
||||||
for(i = 0; i < hl; i++) {
|
for(i = 0; i < hl; i++) {
|
||||||
|
local binding_t [] binding = [movement_binding_hash getItemAt: i];
|
||||||
draw_val_item (20, 40 + ( i * 10), bind_desc_pad,
|
draw_val_item (20, 40 + ( i * 10), bind_desc_pad,
|
||||||
StringHash_GetIdx (movement_binding_hash, i, -1),
|
binding.text, binding.keys);
|
||||||
StringHash_GetIdx (movement_binding_hash, i, 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
opt_cursor (12, (Menu_GetIndex () * 10) + cursor_pad);
|
opt_cursor (12, (Menu_GetIndex () * 10) + cursor_pad);
|
||||||
|
@ -288,7 +307,7 @@ MENU_basic_control_binding =
|
||||||
Menu_EnterHook (CB_ME_basic_control_binding);
|
Menu_EnterHook (CB_ME_basic_control_binding);
|
||||||
Menu_Draw (DRAW_basic_control_binding);
|
Menu_Draw (DRAW_basic_control_binding);
|
||||||
|
|
||||||
hl = StringHash_Length (movement_binding_hash);
|
hl = [movement_binding_hash count];
|
||||||
for (i = 0; i < hl; i++) {
|
for (i = 0; i < hl; i++) {
|
||||||
Menu_Item (20, 40 + i * 10, itos (i), CB_basic_control_binding, 1);
|
Menu_Item (20, 40 + i * 10, itos (i), CB_basic_control_binding, 1);
|
||||||
}
|
}
|
||||||
|
@ -303,8 +322,7 @@ MENU_basic_control_binding =
|
||||||
integer (string text, integer key)
|
integer (string text, integer key)
|
||||||
CB_misc_control_binding =
|
CB_misc_control_binding =
|
||||||
{
|
{
|
||||||
local string binding = StringHash_GetIdx (misc_binding_hash, stoi (text),
|
local binding_t [] binding = [misc_binding_hash getItemAt: stoi (text)];
|
||||||
0);
|
|
||||||
local integer ret = CB_MAIN_control_binding (binding, key);
|
local integer ret = CB_MAIN_control_binding (binding, key);
|
||||||
|
|
||||||
// fetch all keynames (possible to optimize.. but not very neccessary)
|
// fetch all keynames (possible to optimize.. but not very neccessary)
|
||||||
|
@ -339,11 +357,11 @@ DRAW_misc_control_binding =
|
||||||
Draw_String (20, 10, "Backspace/Delete: Del binding");
|
Draw_String (20, 10, "Backspace/Delete: Del binding");
|
||||||
Draw_String (20, 20, "Enter: New binding");
|
Draw_String (20, 20, "Enter: New binding");
|
||||||
|
|
||||||
hl = StringHash_Length(misc_binding_hash);
|
hl = [misc_binding_hash count];
|
||||||
for(i=0;i < hl; i++) {
|
for(i=0;i < hl; i++) {
|
||||||
|
local binding_t [] binding = [misc_binding_hash getItemAt: i];
|
||||||
draw_val_item (20, 40+(i*10), bind_desc_pad,
|
draw_val_item (20, 40+(i*10), bind_desc_pad,
|
||||||
StringHash_GetIdx(misc_binding_hash, i, -1),
|
binding.text, binding.keys);
|
||||||
StringHash_GetIdx(misc_binding_hash, i, 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
opt_cursor (12, (Menu_GetIndex() * 10) + cursor_pad);
|
opt_cursor (12, (Menu_GetIndex() * 10) + cursor_pad);
|
||||||
|
@ -365,7 +383,7 @@ MENU_misc_control_binding =
|
||||||
Menu_EnterHook (CB_ME_misc_control_binding);
|
Menu_EnterHook (CB_ME_misc_control_binding);
|
||||||
Menu_Draw (DRAW_misc_control_binding);
|
Menu_Draw (DRAW_misc_control_binding);
|
||||||
|
|
||||||
hl = StringHash_Length(movement_binding_hash);
|
hl = [movement_binding_hash count];
|
||||||
for (i = 0; i < hl; i++) {
|
for (i = 0; i < hl; i++) {
|
||||||
Menu_Item (20, 40 + i * 10, itos (i), CB_misc_control_binding, 1);
|
Menu_Item (20, 40 + i * 10, itos (i), CB_misc_control_binding, 1);
|
||||||
}
|
}
|
||||||
|
@ -380,8 +398,7 @@ MENU_misc_control_binding =
|
||||||
integer (string text, integer key)
|
integer (string text, integer key)
|
||||||
CB_weapon_control_binding =
|
CB_weapon_control_binding =
|
||||||
{
|
{
|
||||||
local string binding = StringHash_GetIdx (weapon_binding_hash, stoi (text),
|
local binding_t [] binding = [weapon_binding_hash getItemAt: stoi (text)];
|
||||||
0);
|
|
||||||
local integer ret = CB_MAIN_control_binding (binding, key);
|
local integer ret = CB_MAIN_control_binding (binding, key);
|
||||||
|
|
||||||
// fetch all keynames (possible to optimize.. but not very neccessary)
|
// fetch all keynames (possible to optimize.. but not very neccessary)
|
||||||
|
@ -416,11 +433,11 @@ DRAW_weapon_control_binding =
|
||||||
Draw_String (20, 10, "Backspace/Delete: Del binding");
|
Draw_String (20, 10, "Backspace/Delete: Del binding");
|
||||||
Draw_String (20, 20, "Enter: New binding");
|
Draw_String (20, 20, "Enter: New binding");
|
||||||
|
|
||||||
hl = StringHash_Length (weapon_binding_hash);
|
hl = [weapon_binding_hash count];
|
||||||
for(i = 0; i < hl; i++) {
|
for(i = 0; i < hl; i++) {
|
||||||
|
local binding_t [] binding = [weapon_binding_hash getItemAt: i];
|
||||||
draw_val_item (20, 40 + (i * 10), bind_desc_pad,
|
draw_val_item (20, 40 + (i * 10), bind_desc_pad,
|
||||||
StringHash_GetIdx (weapon_binding_hash, i, -1),
|
binding.text, binding.keys);
|
||||||
StringHash_GetIdx (weapon_binding_hash, i, 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
opt_cursor (12, (Menu_GetIndex () * 10) + cursor_pad);
|
opt_cursor (12, (Menu_GetIndex () * 10) + cursor_pad);
|
||||||
|
@ -443,7 +460,7 @@ MENU_weapon_control_binding =
|
||||||
Menu_EnterHook (CB_ME_weapon_control_binding);
|
Menu_EnterHook (CB_ME_weapon_control_binding);
|
||||||
Menu_Draw (DRAW_weapon_control_binding);
|
Menu_Draw (DRAW_weapon_control_binding);
|
||||||
|
|
||||||
hl = StringHash_Length (movement_binding_hash);
|
hl = [movement_binding_hash count];
|
||||||
for (i = 0; i < hl; i++) {
|
for (i = 0; i < hl; i++) {
|
||||||
Menu_Item (20, 40 + i * 10, itos (i), CB_weapon_control_binding, 1);
|
Menu_Item (20, 40 + i * 10, itos (i), CB_weapon_control_binding, 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
#ifndef __stringh_h
|
|
||||||
#define __stringh_h
|
|
||||||
|
|
||||||
@extern integer () StringHash_Create;
|
|
||||||
@extern integer (integer hashid) StringHash_Destroy;
|
|
||||||
@extern integer (integer hashid, string key, string value, integer value_id) StringHash_Set;
|
|
||||||
@extern string (integer hashid, string key, integer value_id) StringHash_Get;
|
|
||||||
@extern integer (integer hashid) StringHash_Length;
|
|
||||||
@extern string (integer hashid, integer idx, integer value_id) StringHash_GetIdx;
|
|
||||||
@extern integer (integer hashid, integer idx, string value, integer value_id) StringHash_SetIdx;
|
|
||||||
|
|
||||||
#endif//__stringh_h
|
|
|
@ -1,9 +0,0 @@
|
||||||
#include "stringh.h"
|
|
||||||
|
|
||||||
integer () StringHash_Create = #0;
|
|
||||||
integer (integer hashid) StringHash_Destroy = #0;
|
|
||||||
integer (integer hashid, string key, string value, integer value_id) StringHash_Set = #0;
|
|
||||||
string (integer hashid, string key, integer value_id) StringHash_Get = #0;
|
|
||||||
integer (integer hashid) StringHash_Length = #0;
|
|
||||||
string (integer hashid, integer idx, integer value_id) StringHash_GetIdx = #0;
|
|
||||||
integer (integer hashid, integer idx, string value, integer value_id) StringHash_SetIdx = #0;
|
|
|
@ -17,6 +17,7 @@
|
||||||
- (void) addItem: (void []) item;
|
- (void) addItem: (void []) item;
|
||||||
- (void []) removeItemAt: (integer) index;
|
- (void []) removeItemAt: (integer) index;
|
||||||
- (void []) insertItemAt: (integer) index item:(void []) item;
|
- (void []) insertItemAt: (integer) index item:(void []) item;
|
||||||
|
- (integer) count;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif//__ruamoko_Array_h
|
#endif//__ruamoko_Array_h
|
||||||
|
|
|
@ -87,4 +87,9 @@
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (integer) count
|
||||||
|
{
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
Loading…
Reference in a new issue