Prechádzať zdrojové kódy

Windows configuration dialog: Sort options and add multi-line imput field

Since CivetWeb has a lot of options by now, sort them.
bel2125 5 rokov pred
rodič
commit
5e7a7a97fb
1 zmenil súbory, kde vykonal 148 pridanie a 36 odobranie
  1. 148 36
      src/main.c

+ 148 - 36
src/main.c

@@ -630,34 +630,46 @@ set_option(char **options, const char *name, const char *value)
 	}
 	}
 
 
 	/* Not an option of main.c, so check if it is a CivetWeb server option */
 	/* Not an option of main.c, so check if it is a CivetWeb server option */
-	type = MG_CONFIG_TYPE_UNKNOWN;
+	type = MG_CONFIG_TYPE_UNKNOWN; /* type "unknown" means "option not found" */
 	for (i = 0; default_options[i].name != NULL; i++) {
 	for (i = 0; default_options[i].name != NULL; i++) {
 		if (!strcmp(default_options[i].name, name)) {
 		if (!strcmp(default_options[i].name, name)) {
 			type = default_options[i].type;
 			type = default_options[i].type;
+			break; /* no need to search for another option */
 		}
 		}
 	}
 	}
+
 	switch (type) {
 	switch (type) {
+
 	case MG_CONFIG_TYPE_UNKNOWN:
 	case MG_CONFIG_TYPE_UNKNOWN:
 		/* unknown option */
 		/* unknown option */
-		return 0;
+		return 0; /* return error */
+
 	case MG_CONFIG_TYPE_NUMBER:
 	case MG_CONFIG_TYPE_NUMBER:
 		/* integer number >= 0, e.g. number of threads */
 		/* integer number >= 0, e.g. number of threads */
-		if (atol(value) < 0) {
-			/* invalid number */
-			return 0;
+		{
+			char *chk = 0;
+			unsigned long num = strtoul(value, &chk, 10);
+			if ((chk == NULL) || (*chk != 0) || (chk == value)) {
+				/* invalid number */
+				return 0;
+			}
 		}
 		}
 		break;
 		break;
+
 	case MG_CONFIG_TYPE_STRING:
 	case MG_CONFIG_TYPE_STRING:
 		/* any text */
 		/* any text */
 		break;
 		break;
+
 	case MG_CONFIG_TYPE_STRING_LIST:
 	case MG_CONFIG_TYPE_STRING_LIST:
 		/* list of text items, separated by , */
 		/* list of text items, separated by , */
 		multi_sep = ",";
 		multi_sep = ",";
 		break;
 		break;
+
 	case MG_CONFIG_TYPE_STRING_MULTILINE:
 	case MG_CONFIG_TYPE_STRING_MULTILINE:
 		/* lines of text, separated by carriage return line feed */
 		/* lines of text, separated by carriage return line feed */
 		multi_sep = "\r\n";
 		multi_sep = "\r\n";
 		break;
 		break;
+
 	case MG_CONFIG_TYPE_BOOLEAN:
 	case MG_CONFIG_TYPE_BOOLEAN:
 		/* boolean value, yes or no */
 		/* boolean value, yes or no */
 		if ((0 != strcmp(value, "yes")) && (0 != strcmp(value, "no"))) {
 		if ((0 != strcmp(value, "yes")) && (0 != strcmp(value, "no"))) {
@@ -665,6 +677,7 @@ set_option(char **options, const char *name, const char *value)
 			return 0;
 			return 0;
 		}
 		}
 		break;
 		break;
+
 	case MG_CONFIG_TYPE_YES_NO_OPTIONAL:
 	case MG_CONFIG_TYPE_YES_NO_OPTIONAL:
 		/* boolean value, yes or no */
 		/* boolean value, yes or no */
 		if ((0 != strcmp(value, "yes")) && (0 != strcmp(value, "no"))
 		if ((0 != strcmp(value, "yes")) && (0 != strcmp(value, "no"))
@@ -673,15 +686,18 @@ set_option(char **options, const char *name, const char *value)
 			return 0;
 			return 0;
 		}
 		}
 		break;
 		break;
+
 	case MG_CONFIG_TYPE_FILE:
 	case MG_CONFIG_TYPE_FILE:
 	case MG_CONFIG_TYPE_DIRECTORY:
 	case MG_CONFIG_TYPE_DIRECTORY:
 		/* TODO (low): check this option when it is set, instead of calling
 		/* TODO (low): check this option when it is set, instead of calling
 		 * verify_existence later */
 		 * verify_existence later */
 		break;
 		break;
+
 	case MG_CONFIG_TYPE_EXT_PATTERN:
 	case MG_CONFIG_TYPE_EXT_PATTERN:
 		/* list of patterns, separated by | */
 		/* list of patterns, separated by | */
 		multi_sep = "|";
 		multi_sep = "|";
 		break;
 		break;
+
 	default:
 	default:
 		die("Unknown option type - option %s", name);
 		die("Unknown option type - option %s", name);
 	}
 	}
@@ -695,7 +711,7 @@ set_option(char **options, const char *name, const char *value)
 			break;
 			break;
 		} else if (!strcmp(options[2 * i], name)) {
 		} else if (!strcmp(options[2 * i], name)) {
 			if (multi_sep) {
 			if (multi_sep) {
-				/* Option already set. Overwrite */
+				/* Option already set. Append new value. */
 				char *s =
 				char *s =
 				    (char *)malloc(strlen(options[2 * i + 1])
 				    (char *)malloc(strlen(options[2 * i + 1])
 				                   + strlen(multi_sep) + strlen(value) + 1);
 				                   + strlen(multi_sep) + strlen(value) + 1);
@@ -2208,6 +2224,9 @@ show_settings_dialog()
 	short LABEL_WIDTH = 115;
 	short LABEL_WIDTH = 115;
 	short FILE_DIALOG_BUTTON_WIDTH = 15;
 	short FILE_DIALOG_BUTTON_WIDTH = 15;
 	short NO_OF_COLUMNS = 3;
 	short NO_OF_COLUMNS = 3;
+	short NO_OF_OPTIONS = 0;       /* to be calculated */
+	short NO_OF_OPTION_SPACES = 0; /* to be calculated */
+	short NO_OF_ROWS = 0;          /* to be calculated */
 
 
 	/* Calculates size */
 	/* Calculates size */
 	short COLUMN_WIDTH = LABEL_WIDTH + CELL_WIDTH + BORDER_WIDTH;
 	short COLUMN_WIDTH = LABEL_WIDTH + CELL_WIDTH + BORDER_WIDTH;
@@ -2215,12 +2234,14 @@ show_settings_dialog()
 
 
 	/* All other variables */
 	/* All other variables */
 	unsigned char mem[16 * 1024], *p;
 	unsigned char mem[16 * 1024], *p;
-	const struct mg_option *options;
+	const struct mg_option *cv_options;
 	DWORD style;
 	DWORD style;
 	DLGTEMPLATE *dia = (DLGTEMPLATE *)mem;
 	DLGTEMPLATE *dia = (DLGTEMPLATE *)mem;
 	WORD i, cl, nelems = 0;
 	WORD i, cl, nelems = 0;
-	short x, y, next_cell_width;
+	short x, y, next_cell_width, next_cell_height;
 	static struct dlg_proc_param s_dlg_proc_param;
 	static struct dlg_proc_param s_dlg_proc_param;
+	short *option_index, *option_top, *option_bottom;
+	char text[64];
 
 
 	const struct dlg_header_param dialog_header = GetDlgHeader(DIALOG_WIDTH);
 	const struct dlg_header_param dialog_header = GetDlgHeader(DIALOG_WIDTH);
 
 
@@ -2237,23 +2258,95 @@ show_settings_dialog()
 	(void)memcpy(p, &dialog_header, sizeof(dialog_header));
 	(void)memcpy(p, &dialog_header, sizeof(dialog_header));
 	p = mem + sizeof(dialog_header);
 	p = mem + sizeof(dialog_header);
 
 
-	options = mg_get_valid_options();
-	for (i = 0; options[i].name != NULL; i++) {
+	/* Determine space required for input fields */
+	cv_options = mg_get_valid_options();
+	for (i = 0; cv_options[i].name != NULL; i++) {
+		NO_OF_OPTIONS++;
+		if (cv_options[i].type == MG_CONFIG_TYPE_STRING_MULTILINE) {
+			/* Multiline input fields require double space */
+			NO_OF_OPTION_SPACES += 2;
+		} else {
+			/* All other option types require single space */
+			NO_OF_OPTION_SPACES++;
+		}
+	}
+	NO_OF_ROWS = (NO_OF_OPTION_SPACES + NO_OF_COLUMNS - 1) / NO_OF_COLUMNS;
+
+	/* All options should be displayed sorted. */
+	/* First allocate some memory to store option order: The array should store
+	 * 1) the option order of all options (NO_OF_OPTIONS), followed by
+	 * 2) the option index for the option name displayed on top of a column
+	 * 3) the option index for the option name displayed on bottom of a column
+	 */
+	option_index = (short *)calloc(NO_OF_OPTIONS + 2 * NO_OF_COLUMNS,
+	                               sizeof(short)); /* 1 */
+	option_top = option_index + NO_OF_OPTIONS;     /* 2 */
+	option_bottom = option_top + NO_OF_COLUMNS;    /* 3 */
+
+	/* Initialize option order */
+	for (i = 0; i < NO_OF_OPTIONS; i++) {
+		option_index[i] = i;
+	}
+	/* Sort all options */
+	for (;;) {
+		int swapped = 0;
+		for (i = 1; i < NO_OF_OPTIONS; i++) {
+			if (strcmp(cv_options[option_index[i - 1]].name,
+			           cv_options[option_index[i]].name)
+			    > 0) {
+				short swap = option_index[i];
+				option_index[i] = option_index[i - 1];
+				option_index[i - 1] = swap;
+				swapped = 1;
+			}
+		}
+		if (!swapped) {
+			break;
+		}
+	}
+
+	/* Create input fields for all options */
+	for (i = 0; i < NO_OF_OPTIONS; i++) {
+
+		/* Get option according to option order */
+		const struct mg_option *opt = &cv_options[option_index[i]];
+
+		/* Template style for all input fields (will be modified for specific
+		 * field types) */
 		style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
 		style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
 
 
-		x = BORDER_WIDTH + COLUMN_WIDTH * (nelems % NO_OF_COLUMNS);
-		y = BORDER_WIDTH / 2 + HEIGHT + HEIGHT * (nelems / NO_OF_COLUMNS);
+		/* TODO: Bottom of a column must not be a MULTILINE input field.
+		 * If the last input field in a column would of multi-line type
+		 * (opt->type == MG_CONFIG_TYPE_STRING_MULTILINE), then
+		 * skip one field (nelems++).
+		 * But in this case, maybe one more ROW might be required. */
+
+		/* Position and size of the input field (will be modified) */
+		x = BORDER_WIDTH + COLUMN_WIDTH * (nelems / NO_OF_ROWS);
+		y = BORDER_WIDTH / 2 + HEIGHT + HEIGHT * (nelems % NO_OF_ROWS);
 		next_cell_width = CELL_WIDTH;
 		next_cell_width = CELL_WIDTH;
+		next_cell_height = HEIGHT - 3;
 
 
-		if (options[i].type == MG_CONFIG_TYPE_NUMBER) {
+		/* Determine top/bottom option for every column */
+		if ((nelems % NO_OF_ROWS) == 0) {
+			/* Set option on top of a new column once */
+			option_top[nelems / NO_OF_ROWS] = option_index[i];
+		}
+		/* Set/overwrite option on bottom of a column */
+		option_bottom[nelems / NO_OF_ROWS] = option_index[i];
+
+		/* Depending on option type: create suitable input field */
+		if (opt->type == MG_CONFIG_TYPE_NUMBER) {
 			style |= ES_NUMBER;
 			style |= ES_NUMBER;
 			cl = 0x81;
 			cl = 0x81;
 			style |= WS_BORDER | ES_AUTOHSCROLL;
 			style |= WS_BORDER | ES_AUTOHSCROLL;
-		} else if (options[i].type == MG_CONFIG_TYPE_BOOLEAN) {
+
+		} else if (opt->type == MG_CONFIG_TYPE_BOOLEAN) {
 			cl = 0x80;
 			cl = 0x80;
 			style |= BS_AUTOCHECKBOX;
 			style |= BS_AUTOCHECKBOX;
-		} else if ((options[i].type == MG_CONFIG_TYPE_FILE)
-		           || (options[i].type == MG_CONFIG_TYPE_DIRECTORY)) {
+
+		} else if ((opt->type == MG_CONFIG_TYPE_FILE)
+		           || (opt->type == MG_CONFIG_TYPE_DIRECTORY)) {
 			style |= WS_BORDER | ES_AUTOHSCROLL;
 			style |= WS_BORDER | ES_AUTOHSCROLL;
 			cl = 0x81;
 			cl = 0x81;
 
 
@@ -2261,7 +2354,7 @@ show_settings_dialog()
 			add_control(&p,
 			add_control(&p,
 			            dia,
 			            dia,
 			            0x80,
 			            0x80,
-			            ID_CONTROLS + i + ID_FILE_BUTTONS_DELTA,
+			            ID_CONTROLS + option_index[i] + ID_FILE_BUTTONS_DELTA,
 			            WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
 			            WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
 			            x + LABEL_WIDTH + CELL_WIDTH - FILE_DIALOG_BUTTON_WIDTH,
 			            x + LABEL_WIDTH + CELL_WIDTH - FILE_DIALOG_BUTTON_WIDTH,
 			            y,
 			            y,
@@ -2271,13 +2364,18 @@ show_settings_dialog()
 
 
 			next_cell_width -= FILE_DIALOG_BUTTON_WIDTH + BORDER_WIDTH / 2;
 			next_cell_width -= FILE_DIALOG_BUTTON_WIDTH + BORDER_WIDTH / 2;
 
 
-		} else if (options[i].type == MG_CONFIG_TYPE_STRING_MULTILINE) {
+		} else if (opt->type == MG_CONFIG_TYPE_STRING_MULTILINE) {
 
 
-			/* TODO: This is not really uer friendly */
+			/* Multiline input */
 			cl = 0x81;
 			cl = 0x81;
 			style |= WS_BORDER | ES_AUTOHSCROLL | ES_MULTILINE | ES_WANTRETURN
 			style |= WS_BORDER | ES_AUTOHSCROLL | ES_MULTILINE | ES_WANTRETURN
-			         | ES_AUTOVSCROLL;
+			         | WS_VSCROLL | ES_AUTOVSCROLL;
+			/* Add more space below */
+			nelems += 1;
+			next_cell_height += HEIGHT;
+
 		} else {
 		} else {
+			/* Standard text input field */
 			cl = 0x81;
 			cl = 0x81;
 			style |= WS_BORDER | ES_AUTOHSCROLL;
 			style |= WS_BORDER | ES_AUTOHSCROLL;
 		}
 		}
@@ -2292,16 +2390,18 @@ show_settings_dialog()
 		            y,
 		            y,
 		            LABEL_WIDTH,
 		            LABEL_WIDTH,
 		            HEIGHT,
 		            HEIGHT,
-		            options[i].name);
+		            opt->name);
+
+		/* Add input field */
 		add_control(&p,
 		add_control(&p,
 		            dia,
 		            dia,
 		            cl,
 		            cl,
-		            ID_CONTROLS + i,
+		            ID_CONTROLS + option_index[i],
 		            style,
 		            style,
 		            x + LABEL_WIDTH,
 		            x + LABEL_WIDTH,
 		            y,
 		            y,
 		            next_cell_width,
 		            next_cell_width,
-		            HEIGHT - 3,
+		            next_cell_height,
 		            "");
 		            "");
 		nelems++;
 		nelems++;
 
 
@@ -2310,16 +2410,23 @@ show_settings_dialog()
 
 
 	/* "Settings" frame around all options */
 	/* "Settings" frame around all options */
 	y = ((nelems + NO_OF_COLUMNS - 1) / NO_OF_COLUMNS + 1) * HEIGHT;
 	y = ((nelems + NO_OF_COLUMNS - 1) / NO_OF_COLUMNS + 1) * HEIGHT;
-	add_control(&p,
-	            dia,
-	            0x80,
-	            ID_GROUP,
-	            WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
-	            BORDER_WIDTH / 2,
-	            BORDER_WIDTH / 2,
-	            DIALOG_WIDTH - BORDER_WIDTH,
-	            y,
-	            " Settings ");
+	for (i = 0; i < NO_OF_COLUMNS; i++) {
+		sprintf(text,
+		        " Settings %c - %c ",
+		        cv_options[option_top[i]].name[0],
+		        cv_options[option_bottom[i]].name[0]);
+		add_control(&p,
+		            dia,
+		            0x80,
+		            ID_GROUP,
+		            WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
+		            BORDER_WIDTH / 2
+		                + i * (DIALOG_WIDTH - BORDER_WIDTH) / NO_OF_COLUMNS,
+		            BORDER_WIDTH / 2,
+		            (DIALOG_WIDTH - BORDER_WIDTH) / NO_OF_COLUMNS,
+		            y + 2,
+		            text);
+	}
 
 
 	/* Buttons below "Settings" frame */
 	/* Buttons below "Settings" frame */
 	y += HEIGHT;
 	y += HEIGHT;
@@ -2385,6 +2492,8 @@ show_settings_dialog()
 	DialogBoxIndirectParam(
 	DialogBoxIndirectParam(
 	    NULL, dia, NULL, SettingsDlgProc, (LPARAM)&s_dlg_proc_param);
 	    NULL, dia, NULL, SettingsDlgProc, (LPARAM)&s_dlg_proc_param);
 
 
+	free(option_index);
+
 	s_dlg_proc_param.hWnd = NULL;
 	s_dlg_proc_param.hWnd = NULL;
 	s_dlg_proc_param.guard = 0;
 	s_dlg_proc_param.guard = 0;
 }
 }
@@ -3042,13 +3151,15 @@ main(int argc, char *argv[])
 @end
 @end
 
 
 @implementation Civetweb
 @implementation Civetweb
-- (void)openBrowser {
+- (void)openBrowser
+{
 	[[NSWorkspace sharedWorkspace]
 	[[NSWorkspace sharedWorkspace]
 	    openURL:[NSURL URLWithString:[NSString stringWithUTF8String:
 	    openURL:[NSURL URLWithString:[NSString stringWithUTF8String:
 	                                               get_url_to_first_open_port(
 	                                               get_url_to_first_open_port(
 	                                                   g_ctx)]]];
 	                                                   g_ctx)]]];
 }
 }
-- (void)editConfig {
+- (void)editConfig
+{
 	create_config_file(g_ctx, g_config_file_name);
 	create_config_file(g_ctx, g_config_file_name);
 	NSString *path = [NSString stringWithUTF8String:g_config_file_name];
 	NSString *path = [NSString stringWithUTF8String:g_config_file_name];
 	if (![[NSWorkspace sharedWorkspace] openFile:path
 	if (![[NSWorkspace sharedWorkspace] openFile:path
@@ -3061,7 +3172,8 @@ main(int argc, char *argv[])
 		(void)[alert runModal];
 		(void)[alert runModal];
 	}
 	}
 }
 }
-- (void)shutDown {
+- (void)shutDown
+{
 	[NSApp terminate:nil];
 	[NSApp terminate:nil];
 }
 }
 @end
 @end