|  | @@ -362,6 +362,7 @@ struct lsp_var_reader_data {
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/* Helper function to read the content of variable values */
 | 
	
		
			
				|  |  |  static const char *
 | 
	
		
			
				|  |  |  lsp_var_reader(lua_State *L, void *ud, size_t *sz)
 | 
	
		
			
				|  |  |  {
 | 
	
	
		
			
				|  | @@ -369,24 +370,30 @@ lsp_var_reader(lua_State *L, void *ud, size_t *sz)
 | 
	
		
			
				|  |  |  	const char *ret;
 | 
	
		
			
				|  |  |  	(void)(L); /* unused */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	/* This reader is called multiple times, to fetch the full Lua script */
 | 
	
		
			
				|  |  |  	switch (reader->state) {
 | 
	
		
			
				|  |  |  	case 0:
 | 
	
		
			
				|  |  | +		/* First call: what function to call */
 | 
	
		
			
				|  |  |  		ret = "mg.write(";
 | 
	
		
			
				|  |  |  		*sz = strlen(ret);
 | 
	
		
			
				|  |  |  		break;
 | 
	
		
			
				|  |  |  	case 1:
 | 
	
		
			
				|  |  | +		/* Second call: forward variable name */
 | 
	
		
			
				|  |  |  		ret = reader->begin;
 | 
	
		
			
				|  |  |  		*sz = reader->len;
 | 
	
		
			
				|  |  |  		break;
 | 
	
		
			
				|  |  |  	case 2:
 | 
	
		
			
				|  |  | +		/* Third call: close function call */
 | 
	
		
			
				|  |  |  		ret = ")";
 | 
	
		
			
				|  |  |  		*sz = strlen(ret);
 | 
	
		
			
				|  |  |  		break;
 | 
	
		
			
				|  |  |  	default:
 | 
	
		
			
				|  |  | +		/* Forth/Final call: tell Lua we got the entire script */
 | 
	
		
			
				|  |  |  		ret = 0;
 | 
	
		
			
				|  |  |  		*sz = 0;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	/* Step to the next state for the next call */
 | 
	
		
			
				|  |  |  	reader->state++;
 | 
	
		
			
				|  |  |  	return ret;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -402,44 +409,79 @@ run_lsp(struct mg_connection *conn,
 | 
	
		
			
				|  |  |  	int i, j, pos = 0, lines = 1, lualines = 0, is_var, lua_ok;
 | 
	
		
			
				|  |  |  	char chunkname[MG_BUF_LEN];
 | 
	
		
			
				|  |  |  	struct lsp_var_reader_data data;
 | 
	
		
			
				|  |  | +	const char lsp_mark1 = '?'; /* Use <? code ?> */
 | 
	
		
			
				|  |  | +	const char lsp_mark2 = '%'; /* Use <% code %> */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	for (i = 0; i < len; i++) {
 | 
	
		
			
				|  |  | -		if (p[i] == '\n')
 | 
	
		
			
				|  |  | +		if (p[i] == '\n') {
 | 
	
		
			
				|  |  |  			lines++;
 | 
	
		
			
				|  |  | -		if (((i + 1) < len) && (p[i] == '<') && (p[i + 1] == '?')) {
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		/* Lua pages are normal text, unless there is a "<?" or "<%" tag. */
 | 
	
		
			
				|  |  | +		if (((i + 1) < len) && (p[i] == '<')
 | 
	
		
			
				|  |  | +		    && ((p[i + 1] == lsp_mark1) || (p[i + 1] == lsp_mark2))) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			/* Opening tag way "<?" or "<%", closing tag must be the same. */
 | 
	
		
			
				|  |  | +			char lsp_mark_used = p[i + 1];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			/* <?= var ?> or <%= var %> means a variable is enclosed and its
 | 
	
		
			
				|  |  | +			 * value should be printed */
 | 
	
		
			
				|  |  | +			if (0 == memcmp("lua", p + i + 1, 3)) {
 | 
	
		
			
				|  |  | +				/* Syntax: <?lua code ?> or <?lua= var ?> */
 | 
	
		
			
				|  |  | +				/* This is added for compatibility to other LSP syntax
 | 
	
		
			
				|  |  | +				 * definitions. */
 | 
	
		
			
				|  |  | +				/* Skip 3 letters ("lua"). */
 | 
	
		
			
				|  |  | +				i += 3;
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -			/* <?= ?> means a variable is enclosed and its value should be
 | 
	
		
			
				|  |  | -			 * printed */
 | 
	
		
			
				|  |  | +			/* Check for '=' in "<?= ..." or "<%= ..." or "<?lua= ..." */
 | 
	
		
			
				|  |  |  			is_var = (((i + 2) < len) && (p[i + 2] == '='));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -			if (is_var)
 | 
	
		
			
				|  |  | +			if (is_var) {
 | 
	
		
			
				|  |  | +				/* use variable value (print it later) */
 | 
	
		
			
				|  |  |  				j = i + 2;
 | 
	
		
			
				|  |  | -			else
 | 
	
		
			
				|  |  | +			} else {
 | 
	
		
			
				|  |  | +				/* execute script code */
 | 
	
		
			
				|  |  |  				j = i + 1;
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  			while (j < len) {
 | 
	
		
			
				|  |  | -				if (p[j] == '\n')
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +				if (p[j] == '\n') {
 | 
	
		
			
				|  |  | +					/* Add line (for line number offset) */
 | 
	
		
			
				|  |  |  					lualines++;
 | 
	
		
			
				|  |  | -				if (((j + 1) < len) && (p[j] == '?') && (p[j + 1] == '>')) {
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +				/* Check for closing tag. */
 | 
	
		
			
				|  |  | +				if (((j + 1) < len) && (p[j] == lsp_mark_used)
 | 
	
		
			
				|  |  | +				    && (p[j + 1] == '>')) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +					/* There was a closing tag. Print everything before
 | 
	
		
			
				|  |  | +					 * the opening tag. */
 | 
	
		
			
				|  |  |  					mg_write(conn, p + pos, i - pos);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +					/* Set a name for debugging purposes */
 | 
	
		
			
				|  |  |  					mg_snprintf(conn,
 | 
	
		
			
				|  |  | -					            NULL, /* name only used for debugging */
 | 
	
		
			
				|  |  | +					            NULL, /* ignore truncation for debugging */
 | 
	
		
			
				|  |  |  					            chunkname,
 | 
	
		
			
				|  |  |  					            sizeof(chunkname),
 | 
	
		
			
				|  |  |  					            "@%s+%i",
 | 
	
		
			
				|  |  |  					            path,
 | 
	
		
			
				|  |  |  					            lines);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +					/* Prepare data for Lua C functions */
 | 
	
		
			
				|  |  |  					lua_pushlightuserdata(L, conn);
 | 
	
		
			
				|  |  |  					lua_pushcclosure(L, lsp_error, 1);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  					if (is_var) {
 | 
	
		
			
				|  |  | +						/* For variables: Print the value */
 | 
	
		
			
				|  |  |  						data.begin = p + (i + 3);
 | 
	
		
			
				|  |  |  						data.len = j - (i + 3);
 | 
	
		
			
				|  |  |  						data.state = 0;
 | 
	
		
			
				|  |  |  						lua_ok = mg_lua_load(
 | 
	
		
			
				|  |  |  						    L, lsp_var_reader, &data, chunkname, NULL);
 | 
	
		
			
				|  |  |  					} else {
 | 
	
		
			
				|  |  | +						/* For scripts: Execute them */
 | 
	
		
			
				|  |  |  						lua_ok = luaL_loadbuffer(L,
 | 
	
		
			
				|  |  |  						                         p + (i + 2),
 | 
	
		
			
				|  |  |  						                         j - (i + 2),
 | 
	
	
		
			
				|  | @@ -1609,6 +1651,85 @@ lwebsocket_set_interval(lua_State *L)
 | 
	
		
			
				|  |  |  	return lwebsocket_set_timer(L, 1);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Debug hook */
 | 
	
		
			
				|  |  | +static void
 | 
	
		
			
				|  |  | +lua_debug_hook(lua_State *L, lua_Debug *ar)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +	int stack_len = lua_gettop(L);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	lua_getinfo(L, "nSlu", ar);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (ar->event == LUA_HOOKCALL) {
 | 
	
		
			
				|  |  | +		printf("call\n");
 | 
	
		
			
				|  |  | +	} else if (ar->event == LUA_HOOKRET) {
 | 
	
		
			
				|  |  | +		printf("ret\n");
 | 
	
		
			
				|  |  | +#if defined(LUA_HOOKTAILRET)
 | 
	
		
			
				|  |  | +	} else if (ar->event == LUA_HOOKTAILRET) {
 | 
	
		
			
				|  |  | +		printf("tail ret\n");
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +#if defined(LUA_HOOKTAILCALL)
 | 
	
		
			
				|  |  | +	} else if (ar->event == LUA_HOOKTAILCALL) {
 | 
	
		
			
				|  |  | +		printf("tail call\n");
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +	} else if (ar->event == LUA_HOOKLINE) {
 | 
	
		
			
				|  |  | +		printf("line\n");
 | 
	
		
			
				|  |  | +	} else if (ar->event == LUA_HOOKCOUNT) {
 | 
	
		
			
				|  |  | +		printf("count\n");
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		printf("unknown (%i)\n", ar->event);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (ar->currentline >= 0) {
 | 
	
		
			
				|  |  | +		printf("%s:%i\n", ar->source, ar->currentline);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	printf("%s (%s)\n", ar->name, ar->namewhat);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (i = 1; i <= stack_len; i++) { /* repeat for each level */
 | 
	
		
			
				|  |  | +		int val_type = lua_type(L, i);
 | 
	
		
			
				|  |  | +		const char *s;
 | 
	
		
			
				|  |  | +		size_t n;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		switch (val_type) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case LUA_TNIL:
 | 
	
		
			
				|  |  | +			/* nil value  on the stack */
 | 
	
		
			
				|  |  | +			printf("nil\n");
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case LUA_TBOOLEAN:
 | 
	
		
			
				|  |  | +			/* boolean (true / false) */
 | 
	
		
			
				|  |  | +			printf("boolean: %s\n", lua_toboolean(L, i) ? "true" : "false");
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case LUA_TNUMBER:
 | 
	
		
			
				|  |  | +			/* number */
 | 
	
		
			
				|  |  | +			printf("number: %g\n", lua_tonumber(L, i));
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		case LUA_TSTRING:
 | 
	
		
			
				|  |  | +			/* string with limited length */
 | 
	
		
			
				|  |  | +			s = lua_tolstring(L, i, &n);
 | 
	
		
			
				|  |  | +			printf("string: '%.*s%s\n",
 | 
	
		
			
				|  |  | +			       (n > 30) ? 28 : s,
 | 
	
		
			
				|  |  | +			       (n > 30) ? ".." : "'");
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		default:
 | 
	
		
			
				|  |  | +			/* other values */
 | 
	
		
			
				|  |  | +			printf("%s\n", lua_typename(L, val_type));
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	printf("\n");
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Lua Environment */
 | 
	
		
			
				|  |  |  enum {
 | 
	
		
			
				|  |  |  	LUA_ENV_TYPE_LUA_SERVER_PAGE = 0,
 | 
	
		
			
				|  |  |  	LUA_ENV_TYPE_PLAIN_LUA_PAGE = 1,
 | 
	
	
		
			
				|  | @@ -1716,9 +1837,15 @@ prepare_lua_environment(struct mg_context *ctx,
 | 
	
		
			
				|  |  |                          int lua_env_type)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	const char *preload_file_name = NULL;
 | 
	
		
			
				|  |  | +	const char *debug_params = NULL;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	civetweb_open_lua_libs(L);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	/* Check if debugging should be enabled */
 | 
	
		
			
				|  |  | +	if ((conn != NULL) && (conn->dom_ctx != NULL)) {
 | 
	
		
			
				|  |  | +		debug_params = conn->dom_ctx->config[LUA_DEBUG_PARAMS];
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #if LUA_VERSION_NUM == 502
 | 
	
		
			
				|  |  |  	/* Keep the "connect" method for compatibility,
 | 
	
		
			
				|  |  |  	 * but do not backport it to Lua 5.1.
 | 
	
	
		
			
				|  | @@ -1861,11 +1988,27 @@ prepare_lua_environment(struct mg_context *ctx,
 | 
	
		
			
				|  |  |  		IGNORE_UNUSED_RESULT(luaL_dofile(L, preload_file_name));
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	/* Call user init function */
 | 
	
		
			
				|  |  |  	if (ctx != NULL) {
 | 
	
		
			
				|  |  |  		if (ctx->callbacks.init_lua != NULL) {
 | 
	
		
			
				|  |  |  			ctx->callbacks.init_lua(conn, L);
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* If debugging is enabled, add a hook */
 | 
	
		
			
				|  |  | +	if (debug_params) {
 | 
	
		
			
				|  |  | +		int mask = 0;
 | 
	
		
			
				|  |  | +		if (0 != strchr(debug_params, "c")) {
 | 
	
		
			
				|  |  | +			mask |= LUA_MASKCALL;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		if (0 != strchr(debug_params, "r")) {
 | 
	
		
			
				|  |  | +			mask |= LUA_MASKRET;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		if (0 != strchr(debug_params, "l")) {
 | 
	
		
			
				|  |  | +			mask |= LUA_MASKLINE;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		lua_sethook(L, lua_debug_hook, mask, 0);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 |