diff --git a/include/amiconf.h b/include/amiconf.h index 47306f9d2..593f3e470 100644 --- a/include/amiconf.h +++ b/include/amiconf.h @@ -48,9 +48,8 @@ extern void nethack_exit(int); extern void amii_setpens(int); extern void getlind(const char *, char *, const char *); -extern void exit(int); extern void CleanUp(void); -extern void Abort(long); +extern void Abort(long) NORETURN; extern int getpid(void); extern int kbhit(void); extern int WindowGetchar(void); @@ -84,6 +83,10 @@ extern void ami_wininit_data(int); #define CHANGE_COLOR 1 #define DEPTH 6 /* Maximum depth of the screen allowed */ #define AMII_MAXCOLORS (1L << DEPTH) +/* Number of palette entries actually populated in amii_init_map[] (AMII text + * mode) and amiv_init_map[] (AMIV tile mode). Indices beyond these read 0. */ +#define AMII_PALETTE_SIZE 8 +#define AMIV_PALETTE_SIZE 32 typedef unsigned short AMII_COLOR_TYPE; #define PORT_HELP "amii.hlp" diff --git a/sys/amiga/amidos.c b/sys/amiga/amidos.c index e7b22259a..097e57905 100644 --- a/sys/amiga/amidos.c +++ b/sys/amiga/amidos.c @@ -142,15 +142,7 @@ getlogin(void) long freediskspace(char *path) { -#ifdef UNTESTED - /* these changes from Patric Mueller for AROS to - * handle larger disks. Also needs limits.h and aros/oldprograms.h - * for AROS. (keni) - */ - unsigned long long freeBytes = 0; -#else long freeBytes = 0; -#endif struct InfoData *infoData; /* Remember... longword aligned */ char fileName[32]; @@ -192,11 +184,6 @@ freediskspace(char *path) infoData->id_NumBlocks - infoData->id_NumBlocksUsed; freeBytes -= (freeBytes + EXTENSION) / (EXTENSION + 1); freeBytes *= infoData->id_BytesPerBlock; -#ifdef UNTESTED - if (freeBytes > LONG_MAX) { - freeBytes = LONG_MAX; - } -#endif } if (freeBytes < 0) freeBytes = 0; @@ -368,8 +355,11 @@ fopenp(const char *name, const char *mode) return (NULL); lastch = *bp++ = *pp++; } - if (lastch != ':' && lastch != '/' && bp != buf) + if (lastch != ':' && lastch != '/' && bp != buf) { + if (bp >= buf + BUFSIZ - 2) + return (NULL); *bp++ = '/'; + } if (bp + strlen(name) > buf + BUFSIZ - 1) return (NULL); strcpy(bp, name); diff --git a/sys/amiga/amirip.c b/sys/amiga/amirip.c index 6c23a4f6c..5ccb9aac1 100644 --- a/sys/amiga/amirip.c +++ b/sys/amiga/amirip.c @@ -81,7 +81,7 @@ static struct NewWindow newwin = { 0, 0, 640, 200, 1, 0, int wh; /* was local in outrip, but needed for SCALE macro */ -int cmap_white, cmap_black; +int cmap_outline, cmap_fill; void amii_outrip(winid tmpwin, int how, time_t when) @@ -99,6 +99,16 @@ amii_outrip(winid tmpwin, int how, time_t when) if (!WINVERS_AMIV || HackScreen->RastPort.BitMap->Depth < 4) goto cleanup; + /* The graphical tombstone uses raw chipset-style palette twiddling + * (LoadRGB4, transpalette fade) and BltBitMap to a SMART_REFRESH + * window. That works on the native chipset and AGA, but on RTG + * setups (Picasso96, CyberGraphX) the visible display is decoupled + * from the chipset registers and the tombstone never appears. + * Detect RTG by screen size beyond what chipset modes can reach + * and fall through to the plain ASCII tombstone instead. */ + if (HackScreen->Width > 800 || HackScreen->Height > 600) + goto cleanup; + /* Use the users display size */ newwin.Height = amiIDisplay->ypix - newwin.TopEdge; newwin.Width = amiIDisplay->xpix; @@ -132,11 +142,11 @@ amii_outrip(winid tmpwin, int how, time_t when) for (i = 0; i < SIZE(cols); i++) cols[i] = cols_base[i] + xoff; - cmap_white = search_cmap(0, 0, 0); - cmap_black = search_cmap(15, 15, 15); + cmap_outline = search_cmap(0, 0, 0); + cmap_fill = search_cmap(15, 15, 15); - BltBitMap(tombimg, 0, 0, rp->BitMap, xoff, yoff, tomb_bmhd.w, tomb_bmhd.h, - 0xc0, 0xff, NULL); + BltBitMapRastPort(tombimg, 0, 0, rp, xoff, yoff, + tomb_bmhd.w, tomb_bmhd.h, 0xc0); /* Put together death description */ formatkiller(buf, sizeof buf, how, FALSE); @@ -254,8 +264,8 @@ cleanup: Forbid(); while (imsg = (struct IntuiMessage *) GetMsg(ripwin->UserPort)) ReplyMsg((struct Message *) imsg); - CloseWindow(ripwin); Permit(); + CloseWindow(ripwin); } LoadRGB4(&HackScreen->ViewPort, sysflags.amii_curmap, amii_numcolors); @@ -279,23 +289,23 @@ tomb_text(char *p) sprintf(buf, " %s ", p); l = TextLength(rp, buf, strlen(buf)); - SetAPen(rp, cmap_white); + SetAPen(rp, cmap_outline); Move(rp, cols[cno] - (l / 2) - 1, tomb_line); Text(rp, buf, strlen(buf)); - SetAPen(rp, cmap_white); + SetAPen(rp, cmap_outline); Move(rp, cols[cno] - (l / 2) + 1, tomb_line); Text(rp, buf, strlen(buf)); - SetAPen(rp, cmap_white); + SetAPen(rp, cmap_outline); Move(rp, cols[cno] - (l / 2), tomb_line - 1); Text(rp, buf, strlen(buf)); - SetAPen(rp, cmap_white); + SetAPen(rp, cmap_outline); Move(rp, cols[cno] - (l / 2), tomb_line + 1); Text(rp, buf, strlen(buf)); - SetAPen(rp, cmap_black); + SetAPen(rp, cmap_fill); Move(rp, cols[cno] - (l / 2), tomb_line); Text(rp, buf, strlen(buf)); } diff --git a/sys/amiga/amiwind.c b/sys/amiga/amiwind.c index d259d5128..c3c1b3394 100644 --- a/sys/amiga/amiwind.c +++ b/sys/amiga/amiwind.c @@ -19,7 +19,8 @@ static struct Message *GetFMsg(struct MsgPort *); static int BufferGetchar(void); void ProcessMessage(struct IntuiMessage *message); -#define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = (ch)) +#define BufferQueueChar(ch) \ + do { if (KbdBuffered < KBDBUFFER) KbdBuffer[KbdBuffered++] = (ch); } while (0) struct Device *ConsoleDevice = NULL; @@ -51,7 +52,7 @@ struct Library *DiskfontBase; #define KBDBUFFER 10 static unsigned char KbdBuffer[KBDBUFFER]; -unsigned char KbdBuffered; +int KbdBuffered; #ifdef HACKFONT @@ -609,10 +610,10 @@ amii_cleanup(void) Forbid(); while (msg = (struct IntuiMessage *) GetMsg(HackPort)) ReplyMsg((struct Message *) msg); + Permit(); kill_nhwindows(1); DeleteMsgPort(HackPort); HackPort = NULL; - Permit(); } /* Close the screen, under v37 or greater it is a pub screen and there may diff --git a/sys/amiga/bmp2iff_host.c b/sys/amiga/bmp2iff_host.c index 85bb42088..1182aa732 100644 --- a/sys/amiga/bmp2iff_host.c +++ b/sys/amiga/bmp2iff_host.c @@ -65,6 +65,41 @@ static const RGB amiv_pal[16] = { {0xFF,0xBB,0x99}, /* 15 peach */ }; +/* --------------------------------------------------------- */ +/* Little-endian readers (BMP is LE regardless of host) */ +/* --------------------------------------------------------- */ + +static int +read_u16le(FILE *fp, uint16_t *out) +{ + int lo = fgetc(fp), hi = fgetc(fp); + if (hi == EOF) return 0; + *out = (uint16_t)(((unsigned) hi << 8) | (unsigned) lo); + return 1; +} + +static int +read_u32le(FILE *fp, uint32_t *out) +{ + int b0 = fgetc(fp), b1 = fgetc(fp); + int b2 = fgetc(fp), b3 = fgetc(fp); + if (b3 == EOF) return 0; + *out = ((uint32_t)(unsigned) b3 << 24) + | ((uint32_t)(unsigned) b2 << 16) + | ((uint32_t)(unsigned) b1 << 8) + | (uint32_t)(unsigned) b0; + return 1; +} + +static int +read_i32le(FILE *fp, int32_t *out) +{ + uint32_t v; + if (!read_u32le(fp, &v)) return 0; + *out = (int32_t) v; + return 1; +} + /* --------------------------------------------------------- */ /* Colour helpers */ /* --------------------------------------------------------- */ @@ -345,7 +380,7 @@ main(int argc, char **argv) int nplanes, maxcol; int i, y; RGB outpal[256]; - int remap[256]; + int remap[256] = {0}; uint8_t *remapped; uint8_t *plane_data[8]; uint8_t cmap_rgb[256 * 3]; @@ -370,8 +405,22 @@ main(int argc, char **argv) bmpfp = fopen(argv[3], "rb"); if (!bmpfp) { perror(argv[3]); return 1; } - if (fread(&fhdr, sizeof(fhdr), 1, bmpfp) != 1 - || fread(&ihdr, sizeof(ihdr), 1, bmpfp) != 1) { + if (!read_u16le(bmpfp, &fhdr.bfType) + || !read_u32le(bmpfp, &fhdr.bfSize) + || !read_u16le(bmpfp, &fhdr.bfReserved1) + || !read_u16le(bmpfp, &fhdr.bfReserved2) + || !read_u32le(bmpfp, &fhdr.bfOffBits) + || !read_u32le(bmpfp, &ihdr.biSize) + || !read_i32le(bmpfp, &ihdr.biWidth) + || !read_i32le(bmpfp, &ihdr.biHeight) + || !read_u16le(bmpfp, &ihdr.biPlanes) + || !read_u16le(bmpfp, &ihdr.biBitCount) + || !read_u32le(bmpfp, &ihdr.biCompression) + || !read_u32le(bmpfp, &ihdr.biSizeImage) + || !read_i32le(bmpfp, &ihdr.biXPelsPerMeter) + || !read_i32le(bmpfp, &ihdr.biYPelsPerMeter) + || !read_u32le(bmpfp, &ihdr.biClrUsed) + || !read_u32le(bmpfp, &ihdr.biClrImportant)) { fprintf(stderr, "Failed to read BMP header\n"); return 1; } @@ -388,6 +437,11 @@ main(int argc, char **argv) img_w = ihdr.biWidth; img_h = abs(ihdr.biHeight); + if (img_w <= 0 || img_w > 16384 || img_h <= 0 || img_h > 16384) { + fprintf(stderr, "BMP dimensions out of range: %dx%d\n", + img_w, img_h); + return 1; + } ncolors = ihdr.biClrUsed ? ihdr.biClrUsed : 256; if (ncolors > 256) ncolors = 256; @@ -410,13 +464,15 @@ main(int argc, char **argv) rowstride = (img_w + 3) & ~3; bmpdata = malloc(rowstride * img_h); if (!bmpdata) { - printf("%s\n", "malloc failure on bmpdata"); + fprintf(stderr, "malloc failure on bmpdata\n"); return 1; } fseek(bmpfp, fhdr.bfOffBits, SEEK_SET); if (fread(bmpdata, 1, rowstride * img_h, bmpfp) != (size_t)(rowstride * img_h)) { fprintf(stderr, "Failed to read pixel data\n"); + free(bmpdata); + fclose(bmpfp); return 1; } fclose(bmpfp); @@ -424,7 +480,8 @@ main(int argc, char **argv) /* flip bottom-up to top-down */ pixels = malloc(img_w * img_h); if (!pixels) { - printf("%s\n", "malloc failure on pixels"); + fprintf(stderr, "malloc failure on pixels\n"); + free(bmpdata); return 1; } if (ihdr.biHeight > 0) { @@ -450,7 +507,7 @@ main(int argc, char **argv) remapped = malloc(img_w * img_h); if (!remapped) { - printf("%s\n", "malloc failure on remapped"); + fprintf(stderr, "malloc failure on remapped\n"); return 1; } for (i = 0; i < img_w * img_h; i++) @@ -458,8 +515,13 @@ main(int argc, char **argv) /* convert to bitplanes */ planesize = (img_w / 8) * img_h; - for (i = 0; i < nplanes; i++) + for (i = 0; i < nplanes; i++) { plane_data[i] = calloc(1, planesize); + if (!plane_data[i]) { + fprintf(stderr, "calloc failure for plane %d\n", i); + return 1; + } + } to_planes(remapped, img_w, img_h, nplanes, plane_data); diff --git a/sys/amiga/clipwin.c b/sys/amiga/clipwin.c index f2d38ce64..6277b6b60 100644 --- a/sys/amiga/clipwin.c +++ b/sys/amiga/clipwin.c @@ -197,7 +197,7 @@ static struct Gadget ClipXSIZE = { static struct PropInfo ClipClipYSIZESInfo = { AUTOKNOB + FREEHORIZ, /* PropInfo flags */ - -25937, -1, /* horizontal and vertical pot values */ + 39599, -1, /* horizontal and vertical pot values */ 10922, -1, /* horizontal and vertical body values */ }; diff --git a/sys/amiga/winamenu.c b/sys/amiga/winamenu.c index 19d439563..7a9e404ed 100644 --- a/sys/amiga/winamenu.c +++ b/sys/amiga/winamenu.c @@ -32,8 +32,7 @@ amii_start_menu(winid window, unsigned long mbehavior UNUSED) cw->data = NULL; } - for (mip = cw->menu.items, i = 0; - (mip = cw->menu.items) && i < cw->menu.count; ++i) { + while ((mip = cw->menu.items) != NULL) { cw->menu.items = mip->next; free(mip); } @@ -149,11 +148,13 @@ amii_end_menu(winid window, const char *morestr) cw->menu.last->next = cw->menu.items; cw->menu.items = cw->menu.last; cw->menu.last = mip; - t = cw->data[cw->cury - 1]; - for (i = cw->cury - 1; i > 0; i--) { - cw->data[i] = cw->data[i - 1]; + if (cw->cury > 0) { + t = cw->data[cw->cury - 1]; + for (i = cw->cury - 1; i > 0; i--) { + cw->data[i] = cw->data[i - 1]; + } + cw->data[0] = t; } - cw->data[0] = t; #endif } @@ -190,6 +191,8 @@ amii_menu_item * find_menu_item(struct amii_WinDesc *cw, int idx) { amii_menu_item *mip; + if (idx < 0) + return NULL; for (mip = cw->menu.items; idx > 0 && mip; mip = mip->next) --idx; @@ -336,7 +339,8 @@ DoMenuScroll(int win, int blocking, int how, menu_item **retmip) nw->Screen = HackScreen; if (win == WIN_INVEN) { - sprintf(title, "%s the %s's Inventory", svp.plname, svp.pl_character); + Snprintf(title, sizeof title, "%s the %s's Inventory", + svp.plname, svp.pl_character); nw->Title = title; if (lastinvent.MaxX != 0) { nw->LeftEdge = lastinvent.MinX; @@ -606,7 +610,8 @@ DoMenuScroll(int win, int blocking, int how, menu_item **retmip) if (how == PICK_ANY) { amip = cw->menu.items; while (amip) { - if (amip->selected) { + if (amip->canselect && amip->selector + && amip->selected) { amip->selected = FALSE; amip->count = -1; amip->str[SOFF + 2] = '-'; @@ -738,8 +743,9 @@ DoMenuScroll(int win, int blocking, int how, menu_item **retmip) } else { reset_counting = TRUE; } - sprintf(countString, "Count: %d", count); - pline(countString); + Snprintf(countString, sizeof countString, + "Count: %ld", count); + pline("%s", countString); } } else if (code == CTRL('D') || code == CTRL('U') || code == MENU_NEXT_PAGE @@ -761,7 +767,7 @@ DoMenuScroll(int win, int blocking, int how, menu_item **retmip) if (code == MENU_FIRST_PAGE) { topidx = 0; } else if (code == MENU_LAST_PAGE) { - topidx = cw->maxrow - wheight; + topidx = max(0, cw->maxrow - wheight); } else for (i = 0; i < endcnt; ++i) { if (code == CTRL('D') || code == MENU_NEXT_PAGE) { @@ -851,6 +857,8 @@ DoMenuScroll(int win, int blocking, int how, menu_item **retmip) } else { int selected = FALSE; for (amip = cw->menu.items; amip; amip = amip->next) { + if (!amip->canselect) + continue; if (amip->selector == code) { if (how == PICK_ONE) aredone = 1; @@ -905,6 +913,8 @@ DoMenuScroll(int win, int blocking, int how, menu_item **retmip) aredone = 1; for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; + if (!gd) + break; pip = (struct PropInfo *) gd->SpecialInfo; totalvis = CountLines(win); @@ -917,6 +927,8 @@ DoMenuScroll(int win, int blocking, int how, menu_item **retmip) case MOUSEMOVE: for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; + if (!gd) + break; pip = (struct PropInfo *) gd->SpecialInfo; totalvis = CountLines(win); diff --git a/sys/amiga/winami.c b/sys/amiga/winami.c index 19a660e42..631af1771 100644 --- a/sys/amiga/winami.c +++ b/sys/amiga/winami.c @@ -339,7 +339,7 @@ struct NewScreen NewHackScreen = { 0, 0, WIDTH, SCREENHEIGHT, 3, 0, void amii_askname(void) { - char plnametmp[300]; /* From winreq.c: sizeof(StrStringSIBuff) */ + char plnametmp[BUFSZ]; /* matches StrStringSIBuff in winreq.c */ *plnametmp = 0; do { amii_getlin("Who are you?", plnametmp); @@ -375,7 +375,7 @@ amii_get_ext_cmd(void) int bottom = 0; struct Window *w; - char obufp[100]; + char obufp[BUFSZ]; char *bufp = obufp; int c; int com_index, oindex; @@ -417,7 +417,7 @@ amii_get_ext_cmd(void) amii_start_menu(win, MENU_BEHAVE_STANDARD); for (i = 0; extcmdlist[i].ef_txt != NULL; ++i) { - id.a_char = extcmdlist[i].ef_txt[0]; + id.a_int = i; sprintf(buf, "%-10s - %s ", extcmdlist[i].ef_txt, extcmdlist[i].ef_desc); amii_add_menu(win, (const glyph_info *) 0, &id, @@ -432,16 +432,14 @@ amii_get_ext_cmd(void) if (sel == 0) { return (-1); } else { - sel = mip->item.a_char; - for (i = 0; extcmdlist[i].ef_txt != NULL; ++i) { - if (sel == extcmdlist[i].ef_txt[0]) - break; - } + i = mip->item.a_int; /* copy in the text */ if (extcmdlist[i].ef_txt != NULL) { amii_clear_nhwindow(WIN_MESSAGE); - strcpy(bufp = obufp, extcmdlist[i].ef_txt); + strncpy(obufp, extcmdlist[i].ef_txt, sizeof(obufp) - 1); + obufp[sizeof(obufp) - 1] = '\0'; + bufp = obufp; (void) put_ext_cmd(obufp, colx, cw, bottom); return (i); } else @@ -499,7 +497,8 @@ amii_get_ext_cmd(void) sel = com_index; } else { colx = put_ext_cmd(obufp, colx, cw, bottom); - if (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO) + if (bufp - obufp < (int) sizeof obufp - 1 + && bufp - obufp < COLNO) bufp++; } } else if (c == ('X' - 64) || c == '\177') { @@ -576,7 +575,7 @@ amii_yn_function(const char *query, const char *resp, char def) char q; char rtmp[40]; boolean digit_ok, allow_num; - char prompt[BUFSZ]; + char prompt[BUFSZ + QBUFSZ + 16]; struct amii_WinDesc *cw; if (cw = amii_wins[WIN_MESSAGE]) @@ -591,10 +590,12 @@ amii_yn_function(const char *query, const char *resp, char def) *rb = '\0'; (void) strncpy(prompt, query, QBUFSZ - 1); prompt[QBUFSZ - 1] = '\0'; - Sprintf(eos(prompt), " [%s]", respbuf); + Snprintf(eos(prompt), sizeof prompt - strlen(prompt), + " [%s]", respbuf); if (def) - Sprintf(eos(prompt), " (%c)", def); - Strcat(prompt, " "); + Snprintf(eos(prompt), sizeof prompt - strlen(prompt), + " (%c)", def); + Snprintf(eos(prompt), sizeof prompt - strlen(prompt), " "); pline("%s", prompt); } else { amii_putstr(WIN_MESSAGE, 0, query); @@ -704,7 +705,8 @@ amii_display_file(const char *fn, boolean complain) if ((fp = dlb_fopen(fn, RDTMODE)) == (dlb *) NULL) { if (complain) { - sprintf(buf, "Can't display %s: %s", fn, strerror(errno)); + Snprintf(buf, sizeof buf, + "Can't display %s: %s", fn, strerror(errno)); amii_addtopl(buf); } return; diff --git a/sys/amiga/winchar.c b/sys/amiga/winchar.c index 9b29152a7..ed486c70e 100644 --- a/sys/amiga/winchar.c +++ b/sys/amiga/winchar.c @@ -79,44 +79,68 @@ struct BitMap *tileimg, *tile; BitMapHeader ReadImageFile(const char *filename, struct BitMap **bmp) { - BitMapHeader *bmhd, bmhds; + BitMapHeader *bmhd, bmhds = { 0 }; int j, np; - struct IFFHandle *iff; + long err; + struct IFFHandle *iff = NULL; struct StoredProperty *prop; + int iff_opened = 0; + const char *errfmt = NULL; + long errcode = 0; IFFParseBase = OpenLibrary("iffparse.library", 0L); if (!IFFParseBase) panic("No iffparse.library"); iff = AllocIFF(); - if (!iff) - panic("can't start IFF processing"); + if (!iff) { + errfmt = "can't start IFF processing"; + goto cleanup; + } iff->iff_Stream = Open(filename, MODE_OLDFILE); - if (iff->iff_Stream == 0) - panic("Can't open %s", filename); + if (iff->iff_Stream == 0) { + errfmt = "Can't open %s"; + goto cleanup; + } InitIFFasDOS(iff); - OpenIFF(iff, IFFF_READ); + if ((err = OpenIFF(iff, IFFF_READ)) != 0) { + errfmt = "OpenIFF failed on %s, code %ld"; + errcode = err; + goto cleanup; + } + iff_opened = 1; + PropChunk(iff, ID_BMAP, ID_BMHD); PropChunk(iff, ID_BMAP, ID_CMAP); PropChunk(iff, ID_BMAP, ID_PDAT); StopChunk(iff, ID_BMAP, ID_PLNE); - if ((j = ParseIFF(iff, IFFPARSE_SCAN)) != 0) - panic("ParseIFF failed on %s, code %d", - filename, j); + if ((err = ParseIFF(iff, IFFPARSE_SCAN)) != 0) { + errfmt = "ParseIFF failed on %s, code %ld"; + errcode = err; + goto cleanup; + } prop = FindProp(iff, ID_BMAP, ID_BMHD); - if (!prop) - panic("No BMHD chunk in %s", filename); + if (!prop) { + errfmt = "No BMHD chunk in %s"; + goto cleanup; + } bmhd = (BitMapHeader *) prop->sp_Data; np = bmhd->nPlanes; + if (np > DEPTH) { + errfmt = "%s: too many bitplanes (code %ld)"; + errcode = np; + goto cleanup; + } + /* Load CMAP into palette arrays if present */ prop = FindProp(iff, ID_BMAP, ID_CMAP); if (prop) { unsigned char *cmap = prop->sp_Data; - for (j = 0; j < (1L << np) * 3; j += 3) { + for (j = 0; j < (1UL << np) * 3; j += 3) { amii_initmap[j / 3] = amiv_init_map[j / 3] = ((cmap[j+0] >> 4) << 8) @@ -132,18 +156,29 @@ ReadImageFile(const char *filename, struct BitMap **bmp) *bmp = MyAllocBitMap(bmhd->w, bmhd->h, np, MEMF_CHIP | MEMF_CLEAR); - if (!*bmp) - panic("Can't allocate bitmap for %s", filename); + if (!*bmp) { + errfmt = "Can't allocate bitmap for %s"; + goto cleanup; + } for (j = 0; j < np; j++) ReadChunkBytes(iff, (*bmp)->Planes[j], RASSIZE(bmhd->w, bmhd->h)); bmhds = *bmhd; - CloseIFF(iff); - Close(iff->iff_Stream); - FreeIFF(iff); + +cleanup: + if (iff_opened) + CloseIFF(iff); + if (iff && iff->iff_Stream) + Close(iff->iff_Stream); + if (iff) + FreeIFF(iff); CloseLibrary(IFFParseBase); + IFFParseBase = NULL; + + if (errfmt) + panic(errfmt, filename, errcode); return bmhds; } @@ -189,9 +224,15 @@ MyAllocBitMap(int xsize, int ysize, int depth, long mflags) if (!bm) return (NULL); + bm->mflags = mflags; bm->xsize = xsize; bm->ysize = ysize; InitBitMap(&bm->bm, depth, xsize, ysize); + /* InitBitMap does not zero Planes[]; if a later AllocRaster fails + * and MyFreeBitMap unwinds, the uninitialized entries above the + * failure would be passed to FreeRaster as garbage pointers. */ + for (j = 0; j < (int) (sizeof bm->bm.Planes / sizeof bm->bm.Planes[0]); ++j) + bm->bm.Planes[j] = NULL; for (j = 0; j < depth; ++j) { if (mflags & MEMF_CHIP) bm->bm.Planes[j] = AllocRaster(xsize, ysize); @@ -784,7 +825,7 @@ amii_lprint_glyph(winid window, int color_index, int glyph) /* * Add it to the end of the buffer */ - amii_glyph_buffer[glyph_buffer_index++] = glyph; + amii_glyph_buffer[glyph_buffer_index++] = (char) glyph; amii_g_nodes[glyph_node_index - 1].len++; } else { /* See if we're out of glyph nodes */ diff --git a/sys/amiga/windefs.h b/sys/amiga/windefs.h index 234d213a8..84faf98ff 100644 --- a/sys/amiga/windefs.h +++ b/sys/amiga/windefs.h @@ -29,7 +29,7 @@ #include "func_tab.h" #ifndef CLIPPING -CLIPPING must be defined for the AMIGA version +#error "CLIPPING must be defined for the AMIGA version" #endif #undef LI diff --git a/sys/amiga/winext.h b/sys/amiga/winext.h index 02d1436a6..adfd83cd6 100644 --- a/sys/amiga/winext.h +++ b/sys/amiga/winext.h @@ -23,6 +23,17 @@ extern struct amii_DisplayDesc *amiIDisplay; /* the Amiga Intuition descriptor */ extern struct window_procs amii_procs; extern struct window_procs amiv_procs; +/* Three similarly-named palette arrays. Note the position of the + * second underscore distinguishes them: + * amii_initmap = working/runtime palette (mutated by tile/tomb load + * and the in-game color editor). + * amii_init_map = AMII (text-mode) compile-time defaults, 8 entries. + * amiv_init_map = AMIV (tile-mode) compile-time defaults, 32 entries + * (mutated by ReadImageFile when a tile/tomb IFF + * carries its own CMAP). + * The naming is historical; sysflags.amii_curmap is yet another related + * array holding the user's saved color choices. + */ extern unsigned short amii_initmap[AMII_MAXCOLORS]; extern unsigned short amiv_init_map[AMII_MAXCOLORS]; extern unsigned short amii_init_map[AMII_MAXCOLORS]; @@ -52,7 +63,7 @@ extern struct Menu HackMenu[]; extern struct Menu *MenuStrip; extern struct NewMenu GTHackMenu[]; extern APTR *VisualInfo; -extern unsigned char KbdBuffered; +extern int KbdBuffered; extern struct TextFont *TextsFont; extern struct TextFont *HackFont; extern struct IOStdReq ConsoleIO; diff --git a/sys/amiga/winfuncs.c b/sys/amiga/winfuncs.c index b964d9ffc..c5d997ef6 100644 --- a/sys/amiga/winfuncs.c +++ b/sys/amiga/winfuncs.c @@ -164,23 +164,23 @@ amii_destroy_nhwindow(winid win) /* just hide */ WIN_OVER = WIN_ERR; } } else if (cw->type == NHW_OVER) { - struct Window *w = amii_wins[WIN_OVER]->win; - amii_oldover.MinX = w->LeftEdge; - amii_oldover.MinY = w->TopEdge; - amii_oldover.MaxX = w->Width; - amii_oldover.MaxY = w->Height; + struct Window *w = cw->win; + if (w) { + amii_oldover.MinX = w->LeftEdge; + amii_oldover.MinY = w->TopEdge; + amii_oldover.MaxX = w->Width; + amii_oldover.MaxY = w->Height; - if (WIN_MESSAGE != WIN_ERR && amii_wins[WIN_MESSAGE]) { - w = amii_wins[WIN_MESSAGE]->win; - amii_oldmsg.MinX = w->LeftEdge; - amii_oldmsg.MinY = w->TopEdge; - amii_oldmsg.MaxX = w->Width; - amii_oldmsg.MaxY = w->Height; - SizeWindow(amii_wins[WIN_MESSAGE]->win, - (amiIDisplay->xpix - - amii_wins[WIN_MESSAGE]->win->LeftEdge) - - amii_wins[WIN_MESSAGE]->win->Width, - 0); + if (WIN_MESSAGE != WIN_ERR && amii_wins[WIN_MESSAGE] + && (w = amii_wins[WIN_MESSAGE]->win) != NULL) { + amii_oldmsg.MinX = w->LeftEdge; + amii_oldmsg.MinY = w->TopEdge; + amii_oldmsg.MaxX = w->Width; + amii_oldmsg.MaxY = w->Height; + SizeWindow(w, + (amiIDisplay->xpix - w->LeftEdge) - w->Width, + 0); + } } } } @@ -227,6 +227,10 @@ amii_destroy_nhwindow(winid win) /* just hide */ WIN_MESSAGE = WIN_ERR; else if (win == WIN_INVEN) WIN_INVEN = WIN_ERR; + else if (win == WIN_OVER) + WIN_OVER = WIN_ERR; + else if (win == WIN_BASE) + WIN_BASE = WIN_ERR; } struct FillParams { @@ -355,6 +359,9 @@ amii_create_nhwindow(int type) panic("no memory for msg port"); } + if (type < 0 || type > NHW_OVER) + panic("bad type %d in create_nhwindow", type); + nw = &new_wins[type].newwin; nw->Width = amiIDisplay->xpix; nw->Screen = HackScreen; @@ -416,8 +423,13 @@ amii_create_nhwindow(int type) if (nw->Width >= amiIDisplay->xpix - nw->LeftEdge) nw->Width = amiIDisplay->xpix - nw->LeftEdge; } else if (WINVERS_AMIV && type == NHW_OVER) { - nw->Flags |= WINDOWSIZING | WINDOWDRAG | WINDOWCLOSE; - nw->IDCMPFlags |= CLOSEWINDOW; + /* No window-system gadgets: BORDERLESS means there is no border + * to attach close/size/drag gadgets to. On some Kickstarts the + * phantom gadgets hit-test against unrelated input (selecting + * the overview and pressing ESC has been observed to destroy + * the window and crash the game). SHIFT-HELP toggles the + * overview cleanly via delayed_key_action; that is the + * supported close path. */ /* Bring up window as half the width of the message window, and make * the message window change to one half the width... */ @@ -906,7 +918,7 @@ amii_init_nhwindows(int *argcp, char **argv) for (t = 1; t <= lclargc; t++) { if (!strcmp("-L", *argv_in) || !strcmp("-l", *argv_in)) { - bigscreen = (*argv_in[1] == 'l') ? -1 : 1; + bigscreen = ((*argv_in)[1] == 'l') ? -1 : 1; /* and eat the flag */ (*argcp)--; } else { @@ -1087,9 +1099,9 @@ amii_init_nhwindows(int *argcp, char **argv) NewHackScreen.Width = max(WIDTH, amiIDisplay->xpix); NewHackScreen.Height = max(SCREENHEIGHT, amiIDisplay->ypix); { - static char fname[18]; - sprintf(fname, "NetHack %d.%d.%d", VERSION_MAJOR, VERSION_MINOR, - PATCHLEVEL); + static char fname[32]; + snprintf(fname, sizeof fname, "NetHack %d.%d.%d", + VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); NewHackScreen.DefaultTitle = fname; } if (IntuitionBase->LibNode.lib_Version >= 37) { @@ -1114,12 +1126,16 @@ amii_init_nhwindows(int *argcp, char **argv) SM_FilterHook.h_Data = 0; SM_FilterHook.h_SubEntry = 0; SMR = AllocAslRequest(ASL_ScreenModeRequest, NULL); - if (AslRequestTags(SMR, ASLSM_FilterFunc, (ULONG) &SM_FilterHook, - TAG_END)) - amii_scrnmode = SMR->sm_DisplayID; - else + if (SMR) { + if (AslRequestTags(SMR, ASLSM_FilterFunc, + (ULONG) &SM_FilterHook, TAG_END)) + amii_scrnmode = SMR->sm_DisplayID; + else + amii_scrnmode = 0; + FreeAslRequest(SMR); + } else { amii_scrnmode = 0; - FreeAslRequest(SMR); + } } if (forcenobig == 0) { @@ -1203,9 +1219,9 @@ amii_init_nhwindows(int *argcp, char **argv) if (WINVERS_AMIV) { extern char *tilefile; - if (amii_numcolors >= 32) { + if (amii_numcolors >= AMIV_PALETTE_SIZE) { tilefile = (char *) fqname("tiles/tiles32.iff", DATAPREFIX, 0); - amii_numcolors = 32; + amii_numcolors = AMIV_PALETTE_SIZE; } else { tilefile = (char *) fqname("tiles/tiles16.iff", DATAPREFIX, 0); } @@ -1216,7 +1232,7 @@ amii_init_nhwindows(int *argcp, char **argv) /* Find out how deep the screen needs to be, 32 planes is enough! */ for (i = 0; i < 32; ++i) { - if ((1L << i) >= amii_numcolors) + if ((1UL << i) >= (unsigned long) amii_numcolors) break; } @@ -1240,7 +1256,12 @@ amii_init_nhwindows(int *argcp, char **argv) if (--NewHackScreen.Depth < 3) Abort(AN_OpenScreen & ~AT_DeadEnd); } - amii_numcolors = 1L << NewHackScreen.Depth; + amii_numcolors = 1UL << NewHackScreen.Depth; + { + int palmax = WINVERS_AMIV ? AMIV_PALETTE_SIZE : AMII_PALETTE_SIZE; + if (amii_numcolors > palmax) + amii_numcolors = palmax; + } if (HackScreen->Height > 300 && forcenobig == 0) bigscreen = 1; else @@ -1526,7 +1547,6 @@ void amii_display_nhwindow(winid win, boolean blocking) { menu_item *mip; - int cnt; static int lastwin = -1; struct amii_WinDesc *cw; @@ -1549,7 +1569,7 @@ amii_display_nhwindow(winid win, boolean blocking) } if (cw->type == NHW_MENU || cw->type == NHW_TEXT) { - cnt = DoMenuScroll(win, blocking, PICK_ONE, &mip); + (void) DoMenuScroll(win, blocking, PICK_ONE, &mip); } else if (cw->type == NHW_MAP) { amii_end_glyphout(win); /* Do more if it is time... */ @@ -1724,7 +1744,7 @@ amii_set_text_font(char *name, int size) /* Look for windows to set, and change them */ - if (DiskfontBase = OpenLibrary("diskfont.library", amii_libvers)) { + if ((DiskfontBase = OpenLibrary("diskfont.library", amii_libvers))) { TextsFont = OpenDiskFont(&TextsFont13); for (i = 0; TextsFont && i < MAXWIN; ++i) { if ((cw = amii_wins[i]) && cw->win != NULL) { @@ -1743,9 +1763,9 @@ amii_set_text_font(char *name, int size) } } } + CloseLibrary(DiskfontBase); + DiskfontBase = NULL; } - CloseLibrary(DiskfontBase); - DiskfontBase = NULL; } void diff --git a/sys/amiga/winproto.h b/sys/amiga/winproto.h index 831db69a3..60bb1adf9 100644 --- a/sys/amiga/winproto.h +++ b/sys/amiga/winproto.h @@ -59,7 +59,7 @@ int amikbhit(void); int WindowGetchar(void); WETYPE WindowGetevent(void); void amii_cleanup(void); -void Abort(long rc); +void Abort(long rc) NORETURN; void CleanUp(void); void flush_glyph_buffer(struct Window *w); void amiga_print_glyph(winid window, int color_index, int glyph); @@ -120,8 +120,6 @@ void amii_display_file(const char *fn, boolean complain); void SetBorder(struct Gadget *gd); /* malloc/free provided by stdlib.h */ -void Abort(long rc); - win_request_info *amii_ctrl_nhwindow(winid, int, win_request_info *); /* amirip.c */ diff --git a/sys/amiga/winreq.c b/sys/amiga/winreq.c index d4a1bc362..4b3056838 100644 --- a/sys/amiga/winreq.c +++ b/sys/amiga/winreq.c @@ -21,8 +21,8 @@ struct IntuiText IText1 = { 3, 0, JAM1, 4, 1, NULL, (UBYTE *) "Cancel", struct Gadget Gadget2 = { NULL, 9, 15, 56, 10, NULL, RELVERIFY, BOOLGADGET, (APTR) &Border1, NULL, &IText1, NULL, NULL, 1, NULL }; -UBYTE StrStringSIBuff[300]; -struct StringInfo StrStringSInfo = { StrStringSIBuff, UNDOBUFFER, 0, 300, 0, +UBYTE StrStringSIBuff[BUFSZ]; +struct StringInfo StrStringSInfo = { StrStringSIBuff, UNDOBUFFER, 0, BUFSZ, 0, 0, 0, 0, 0, 0, 0, 0, NULL }; SHORT BorderVectors2[] = { 0, 0, 439, 0, 439, 11, 0, 11, 0, 0 }; struct Border Border2 = { -1, -1, 3, 0, JAM1, 5, BorderVectors2, NULL }; @@ -187,14 +187,23 @@ EditColor(void) break; } - strcpy(oname, dirname((char *) configfile)); - if (oname[strlen(oname) - 1] != ':') { - sprintf(nname, "%s/New_NetHack.cnf", oname); - strcat(oname, "/"); - strcat(oname, "Old_NetHack.cnf"); - } else { - sprintf(nname, "%sNew_NetHack.cnf", oname); - strcat(oname, "Old_NetHack.cnf"); + { + size_t olen; + strncpy(oname, dirname((char *) configfile), + sizeof(oname) - 1); + oname[sizeof(oname) - 1] = '\0'; + olen = strlen(oname); + if (olen > 0 && oname[olen - 1] != ':') { + Snprintf(nname, sizeof nname, + "%s/New_NetHack.cnf", oname); + Snprintf(oname + olen, sizeof(oname) - olen, + "/Old_NetHack.cnf"); + } else { + Snprintf(nname, sizeof nname, + "%sNew_NetHack.cnf", oname); + Snprintf(oname + olen, sizeof(oname) - olen, + "Old_NetHack.cnf"); + } } nfp = fopen(nname, "w"); @@ -506,20 +515,19 @@ EditClipping(void) char * dirname(char *str) { - char *t, c; static char dir[300]; + char *t; - t = strrchr(str, '/'); + strncpy(dir, str, sizeof(dir) - 1); + dir[sizeof(dir) - 1] = '\0'; + + t = strrchr(dir, '/'); + if (!t) + t = strrchr(dir, ':'); if (!t) - t = strrchr(str, ':'); - if (!t) { dir[0] = '\0'; - } else { - c = *t; - *t = 0; - strcpy(dir, str); - *t = c; - } + else + *t = '\0'; return (dir); } @@ -696,6 +704,9 @@ DispCol(struct Window *w, int idx, UWORD *colors) char buf[50]; char *colname, *defval; + if (idx < 0 || idx >= amii_numcolors) + return; + if (WINVERS_AMIV) { colname = amiv_colnames[idx].name; defval = amiv_colnames[idx].defval; diff --git a/sys/amiga/winstr.c b/sys/amiga/winstr.c index 2f7329467..9d3e207f4 100644 --- a/sys/amiga/winstr.c +++ b/sys/amiga/winstr.c @@ -125,8 +125,25 @@ amii_putstr(winid window, int attr, const char *str) p = (char *) str; if (p == str) { - /* p = (char *)&str[ cw->cols ]; */ - outmore(cw); + /* No whitespace within visible width. */ + if (cw->curx > 0) { + /* Mid-line: clear it and retry at column 0. */ + outmore(cw); + continue; + } + /* Already at line start: word is longer than one + * line, so force-break it at the column boundary. */ + i = cw->cols - 1 - fudge; + if (i <= 0) + i = 1; + if ((size_t) i > strlen(str)) + i = strlen(str); + outsubstr(cw, (char *) str, i, fudge); + cw->curx += i; + str += i; + if (*str) + amii_scrollmsg(w, cw); + amii_cl_end(cw, cw->curx); continue; } @@ -205,6 +222,7 @@ amii_putstr(winid window, int attr, const char *str) TextSpaces(w->RPort, cw->cols); cw->cury--; } + wrapping = 0; } amii_curs(window, cw->curx + 1, cw->cury); Text(w->RPort, (char *) str, strlen((char *) str)); diff --git a/sys/amiga/xpm2iff_host.c b/sys/amiga/xpm2iff_host.c index 589d4f56f..5a968979e 100644 --- a/sys/amiga/xpm2iff_host.c +++ b/sys/amiga/xpm2iff_host.c @@ -62,12 +62,13 @@ xpmgetline(void) /* strip trailing <",> and whitespace */ for (bp = xbuf; *bp; bp++) ; - bp--; - while (isspace((unsigned char)*bp)) + if (bp > xbuf) bp--; - if (*bp == ',') + while (bp > xbuf && isspace((unsigned char)*bp)) bp--; - if (*bp == '"') + if (bp > xbuf && *bp == ',') + bp--; + if (bp > xbuf && *bp == '"') bp--; bp++; *bp = '\0'; @@ -209,10 +210,19 @@ main(int argc, char **argv) return 1; } + if (XpmScreen.Colors < 1 || XpmScreen.Colors > 256) { + fprintf(stderr, + "xpm2iff_host: unsupported color count %d\n", + XpmScreen.Colors); + return 1; + } + /* nplanes = ceil(log2(Colors)) */ nplanes = 0; i = XpmScreen.Colors - 1; while (i > 0) { nplanes++; i >>= 1; } + if (nplanes == 0) + nplanes = 1; colors = 1 << nplanes; diff --git a/sys/unix/hints/include/cross-post.500 b/sys/unix/hints/include/cross-post.500 index 42e562690..e01623002 100644 --- a/sys/unix/hints/include/cross-post.500 +++ b/sys/unix/hints/include/cross-post.500 @@ -307,7 +307,7 @@ UUDECODE = ../util/uudecode ../util/uudecode: ../sys/share/uudecode.c $(CC) $(CFLAGS) -o $@ $< -amigapkg: $(AMITILES) ../util/uudecode +amigapkg: $(GAMEBIN) $(AMITILES) ../util/uudecode mkdir -p $(TARGETPFX)pkg/NetHack/tiles $(TARGETPFX)pkg/NetHack/hack cp $(GAMEBIN) $(TARGETPFX)pkg/NetHack/nethack cp ../dat/nhdat $(TARGETPFX)pkg/NetHack/nhdat