diff -u -r src-std/actions.c src/actions.c --- src-std/actions.c Thu Nov 25 13:57:54 1999 +++ src/actions.c Mon Dec 06 20:22:06 1999 @@ -932,6 +937,7 @@ { struct command_context_s context; + interactive_t *ip; Bool res; /* Save the current context */ @@ -943,6 +949,28 @@ command_giver = ob; marked_command_giver = ob; last_command = str; + + /* If the command is "%%", use the previous command. + * Either way, update ip->last_command. + */ + if (O_SET_INTERACTIVE(ip, command_giver)) + { + if (strcmp(str, "%%")==0) + { + if (ip->last_command) + { + strcpy(str, ip->last_command); + last_command = str; + } + } + else + { + if (ip->last_command) + xfree(ip->last_command); + ip->last_command = xalloc(strlen(str)+1); + strcpy(ip->last_command, str); + } + } /* Execute the command */ if (closure_hook[H_COMMAND].type == T_STRING) diff -u -r src-std/comm.c src/comm.c --- src-std/comm.c Mon Dec 06 19:03:10 1999 +++ src/comm.c Mon Dec 06 20:22:08 1999 @@ -826,6 +826,46 @@ } /*-------------------------------------------------------------------------*/ +static Bool +isansi (char *arr, int i, Bool rec) + +/* Check if the textbuffer at position contains an ANSI sequence. + * If is passed as FALSE, has to point to the beginning of + * an ANSI sequence, otherwise may point into an ANSI sequence. + * Only sequences of the form "[m" are recognized. + * + * Returns TRUE if there is an ANSI command, FALSE otherwise. + */ + +{ + if (arr[i] == '\e' && arr[i+1] == '[' && isdigit(arr[i+2])) + { + if (isdigit(arr[i+3])) + { + if ((isdigit(arr[i+4]) && arr[i+5] == 'm') + || (arr[i+4] == 'm')) + return MY_TRUE; + } + else if (arr[i+3] == 'm') + return MY_TRUE; + } + + if (rec) + { + if (i > 0 && isansi(arr, i-1, MY_FALSE)) + return MY_TRUE; + if (i > 1 && isansi(arr, i-2, MY_FALSE)) + return MY_TRUE; + if (i > 2 && isansi(arr, i-3, MY_FALSE)) + return MY_TRUE; + if (i > 3 && isansi(arr, i-4, MY_FALSE)) + return MY_TRUE; + } + + return MY_FALSE; +} /* isansi() */ + +/*-------------------------------------------------------------------------*/ void add_message (char *fmt, ...) @@ -858,7 +898,8 @@ */ { - char buff[2130]; +# define BUFFSIZE 3000 + char buff[BUFFSIZE]; /* Composition buffer for the final message. * We hope that it's big enough, but to be sure the code will * check for buffer overruns. @@ -1025,6 +1066,92 @@ , (long)strlen(source), source); #endif + + /* Conversion of message to 80 column wrap */ + + { + char buff3[2*BUFFSIZE+1]; /* Workspace */ + int from2; /* Source index in buff[] */ + int to2; /* Dest index in buff3[]*/ + int last2; /* Source index in buff[] of last printed */ + Bool converted; /* TRUE if data was wrapped */ + + converted = MY_FALSE; + buff3[0] = '\0'; + + for ( from2 = 0, to2 = 0, last2 = 0 + ; to2 < sizeof buff3 && source[last2]!='\0' + ;) + { + converted = MY_TRUE; + while (!isspace(source[from2]) && source[from2]) + { + /* until whitespace appears, count line_pos, and from2 up */ + if (source[from2] == '\t') + ip->line_pos = (ip->line_pos/8+1)*8; + else if (!isansi(source, from2, MY_TRUE)) + ip->line_pos++; + from2++; + } // while (!isspace(source[from2]) && source[from2]) + + if (ip->line_pos >= 80 && ip->line_pos != from2-last2) + { + /* need to wrap, && white space somewhere in line */ + ip->line_pos = 0; + buff3[to2++] = '\r'; + buff3[to2++] = '\n'; + while (isspace(source[last2])) + last2++; + from2 = last2; + } + else + { + if (ip->line_pos >= 80) /* need to wrap, line full of non-white spaces */ + from2 = last2+80-1; + + while (last2 < from2) + { + if (source[last2] == '\n') /* make cr/lf */ + { + buff3[to2++] = '\r'; + buff3[to2++] = source[last2++]; + } + else + buff3[to2++] = source[last2++]; /* keep the same */ + } + + if (ip->line_pos >= 80) + { + buff3[to2++] = '\r'; + buff3[to2++] = '\n'; + ip->line_pos = 0; + } + else + { + if (source[from2] == '\n') + ip->line_pos = 0; + else if (!isansi(source, from2, MY_TRUE) && source[from2]) + ip->line_pos++; + from2++; + } + } + } /* for() */ + + /* If we did wrapping and ANSI conversion, copy the final + * data back into the buffer buff[]. + */ + if (converted) + { + strncpy(buff, buff3, sizeof(buff)); + source = buff; + if (to2 >= sizeof(buff)-1) + source[sizeof(buff)-1] = '\0'; /* too long message */ + else + source[to2++] = '\0'; + } + } // if (filter_eol) + + /* --- Send the final message --- */ /* Append the final message to the .message_buf[], taking @@ -1967,6 +2094,7 @@ strcpy(buff, ip->text); command_giver = ip->ob; trace_level = ip->trace_level; + ip->line_pos = 0; /* Reinitialize the telnet machine, possibly already * producing the next command in .text[]. @@ -2070,6 +2198,11 @@ ob = interactive->ob; } + if (interactive->last_command) + { + xfree(interactive->last_command); + interactive->last_command = NULL; + } interactive->catch_tell_activ = MY_FALSE; /* Untie eventual snooping relations */ @@ -2143,6 +2276,16 @@ free_object(interactive->modify_command, "remove_interactive"); } +#if 0 + /* TODO: Kickaha added the following loop - but what is it good for? */ + for (i = 0; i < 10; i++) + { + interactive_t *ip; + + ip = O_GET_INTERACTIVE(ob); + } +#endif + free_svalue(&interactive->prompt); /* If the shadow_sentence in the interactive structure is used @@ -2400,6 +2543,8 @@ put_volatile_string(&new_interactive->prompt, "> "); new_interactive->modify_command = NULL; new_interactive->set_input_to = MY_FALSE; + new_interactive->line_pos = 0; + new_interactive->last_command = NULL; new_interactive->closing = MY_FALSE; new_interactive->do_close = 0; new_interactive->noecho = 0; @@ -2835,15 +2980,33 @@ /* Destruct all user objects. This is first tried by calling master->remove() * for every object. If this doesn't destruct the user object, * destruct() is used. + * + * Before a player is destructed, it's lfun "save_character" is called. + * * The function is called when the game is shut down. */ { int i; - for (i = 0; i < MAX_PLAYERS; i++) { - if (all_players[i] == 0) + for (i = 0; i < MAX_PLAYERS; i++) + { + if (all_players[i] == NULL) + continue; + + /* First try to save the character */ + command_giver = all_players[i]->ob; + trace_level |= all_players[i]->trace_level; + RESET_LIMITS; + CLEAR_EVAL_COST; + secure_apply(STR_SAVE_PL, all_players[i]->ob, 0); + + /* Does the player still exist? */ + if (!(all_players[i]->ob) || (all_players[i]->ob->flags & O_DESTRUCTED)) continue; + + /* Now destruct the player */ + command_giver = all_players[i]->ob; trace_level |= all_players[i]->trace_level; RESET_LIMITS; @@ -5204,7 +5367,7 @@ free_svalue(sp); put_number(sp, wrote); return sp; -} /* f_binary_message() */ +} /*-------------------------------------------------------------------------*/ svalue_t * diff -u -r src-std/comm.h src/comm.h --- src-std/comm.h Sun Dec 05 15:42:48 1999 +++ src/comm.h Mon Dec 06 20:22:08 1999 @@ -118,7 +118,8 @@ object_t *modify_command; /* modify_command() handler() */ svalue_t prompt; /* The prompt to print. */ struct sockaddr_in addr; /* Address of connected user */ - + char *last_command; /* the last command executed by this player */ + unsigned char line_pos; /* pos on line, for 80 column wrap */ CBool set_input_to; /* True if input_to was set in this cycle */ CBool closing; /* True when closing this socket. */ char do_close; /* Bitflags: Close this down; Proto-ERQ. */ diff -u -r src-std/ed.c src/ed.c --- src-std/ed.c Mon Dec 06 19:05:00 1999 +++ src/ed.c Mon Dec 06 20:22:10 1999 @@ -173,6 +173,7 @@ /*-------------------------------------------------------------------------*/ /* The ed_buffer holds all the information for one editor session. + * Note: Kickaha also added an "object_t *ed_object", but this was never used. */ struct ed_buffer diff -u -r src-std/efuns.c src/efuns.c --- src-std/efuns.c Mon Dec 06 19:40:04 1999 +++ src/efuns.c Mon Dec 06 20:22:12 1999 @@ -27,6 +27,7 @@ * tefun: transfer() (optional) * efun: say() * efun: tell_room() + * vefun: describe_items() * * Values: * tefun: copy() @@ -3709,6 +3710,467 @@ return sp; } /* f_set_prompt() */ + +/*-------------------------------------------------------------------------*/ +#ifdef F_DESCRIBE_ITEMS + +#define DATALEN 200 +#define GET_NUMBER(x) ((x)->type == T_NUMBER ? (x)->u.number : 0) +#define GET_OBJECT(x) ((x)->type == T_OBJECT ? (x)->u.ob : NULL) + +/*-------------------------------------------------------------------------*/ +static char * +di_add_num (char *dest, char *str, int ant) + +/* Add a prefix number in textform to the noun + */ + +{ + strcpy(dest,""); + + if (ant == 2) + strcpy(dest, "two "); + else if (ant == 3) + strcpy(dest, "three "); + else if (ant == 4) + strcpy(dest, "four "); + else if (ant < 8) + strcpy(dest, "some "); + else + strcpy(dest, "many "); + + strcat(dest, str); + + return dest; +} /* di_add_num() */ + +/*-------------------------------------------------------------------------*/ +static char * +di_pfix (char *str) + +/* Change a noun in singularform to a noun in pluralform + */ + +{ + static char plur[DATALEN+10]; + char *sp, *sp2; + int sl; + + sl = strlen(str); + if (sl < 2) + return strcpy(plur, str); + + sp = &str[sl-1]; + strcpy(plur,str); + plur[sl-1] = '\0'; + sp2 = &str[sl-2]; + + if (!strcmp(sp,"s")) strcat(plur,"ses"); + else if (!strcmp(sp,"x")) strcat(plur,"xes"); + else if (!strcmp(sp,"h")) strcat(plur,"hes"); + else if (!strcmp(sp,"y")) strcat(plur,"ies"); + else if (!strcmp(sp2,"fe")) + { + strcpy(plur,str); + plur[sl-2] = '0'; + strcat(plur, "ves"); + } + else if (!strcmp(str,"tooth")) strcpy(plur,"teeth"); + else if (!strcmp(str,"foot")) strcpy(plur,"feet"); + else if (!strcmp(str,"man")) strcpy(plur,"men"); + else if (!strcmp(str,"woman")) strcpy(plur,"women"); + else if (!strcmp(str,"children")) strcpy(plur,"child"); + else if (!strcmp(str,"sheep")) strcpy(plur,"sheep"); + else + { + strcpy(plur, str); + strcat(plur, "s"); + } + + return plur; +} /* di_pfix() */ + +/*-------------------------------------------------------------------------*/ +static char * +di_splitfix (char *str, int ant) + +/* Get the last word of the description and fix it to the right form + */ + +{ + char *sp; + char tmp2[DATALEN+10]; + static char tmp[DATALEN+10]; + + strcpy(tmp2, str); + sp = strrchr(tmp2, ' '); /* sp => last word in desc */ + if (!sp) + { + /* Only 1 word in desc */ + strcpy(tmp,str); + if (ant > 1) + strcpy(tmp, di_pfix(tmp)); + return tmp; + } + else + { + *sp = '\0'; + strcpy(tmp, &sp[1]); + } + if (ant > 1) + strcpy(tmp, di_pfix(tmp)); + + strcat(tmp2, " "); + strcat(tmp2, tmp); + strcpy(tmp,tmp2); + + return tmp; +} /* di_splitfix() */ + +/*-------------------------------------------------------------------------*/ +static char * +di_artfix (char *str) + +/* Add the correct article to a noun ( a or an ) + */ + +{ + static char tmp[DATALEN+3]; + + if (strchr("AEIOUaeiou", str[0])) + { + strcpy(tmp, "an "); + strcat(tmp, str); + return tmp; + } + strcpy(tmp, "a "); + strcat(tmp, str); + return tmp; +} /* di_artfix() */ + +/*-------------------------------------------------------------------------*/ +static char * +di_plurfix (char *dest, char *str, int ant, Bool check) + +/* Fix the description into pluralform, used when no "plural_" exists + */ + +{ + char tmp[DATALEN]; + int itmp; + + if (sscanf(str,"%d",&itmp)) + { + strcpy(dest, str); + return dest; + } + + if (ant == 1) + { + if (!strcmp("the ",str)) + { + strcpy(dest, "the "); + strcat(dest, di_splitfix(&str[4],ant)); + return dest; + } + + if (!strcmp("The ",str)) + { + strcpy(dest, "the "); + strcat(dest, di_splitfix(&str[4],ant)); + return dest; + } + + if (check) + { + strcpy(dest, di_splitfix(str,ant)); + return dest; + } + strcpy(dest, di_artfix(di_splitfix(str,ant))); + return dest; + } + else + { + itmp = sscanf(str, "the %s", tmp); + if (!itmp) + itmp = sscanf(str, "The %s", tmp); + if (!itmp) + strcpy(tmp, str); + return di_add_num(dest, di_splitfix(str,ant), ant); + } +} /* di_plurfix() */ + +/*-------------------------------------------------------------------------*/ +static char * +di_fixname (object_t *ob, int ant, char *func) + +/* Generate the description for nonliving jects. + * Call ->(plural_)() to retrieve the basic description. + * Return a pointer to a static buffer or NULL. + */ + +{ + char *str, *name, tmp[DATALEN]; + svalue_t *v; + static char retval[2*DATALEN]; + + v = apply(func, ob, 0); + if (v && v->type == T_STRING) + str = v->u.string; + else + str = "shadow thing"; + + if (ant > 1) + { + strcpy(tmp, "plural_"); + strcpy(tmp+7, func); + v = apply(tmp, ob, 0); + if (v && v->type == T_STRING) + name = v->u.string; + else + name = NULL; + if (name) + { + strncpy(tmp, name, sizeof(tmp)-1); + tmp[sizeof(tmp)-1] = '\0'; + return di_add_num(retval,tmp,ant); + } + } + strncpy(tmp, str, sizeof(tmp)-1); + tmp[sizeof(tmp)-1] = '\0'; + if (!strncmp("a ",tmp, 2)) + return di_plurfix(retval, &tmp[2], ant, MY_FALSE); + else if (!strncmp("an ",tmp, 3)) + return di_plurfix(retval, &tmp[3], ant, MY_FALSE); + else if (!strncmp("A ",tmp, 2)) + return di_plurfix(retval, &tmp[2], ant, MY_FALSE); + else if (!strncmp("An ",tmp, 3)) + return di_plurfix(retval, &tmp[3], ant, MY_FALSE); + else if (!strncmp("AN ",tmp, 3)) + return di_plurfix(retval, &tmp[3], ant, MY_FALSE); + else if (!strncmp("aN ",tmp, 3)) + return di_plurfix(retval, &tmp[3], ant, MY_FALSE); + return di_plurfix(retval, tmp, ant, MY_TRUE); +} /* di_fixname() */ + +/*-------------------------------------------------------------------------*/ +static INLINE char * +di_live_plurfix (object_t *ob, int ant, char * func) + +/* Generate the description for living jects. + * The function calls several standard lfuns to get the basic description, + * and call ->(plural_)() as last resort. + * Return a pointer to a static buffer or NULL. + */ + +{ + char *str, *name, tmp[DATALEN]; + svalue_t *v; + static char retval[2*DATALEN]; + + v = apply(STR_DI_Q_LIVING, ob, 0); + if (!v || v->type != T_NUMBER || v->u.number) + return di_fixname(ob, ant, func); + + if (ant == 1) + { + v = apply(STR_DI_Q_LOOKS, ob, 0); + if (v && v->type == T_STRING) + { + str = v->u.string; + if (!strcmp("Someone", str)) /* Invisible being */ + return NULL; + } + else + { + v = apply(func,ob,0); + if (v && v->type==T_STRING) + str = v->u.string; + else + return NULL; + } + strncpy(retval, str, sizeof(retval)-1); + retval[sizeof(retval)-1] = '\0'; + return retval; + } + else + { + v = apply(STR_DI_PL_Q_LOOKS, ob, 0); + if (v && v->type == T_STRING) + name = v->u.string; + else + { + strcpy(tmp, "plural_"); + strcpy(tmp+7, func); + v = apply(tmp, ob, 0); + if (v && v->type==T_STRING) + name = v->u.string; + else + name = NULL; + } + if (name) + { + strncpy(tmp, name, sizeof(tmp)-1); + tmp[sizeof(tmp)] = '\0'; + return di_add_num(retval, tmp, ant); + } + strncpy(tmp, str, sizeof(tmp)-1); + tmp[sizeof(tmp)-1] = '\0'; + return di_plurfix(retval, tmp, ant, 0); + } +} /* di_live_plurfix() */ + +/*-------------------------------------------------------------------------*/ +static char * +describe_items(svalue_t *arr, char *func, Bool live) + +/* Create the description of the items in in a static buffer and + * return the pointer to this buffer. If an error occurs, NULL is returned. + * + * and plural_ are the functions used to create the short + * description from every dead item, for living things the functions + * query_looks() and plural_query_looks() are tried first. + * is TRUE if the function shall look for living things among the items. + * + * The first element of is a number and gives the count of items + * in the array, which are stored from index 1 upward. Every item is + * again described by a two-element array: first element is the number + * of objects to be described, second is the object itself. For example: + * ({ 2 + * , ({ 3, /obj/torch }) + * , ({ 1, /obj/key }) + * , ({ 8, /obj/sword }) <-- ignored because beyond given count '2' + * }) + * + * This is the actual implementation of the efun. + */ + +{ + vector_t *p, *v1; + object_t *ob; + char *tmp; + int siz, num, cnt1, cnt2, nr; + static char res[10*DATALEN]; + + p = arr->u.vec; + if (VEC_SIZE(p) < 1) + return NULL; + siz = GET_NUMBER(&(p->item[0])); + if (!siz) + return NULL; + + res[0] = '\0'; + cnt1 = 1; + cnt2 = siz; + nr = siz; + while (cnt1 <= cnt2) + { + if (p->item[cnt1].type != T_POINTER) + return res; + v1 = p->item[cnt1].u.vec; + if (VEC_SIZE(v1) < 2) + return res; + num = GET_NUMBER(&v1->item[0]); + ob = GET_OBJECT(&v1->item[1]); + if ((!num) || (!ob)) + return res; + if (live) + tmp = di_live_plurfix(ob, num, func); + else + tmp = di_fixname(ob, num, func); + + if (tmp != NULL) + { + size_t tmplen; + + tmplen = strlen(tmp); + while (tmplen && tmp[tmplen-1] == ' ') + { + tmp[tmplen-1] = '\0'; + tmplen--; + } + + if (tmplen + strlen(res) > sizeof(res) - DATALEN) + { + strcat(res, " among other things"); + return res; + } + + if (siz == cnt2) { strcat(res,tmp); } + else if (siz == 1 && nr > 1) { strcat(res," and ");strcat(res,tmp); } + else if (siz >= 2 && nr > siz) { strcat(res,", ");strcat(res,tmp); } + else if (siz == 2 && nr <= 2) { strcat(res,tmp); } + else if (siz == 1 && nr <= 1) { strcat(res,tmp); } + } + + cnt1++; + siz--; + } + + return res; +} /* describe_items() */ + +/*-------------------------------------------------------------------------*/ +svalue_t * +f_describe_items (svalue_t *sp, int num_arg) + +/* VEFUN describe_items() + * + * string describe_items (mixed * items, string func [, int live]); + * + * Create a single descriptive string from the and return it. + * If an error occurs, 0 is returned. + * + * and plural_ are the functions used to create the short + * description from every dead item, for living things the functions + * query_looks() and plural_query_looks() are tried first. + * is TRUE if the function shall look for living things among the items. + * + * The first element of is a number and gives the count of items + * in the array, which are stored from index 1 upward. Every item is + * again described by a two-element array: first element is the number + * of objects to be described, second is the object itself. For example: + * ({ 2 + * , ({ 3, /obj/torch }) + * , ({ 1, /obj/key }) + * , ({ 8, /obj/sword }) <-- ignored because beyond given count '2' + * }) + */ + +{ + svalue_t *arg; + Bool live; + char *str; + + arg = sp - num_arg + 1; + + TYPE_TESTV2(arg+1, T_STRING); + if (num_arg < 3) + live = MY_FALSE; + else + { + TYPE_TESTV3(arg+2, T_NUMBER); + live = (arg[2].u.number != 0); + } + + str = describe_items(arg, arg[1].u.string, live); + + sp = pop_n_elems(num_arg, sp); + + sp++; + if (str) + put_malloced_string(sp, string_copy (str)); + else + put_number(sp, 0); + + return sp; +} /* f_describe_items() */ + +#undef DATALEN +#undef GET_NUMBER(x) +#undef GET_OBJECT(x) + +#endif /* F_DESCRIBE_ITEMS */ /*=========================================================================*/ /* VALUES */ diff -u -r src-std/efuns.h src/efuns.h --- src-std/efuns.h Tue Oct 05 16:58:04 1999 +++ src/efuns.h Mon Dec 06 20:22:14 1999 @@ -43,5 +43,9 @@ extern svalue_t *f_debug_info(svalue_t *sp, int num_arg); extern svalue_t *f_shutdown(svalue_t *sp); +#ifdef F_DESCRIBE_ITEMS +extern svalue_t * f_describe_items (svalue_t *sp, int num_arg); +#endif + #endif /* __EFUNS_H__ */ diff -u -r src-std/exec.h src/exec.h --- src-std/exec.h Mon Nov 15 14:21:56 1999 +++ src/exec.h Mon Dec 06 20:22:14 1999 @@ -197,8 +197,9 @@ #define TYPE_CLOSURE 8 #define TYPE_SYMBOL 9 #define TYPE_QUOTED_ARRAY 10 +#define TYPE_ARRAY 11 /* Alternative to "*" */ -#define TYPEMAP_SIZE 11 /* Number of types */ +#define TYPEMAP_SIZE 12 /* Number of types */ /* Flags, or'ed on top of the basic type */ diff -u -r src-std/func_spec src/func_spec --- src-std/func_spec Wed Dec 01 16:50:22 1999 +++ src/func_spec Mon Dec 06 20:22:14 1999 @@ -611,4 +611,8 @@ string process_string(string); int set_is_wizard(object, int default: F_CONST1); + /* Deeper Trouble II efuns */ + +string describe_items(mixed *, string, void|int); + /***************************************************************************/ diff -u -r src-std/gcollect.c src/gcollect.c --- src-std/gcollect.c Mon Dec 06 19:35:18 1999 +++ src/gcollect.c Mon Dec 06 20:22:16 1999 @@ -931,6 +931,9 @@ if (all_players[i] == NULL) continue; + if (all_players[i]->last_command) + clear_memory_reference(all_players[i]->last_command); + for ( it = all_players[i]->input_to; it != NULL; it = it->next) { clear_memory_reference(it); @@ -1067,6 +1070,8 @@ continue; NOTE_REF(all_players[i]); + if (all_players[i]->last_command) + NOTE_REF(all_players[i]->last_command); /* There are no destructed interactives */ diff -u -r src-std/lex.c src/lex.c --- src-std/lex.c Mon Dec 06 18:48:50 1999 +++ src/lex.c Mon Dec 06 20:22:18 1999 @@ -417,7 +417,8 @@ }; static struct s_reswords reswords[] - = { { "break", L_BREAK } + = { { "array", L_ARRAY } + , { "break", L_BREAK } , { "case", L_CASE } , { "catch", L_CATCH } , { "closure", L_CLOSURE_DECL } diff -u -r src-std/object.c src/object.c --- src-std/object.c Mon Dec 06 18:59:52 1999 +++ src/object.c Mon Dec 06 20:22:20 1999 @@ -194,6 +194,11 @@ #include "../mudlib/sys/driver_hook.h" +/* Deeper Trouble II needs DGD compatible save files. + * Define this macro to get them. + */ +#define DGD_COMPATIBLE + /*-------------------------------------------------------------------------*/ replace_ob_t *obj_list_replace = NULL; @@ -1171,6 +1176,8 @@ } /* write_buffer() */ /*-------------------------------------------------------------------------*/ +#ifndef DGD_COMPATIBLE + static Bool recall_pointer (void *pointer) @@ -1244,6 +1251,8 @@ /* NOTREACHED */ } /* recall_pointer() */ +#endif /* DGD_COMPATIBLE */ + /*-------------------------------------------------------------------------*/ static void save_string (char *src) @@ -1305,7 +1314,12 @@ { mp_int old_written; +#ifdef DGD_COMPATIBLE + int i; + char *source, c; +#endif +#ifndef DGD_COMPATIBLE /* If it is shared, write its ID, and maybe we're already * done then. */ @@ -1313,13 +1327,24 @@ return; /* Nope, write it */ +#endif MY_PUTC('(') MY_PUTC('[') check_map_for_destr(m); old_written = bytes_written - buf_left; +#ifdef DGD_COMPATIBLE + i = MAP_SIZE(m); + source = number_buffer; + sprintf(source, "%d", i); + c = *source++; + do MY_PUTC(c) while ('\0' != (c = *source++)); + MY_PUTC('|'); +#endif + walk_mapping(m, save_mapping_filter, (void *)(p_int)m->num_values); +#ifndef DGD_COMPATIBLE /* If the mapping is empty and has width other than 1, * use a special format */ @@ -1333,6 +1358,7 @@ c = *source++; do MY_PUTC(c) while ( '\0' != (c = *source++) ); } +#endif MY_PUTC(']') MY_PUTC(')') @@ -1467,17 +1493,30 @@ long i; svalue_t *val; +#ifndef DGD_COMPATIBLE /* Recall the array from the pointer table. * If it is a shared one, there's nothing else to do. */ if (recall_pointer(v)) return; - +#endif + /* Write the '({'... */ { +#ifdef DGD_COMPATIBLE + char *source, c; +#endif + L_PUTC_PROLOG L_PUTC('(') L_PUTC('{') +#ifdef DGD_COMPATIBLE + source = number_buffer; + sprintf(source, "%lu", VEC_SIZE(v)); + c = *source++; + do L_PUTC(c) while ('\0' != (c = *source++)); + L_PUTC('|'); +#endif L_PUTC_EPILOG } @@ -1982,9 +2021,11 @@ { char *pt; /* Read pointer */ int siz; /* Number of entries (so far) */ +#ifndef DGD_COMPATIBLE int num_values = -1; /* Last recognized width of the mapping */ int current_num_values = 0; /* Width of current entry */ - +#endif + pt = parameters->str; siz = 0; @@ -1992,6 +2033,16 @@ if (!pt) return -1; +#ifdef DGD_COMPATIBLE + if (sscanf(pt, "%d", &siz) == 1) + { + parameters->str = ((char *)(strchr(pt, '|')))+1; + parameters->num_values = 1; /* May not be good ... */ + return siz; + } + else + return -1; +#else /* The parse loop */ while (MY_TRUE) @@ -2142,6 +2193,7 @@ /* NOTREACHED */ return -1; +#endif /* DGD_COMPATIBLE */ } /* restore_map_size() */ /*-------------------------------------------------------------------------*/ @@ -2176,6 +2228,9 @@ int i; struct rms_parameters tmp_par; int siz; +#ifdef DGD_COMPATIBLE + char *pt; +#endif /* Determine the size and width of the mapping */ @@ -2195,6 +2250,10 @@ return MY_FALSE; } +#ifdef DGD_COMPATIBLE + *str = tmp_par.str; +#endif + /* Allocate the mapping */ z = allocate_mapping(siz, tmp_par.num_values); @@ -2226,7 +2285,19 @@ return MY_FALSE; } } +#ifndef DGD_COMPATIBLE *str = tmp_par.str; +#else + pt = *str; + if (*pt++ != ']' || *pt++ != ')' ) + { + free_mapping(z); + *svp = const0; + return MY_FALSE; + } + *str = pt; +#endif + return MY_TRUE; } @@ -2246,9 +2317,22 @@ */ { - char *pt, *pt2; + char *pt; +#ifndef DGD_COMPATIBLE + char *pt2; +#endif int siz; +#ifdef DGD_COMPATIBLE + if (sscanf(*str, "%d", &siz) == 1) /* Fetch size immediately */ + { + pt = strchr(*str, '|'); + *str = &pt[1]; + return siz; + } + else + return -1; +#else pt = *str; siz = 0; @@ -2341,6 +2425,7 @@ } /* while() */ return -1; +#endif /* DGD_COMPATIBLE */ } /* restore_size() */ /*-------------------------------------------------------------------------*/ diff -u -r src-std/prolang.y src/prolang.y --- src-std/prolang.y Mon Dec 06 18:44:40 1999 +++ src/prolang.y Mon Dec 06 20:22:22 1999 @@ -948,7 +948,7 @@ static char buff[100]; static char *type_name[] = { "unknown", "int", "string", "void", "object", "mapping", "float", "mixed", "closure", - "symbol", "quoted_array", }; + "symbol", "quoted_array", "array" }; Bool pointer = MY_FALSE, reference = MY_FALSE; @@ -2371,6 +2371,7 @@ /*-------------------------------------------------------------------------*/ %token L_ASSIGN +%token L_ARRAY %token L_ARROW %token L_BREAK %token L_CASE @@ -3208,6 +3209,7 @@ | L_FLOAT_DECL { $$ = TYPE_FLOAT; current_type = $$; }; | L_MAPPING { $$ = TYPE_MAPPING; current_type = $$; }; | L_VOID { $$ = TYPE_VOID; current_type = $$; } + | L_ARRAY { $$ = TYPE_ARRAY; current_type = $$; } | L_MIXED { $$ = TYPE_ANY; current_type = $$; } ; /* basic_type */ diff -u -r src-std/simulate.c src/simulate.c --- src-std/simulate.c Mon Dec 06 18:58:04 1999 +++ src/simulate.c Mon Dec 06 20:22:26 1999 @@ -1404,7 +1404,8 @@ while (--i > 0) { /* isdigit would need to check isascii first... */ if ( (c = *--p) < '0' || c > '9' ) { - if (c == '#' && name_length - i > 1) + /* TODO: Why used Kickaha '@' instead of '#' ? */ + if (c == '@' && name_length - i > 1) { fprintf(stderr, "%s Illegal file to load: %s\n" , time_stamp(), name); @@ -1770,7 +1771,7 @@ name = ob->name; /* If the ob is a clone, we have to test if its name is something - * illegal like 'foobar#34'. In that case, we have to use the + * illegal like 'foobar@34'. In that case, we have to use the * load_name as template. */ if (ob->flags & O_CLONE) @@ -4792,12 +4793,13 @@ /* EFUN cat() * - * int cat(string pathi [, int start [, int num]]) + * int cat(string path [, int start [, int num]]) * * List the file found at path. * The optional arguments start and num are start line * number and number of lines. If they are not given the * file is printed from the beginning. + * If is negative, it is counted from the end of the file. * * Result is the number of lines printed, but never more than 50. */ @@ -4816,8 +4818,6 @@ if (path == 0) return 0; - if (start < 0) - return 0; f = fopen(path, "r"); if (f == NULL) return 0; @@ -4827,6 +4827,16 @@ len = MAX_LINES; if (len > MAX_LINES) len = MAX_LINES; + + if (start < 0) + { + int lines; + lines = 0; + while (fgets(buff, sizeof buff, f) != 0) + lines++; + rewind(f); + start = lines-len+1; + } if (start == 0) start = 1; diff -u -r src-std/string_spec src/string_spec --- src-std/string_spec Mon Dec 06 17:39:26 1999 +++ src/string_spec Mon Dec 06 20:24:30 1999 @@ -97,4 +97,14 @@ #endif /* COMPAT_MODE */ #endif /* SUPPLY_PARSE_COMMAND */ + /* Deeper Trouble II lfuns */ + +SAVE_PL "save_character" + + /* describe_items() lfuns */ +DI_Q_NPC "query_npc" +DI_Q_LOOKS "query_looks" +DI_PL_Q_LOOKS "plural_query_looks" +DI_Q_LIVING "query_living" + /***************************************************************************/