Merge branch '_pret/master' into _RHH/pr/upcoming/pret_20240210

# Conflicts:
#	gflib/malloc.c
This commit is contained in:
Eduardo Quezada 2024-02-10 18:05:20 -03:00
commit ec83b11354
13 changed files with 159 additions and 119 deletions

View file

@ -38,18 +38,24 @@ void *AllocInternal(void *heapStart, u32 size, const char *location)
if (size & 3)
size = 4 * ((size / 4) + 1);
for (;;) {
for (;;)
{
// Loop through the blocks looking for unused block that's big enough.
if (!pos->allocated) {
if (!pos->allocated)
{
foundBlockSize = pos->size;
if (foundBlockSize >= size) {
if (foundBlockSize - size < 2 * sizeof(struct MemBlock)) {
if (foundBlockSize >= size)
{
if (foundBlockSize - size < 2 * sizeof(struct MemBlock))
{
// The block isn't much bigger than the requested size,
// so just use it.
pos->allocated = TRUE;
} else {
}
else
{
// The block is significantly bigger than the requested
// size, so split the rest into a separate block.
foundBlockSize -= sizeof(struct MemBlock);
@ -104,15 +110,18 @@ void *AllocInternal(void *heapStart, u32 size, const char *location)
void FreeInternal(void *heapStart, void *pointer)
{
if (pointer) {
if (pointer)
{
struct MemBlock *head = (struct MemBlock *)heapStart;
struct MemBlock *block = (struct MemBlock *)((u8 *)pointer - sizeof(struct MemBlock));
block->allocated = FALSE;
// If the freed block isn't the last one, merge with the next block
// if it's not in use.
if (block->next != head) {
if (!block->next->allocated) {
if (block->next != head)
{
if (!block->next->allocated)
{
block->size += sizeof(struct MemBlock) + block->next->size;
block->next->magic = 0;
block->next = block->next->next;
@ -123,8 +132,10 @@ void FreeInternal(void *heapStart, void *pointer)
// If the freed block isn't the first one, merge with the previous block
// if it's not in use.
if (block != head) {
if (!block->prev->allocated) {
if (block != head)
{
if (!block->prev->allocated)
{
block->prev->next = block->next;
if (block->next != head)
@ -141,7 +152,8 @@ void *AllocZeroedInternal(void *heapStart, u32 size, const char *location)
{
void *mem = AllocInternal(heapStart, size, location);
if (mem != NULL) {
if (mem != NULL)
{
if (size & 3)
size = 4 * ((size / 4) + 1);

View file

@ -9,18 +9,6 @@
#define METATILE_BattleDome_Door_Lobby 0x209
#define METATILE_BattleDome_Door_PreBattleRoom 0x20A
// gTileset_BattleFrontierOutsideEast
#define METATILE_BattleFrontierOutsideEast_Door 0x3FC
#define METATILE_BattleFrontierOutsideEast_Door_BattleArena 0x291
#define METATILE_BattleFrontierOutsideEast_Door_BattleTower 0x329
#define METATILE_BattleFrontierOutsideEast_Door_Sliding 0x396
// gTileset_BattleFrontierOutsideWest
#define METATILE_BattleFrontierOutsideWest_Door 0x3FC
#define METATILE_BattleFrontierOutsideWest_Door_BattleDome 0x28A
#define METATILE_BattleFrontierOutsideWest_Door_BattleFactory 0x263
#define METATILE_BattleFrontierOutsideWest_Door_Sliding 0x396
// gTileset_BattleFrontier
#define METATILE_BattleFrontier_CorridorOpenDoor_Bottom 0x20F
#define METATILE_BattleFrontier_CorridorOpenDoor_Top 0x207
@ -36,6 +24,18 @@
#define METATILE_BattleFrontier_Elevator_Top1 0x32A
#define METATILE_BattleFrontier_Elevator_Top2 0x32B
// gTileset_BattleFrontierOutsideEast
#define METATILE_BattleFrontierOutsideEast_Door 0x3FC
#define METATILE_BattleFrontierOutsideEast_Door_BattleArena 0x291
#define METATILE_BattleFrontierOutsideEast_Door_BattleTower 0x329
#define METATILE_BattleFrontierOutsideEast_Door_Sliding 0x396
// gTileset_BattleFrontierOutsideWest
#define METATILE_BattleFrontierOutsideWest_Door 0x3FC
#define METATILE_BattleFrontierOutsideWest_Door_BattleDome 0x28A
#define METATILE_BattleFrontierOutsideWest_Door_BattleFactory 0x263
#define METATILE_BattleFrontierOutsideWest_Door_Sliding 0x396
// gTileset_BattlePalace
#define METATILE_BattlePalace_Door 0x219
@ -272,6 +272,18 @@
#define METATILE_Lavaridge_NormalGrass 0x206
#define METATILE_Lavaridge_RockWall 0x274
// gTileset_Lilycove
#define METATILE_Lilycove_Door 0x246
#define METATILE_Lilycove_Door_DeptStore 0x30C
#define METATILE_Lilycove_Door_SafariZone 0x32D
#define METATILE_Lilycove_Door_Wooden 0x28E
#define METATILE_Lilycove_Wailmer0 0x290
#define METATILE_Lilycove_Wailmer0_Alt 0x298
#define METATILE_Lilycove_Wailmer1 0x291
#define METATILE_Lilycove_Wailmer1_Alt 0x299
#define METATILE_Lilycove_Wailmer2 0x2A0
#define METATILE_Lilycove_Wailmer3 0x2A1
// gTileset_LilycoveMuseum
#define METATILE_LilycoveMuseum_Painting0_Left 0x25A
#define METATILE_LilycoveMuseum_Painting0_Right 0x25B
@ -284,17 +296,31 @@
#define METATILE_LilycoveMuseum_Painting4_Left 0x262
#define METATILE_LilycoveMuseum_Painting4_Right 0x263
// gTileset_Lilycove
#define METATILE_Lilycove_Door 0x246
#define METATILE_Lilycove_Door_DeptStore 0x30C
#define METATILE_Lilycove_Door_SafariZone 0x32D
#define METATILE_Lilycove_Door_Wooden 0x28E
#define METATILE_Lilycove_Wailmer0 0x290
#define METATILE_Lilycove_Wailmer0_Alt 0x298
#define METATILE_Lilycove_Wailmer1 0x291
#define METATILE_Lilycove_Wailmer1_Alt 0x299
#define METATILE_Lilycove_Wailmer2 0x2A0
#define METATILE_Lilycove_Wailmer3 0x2A1
// gTileset_Mauville
#define METATILE_Mauville_DeepSand_BottomMid 0x259
#define METATILE_Mauville_DeepSand_Center 0x251
#define METATILE_Mauville_Door 0x2AC
#define METATILE_Mauville_Door_BattleTent 0x3D4
#define METATILE_Mauville_Door_CyclingRoad 0x289
#define METATILE_Mauville_Door_Verdanturf 0x3A1
#define METATILE_Mauville_MirageTower_Tile0 0x3D8
#define METATILE_Mauville_MirageTower_Tile1 0x3D9
#define METATILE_Mauville_MirageTower_Tile10 0x3E4
#define METATILE_Mauville_MirageTower_Tile11 0x3E5
#define METATILE_Mauville_MirageTower_Tile2 0x3DA
#define METATILE_Mauville_MirageTower_Tile3 0x3E0
#define METATILE_Mauville_MirageTower_Tile4 0x3E1
#define METATILE_Mauville_MirageTower_Tile5 0x3E2
#define METATILE_Mauville_MirageTower_Tile6 0x3E8
#define METATILE_Mauville_MirageTower_Tile7 0x3E9
#define METATILE_Mauville_MirageTower_Tile8 0x3EA
#define METATILE_Mauville_MirageTower_Tile9 0x3F0
#define METATILE_Mauville_MirageTower_TileA 0x3F1
#define METATILE_Mauville_MirageTower_TileB 0x3F2
#define METATILE_Mauville_MirageTower_TileC 0x3DB
#define METATILE_Mauville_MirageTower_TileD 0x3DC
#define METATILE_Mauville_MirageTower_TileE 0x3DD
#define METATILE_Mauville_MirageTower_TileF 0x3E3
// gTileset_MauvilleGym
#define METATILE_MauvilleGym_FloorTile 0x21A
@ -325,38 +351,16 @@
#define METATILE_MauvilleGym_RedBeamV1_On 0x241
#define METATILE_MauvilleGym_RedBeamV2_On 0x249
// gTileset_Mauville
#define METATILE_Mauville_DeepSand_BottomMid 0x259
#define METATILE_Mauville_DeepSand_Center 0x251
#define METATILE_Mauville_Door 0x2AC
#define METATILE_Mauville_Door_BattleTent 0x3D4
#define METATILE_Mauville_Door_CyclingRoad 0x289
#define METATILE_Mauville_Door_Verdanturf 0x3A1
#define METATILE_Mauville_MirageTower_Tile0 0x3D8
#define METATILE_Mauville_MirageTower_Tile1 0x3D9
#define METATILE_Mauville_MirageTower_Tile10 0x3E4
#define METATILE_Mauville_MirageTower_Tile11 0x3E5
#define METATILE_Mauville_MirageTower_Tile2 0x3DA
#define METATILE_Mauville_MirageTower_Tile3 0x3E0
#define METATILE_Mauville_MirageTower_Tile4 0x3E1
#define METATILE_Mauville_MirageTower_Tile5 0x3E2
#define METATILE_Mauville_MirageTower_Tile6 0x3E8
#define METATILE_Mauville_MirageTower_Tile7 0x3E9
#define METATILE_Mauville_MirageTower_Tile8 0x3EA
#define METATILE_Mauville_MirageTower_Tile9 0x3F0
#define METATILE_Mauville_MirageTower_TileA 0x3F1
#define METATILE_Mauville_MirageTower_TileB 0x3F2
#define METATILE_Mauville_MirageTower_TileC 0x3DB
#define METATILE_Mauville_MirageTower_TileD 0x3DC
#define METATILE_Mauville_MirageTower_TileE 0x3DD
#define METATILE_Mauville_MirageTower_TileF 0x3E3
// gTileset_MeteorFalls
#define METATILE_MeteorFalls_CaveEntrance_Bottom 0x24E
#define METATILE_MeteorFalls_CaveEntrance_Left 0x24D
#define METATILE_MeteorFalls_CaveEntrance_Right 0x24F
#define METATILE_MeteorFalls_CaveEntrance_Top 0x246
// gTileset_Mossdeep
#define METATILE_Mossdeep_Door 0x2A1
#define METATILE_Mossdeep_Door_SpaceCenter 0x2ED
// gTileset_MossdeepGameCorner
#define METATILE_MossdeepGameCorner_CounterClosed_Bottom 0x232
#define METATILE_MossdeepGameCorner_CounterClosed_Top 0x22A
@ -366,10 +370,6 @@
// gTileset_MossdeepGym
#define METATILE_MossdeepGym_YellowArrow_Right 0x250
// gTileset_Mossdeep
#define METATILE_Mossdeep_Door 0x2A1
#define METATILE_Mossdeep_Door_SpaceCenter 0x2ED
// gTileset_Pacifidlog
#define METATILE_Pacifidlog_Door 0x21A
#define METATILE_Pacifidlog_FloatingLogs_HorizontalLeft 0x250
@ -388,6 +388,11 @@
#define METATILE_Pacifidlog_SubmergedLogs_VerticalBottom 0x262
#define METATILE_Pacifidlog_SubmergedLogs_VerticalTop 0x25A
// gTileset_Petalburg
#define METATILE_Petalburg_Door_BirchsLab 0x249
#define METATILE_Petalburg_Door_Littleroot 0x248
#define METATILE_Petalburg_Door_Oldale 0x287
// gTileset_PetalburgGym
#define METATILE_PetalburgGym_Door 0x224
#define METATILE_PetalburgGym_RoomEntrance_Left 0x210
@ -398,11 +403,6 @@
#define METATILE_PetalburgGym_SlidingDoor_Frame3 0x21B
#define METATILE_PetalburgGym_SlidingDoor_Frame4 0x21C
// gTileset_Petalburg
#define METATILE_Petalburg_Door_BirchsLab 0x249
#define METATILE_Petalburg_Door_Littleroot 0x248
#define METATILE_Petalburg_Door_Oldale 0x287
// gTileset_PokemonCenter
#define METATILE_PokemonCenter_CounterBarrier 0x25D
#define METATILE_PokemonCenter_Door_CableClub 0x264
@ -431,14 +431,6 @@
#define METATILE_PokemonCenter_Floor_ShadowTop 0x21E
#define METATILE_PokemonCenter_Floor_ShadowTop_Alt 0x2DC
// gTileset_RSMossdeepGym
#define METATILE_RSMossdeepGym_RedArrow_Down 0x205
#define METATILE_RSMossdeepGym_RedArrow_Left 0x20C
#define METATILE_RSMossdeepGym_RedArrow_Right 0x204
#define METATILE_RSMossdeepGym_RedArrow_Up 0x20D
#define METATILE_RSMossdeepGym_Switch_Down 0x239
#define METATILE_RSMossdeepGym_Switch_Up 0x238
// gTileset_Rustboro
#define METATILE_Rustboro_Door_Gray 0x21F
#define METATILE_Rustboro_Door_Tan 0x22F
@ -726,11 +718,6 @@
#define METATILE_Slateport_Door 0x2DC
#define METATILE_Slateport_Door_BattleTent 0x393
// gTileset_SootopolisGym
#define METATILE_SootopolisGym_Ice_Broken 0x206
#define METATILE_SootopolisGym_Ice_Cracked 0x20E
#define METATILE_SootopolisGym_Stairs 0x207
// gTileset_Sootopolis
#define METATILE_Sootopolis_Door 0x21E
#define METATILE_Sootopolis_Door_Closed 0x248
@ -738,6 +725,11 @@
#define METATILE_Sootopolis_GymDoor_Closed 0x250
#define METATILE_Sootopolis_RoughWater 0x290
// gTileset_SootopolisGym
#define METATILE_SootopolisGym_Ice_Broken 0x206
#define METATILE_SootopolisGym_Ice_Cracked 0x20E
#define METATILE_SootopolisGym_Stairs 0x207
// gTileset_TrainerHill
#define METATILE_TrainerHill_CounterDoor 0x334
#define METATILE_TrainerHill_Door_Elevator_Lobby 0x32C
@ -787,4 +779,12 @@
#define METATILE_Underwater_FloorShadow 0x228
#define METATILE_Underwater_RockWall 0x21E
// Other
#define METATILE_RSMossdeepGym_RedArrow_Down 0x205
#define METATILE_RSMossdeepGym_RedArrow_Left 0x20C
#define METATILE_RSMossdeepGym_RedArrow_Right 0x204
#define METATILE_RSMossdeepGym_RedArrow_Up 0x20D
#define METATILE_RSMossdeepGym_Switch_Down 0x239
#define METATILE_RSMossdeepGym_Switch_Up 0x238
#endif // GUARD_METATILE_LABELS_H

View file

@ -694,11 +694,13 @@ static void AnimTask_SpiteTargetShadow_Step1(u8 taskId)
task->data[3] = 16;
task->data[13] = GetAnimBattlerSpriteId(ANIM_TARGET);
task->data[4] = OBJ_PLTT_ID2(gSprites[task->data[13]].oam.paletteNum);
if (position == 1) {
if (position == 1)
{
u16 mask = DISPCNT_BG1_ON;
mask2 = mask;
}
else {
else
{
u16 mask = DISPCNT_BG2_ON;
mask2 = mask;
}

View file

@ -2050,7 +2050,8 @@ static void UpdateSpeedFromHit(u16 cmd)
switch (cmd)
{
case LINKCMD_BLENDER_SCORE_BEST:
if (sBerryBlender->speed < 1500) {
if (sBerryBlender->speed < 1500)
{
sBerryBlender->speed += (384 / sNumPlayersToSpeedDivisor[sBerryBlender->numPlayers]);
}
else

View file

@ -138,7 +138,8 @@ static void ContestEffect_StartleFrontMon(void)
u8 idx = 0;
u8 a = eContestAppealResults.contestant;
if (eContestAppealResults.turnOrder[a] != 0) {
if (eContestAppealResults.turnOrder[a] != 0)
{
int i;
for (i = 0; i < CONTESTANT_COUNT; i++)

View file

@ -218,7 +218,8 @@ static void UNUSED StitchObjectsOn8x8Canvas(s32 object_size, s32 object_count, u
// While the remaining space will be filled with actual data
if (object_size == 6)
{
for (k = 0; k < 256; k++) {
for (k = 0; k < 256; k++)
{
*dest = 0;
dest++;
}
@ -228,14 +229,16 @@ static void UNUSED StitchObjectsOn8x8Canvas(s32 object_size, s32 object_count, u
{
if (object_size == 6)
{
for (k = 0; k < 32; k++) {
for (k = 0; k < 32; k++)
{
*dest = 0;
dest++;
}
}
// Copy tile data
for (k = 0; k < 32 * object_size; k++) {
for (k = 0; k < 32 * object_size; k++)
{
*dest = *src;
src++;
dest++;
@ -243,7 +246,8 @@ static void UNUSED StitchObjectsOn8x8Canvas(s32 object_size, s32 object_count, u
if (object_size == 6)
{
for (k = 0; k < 32; k++) {
for (k = 0; k < 32; k++)
{
*dest = 0;
dest++;
}
@ -252,7 +256,8 @@ static void UNUSED StitchObjectsOn8x8Canvas(s32 object_size, s32 object_count, u
if (object_size == 6)
{
for (k = 0; k < 256; k++) {
for (k = 0; k < 256; k++)
{
*dest = 0;
dest++;
}

View file

@ -1340,7 +1340,8 @@ static void DecorationItemsMenuAction_AttemptPlace(u8 taskId)
else
{
ConvertIntToDecimalStringN(gStringVar1, sDecorationContext.size, STR_CONV_MODE_RIGHT_ALIGN, 2);
if (sDecorationContext.isPlayerRoom == FALSE) {
if (sDecorationContext.isPlayerRoom == FALSE)
{
StringExpandPlaceholders(gStringVar4, gText_NoMoreDecorations);
}
else
@ -2254,7 +2255,8 @@ static void Task_PutAwayDecoration(u8 taskId)
gTasks[taskId].tState = 1;
break;
case 1:
if (!gPaletteFade.active) {
if (!gPaletteFade.active)
{
DrawWholeMapView();
ScriptContext_SetupScript(SecretBase_EventScript_PutAwayDecoration);
ClearDialogWindowAndFrame(0, TRUE);

View file

@ -1091,32 +1091,39 @@ static void InitResults_Member(void)
{
u8 i;
switch (sGame->state) {
switch (sGame->state)
{
case 0:
if (SendBlock(0, sGame->berryResults[sGame->timer], sizeof(sGame->berryResults))) {
if (SendBlock(0, sGame->berryResults[sGame->timer], sizeof(sGame->berryResults)))
{
sGame->playersReceived = 0;
sGame->state++;
}
break;
case 1:
if (IsLinkTaskFinished()) {
if (IsLinkTaskFinished())
{
sGame->state++;
}
break;
case 2:
if (AllLinkBlocksReceived()) {
for (i = 0; i < sGame->numPlayers; i++) {
if (AllLinkBlocksReceived())
{
for (i = 0; i < sGame->numPlayers; i++)
{
memcpy(sGame->berryResults, gBlockRecvBuffer, sizeof(sGame->berryResults));
sGame->playersReceived = sGame->numPlayers;
}
}
if (sGame->playersReceived >= sGame->numPlayers) {
if (sGame->playersReceived >= sGame->numPlayers)
{
sGame->timer++;
sGame->state++;
}
break;
default:
if (WaitFanfare(TRUE)) {
if (WaitFanfare(TRUE))
{
sGame->maxBerriesPickedInRow = sGame->berryResults[sGame->multiplayerId][BERRY_IN_ROW];
SetGameFunc(FUNC_RESULTS);
FadeOutAndPlayNewMapMusic(MUS_RG_VICTORY_WILD, 4);

View file

@ -317,8 +317,13 @@ void HideMapNamePopUpWindow(void)
{
if (FuncIsActiveTask(Task_MapNamePopUpWindow))
{
ClearStdWindowAndFrame(GetMapNamePopUpWindowId(), TRUE);
RemoveMapNamePopUpWindow();
#ifdef UBFIX
if (GetMapNamePopUpWindowId() != WINDOW_NONE)
#endif // UBFIX
{
ClearStdWindowAndFrame(GetMapNamePopUpWindowId(), TRUE);
RemoveMapNamePopUpWindow();
}
SetGpuReg_ForcedBlank(REG_OFFSET_BG0VOFS, 0);
DestroyTask(sPopupTaskId);
}

View file

@ -102,8 +102,10 @@ static s32 _putsAscii(char *s, s32 len, void *buf)
p0 = b->buffer;
/* Copy to buffer */
for (i = 0; i < len; i++) {
if(b->pbuffer == b->buffer + b->buffer_len - 1) {
for (i = 0; i < len; i++)
{
if(b->pbuffer == b->buffer + b->buffer_len - 1)
{
break;
}
*(b->pbuffer ++) = s[i];
@ -125,8 +127,10 @@ static s32 _putsEncoded(char *s, s32 len, void *buf)
p0 = b->buffer;
/* Copy to buffer */
for (i = 0; i < len; i++) {
if(b->pbuffer == b->buffer + b->buffer_len - 1) {
for (i = 0; i < len; i++)
{
if(b->pbuffer == b->buffer + b->buffer_len - 1)
{
break;
}
*(b->pbuffer ++) = mini_pchar_decode(s[i]);
@ -191,7 +195,8 @@ static s32 mini_pad(char* ptr, s32 len, char pad_char, s32 pad_to, char *buffer)
char * pbuffer = buffer;
if(pad_to == 0)
pad_to = len;
if (len > pad_to) {
if (len > pad_to)
{
len = pad_to;
overflow = TRUE;
}

View file

@ -3324,7 +3324,8 @@ static void SpriteCB_FlashMatchingLines(struct Sprite *sprite)
if (sprite->sNumFullFlashes)
sprite->sNumFullFlashes--;
}
else if (sprite->sColor >= maxColorChange) {
else if (sprite->sColor >= maxColorChange)
{
// Reached peak darkness, reverse
sprite->sColorIncr = -sprite->sColorIncr;
}
@ -6984,7 +6985,7 @@ static const struct SubspriteTable sSubspriteTable_DigitalDisplay_Win[] =
{ARRAY_COUNT(sSubsprites_DigitalDisplay_Win), sSubsprites_DigitalDisplay_Win}
};
static const struct Subsprite sSubsprites_DigitalDisplay_Smoke[] =
static const struct Subsprite sSubsprites_DigitalDisplay_SmokeBig[] =
{
{
.x = -16,
@ -6996,7 +6997,7 @@ static const struct Subsprite sSubsprites_DigitalDisplay_Smoke[] =
}
};
static const struct Subsprite sSubsprites_DigitalDisplay_Unused2[] =
static const struct Subsprite sSubsprites_DigitalDisplay_SmokeSmall[] =
{
{
.x = -8,
@ -7010,12 +7011,8 @@ static const struct Subsprite sSubsprites_DigitalDisplay_Unused2[] =
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_Smoke[] =
{
{ARRAY_COUNT(sSubsprites_DigitalDisplay_Smoke), sSubsprites_DigitalDisplay_Smoke}
};
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_Unused2[] =
{
{ARRAY_COUNT(sSubsprites_DigitalDisplay_Unused2), sSubsprites_DigitalDisplay_Unused2}
{ARRAY_COUNT(sSubsprites_DigitalDisplay_SmokeBig), sSubsprites_DigitalDisplay_SmokeBig},
{ARRAY_COUNT(sSubsprites_DigitalDisplay_SmokeSmall), sSubsprites_DigitalDisplay_SmokeSmall}
};
/*

View file

@ -62,7 +62,7 @@ static unsigned char *ConvertBitDepth(unsigned char *src, int srcBitDepth, int d
for (j = 8 - srcBitDepth; j >= 0; j -= srcBitDepth)
{
unsigned char pixel = (srcByte >> j) % (1 << destBitDepth);
unsigned char pixel = ((srcByte >> j) % (1 << srcBitDepth)) % (1 << destBitDepth);
*dest |= pixel << destBit;
destBit -= destBitDepth;
if (destBit < 0)

View file

@ -105,10 +105,13 @@ int main(int argc, char *argv[])
});
env.add_callback("cleanString", 1, [](Arguments& args) {
string badChars = ".'{} \n\t-\u00e9";
string str = args.at(0)->get<string>();
for (unsigned int i = 0; i < str.length(); i++) {
if (badChars.find(str[i]) != std::string::npos) {
// This code is not Unicode aware, so UTF-8 is not easily parsable without introducing
// another library. Just filter out any non-alphanumeric characters for now.
// TODO: proper Unicode string normalization
if ((i == 0 && isdigit(str[i]))
|| !isalnum(str[i])) {
str[i] = '_';
}
}