mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 09:44:18 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			217 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* $Id: cfg.c,v 1.6 2008-06-02 22:16:27 nicm Exp $ */
 | 
						|
 | 
						|
/*
 | 
						|
 * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, and distribute this software for any
 | 
						|
 * purpose with or without fee is hereby granted, provided that the above
 | 
						|
 * copyright notice and this permission notice appear in all copies.
 | 
						|
 *
 | 
						|
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
						|
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
						|
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
						|
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
						|
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
 | 
						|
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 | 
						|
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 */
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#include "tmux.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * Config file parser. Pretty quick and simple, each line is parsed into a
 | 
						|
 * argv array and executed as a command.
 | 
						|
 */
 | 
						|
 | 
						|
char	 *cfg_string(FILE *, char, int);
 | 
						|
void printflike2 cfg_print(struct cmd_ctx *, const char *, ...);
 | 
						|
void printflike2 cfg_error(struct cmd_ctx *, const char *, ...);
 | 
						|
 | 
						|
char	 *cfg_cause;
 | 
						|
 | 
						|
void printflike2
 | 
						|
cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void printflike2
 | 
						|
cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...)
 | 
						|
{
 | 
						|
	va_list	ap;
 | 
						|
 | 
						|
	va_start(ap, fmt);
 | 
						|
	xvasprintf(&cfg_cause, fmt, ap);
 | 
						|
	va_end(ap);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
load_cfg(const char *path, char **causep)
 | 
						|
{
 | 
						|
	FILE   	       *f;
 | 
						|
	int		ch, argc;
 | 
						|
	u_int		line;
 | 
						|
	char	      **argv, *buf, *s, *cause;
 | 
						|
	size_t		len;
 | 
						|
	struct cmd     *cmd;
 | 
						|
	struct cmd_ctx	ctx;
 | 
						|
 | 
						|
	if ((f = fopen(path, "rb")) == NULL) {
 | 
						|
		xasprintf(causep, "%s: %s", path, strerror(errno));
 | 
						|
		return (1);
 | 
						|
	}
 | 
						|
	cause = NULL;
 | 
						|
 | 
						|
	argv = NULL;
 | 
						|
	argc = 0;
 | 
						|
 | 
						|
	buf = NULL;
 | 
						|
	len = 0;
 | 
						|
 | 
						|
	line = 0;
 | 
						|
	while ((ch = getc(f)) != EOF) {
 | 
						|
		switch (ch) {
 | 
						|
		case '\'':
 | 
						|
			if ((s = cfg_string(f, '\'', 0)) == NULL)
 | 
						|
				goto error;
 | 
						|
			argv = xrealloc(argv, argc + 1, sizeof (char *));
 | 
						|
			argv[argc++] = s;
 | 
						|
			break;
 | 
						|
		case '"':
 | 
						|
			if ((s = cfg_string(f, '"', 1)) == NULL)
 | 
						|
				goto error;
 | 
						|
			argv = xrealloc(argv, argc + 1, sizeof (char *));
 | 
						|
			argv[argc++] = s;
 | 
						|
			break;
 | 
						|
		case '#':
 | 
						|
			/* Comment: discard until EOL. */
 | 
						|
			while ((ch = getc(f)) != '\n' && ch != EOF)
 | 
						|
				;
 | 
						|
			/* FALLTHROUGH */
 | 
						|
		case '\n':
 | 
						|
		case EOF:
 | 
						|
		case ' ':
 | 
						|
		case '\t':
 | 
						|
			if (len != 0) {
 | 
						|
				buf[len] = '\0';
 | 
						|
			
 | 
						|
				argv = xrealloc(
 | 
						|
				    argv, argc + 1, sizeof (char *));
 | 
						|
				argv[argc++] = buf;
 | 
						|
				
 | 
						|
				buf = NULL;
 | 
						|
				len = 0;
 | 
						|
			}				
 | 
						|
 | 
						|
			if (ch != '\n' && ch != EOF)
 | 
						|
				break;
 | 
						|
			line++;
 | 
						|
			if (argc == 0)
 | 
						|
				break;
 | 
						|
			
 | 
						|
			if ((cmd = cmd_parse(argc, argv, &cause)) == NULL)
 | 
						|
				goto error;
 | 
						|
 | 
						|
			ctx.msgdata = NULL;
 | 
						|
			ctx.cursession = NULL;
 | 
						|
			ctx.curclient = NULL;
 | 
						|
			
 | 
						|
			ctx.error = cfg_error;
 | 
						|
			ctx.print = cfg_print;
 | 
						|
			
 | 
						|
			ctx.cmdclient = NULL;
 | 
						|
			ctx.flags = 0;
 | 
						|
			
 | 
						|
			cfg_cause = NULL;
 | 
						|
			cmd_exec(cmd, &ctx);			
 | 
						|
			cmd_free(cmd);
 | 
						|
			if (cfg_cause != NULL) {
 | 
						|
				cause = cfg_cause;
 | 
						|
				goto error;
 | 
						|
			}
 | 
						|
 | 
						|
			while (--argc >= 0)
 | 
						|
				xfree(argv[argc]);
 | 
						|
			argc = 0;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			if (len >= SIZE_MAX - 2)
 | 
						|
				goto error;
 | 
						|
				
 | 
						|
			buf = xrealloc(buf, 1, len + 1);
 | 
						|
			buf[len++] = ch;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	fclose(f);
 | 
						|
 | 
						|
	return (0);
 | 
						|
 | 
						|
error:
 | 
						|
	while (--argc >= 0)
 | 
						|
		xfree(argv[argc]);
 | 
						|
	xfree(argv);
 | 
						|
 | 
						|
	if (buf != NULL)
 | 
						|
		xfree(buf);
 | 
						|
 | 
						|
	if (cause == NULL)
 | 
						|
		xasprintf(causep, "%s: error at line %u", path, line);
 | 
						|
	else 
 | 
						|
		xasprintf(causep, "%s: %s at line %u", path, cause, line);
 | 
						|
	return (1);
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
cfg_string(FILE *f, char endch, int esc)
 | 
						|
{
 | 
						|
	int	ch;
 | 
						|
	char   *buf;
 | 
						|
	size_t	len;
 | 
						|
 | 
						|
        buf = NULL;
 | 
						|
	len = 0;
 | 
						|
 | 
						|
        while ((ch = getc(f)) != endch) {
 | 
						|
                switch (ch) {
 | 
						|
		case EOF:
 | 
						|
			xfree(buf);
 | 
						|
			return (NULL);
 | 
						|
                case '\\':
 | 
						|
			if (!esc)
 | 
						|
				break;
 | 
						|
                        switch (ch = getc(f)) {
 | 
						|
			case EOF:
 | 
						|
				xfree(buf);
 | 
						|
				return (NULL);
 | 
						|
                        case 'r':
 | 
						|
                                ch = '\r';
 | 
						|
                                break;
 | 
						|
                        case 'n':
 | 
						|
                                ch = '\n';
 | 
						|
                                break;
 | 
						|
                        case 't':
 | 
						|
                                ch = '\t';
 | 
						|
                                break;
 | 
						|
                        }
 | 
						|
                        break;
 | 
						|
                }
 | 
						|
 | 
						|
		if (len >= SIZE_MAX - 2) {
 | 
						|
			xfree(buf);
 | 
						|
			return (NULL);
 | 
						|
		}
 | 
						|
		buf = xrealloc(buf, 1, len + 1);
 | 
						|
                buf[len++] = ch;
 | 
						|
        }
 | 
						|
 | 
						|
        buf[len] = '\0';
 | 
						|
	return (buf);
 | 
						|
}
 |