Unlike sfrotz, xfrotz will segfault if you run it as xfrotz --help

If a user attempts to use the standard --help command line flag to request program help, sfrotz will not recognize the flag, but because it doesn't recognize the flag, it will report "sfrotz: unrecognized option '--help'", then print the standard usage summary and exit with an error result:

$ sfrotz --help
sfrotz: unrecognized option '--help'
FROTZ V2.55 - SDL graphics and audio interface.
An interpreter for all Infocom and other Z-Machine games.

Syntax: sfrotz [options] story-file [blorb file]
  -a   watch attribute setting            -A   watch attribute testing
  -b <colourname> background colour       -c # context lines
  -C <file> load this configuration file  -d   disable color
  -f <colorname> foreground colour        -F   fullscreen mode
  -H # screen height                      -i   ignore runtime errors
  -I # interpreter number                 -l # left margin
  -L <file> load this save file           -o   watch object movement
  -O   watch object locating              -P   alter piracy opcode
  -q   quiet (disable sound)              -r # right margin
  -s # random number seed value           -S # transcript width
  -t   set Tandy bit                      -u # slots for multiple undo
  -W # screen width                       -x   expand abbreviations g/x/z
  -X   show extended options              -v   show version information
  -Z # error checking (see below)

Error checking: 0 none, 1 first only (default), 2 all, 3 exit after any error.
More options and information are in the manual page.  Type "man sfrotz".

This is because sfrotz's os_process_arguments() calls parse_options(), which uses getopt(). When faced with an unknown command line option, getopt will return the character '?'. parse_options() recognizes this and takes appropriate action:

// sf_util.c lines 380:382
		if (c == '?') {
			usage(USAGE_NORMAL);
			os_quit(EXIT_FAILURE);

In both cases this is controlled by the main() function shared by all frotz variants:

// common/main.c 114:131
{
	init_header();
	init_setup();
	os_init_setup();
	os_process_arguments(argc, argv);
	init_buffer();
	init_err();
	init_memory();
	init_process();
	init_sound();
	os_init_screen();
	init_undo();
	z_restart();
	interpret();
	reset_screen();
	reset_memory();
	os_reset_screen();
	os_quit(EXIT_SUCCESS);
	return 0;

But when xfrotz gets an argument of --help, bad things happen:

$ xfrotz --help

Fatal error: Cannot open story file

[3]    1235753 segmentation fault (core dumped)  xfrotz --help

That's because the argument passes right through os_process_arguments(), which treats it as the name of a story file to load. The xfrotz startup then continues on its initialization journey (above), through init_buffer() and init_err(), all the way to init_memory() from fastmem.c.

There, upon failing to load --help as a story file, it will attempt to report this failure with an os_fatal():

// fastmem.c lines 468:470
	/* Open story file */
	if ((story_fp = os_load_story()) == NULL)
		os_fatal("Cannot open story file");

Problem is that, unlike os_quit(), os_fatal() in the xfrotz code assumes it's outputting to a graphical display, and calls several functions that use X protocol features, including os_set_text_style():

// x_init.c lines 93:120
void os_fatal(const char *s, ...)
{
	va_list m;
	char errorstring[81];

	os_beep(BEEP_HIGH);
	fprintf(stderr, "\nFatal error: ");
	va_start(m, s);
	vfprintf(stderr, s, m);
	vsnprintf(errorstring, sizeof(char) * 80, s, m);
	va_end(m);
	fprintf(stderr, "\n\n");

	os_set_text_style(BOLDFACE_STYLE);
	print_c_string("Fatal error: ");
	os_set_text_style(NORMAL_STYLE);
	print_c_string(errorstring);
	new_line();

	if (f_setup.ignore_errors) {
		os_display_string((zchar *) "Continuing anyway...");
		new_line();
		new_line();
	}

	os_reset_screen();
	os_quit(EXIT_FAILURE);
} /* os_fatal */

os_set_text_style() attempts to call XSetFont(), passing it the current_gc which will be set to either reversed_gc or normal_gc depending on its argument.

// x_text.c lines 292:308
void os_set_text_style(int new_style)
{
	if (new_style & REVERSE_STYLE)
		current_gc = reversed_gc;
	else
		current_gc = normal_gc;

	current_font_info = get_font(current_zfont, new_style);
	if (current_font_info == NULL) {
		fprintf(stderr, "Could not find font for style %d\n",
			new_style);
		current_font_info = get_font(current_zfont, 0);
	}
	XSetFont(dpy, current_gc, current_font_info->fid);

	current_style = new_style;
} /* os_set_text_style */

Unfortunately, none of the *_gc globals have been initialized yet. That won't happen until os_init_screen() is called, which happens waaaay after init_memory() in the main() code. So os_set_text_style() calls XSetFont(dpy, NULL, current_font_info->fid) and... 💣 .

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information