Progress! Thank you, https://stackoverflow.com/users/6879826/ad-absurdum, for putting me on the right path! After a few tweaks, converting things to/from wchar_t, it's now returning the full names (with the \n characters, but that's a separate problem).
Here's the revised load_charlist code (only code that's changed):
int load_charlist()
{
errno_t err;
wchar_t tempstr[48]; //ML_CHARNAME * 2, to be on the safe side
int i = 0;
size_t j;
err = fopen_s(&inputfile, "Saves//charlist.dat", "r, ccs=UTF-8");
if (!inputfile) {
set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
allegro_message("Can't open Saves\\charlist.dat. Exiting.");
return 1;
}
charcount = 0;
while (!feof(inputfile) && !ferror(inputfile))
{
if (fgetws(tempstr, _countof(tempstr), inputfile) != NULL)
{
trim_trailing_chars(tempstr, "\r\n");
if (strcmp(tempstr, "none") != 0)
{
++charcount;
wcstombs_s(&j, charlist[i], (size_t)48, tempstr, (size_t)48 - 1);
i++;
}
}
strcpy_s(tempstr, _countof(tempstr), "");
}
err = fclose(inputfile);
}