r4401 - in trunk/src/host: . envedit
werner at docs.openmoko.org
werner at docs.openmoko.org
Mon Apr 28 07:25:43 CEST 2008
Author: werner
Date: 2008-04-28 07:25:40 +0200 (Mon, 28 Apr 2008)
New Revision: 4401
Added:
trunk/src/host/envedit/
trunk/src/host/envedit/Makefile
trunk/src/host/envedit/cpp.c
trunk/src/host/envedit/cpp.h
trunk/src/host/envedit/env.c
trunk/src/host/envedit/env.h
trunk/src/host/envedit/envcpp.pl
trunk/src/host/envedit/envedit.c
trunk/src/host/envedit/parse.c
trunk/src/host/envedit/parse.h
trunk/src/host/envedit/var.c
trunk/src/host/envedit/var.h
Log:
Replacement for devirginator/envedit.pl
Improvements:
- no interminable CRC calculations in Perl
- if used with -n, can run in an environment without Perl
- options can be passed in any order
Added: trunk/src/host/envedit/Makefile
===================================================================
--- trunk/src/host/envedit/Makefile (rev 0)
+++ trunk/src/host/envedit/Makefile 2008-04-28 05:25:40 UTC (rev 4401)
@@ -0,0 +1,31 @@
+PREFIX=/usr
+
+CFLAGS_WARN=-Wall -Wshadow -Wstrict-prototypes -Wmissing-prototypes \
+ -Wmissing-declarations
+CFLAGS=-g -O $(CFLAGS_WARN) -DCPP='"$(PREFIX)/bin/envcpp.pl"'
+LDFLAGS=-lz
+
+OBJS=envedit.o env.o parse.o var.o cpp.o
+
+.PHONY: all install uninstall dep depend clean spotless
+
+all: envedit
+
+envedit: $(OBJS)
+
+install: envedit
+ install -D envedit $(PREFIX)/bin/envedit
+ install -D envcpp.pl $(PREFIX)/bin/envcpp.pl
+
+uninstall:
+ rm -f $(PREFIX)/bin/{envedit,envcpp.pl}
+
+dep depend .depend:
+ $(CPP) $(CFLAGS) -MM -MG *.c >.depend || \
+ { rm -f .depend; exit 1; }
+
+clean:
+ rm -f $(OBJS)
+
+spotless: clean
+ rm -f envedit
Added: trunk/src/host/envedit/cpp.c
===================================================================
--- trunk/src/host/envedit/cpp.c (rev 0)
+++ trunk/src/host/envedit/cpp.c 2008-04-28 05:25:40 UTC (rev 4401)
@@ -0,0 +1,210 @@
+/*
+ * cpp.c - CPP subprocess
+ *
+ * Written 2002-2004, 2006 by Werner Almesberger
+ * Copyright 2002,2003 California Institute of Technology
+ * Copyright 2004, 2006 Werner Almesberger
+ *
+ * Distributed under GPLv2, or any later version.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "cpp.h"
+
+
+static pid_t cpp_pid;
+static int cpp_argc = 0;
+static const char **cpp_argv = NULL;
+static int real_stdin = -1;
+
+
+void add_cpp_arg(const char *arg)
+{
+ if (!cpp_argc)
+ cpp_argc = 1;
+ cpp_argv = realloc(cpp_argv,sizeof(const char *)*(cpp_argc+1));
+ if (!cpp_argv) {
+ perror("realloc");
+ exit(1);
+ }
+ if (cpp_argc == 1)
+ cpp_argv[0] = CPP;
+ if (arg) {
+ arg = strdup(arg);
+ if (!arg) {
+ perror("strdup");
+ exit(1);
+ }
+ }
+ cpp_argv[cpp_argc++] = arg;
+}
+
+
+void add_cpp_Wp(const char *arg)
+{
+ char *tmp = strdup(arg);
+ char *curr,*end;
+
+ if (!tmp) {
+ perror("strdup");
+ exit(1);
+ }
+ curr = tmp;
+ do {
+ end = strchr(curr,',');
+ if (end)
+ *end++ = 0;
+ add_cpp_arg(curr);
+ curr = end;
+ }
+ while (end);
+ free(tmp);
+}
+
+
+static void kill_cpp(void)
+{
+ if (cpp_pid)
+ (void) kill(cpp_pid,SIGTERM);
+}
+
+
+static void run_cpp(const char *name,int fd,int close_fd)
+{
+ char **arg;
+ int fds[2];
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ exit(1);
+ }
+ if (name)
+ add_cpp_arg(name);
+ add_cpp_arg(NULL);
+ cpp_pid = fork();
+ if (cpp_pid < 0) {
+ perror("fork");
+ exit(1);
+ }
+ if (!cpp_pid) {
+ if (close(fds[0]) < 0) {
+ perror("close");
+ exit(1);
+ }
+ if (close_fd != -1 && close(close_fd) < 0) {
+ perror("close");
+ exit(1);
+ }
+ if (fd != -1 && dup2(fd,0) < 0) {
+ perror("dup2");
+ exit(1);
+ }
+ if (dup2(fds[1],1) < 0) {
+ perror("dup2");
+ exit(1);
+ }
+ if (execvp(CPP,(char **) cpp_argv) < 0) { /* prototype is weird */
+ perror("execvp " CPP);
+ exit(1);
+ }
+ /* not reached */
+ }
+ if (close(fds[1]) < 0) {
+ perror("close");
+ exit(1);
+ }
+ real_stdin = dup(0);
+ if (real_stdin < 0) {
+ perror("dup");
+ exit(1);
+ }
+ if (fd != -1 && close(fd) < 0) {
+ perror("close");
+ exit(1);
+ }
+ if (dup2(fds[0],0) < 0) {
+ perror("dup2");
+ exit(1);
+ }
+ for (arg = (char **) cpp_argv+1; *arg; arg++)
+ free(*arg);
+ free(cpp_argv);
+ cpp_argv = NULL;
+ cpp_argc = 0;
+}
+
+
+void run_cpp_on_file(const char *name)
+{
+ run_cpp(name,name ? -1 : 0,-1);
+ atexit(kill_cpp);
+}
+
+
+void run_cpp_on_string(const char *str)
+{
+ int fds[2];
+ pid_t pid;
+ int left,wrote;
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ exit(1);
+ }
+ run_cpp(NULL,fds[0],fds[1]);
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ exit(1);
+ }
+ if (!pid) {
+ for (left = strlen(str); left; left -= wrote) {
+ wrote = write(fds[1],str,left);
+ if (wrote < 0)
+ break; /* die silently */
+ str += wrote;
+ }
+ exit(0);
+ }
+ if (close(fds[1]) < 0) {
+ perror("close");
+ exit(1);
+ }
+ atexit(kill_cpp);
+}
+
+
+void reap_cpp(void)
+{
+ int status;
+
+ cpp_pid = 0;
+ if (waitpid(cpp_pid,&status,0) < 0) {
+ perror("waitpid");
+ exit(1);
+ }
+ if (!status) {
+ if (dup2(real_stdin,0) < 0) {
+ perror("dup2");
+ exit(1);
+ }
+ return;
+ }
+ if (WIFEXITED(status))
+ exit(WEXITSTATUS(status));
+ if (WIFSIGNALED(status))
+ fprintf(stderr,"cpp terminated with signal %d\n",WTERMSIG(status));
+ else
+ fprintf(stderr,"cpp terminated with incomprehensible status %d\n",
+ status);
+ exit(1);
+}
Added: trunk/src/host/envedit/cpp.h
===================================================================
--- trunk/src/host/envedit/cpp.h (rev 0)
+++ trunk/src/host/envedit/cpp.h 2008-04-28 05:25:40 UTC (rev 4401)
@@ -0,0 +1,19 @@
+/*
+ * cpp.h - CPP subprocess
+ *
+ * Written 2002,2003 by Werner Almesberger, Caltech Netlab FAST project
+ *
+ * Distributed under GPLv2, or any later version.
+ *
+ */
+
+#ifndef CPP_H
+#define CPP_H
+
+void add_cpp_arg(const char *arg);
+void add_cpp_Wp(const char *arg);
+void run_cpp_on_file(const char *name); /* NULL for stdin */
+void run_cpp_on_string(const char *str);
+void reap_cpp(void);
+
+#endif /* CPP_H */
Added: trunk/src/host/envedit/env.c
===================================================================
--- trunk/src/host/envedit/env.c (rev 0)
+++ trunk/src/host/envedit/env.c 2008-04-28 05:25:40 UTC (rev 4401)
@@ -0,0 +1,256 @@
+/*
+ * env.c - Environment access and file handling
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <zlib.h>
+
+#include "var.h"
+#include "cpp.h"
+#include "parse.h"
+#include "env.h"
+
+
+#define SCRATCH_SIZE 1024 /* buffer for reading in extra environment
+ data. Any value > 0 is fine. */
+
+
+unsigned long env_size = 16384;
+
+static char *env;
+
+
+static uint32_t crc_env(void)
+{
+ return crc32(crc32(0, NULL, 0), (void *) env+4, env_size-4);
+}
+
+
+static FILE *file_open(const char *name, const char *mode, FILE *default_file)
+{
+ FILE *file;
+
+ if (!strcmp(name, "-"))
+ return default_file;
+ file = fopen(name, mode);
+ if (file)
+ return file;
+ perror(name);
+ exit(1);
+}
+
+
+static void file_close(const char *name, FILE *file, FILE *default_file)
+{
+ if (file == default_file)
+ return;
+ if (fclose(file) != EOF)
+ return;
+ perror(name);
+ exit(1);
+}
+
+
+void read_env(const char *name, int warn_crc)
+{
+ FILE *file;
+ size_t got;
+ uint32_t orig, crc;
+
+ env = malloc(env_size+1);
+ if (!env) {
+ perror("malloc");
+ exit(1);
+ }
+ env[env_size] = 0; /* make sure parse_env stops */
+
+ file = file_open(name, "r", stdin);
+ got = fread(env, 1, env_size, file);
+
+ /* too small for CRC plus \0\0 */
+ if (got < 6) {
+ fprintf(stderr, "environment is too small (%lu bytes < 6)\n",
+ (unsigned long) got);
+ exit(1);
+ }
+
+ if (got < env_size)
+ memset(env+got, 0, env_size-got);
+ else {
+ char scratch[SCRATCH_SIZE];
+ size_t more;
+
+ do {
+ more = fread(scratch, 1, SCRATCH_SIZE, file);
+ got += more;
+ }
+ while (more);
+ }
+ if (got != env_size)
+ fprintf(stderr,
+ "warning: environment is %lu bytes, expected %lu\n",
+ (unsigned long) got, env_size);
+
+ orig = (uint8_t) env[0] | ((uint8_t) env[1] << 8) |
+ ((uint8_t) env[2] << 16) | ((uint8_t) env[3] << 24);
+ crc = crc_env();
+ if (crc != orig) {
+ fprintf(stderr,
+ "CRC error: file says 0x%08lx, calculated 0x%08lx\n",
+ (unsigned long) orig, (unsigned long) crc);
+ if (!warn_crc)
+ exit(1);
+ }
+
+ file_close(name, file, stdin);
+}
+
+
+void parse_env(void)
+{
+ char *p, *next, *eq;
+
+ for (p = env+4; p != env+env_size; p = next+1) {
+ next = strchr(p, 0);
+ if (next == p)
+ break;
+ if (next == env+env_size) {
+ fprintf(stderr,
+ "warning: unterminated entry in environment "
+ "\"%s\"\n", p);
+ break;
+ }
+ eq = strchr(p, '=');
+ if (!eq) {
+ fprintf(stderr,
+ "warning: ignoring invalid environment entry "
+ "\"%s\"\n", p);
+ continue;
+ }
+ if (next == eq+1) {
+ fprintf(stderr,
+ "warning: skipping empty entry for \"%s\"\n", p);
+ continue;
+ }
+ *eq = 0;
+ set_var(p, eq+1);
+ }
+}
+
+
+void print_env(const char *name)
+{
+ FILE *file;
+
+ file = file_open(name, "w", stdout);
+ reset_var();
+ while (1) {
+ const char *var, *value;
+
+ var = next_var(&value);
+ if (!var)
+ break;
+ if (fprintf(file, "%s=%s\n", var, value) < 0) {
+ perror(name);
+ exit(1);
+ }
+ }
+ file_close(name, file, stdout);
+}
+
+
+void write_env(const char *name)
+{
+ FILE *file;
+ char *p;
+ int n;
+ uint32_t crc;
+ size_t wrote;
+
+ memset(env, 0, env_size);
+ reset_var();
+ for (p = env+4; 1; p += n+1) {
+ const char *var, *value;
+
+ var = next_var(&value);
+ if (!var)
+ break;
+ if (p-env+strlen(var)+strlen(value)+3 > env_size) {
+ fprintf(stderr, "environment too big\n");
+ exit(1);
+ }
+ n = sprintf(p, "%s=%s", var, value);
+ }
+ crc = crc_env();
+ env[0] = crc;
+ env[1] = crc >> 8;
+ env[2] = crc >> 16;
+ env[3] = crc >> 24;
+
+ file = file_open(name, "w", stdout);
+ wrote = fwrite(env, 1, env_size, file);
+ if (ferror(file)) {
+ perror(name);
+ exit(1);
+ }
+ if (wrote != env_size) {
+ fprintf(stderr, "%s: short write %lu < %lu\n", name,
+ (unsigned long) wrote, env_size);
+ exit(1);
+ }
+ file_close(name, file, stdout);
+}
+
+
+void set_env(const char *var)
+{
+ char *tmp, *eq;
+
+ tmp = strdup(var);
+ if (!tmp) {
+ perror("strdup");
+ exit(1);
+ }
+ eq = strchr(tmp, '=');
+ if (!eq) {
+ fprintf(stderr, "invalid assignment syntax: \"%s\"\n", tmp);
+ exit(1);
+ }
+ *eq = 0;
+ if (eq[1])
+ set_var(var, eq+1);
+ else
+ del_var(var);
+}
+
+
+void edit_env(const char *name, int cpp)
+{
+ FILE *file;
+
+ if (!cpp)
+ file = file_open(name, "r", stdin);
+ else {
+ run_cpp_on_file(name);
+ file = stdin;
+ }
+ parse_edit(file);
+ if (cpp)
+ reap_cpp();
+ else
+ file_close(name, file, stdin);
+}
Added: trunk/src/host/envedit/env.h
===================================================================
--- trunk/src/host/envedit/env.h (rev 0)
+++ trunk/src/host/envedit/env.h 2008-04-28 05:25:40 UTC (rev 4401)
@@ -0,0 +1,27 @@
+/*
+ * env.h - Environment access and file handling
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+
+#ifndef ENV_H
+#define ENV_H
+
+extern unsigned long env_size;
+
+void read_env(const char *name, int warn_crc);
+void parse_env(void);
+void print_env(const char *name);
+void write_env(const char *name);
+void set_env(const char *var);
+void edit_env(const char *name, int cpp);
+
+#endif /* ENV_H */
Added: trunk/src/host/envedit/envcpp.pl
===================================================================
--- trunk/src/host/envedit/envcpp.pl (rev 0)
+++ trunk/src/host/envedit/envcpp.pl 2008-04-28 05:25:40 UTC (rev 4401)
@@ -0,0 +1,189 @@
+#!/usr/bin/perl
+#
+# envcpp.pl - U-Boot environment editor
+#
+# Copyright (C) 2006-2008 by OpenMoko, Inc.
+# Written by Werner Almesberger <werner at openmoko.org>
+# All Rights Reserved
+#
+# 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+#
+# Preprocessing operations:
+#
+# CPP-like conditionals:
+#
+# #ifdef VAR
+# #ifndef VAR
+# #else
+# #endif
+#
+# Macro expansion:
+#
+# #define MACRO
+# #define MACRO TEXT ...
+# MACRO
+# MACRO##TOKEN
+#
+# Note that #ifdef/#ifndef use both existing environment variables (i.e., those
+# present in the environment at the time of processing) and preprocessing
+# variables (i.e., those set with -D), while macro expansion only uses
+# preprocessing variables.
+#
+
+
+sub usage
+{
+ print STDERR
+"usage: $0 [-D var[=value]] [env_file]\n".
+" -D var[=value] define a variable for env_file preprocessing only\n";
+ exit(1);
+}
+
+
+sub expand
+{
+ local ($s, @key) = @_;
+ local ($tmp, $pre, $exp, $post);
+ local ($i, @tmp);
+
+ $tmp = "";
+ while (length $s) {
+ $pre = $s;
+ $exp = "";
+ $post = "";
+ for ($i = 0; $i <= $#key; $i++) {
+ @tmp = @key;
+ splice(@tmp, $i, 1);
+ if ($s =~ /(##)?\b$key[$i]\b(##)?/) {
+ if (length $` < length $pre) {
+ $pre = $`;
+ $post = $';
+ $exp = &expand($def{$key[$i]}, @tmp);
+ }
+ }
+ }
+ $tmp .= $pre.$exp;
+ $s = $post;
+ }
+ return $tmp;
+}
+
+
+if ($0 =~ m#/[^/]*$#) {
+ push(@INC, $`);
+}
+
+while (@ARGV) {
+ if ($ARGV[0] =~ /^-D/) {
+ shift @ARGV;
+ if ($' ne "") {
+ $def = $';
+ }
+ else {
+ &usage unless defined $ARGV[1];
+ $def = shift @ARGV;
+ }
+ if ($def =~ /=/) {
+ $def{$`} = $';
+ }
+ else {
+ $def{$def} = 1;
+ }
+ }
+ elsif ($ARGV[0] =~ /^-.+/) {
+ &usage;
+ }
+ else {
+ &usage if defined $ARGV[1];
+ last;
+ }
+}
+
+$file = shift(@ARGV);
+undef $line;
+if (defined $file) {
+ open(FILE, $file) || die "$file: $!";
+}
+else {
+ *FILE = *STDIN;
+}
+while (<FILE>) {
+ chop;
+ if (/^\s*#if(n?)def\s+(\S+)/) {
+ if (!$false &&
+ (defined $env{$2} || defined $def{$2}) == ($1 ne "n")) {
+ $true++;
+ }
+ else {
+ $false++;
+ }
+ }
+ elsif (/^\s*#else\b/) {
+ if (!$false && !$true) {
+ print STDERR "$file:$.: #else without #if...\n";
+ exit(1);
+ }
+ if (!$false) {
+ $true--;
+ $false++;
+ }
+ elsif ($false == 1) {
+ $false--;
+ $true++;
+ }
+ }
+ elsif (/^\s*#endif\b/) {
+ if (!$false && !$true) {
+ print STDERR "$file:$.: #endif without #if...\n";
+ exit(1);
+ }
+ if ($false) {
+ $false--;
+ }
+ else {
+ $true--;
+ }
+ }
+ next if $false;
+
+ if (/^\s*#define\s+(\S+)(\s*(.*?))?\s*$/) {
+ if (defined $def{$1} && $def{$1} ne $3) {
+ print STDERR "$file:$.: redefinition of macro \"$1\"\n";
+ exit(1);
+ }
+ $def{$1} = $3;
+ }
+
+ $_ = &expand($_, keys %def);
+
+ s/#.*//;
+ s/\s*$//;
+ next if /^\s*$/;
+ if (/^\s+/) {
+ if (!defined $line) {
+ print STDERR "first line cannot be a continuation\n";
+ exit(1);
+ }
+ $line .= " ".$';
+ }
+ else {
+ print "$line\n" || die $! if defined $line;
+ $line = $_;
+ }
+}
+close FILE || die $!;
+print "$line\n" || die $! if defined $line;
Property changes on: trunk/src/host/envedit/envcpp.pl
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/src/host/envedit/envedit.c
===================================================================
--- trunk/src/host/envedit/envedit.c (rev 0)
+++ trunk/src/host/envedit/envedit.c 2008-04-28 05:25:40 UTC (rev 4401)
@@ -0,0 +1,118 @@
+/*
+ * envedit.c - U-Boot environment editor
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "cpp.h"
+#include "env.h"
+
+
+static void usage(const char *name)
+{
+ fprintf(stderr,
+"usage: %s [-f env_file [-n]] [-i file [-c]] [-o file|-p] [-s bytes]\n"
+" %8s[-D var[=value]] [var=[value] ...]\n\n"
+" -c ignore CRC errors in input environment\n"
+" -f env_file read changed from file (default: no changes from file)\n"
+" -i file read environment from file (default: use empty environment)\n"
+" -n don't run env_file through CPP\n"
+" -o file write environment to file (default: write to stdout)\n"
+" -p print environment in human-readable form\n"
+" -s bytes environment size in bytes (default: 16384)\n"
+" -D var[=value] define a variable for env_file processing only\n"
+" var= remove the specified variable\n"
+" var=value set the specified variable\n",
+ name, "");
+ exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+ int warn_crc = 0;
+ const char *env_file = NULL;
+ const char *in_file = NULL, *out_file = NULL;
+ int cpp = 1;
+ int print = 0;
+ char *tmp, *end;
+ int c, i;
+
+ while ((c = getopt(argc, argv, "cf:i:no:ps:D:")) != EOF)
+ switch (c) {
+ case 'c':
+ warn_crc = 1;
+ break;
+ case 'f':
+ env_file = optarg;
+ break;
+ case 'i':
+ in_file = optarg;
+ break;
+ case 'n':
+ cpp = 0;
+ break;
+ case 'o':
+ out_file = optarg;
+ break;
+ case 'p':
+ print = 1;
+ break;
+ case 's':
+ env_size = strtoul(optarg, &end, 0);
+ if (*end)
+ usage(*argv);
+ break;
+ case 'D':
+ tmp = malloc(strlen(optarg)+3);
+ if (!tmp) {
+ perror("strdup");
+ exit(1);
+ }
+ tmp[0] = '-';
+ tmp[1] = 'D';
+ strcpy(tmp+2, optarg);
+ add_cpp_arg(tmp);
+ free(tmp);
+ break;
+ default:
+ usage(*argv);
+ }
+
+ if (!in_file && warn_crc)
+ usage(*argv);
+ if (out_file && print)
+ usage(*argv);
+ if (!env_file && !cpp)
+ usage(*argv);
+
+ if (in_file) {
+ read_env(in_file, warn_crc);
+ parse_env();
+ }
+ if (env_file)
+ edit_env(env_file, cpp);
+
+ for (i = optind; i != argc; i++)
+ set_env(argv[i]);
+
+ if (print)
+ print_env("-");
+ else
+ write_env(out_file ? out_file : "-");
+
+ return 0;
+}
Added: trunk/src/host/envedit/parse.c
===================================================================
--- trunk/src/host/envedit/parse.c (rev 0)
+++ trunk/src/host/envedit/parse.c 2008-04-28 05:25:40 UTC (rev 4401)
@@ -0,0 +1,249 @@
+/*
+ * parse.c - Environment edits parser
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+
+#include "var.h"
+#include "parse.h"
+
+
+static enum state {
+ st_0, /* waiting for variable */
+ st_var, /* in variable name */
+ st_spc_var, /* skipping whitespace after variable name */
+ st_spc_eq, /* skipping whitespace after equal sign */
+ st_val, /* in value */
+ st_spc_val, /* skipping whitespace in value */
+} state = st_0;
+
+
+static char *var = NULL, *value = NULL;
+static int line = 1;
+
+
+static void syntax(void)
+{
+ fprintf(stderr, "syntax error in line %d\n", line);
+ exit(1);
+}
+
+
+static void flush(void)
+{
+ assert(var);
+ if (value)
+ set_var(var, value);
+ else
+ del_var(var);
+ free(var);
+ if (value)
+ free(value);
+ var = value = NULL;
+}
+
+
+/*
+ * A bit on the inefficient side, but who really cares ?
+ */
+
+static void add_char(char **base, char c)
+{
+ int len;
+
+ len = *base ? strlen(*base) : 0;
+ *base = realloc(*base, len+2);
+ (*base)[len] = c;
+ (*base)[len+1] = 0;
+}
+
+
+static void add_to_var(char c)
+{
+ add_char(&var, c);
+}
+
+
+static void add_to_value(char c)
+{
+ add_char(&value, c);
+}
+
+
+static int alpha(char c)
+{
+ return c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+}
+
+
+static int alnum(char c)
+{
+ return isdigit(c) ? 1 : alpha(c);
+}
+
+
+static void in_line(int c)
+{
+ switch (state) {
+ case st_var:
+ if (isspace(c)) {
+ state = st_spc_var;
+ break;
+ }
+ if (c == '=') {
+ state = st_spc_eq;
+ break;
+ }
+ if (!alnum(c))
+ syntax();
+ add_to_var(c);
+ break;
+ case st_spc_var:
+ if (isspace(c))
+ break;
+ if (c == '=') {
+ state = st_spc_eq;
+ break;
+ }
+ syntax();
+ break;
+ case st_spc_eq:
+ case st_spc_val:
+ if (isspace(c))
+ break;
+ add_to_value(c);
+ state = st_val;
+ break;
+ case st_val:
+ add_to_value(c);
+ break;
+ default:
+ abort();
+ }
+}
+
+
+static void newline(int c)
+{
+ switch (state) {
+ flush:
+ flush();
+ state = st_0;
+ /* fall through */
+ case st_0:
+ if (isspace(c))
+ syntax();
+ if (!alpha(c))
+ syntax();
+ add_to_var(c);
+ state = st_var;
+ break;
+ case st_var:
+ state = st_spc_var;
+ /* fall through */
+ case st_spc_var:
+ in_line(c);
+ break;
+ case st_spc_eq:
+ if (isspace(c))
+ break;
+ goto flush;
+ case st_val:
+ if (isspace(c)) {
+ state = st_spc_val;
+ break;
+ }
+ goto flush;
+ case st_spc_val:
+ if (isspace(c))
+ break;
+ goto flush;
+ default:
+ abort();
+ }
+}
+
+
+static void double_newline(void)
+{
+ switch (state) {
+ case st_0:
+ break;
+ case st_var:
+ case st_spc_var:
+ syntax();
+ break;
+ case st_spc_eq:
+ case st_val:
+ case st_spc_val:
+ flush();
+ state = st_0;
+ break;
+ default:
+ abort();
+ }
+}
+
+
+void parse_edit(FILE *file)
+{
+ int comment = 0, nl = 1;
+
+ while (1) {
+ int c;
+
+ c = fgetc(file);
+ if (c == EOF)
+ break;
+ if (c == '#')
+ comment = 1;
+ if (c == '\n')
+ line++;
+ if (comment && c != '\n')
+ continue;
+ comment = 0;
+ if (c == '\n') {
+ if (nl)
+ double_newline();
+ nl = 1;
+ if (state == st_val)
+ state = st_spc_val;
+ continue;
+ }
+ if (nl)
+ newline(c);
+ else
+ in_line(c);
+ nl = 0;
+ }
+
+ switch (state) {
+ case st_0:
+ break;
+ case st_var:
+ case st_spc_var:
+ syntax();
+ break;
+ case st_spc_eq:
+ case st_val:
+ case st_spc_val:
+ flush();
+ break;
+ default:
+ abort();
+ }
+}
Added: trunk/src/host/envedit/parse.h
===================================================================
--- trunk/src/host/envedit/parse.h (rev 0)
+++ trunk/src/host/envedit/parse.h 2008-04-28 05:25:40 UTC (rev 4401)
@@ -0,0 +1,23 @@
+/*
+ * parse.h - Environment edits parser
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+
+#ifndef PARSE_H
+#define PARSE_H
+
+#include <stdio.h>
+
+
+void parse_edit(FILE *file);
+
+#endif /* PARSE_H */
Added: trunk/src/host/envedit/var.c
===================================================================
--- trunk/src/host/envedit/var.c (rev 0)
+++ trunk/src/host/envedit/var.c 2008-04-28 05:25:40 UTC (rev 4401)
@@ -0,0 +1,116 @@
+/*
+ * var.c - Environment variable repository
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "var.h"
+
+
+static struct var {
+ const char *name; /* NULL if deleted */
+ const char *value;
+} *vars = NULL, *curr_var;
+
+static int n_vars = 0;
+
+
+void set_var(const char *name, const char *value)
+{
+ struct var *p, *unused = NULL;
+
+ for (p = vars; p != vars+n_vars; p++) {
+ if (!p->name)
+ unused = p;
+ else {
+ if (!strcmp(p->name, name))
+ break;
+ }
+ }
+ if (p == vars+n_vars && unused)
+ p = unused;
+ if (p == vars+n_vars) {
+ vars = realloc(vars, sizeof(struct var)*2*(n_vars+1));
+ if (!vars) {
+ perror("realloc");
+ exit(1);
+ }
+ memset(vars+n_vars, 0, sizeof(struct var)*(n_vars+2));
+ p = vars+n_vars;
+ n_vars = 2*(n_vars+1);
+ }
+ if (!p->name) {
+ p->name = strdup(name);
+ if (!p->name) {
+ perror("strdup");
+ exit(1);
+ }
+ }
+ if (p->value)
+ free((void *) p->value);
+ p->value = strdup(value);
+ if (!p->value) {
+ perror("strdup");
+ exit(1);
+ }
+}
+
+
+void del_var(const char *name)
+{
+ struct var *p;
+
+ for (p = vars; p != vars+n_vars; p++)
+ if (p->name && !strcmp(p->name, name))
+ break;
+ if (p == vars+n_vars)
+ return;
+ free((void *) p->name);
+ free((void *) p->value);
+ p->name = NULL;
+ p->value = NULL;
+}
+
+
+static int comp(const void *_a, const void *_b)
+{
+ const struct var *a = _a;
+ const struct var *b = _b;
+
+ return a->name ? b->name ? strcmp(a->name, b->name) :
+ 1 : b->name ? -1 : 0;
+}
+
+
+void reset_var(void)
+{
+ if (!vars)
+ return;
+ qsort(vars, n_vars, sizeof(struct var), comp);
+ curr_var = vars;
+}
+
+
+const char *next_var(const char **value)
+{
+ if (!vars)
+ return NULL;
+ while (curr_var != vars+n_vars && !curr_var->name)
+ curr_var++;
+ if (curr_var == vars+n_vars)
+ return NULL;
+ *value = curr_var->value;
+ return (curr_var++)->name;
+}
Added: trunk/src/host/envedit/var.h
===================================================================
--- trunk/src/host/envedit/var.h (rev 0)
+++ trunk/src/host/envedit/var.h 2008-04-28 05:25:40 UTC (rev 4401)
@@ -0,0 +1,23 @@
+/*
+ * var.h - Environment variable repository
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+
+#ifndef VAR_H
+#define VAR_H
+
+void set_var(const char *name, const char *value);
+void del_var(const char *name);
+void reset_var(void);
+const char *next_var(const char const **value);
+
+#endif /* VAR_H */
More information about the commitlog
mailing list