#ifdef __STDC__ #include #endif #include /* * Copyright (c) 1999, J. Ali Harlow, J.A.Harlow@city.ac.uk. * Free for use with NetHack or any derivatives covered by its license. */ /* * This module deals with reading and writing basic NetHack types * from and to the NHXDR stream. Note that we only have to concern * ourselves with being able to read and write values that should * be present in a quantity, not what is physically possible on this * machine. For example, NetHack only stores values from -32768 to 32767 * in an int. Any values found in an int outside this range represents * an illegal value and the result is udefined. */ int nhxdr_write_schar(sc) schar sc; { /* * The schar type has a range of possible values -128 to 127 (config.h). * We encode these as uchars. We map 0-127 onto 0-127 and -128 to -1 * onto 128 to 255. On 2's compliment machines this results in the * same bit pattern, but we don't assume this. */ return nhxdr_write_uchar(sc>=0?(uchar)sc:(uchar)(256+(int)sc)); } int nhxdr_read_schar(sc) schar *sc; { /* * Reverse the process used when writing. */ uchar uc; int retval; retval=nhxdr_read_uchar(&uc); if (!retval) *sc=uc<128?(schar)sc:(schar)((int)uc-256); return retval; } int nhxdr_write_xchar(xc) xchar xc; { /* * The xchar type has a range of possible values 0 to 127 (global.h). * It can be cast to uchar without loss. */ return nhxdr_write_uchar((uchar)xc); } int nhxdr_read_xchar(xc) xchar *xc; { uchar uc; int retval; retval=nhxdr_read_uchar(&uc); if (!retval) *xc=uc; return retval; } int nhxdr_write_boolean(b) boolean b; { /* * The boolean type has a range of possible values 0 to 1 (global.h). * It can be cast to uchar without loss. */ return nhxdr_write_uchar((uchar)b); } int nhxdr_read_boolean(b) boolean *b; { uchar uc; int retval; retval=nhxdr_read_uchar(&uc); if (!retval) *b=uc; return retval; } int nhxdr_write_int(i) int i; { /* * The int type has a range of possible values -32768 to 32767 (global.h). * * We use the / operator because ANSI and K&R agree on its definition. * * Where i is an exact multiple of 256 then i/256 is the exact value. * * Where i is positive then i/256 is the largest integer less than * i/256.0, ie., quotient=floor(i/256.0). * * Where i is negative then i/256 is either * a. The largest integer less than i/256.0 (ie., floor(i/256.0)), or * b. The smallest integer greater than i/256.0 (ie., ceil(i/256.0)). * * In all cases (i/256)*256+i%256 == i * * Therefore: * * Where i is an exact multiple of 256 then i%256 is zero. * * Where i is positive then i%256 is positive. * * Where i is negative then i%256 is either * a. positive, or * b. negative. * * We normalize this by trapping the case of i%256 being negative and * adjusting to what we would have calculated had the machine been * of type a. The remainder must then have a value in the range 0 to 255. * The quotient must have a value in the range -128 to 127. */ int quotient,remainder; quotient=i/256; remainder=i%256; if (remainder<0) { quotient--; remainder+=256; } return nhxdr_write_uchar((uchar)remainder) || nhxdr_write_schar((schar)quotient); } int nhxdr_read_int(i) int *i; { uchar uc; schar sc; int retval; retval=nhxdr_read_uchar(&uc) || nhxdr_read_schar(&sc); if (!retval) *i=(int)(sc*256+uc); return retval; } int nhxdr_write_uint(ui) unsigned int ui; { /* * We assume that unsigned ints have a range of 0 to 65535. * * These are just a much simpler case of ints (above), since * ui can never be negative. The range of both the quotient * and the remainder is 0 to 255. */ int quotient,remainder; quotient=ui/256; remainder=ui%256; return nhxdr_write_uchar((uchar)remainder) || nhxdr_write_uchar((uchar)quotient); } int nhxdr_read_uint(ui) unsigned int *ui; { uchar q,r; int retval; retval=nhxdr_read_uchar(&r) || nhxdr_read_uchar(&q); if (!retval) /* * These casts are probably excessive, but we do have to * be careful that nothing is promoted to type int, since * that may not be able to store values larger than 32767. */ *ui=(unsigned int)q*(unsigned int)256+(unsigned int)r; return retval; } int nhxdr_write_short(si) short int si; { /* * short ints are no different to ints as far as we're concerned. */ return nhxdr_write_int((int)si); } int nhxdr_read_short(si) short int *si; { int i; int retval; retval=nhxdr_read_int(&i); if (!retval) *si=i; return retval; } int nhxdr_write_ushort(usi) unsigned short int usi; { /* * And similarly unsigned short ints == unsigned ints. */ return nhxdr_write_uint((unsigned int)usi); } int nhxdr_read_ushort(usi) unsigned short int *usi; { unsigned int ui; int retval; retval=nhxdr_read_uint(&ui); if (!retval) *usi=ui; return retval; } int nhxdr_write_long(l) long l; { /* * The long type is assumed to be at least 32-bit in lots of places * (eg., monst.h). * * The problem is analogous to ints and is solved in the same way. */ long quotient,remainder; quotient=i/65536; remainder=i%65536; if (remainder<0) { quotient--; remainder+=65536; } return nhxdr_write_uint((unsigned int)remainder) || nhxdr_write_int((int)quotient); } int nhxdr_read_long(l) long *l; { unsigned int ui; int retval; retval=nhxdr_read_uint(&ui) || nhxdr_read_int(&i); if (!retval) *l=(long)i*256+ui; return retval; } int nhxdr_write_ulong(ul) unsigned long ul; { /* * unsigned longs are solved as unsigned ints. */ long quotient,remainder; quotient=i/65536; remainder=i%65536; return nhxdr_write_uint((unsigned int)remainder) || nhxdr_write_uint((unsigned int)quotient); } int nhxdr_read_ulong(ul) unsigned long *ul; { unsigned int q,r; int retval; retval=nhxdr_read_uint(&r) || nhxdr_read_uint(&q); if (!retval) *l=(unsigned long)q*256+r; return retval; } /* * NOTE: chars are _not_ small integers. Use uchar, schar, or xchar. * chars contain characters from the execution character set. * * The following characters are assumed to exist in the execution * character set: * * The 52 upper-case and lower-case letters of the English alphabet * The 10 decimal digits * The following 29 graphic characters: !"#$&'()*+,-./:;<=>?[\]^_{|}~ * The space character * The following 6 control characters: \0\n\t\b\r\f * * making 98 in all. * * ANSI defines a further 2 that are not present in K&R (\a and \v). * * The two remaining ASCII characters (@ and `) are missing, as * are DEL and the other 25 control codes. No values greater than * 127 are supported. * * We include @ and ` anyway since NetHack uses them. Any machine * that has problems with them will probably have problems with NetHack. * * Unsupported characters are written as 0xFF, which will be * converted to '?' on reading. A warning is issued if any unsupported * characters are read (which should never happen). * * There's no particular reason I standardised on ASCII, just writer's * privilege. */ static uchar nhxdr_charset[128]={ #ifdef __STDC__ /* NUL - BEL */ '\0', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, '\a', /* BS - SI */ '\b', '\t', '\n', '\v', '\f', '\r', 0xFF, 0xFF, #else /* NUL - BEL */ '\0', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* BS - SI */ '\b', '\t', '\n', 0xFF, '\f', '\r', 0xFF, 0xFF, #endif /* DLE - ETB */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* CAN - US */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0xFF }; static uchar nhxdr_rcharset[128]={0xFE}; int nhxdr_write_char(c) char c; { int i; if (nhxdr_rcharset[0]==0xFE) { for(i=0;i<128;i++) nhxdr_rcharset[i]=0xFF; for(i=0;i<128;i++) if (nhxdr_charset[i]!=0xFF) nhxdr_rcharset[nhxdr_charset[i]]=i; } i=c; /* Avoid warnings from "clever" compilers */ if (i>=0 && i<128) return nhxdr_write_uchar(nhxdr_rcharset[i]); else return nhxdr_write_uchar((uchar)0xFF); } int nhxdr_read_char(c) char *c; { uchar uc; int retval; retval=nhxdr_read_uchar(&uc); if (!retval) { if (uc==0xFF) *c='?'; else if (uc>128 || nhxdr_charset[uc]==0xFF) { fprintf(stderr, "Warning: Unsupported character in NHXDR stream (0x%02X)",uc); *c='?'; } else *c=nhxdr_charset[uc]; } return retval; }