/* NetHack 3.7 utf8map.c */ /* Copyright (c) Michael Allison, 2021. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include #ifdef ENHANCED_SYMBOLS extern const struct symparse loadsyms[]; extern struct enum_dump monsdump[]; extern struct enum_dump objdump[]; extern glyph_map glyphmap[MAX_GLYPH]; extern const char *const known_handling[]; /* symbols.c */ /* hexdd[] is defined in decl.c */ int unicode_val(const char *cp) { const char *dp; int cval = 0, dcount; if (cp && *cp) { cval = dcount = 0; if ((*cp == 'U' || *cp == 'u') && cp[1] == '+' && cp[2] && (dp = strchr(hexdd, cp[2])) != 0) { cp += 2; /* move past the 'U' and '+' */ do { cval = (cval * 16) + ((int) (dp - hexdd) / 2); } while (*++cp && (dp = strchr(hexdd, *cp)) != 0 && ++dcount < 7); } } return cval; } int set_map_u(glyph_map *gmap, uint32 utf32ch, const uint8 *utf8str) { glyph_map *tmpgm = gmap; if (!tmpgm || !utf32ch) return 0; if (gmap->u == 0) { gmap->u = (struct unicode_representation *) alloc(sizeof *gmap->u); gmap->u->utf8str = 0; } if (gmap->u->utf8str != 0) { free(gmap->u->utf8str); gmap->u->utf8str = 0; } gmap->u->utf8str = (uint8 *) dupstr((const char *) utf8str); gmap->u->utf32ch = utf32ch; return 1; } void free_all_glyphmap_u(void) { int glyph; int x, y; for (glyph = 0; glyph < MAX_GLYPH; ++glyph) { if (glyphmap[glyph].u) { if (glyphmap[glyph].u->utf8str) { free(glyphmap[glyph].u->utf8str); glyphmap[glyph].u->utf8str = 0; } free(glyphmap[glyph].u); glyphmap[glyph].u = 0; } } /* Prevent use after free from gg.gbuf */ for (y = 0; y < ROWNO; ++y) { for (x = 0; x < COLNO; ++x) { gg.gbuf[y][x].glyphinfo.gm.u = NULL; } } } /* helper routine if a window port wants to embed any UTF-8 sequences for the glyph representation in the string in place of the \GNNNNNNNN reference */ char * mixed_to_utf8(char *buf, size_t bufsz, const char *str, int *retflags) { char *put = buf; glyph_info glyphinfo = nul_glyphinfo; if (!str) return strcpy(buf, ""); while (*str && put < (buf + bufsz) - 1) { if (*str == '\\') { int dcount, so, ggv; const char *save_str; save_str = str++; switch (*str) { case 'G': /* glyph value \GXXXXNNNN*/ if ((dcount = decode_glyph(str + 1, &ggv))) { str += (dcount + 1); map_glyphinfo(0, 0, ggv, 0, &glyphinfo); if (glyphinfo.gm.u && glyphinfo.gm.u->utf8str) { uint8 *ucp = glyphinfo.gm.u->utf8str; while (*ucp && put < (buf + bufsz) - 1) *put++ = *ucp++; if (retflags) *retflags = 1; } else { so = glyphinfo.gm.sym.symidx; *put++ = gs.showsyms[so]; if (retflags) *retflags = 0; } /* 'str' is ready for the next loop iteration and '*str' should not be copied at the end of this iteration */ continue; } else { /* possible forgery - leave it the way it is */ str = save_str; } break; case '\\': break; case '\0': /* String ended with '\\'. This can happen when someone names an object with a name ending with '\\', drops the named object on the floor nearby and does a look at all nearby objects. */ /* brh - should we perhaps not allow things to have names that contain '\\' */ str = save_str; break; } } if (put < (buf + bufsz) - 1) *put++ = *str++; } *put = '\0'; return buf; } int add_custom_urep_entry( const char *customization_name, int glyphidx, uint32 utf32ch, const uint8 *utf8str, enum graphics_sets which_set) { struct symset_customization *gdc = &gs.sym_customizations[which_set][custom_ureps]; struct customization_detail *details, *newdetails = 0; if (!gdc->details) { gdc->customization_name = dupstr(customization_name); gdc->custtype = custom_ureps; gdc->details = 0; gdc->details_end = 0; } details = find_matching_customization(customization_name, custom_ureps, which_set); /* FIXME */ if (details) { while (details) { if (details->content.urep.glyphidx == glyphidx) { if (details->content.urep.u.utf8str) free(details->content.urep.u.utf8str); if (utf32ch) { details->content.urep.u.utf8str = (uint8 *) dupstr((const char *) utf8str); details->content.urep.u.utf32ch = utf32ch; } else { details->content.urep.u.utf8str = (uint8 *) 0; details->content.urep.u.utf32ch = 0; } return 1; } details = details->next; } } /* create new details entry */ newdetails = (struct customization_detail *) alloc( sizeof (struct customization_detail)); newdetails->content.urep.glyphidx = glyphidx; if (utf8str && *utf8str) { newdetails->content.urep.u.utf8str = (uint8 *) dupstr((const char *) utf8str); } else { newdetails->content.urep.u.utf8str = (uint8 *) 0; } newdetails->content.urep.u.utf32ch = utf32ch; newdetails->next = (struct customization_detail *) 0; if (gdc->details == NULL) { gdc->details = newdetails; } else { gdc->details_end->next = newdetails; } gdc->details_end = newdetails; gdc->count++; return 1; } #endif /* ENHANCED_SYMBOLS */ void reset_customsymbols(void) { #ifdef ENHANCED_SYMBOLS free_all_glyphmap_u(); apply_customizations(gc.currentgraphics, do_custom_symbols); #endif } /* utf8map.c */