/branches/dd/tools/xtui.py |
---|
0,0 → 1,260 |
# |
# Copyright (c) 2009 Martin Decky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - Redistributions in binary form must reproduce the above copyright |
# notice, this list of conditions and the following disclaimer in the |
# documentation and/or other materials provided with the distribution. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
""" |
Text User Interface wrapper |
""" |
import sys |
import os |
def call_dlg(dlgcmd, *args, **kw): |
"Wrapper for calling 'dialog' program" |
indesc, outdesc = os.pipe() |
pid = os.fork() |
if (not pid): |
os.close(2) |
os.dup(outdesc) |
os.close(indesc) |
dlgargs = [dlgcmd] |
for key, val in kw.items(): |
dlgargs.append('--' + key) |
dlgargs.append(val) |
dlgargs += args |
os.execlp(dlgcmd, *dlgargs) |
os.close(outdesc) |
try: |
errout = os.fdopen(indesc, 'r') |
data = errout.read() |
errout.close() |
pid, status = os.wait() |
except: |
# Reset terminal |
os.system('reset') |
raise |
if (not os.WIFEXITED(status)): |
# Reset terminal |
os.system('reset') |
raise EOFError |
status = os.WEXITSTATUS(status) |
if (status == 255): |
raise EOFError |
return (status, data) |
try: |
import snack |
newt = True |
dialog = False |
except ImportError: |
newt = False |
dlgcmd = os.environ.get('DIALOG', 'dialog') |
if (call_dlg(dlgcmd, '--print-maxsize')[0] != 0): |
dialog = False |
else: |
dialog = True |
width_extra = 13 |
height_extra = 11 |
def width_fix(screen, width): |
"Correct width to screen size" |
if (width + width_extra > screen.width): |
width = screen.width - width_extra |
if (width <= 0): |
width = screen.width |
return width |
def height_fix(screen, height): |
"Correct height to screen size" |
if (height + height_extra > screen.height): |
height = screen.height - height_extra |
if (height <= 0): |
height = screen.height |
return height |
def screen_init(): |
"Initialize the screen" |
if (newt): |
return snack.SnackScreen() |
return None |
def screen_done(screen): |
"Cleanup the screen" |
if (newt): |
screen.finish() |
def choice_window(screen, title, text, options, position): |
"Create options menu" |
maxopt = 0 |
for option in options: |
length = len(option) |
if (length > maxopt): |
maxopt = length |
width = maxopt |
height = len(options) |
if (newt): |
width = width_fix(screen, width + width_extra) |
height = height_fix(screen, height) |
if (height > 3): |
large = True |
else: |
large = False |
buttonbar = snack.ButtonBar(screen, ('Done', 'Cancel')) |
textbox = snack.TextboxReflowed(width, text) |
listbox = snack.Listbox(height, scroll = large, returnExit = 1) |
cnt = 0 |
for option in options: |
listbox.append(option, cnt) |
cnt += 1 |
if (position != None): |
listbox.setCurrent(position) |
grid = snack.GridForm(screen, title, 1, 3) |
grid.add(textbox, 0, 0) |
grid.add(listbox, 0, 1, padding = (0, 1, 0, 1)) |
grid.add(buttonbar, 0, 2, growx = 1) |
retval = grid.runOnce() |
return (buttonbar.buttonPressed(retval), listbox.current()) |
elif (dialog): |
if (width < 35): |
width = 35 |
args = [] |
cnt = 0 |
for option in options: |
args.append(str(cnt + 1)) |
args.append(option) |
cnt += 1 |
kw = {} |
if (position != None): |
kw['default-item'] = str(position + 1) |
status, data = call_dlg(dlgcmd, '--title', title, '--extra-button', '--extra-label', 'Done', '--menu', text, str(height + height_extra), str(width + width_extra), str(cnt), *args, **kw) |
if (status == 1): |
return ('cancel', None) |
try: |
choice = int(data) - 1 |
except ValueError: |
return ('cancel', None) |
if (status == 0): |
return (None, choice) |
return ('done', choice) |
sys.stdout.write("\n *** %s *** \n%s\n\n" % (title, text)) |
maxcnt = len(str(len(options))) |
cnt = 0 |
for option in options: |
sys.stdout.write("%*s. %s\n" % (maxcnt, cnt + 1, option)) |
cnt += 1 |
sys.stdout.write("\n%*s. Done\n" % (maxcnt, '0')) |
sys.stdout.write("%*s. Quit\n\n" % (maxcnt, 'q')) |
while True: |
if (position != None): |
sys.stdout.write("Selection[%s]: " % str(position + 1)) |
else: |
sys.stdout.write("Selection: ") |
inp = sys.stdin.readline() |
if (not inp): |
raise EOFError |
if (not inp.strip()): |
if (position != None): |
return (None, position) |
continue |
if (inp.strip() == 'q'): |
return ('cancel', None) |
try: |
choice = int(inp.strip()) |
except ValueError: |
continue |
if (choice == 0): |
return ('done', 0) |
if (choice < 1) or (choice > len(options)): |
continue |
return (None, choice - 1) |
def error_dialog(screen, title, msg): |
"Print error dialog" |
width = len(msg) |
if (newt): |
width = width_fix(screen, width) |
buttonbar = snack.ButtonBar(screen, ['Ok']) |
textbox = snack.TextboxReflowed(width, msg) |
grid = snack.GridForm(screen, title, 1, 2) |
grid.add(textbox, 0, 0, padding = (0, 0, 0, 1)) |
grid.add(buttonbar, 0, 1, growx = 1) |
grid.runOnce() |
elif (dialog): |
call_dlg(dlgcmd, '--title', title, '--msgbox', msg, '6', str(width + width_extra)) |
else: |
sys.stdout.write("\n%s: %s\n" % (title, msg)) |
/branches/dd/tools/xstruct.py |
---|
0,0 → 1,110 |
# |
# Copyright (c) 2008 Martin Decky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - Redistributions in binary form must reproduce the above copyright |
# notice, this list of conditions and the following disclaimer in the |
# documentation and/or other materials provided with the distribution. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
""" |
Convert descriptive structure definitions to structure object |
""" |
import struct |
class Struct: |
def size(self): |
return struct.calcsize(self._format_) |
def pack(self): |
args = [] |
for variable in self._args_: |
if (isinstance(self.__dict__[variable], list)): |
for item in self.__dict__[variable]: |
args.append(item) |
else: |
args.append(self.__dict__[variable]) |
return struct.pack(self._format_, *args) |
def create(definition): |
"Create structure object" |
tokens = definition.split(None) |
# Initial byte order tag |
format = { |
"little:": lambda: "<", |
"big:": lambda: ">", |
"network:": lambda: "!" |
}[tokens[0]]() |
inst = Struct() |
args = [] |
# Member tags |
comment = False |
variable = None |
for token in tokens[1:]: |
if (comment): |
if (token == "*/"): |
comment = False |
continue |
if (token == "/*"): |
comment = True |
continue |
if (variable != None): |
subtokens = token.split("[") |
if (len(subtokens) > 1): |
format += "%d" % int(subtokens[1].split("]")[0]) |
format += variable |
inst.__dict__[subtokens[0]] = None |
args.append(subtokens[0]) |
variable = None |
continue |
if (token[0:8] == "padding["): |
size = token[8:].split("]")[0] |
format += "%dx" % int(size) |
continue |
variable = { |
"char": lambda: "s", |
"uint8_t": lambda: "B", |
"uint16_t": lambda: "H", |
"uint32_t": lambda: "L", |
"uint64_t": lambda: "Q", |
"int8_t": lambda: "b", |
"int16_t": lambda: "h", |
"int32_t": lambda: "l", |
"int64_t": lambda: "q" |
}[token]() |
inst.__dict__['_format_'] = format |
inst.__dict__['_args_'] = args |
return inst |
/branches/dd/tools/fix_symlinks.sh |
---|
1,3 → 1,5 |
#!/bin/bash |
# by Alf |
# This script solves malfunction of symlinks in cygwin |
# |
6,17 → 8,17 |
if uname | grep 'CYGWIN' > /dev/null; then |
echo "Good ... you have cygwin" |
echo "Good ... you have cygwin" |
else |
echo "Wrong. This script is only for cygwin" |
exit |
echo "Wrong. This script is only for cygwin" |
exit |
fi |
for linkName in `find . ! -iwholename '.*svn*' ! -type d -print`; do |
if head -n 1 $linkName | grep '^link' > /dev/null; then |
linkTarget=`head -n 1 $linkName | sed 's/^link //'` |
echo $linkName " -->" $linkTarget |
rm $linkName |
ln -s "$linkTarget" "$linkName" |
fi |
if head -n 1 $linkName | grep '^link' > /dev/null; then |
linkTarget=`head -n 1 $linkName | sed 's/^link //'` |
echo $linkName " -> " $linkTarget |
rm $linkName |
ln -s "$linkTarget" "$linkName" |
fi |
done |
/branches/dd/tools/mktmpfs.py |
---|
32,69 → 32,107 |
import sys |
import os |
import struct |
import xstruct |
def align_up(size, alignment): |
return (((size) + ((alignment) - 1)) & ~((alignment) - 1)) |
exclude_names = set(['.svn']) |
HEADER = """little: |
char tag[5] /* 'TMPFS' */ |
""" |
DENTRY_NONE = """little: |
uint8_t kind /* NONE */ |
uint32_t fname_len /* 0 */ |
""" |
DENTRY_FILE = """little: |
uint8_t kind /* FILE */ |
uint32_t fname_len /* filename length */ |
char fname[%d] /* filename */ |
uint32_t flen /* file length */ |
""" |
DENTRY_DIRECTORY = """little: |
uint8_t kind /* DIRECTORY */ |
uint32_t fname_len /* filename length */ |
char fname[%d] /* filename */ |
""" |
TMPFS_NONE = 0 |
TMPFS_FILE = 1 |
TMPFS_DIRECTORY = 2 |
def usage(prname): |
"Print usage syntax" |
print prname + " <ALIGNMENT> <PATH> <IMAGE>" |
print prname + " <PATH> <IMAGE>" |
def main(): |
if (len(sys.argv) < 4): |
usage(sys.argv[0]) |
return |
def recursion(root, outf): |
"Recursive directory walk" |
if (not sys.argv[1].isdigit()): |
print "<ALIGNMENT> must be a number" |
return |
align = int(sys.argv[1], 0) |
path = os.path.abspath(sys.argv[2]) |
if (not os.path.isdir(path)): |
print "<PATH> must be a directory" |
return |
header_size = align_up(18, align) |
payload_size = 0 |
outf = file(sys.argv[3], "w") |
outf.write(struct.pack("<" + ("%d" % header_size) + "x")) |
for root, dirs, files in os.walk(path): |
relpath = root[len(path):len(root)] |
for name in files: |
canon = os.path.join(relpath, name) |
outf.write(struct.pack("<BL" + ("%d" % len(canon)) + "s", 1, len(canon), canon)) |
payload_size += 5 + len(canon) |
for name in os.listdir(root): |
canon = os.path.join(root, name) |
if (os.path.isfile(canon) and (not name in exclude_names)): |
size = os.path.getsize(canon) |
fn = os.path.join(root, name) |
size = os.path.getsize(fn) |
dentry = xstruct.create(DENTRY_FILE % len(name)) |
dentry.kind = TMPFS_FILE |
dentry.fname_len = len(name) |
dentry.fname = name |
dentry.flen = size |
outf.write(dentry.pack()) |
inf = file(canon, "r") |
rd = 0; |
outf.write(struct.pack("<L", size)) |
payload_size += 4 |
inf = file(fn, "r") |
while (rd < size): |
data = inf.read(4096); |
outf.write(data) |
payload_size += len(data) |
rd += len(data) |
inf.close() |
for name in dirs: |
canon = os.path.join(relpath, name) |
outf.write(struct.pack("<BL" + ("%d" % len(canon)) + "s", 2, len(canon), canon)) |
payload_size += 5 + len(canon) |
if (os.path.isdir(canon) and (not name in exclude_names)): |
dentry = xstruct.create(DENTRY_DIRECTORY % len(name)) |
dentry.kind = TMPFS_DIRECTORY |
dentry.fname_len = len(name) |
dentry.fname = name |
outf.write(dentry.pack()) |
recursion(canon, outf) |
dentry = xstruct.create(DENTRY_NONE) |
dentry.kind = TMPFS_NONE |
dentry.fname_len = 0 |
outf.write(dentry.pack()) |
def main(): |
if (len(sys.argv) < 3): |
usage(sys.argv[0]) |
return |
aligned_size = align_up(payload_size, align) |
path = os.path.abspath(sys.argv[1]) |
if (not os.path.isdir(path)): |
print "<PATH> must be a directory" |
return |
if (aligned_size - payload_size > 0): |
outf.write(struct.pack("<" + ("%d" % (aligned_size - payload_size)) + "x")) |
outf = file(sys.argv[2], "w") |
outf.seek(0) |
outf.write(struct.pack("<4sBBLQ", "HORD", 1, 1, header_size, aligned_size)) |
header = xstruct.create(HEADER) |
header.tag = "TMPFS" |
outf.write(header.pack()) |
recursion(path, outf) |
dentry = xstruct.create(DENTRY_NONE) |
dentry.kind = TMPFS_NONE |
dentry.fname_len = 0 |
outf.write(dentry.pack()) |
outf.close() |
if __name__ == '__main__': |
main() |
/branches/dd/tools/mkfat.py |
---|
0,0 → 1,450 |
#!/usr/bin/env python |
# |
# Copyright (c) 2008 Martin Decky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - Redistributions in binary form must reproduce the above copyright |
# notice, this list of conditions and the following disclaimer in the |
# documentation and/or other materials provided with the distribution. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
""" |
FAT creator |
""" |
import sys |
import os |
import random |
import xstruct |
import array |
exclude_names = set(['.svn']) |
def align_up(size, alignment): |
"Return size aligned up to alignment" |
if (size % alignment == 0): |
return size |
return (((size / alignment) + 1) * alignment) |
def subtree_size(root, cluster_size, dirent_size): |
"Recursive directory walk and calculate size" |
size = 0 |
files = 2 |
for name in os.listdir(root): |
canon = os.path.join(root, name) |
if (os.path.isfile(canon) and (not name in exclude_names)): |
size += align_up(os.path.getsize(canon), cluster_size) |
files += 1 |
if (os.path.isdir(canon) and (not name in exclude_names)): |
size += subtree_size(canon, cluster_size, dirent_size) |
files += 1 |
return size + align_up(files * dirent_size, cluster_size) |
def root_entries(root): |
"Return number of root directory entries" |
return len(os.listdir(root)) |
def write_file(path, outf, cluster_size, data_start, fat, reserved_clusters): |
"Store the contents of a file" |
size = os.path.getsize(path) |
prev = -1 |
first = 0 |
inf = file(path, "r") |
rd = 0; |
while (rd < size): |
empty_cluster = fat.index(0) |
fat[empty_cluster] = 0xffff |
if (prev != -1): |
fat[prev] = empty_cluster |
else: |
first = empty_cluster |
prev = empty_cluster |
data = inf.read(cluster_size); |
outf.seek(data_start + (empty_cluster - reserved_clusters) * cluster_size) |
outf.write(data) |
rd += len(data) |
inf.close() |
return first, size |
def write_directory(directory, outf, cluster_size, data_start, fat, reserved_clusters, dirent_size, empty_cluster): |
"Store the contents of a directory" |
length = len(directory) |
size = length * dirent_size |
prev = -1 |
first = 0 |
i = 0 |
rd = 0; |
while (rd < size): |
if (prev != -1): |
empty_cluster = fat.index(0) |
fat[empty_cluster] = 0xffff |
fat[prev] = empty_cluster |
else: |
first = empty_cluster |
prev = empty_cluster |
data = '' |
data_len = 0 |
while ((i < length) and (data_len < cluster_size)): |
if (i == 0): |
directory[i].cluster = empty_cluster |
data += directory[i].pack() |
data_len += dirent_size |
i += 1 |
outf.seek(data_start + (empty_cluster - reserved_clusters) * cluster_size) |
outf.write(data) |
rd += len(data) |
return first, size |
DIR_ENTRY = """little: |
char name[8] /* file name */ |
char ext[3] /* file extension */ |
uint8_t attr /* file attributes */ |
padding[1] /* reserved for NT */ |
uint8_t ctime_fine /* create time (fine resolution) */ |
uint16_t ctime /* create time */ |
uint16_t cdate /* create date */ |
uint16_t adate /* access date */ |
padding[2] /* EA-index */ |
uint16_t mtime /* modification time */ |
uint16_t mdate /* modification date */ |
uint16_t cluster /* first cluster */ |
uint32_t size /* file size */ |
""" |
DOT_DIR_ENTRY = """little: |
uint8_t signature /* 0x2e signature */ |
char name[7] /* empty */ |
char ext[3] /* empty */ |
uint8_t attr /* file attributes */ |
padding[1] /* reserved for NT */ |
uint8_t ctime_fine /* create time (fine resolution) */ |
uint16_t ctime /* create time */ |
uint16_t cdate /* create date */ |
uint16_t adate /* access date */ |
padding[2] /* EA-index */ |
uint16_t mtime /* modification time */ |
uint16_t mdate /* modification date */ |
uint16_t cluster /* first cluster */ |
uint32_t size /* file size */ |
""" |
DOTDOT_DIR_ENTRY = """little: |
uint8_t signature[2] /* 0x2e signature */ |
char name[6] /* empty */ |
char ext[3] /* empty */ |
uint8_t attr /* file attributes */ |
padding[1] /* reserved for NT */ |
uint8_t ctime_fine /* create time (fine resolution) */ |
uint16_t ctime /* create time */ |
uint16_t cdate /* create date */ |
uint16_t adate /* access date */ |
padding[2] /* EA-index */ |
uint16_t mtime /* modification time */ |
uint16_t mdate /* modification date */ |
uint16_t cluster /* first cluster */ |
uint32_t size /* file size */ |
""" |
def mangle_fname(name): |
# FIXME: filter illegal characters |
parts = name.split('.') |
if (len(parts) > 0): |
fname = parts[0] |
else: |
fname = '' |
return (fname + ' ').upper()[0:8] |
def mangle_ext(name): |
# FIXME: filter illegal characters |
parts = name.split('.') |
if (len(parts) > 1): |
ext = parts[1] |
else: |
ext = '' |
return (ext + ' ').upper()[0:3] |
def create_dirent(name, directory, cluster, size): |
dir_entry = xstruct.create(DIR_ENTRY) |
dir_entry.name = mangle_fname(name) |
dir_entry.ext = mangle_ext(name) |
if (directory): |
dir_entry.attr = 0x30 |
else: |
dir_entry.attr = 0x20 |
dir_entry.ctime_fine = 0 # FIXME |
dir_entry.ctime = 0 # FIXME |
dir_entry.cdate = 0 # FIXME |
dir_entry.adate = 0 # FIXME |
dir_entry.mtime = 0 # FIXME |
dir_entry.mdate = 0 # FIXME |
dir_entry.cluster = cluster |
if (directory): |
dir_entry.size = 0 |
else: |
dir_entry.size = size |
return dir_entry |
def create_dot_dirent(empty_cluster): |
dir_entry = xstruct.create(DOT_DIR_ENTRY) |
dir_entry.signature = 0x2e |
dir_entry.name = ' ' |
dir_entry.ext = ' ' |
dir_entry.attr = 0x10 |
dir_entry.ctime_fine = 0 # FIXME |
dir_entry.ctime = 0 # FIXME |
dir_entry.cdate = 0 # FIXME |
dir_entry.adate = 0 # FIXME |
dir_entry.mtime = 0 # FIXME |
dir_entry.mdate = 0 # FIXME |
dir_entry.cluster = empty_cluster |
dir_entry.size = 0 |
return dir_entry |
def create_dotdot_dirent(parent_cluster): |
dir_entry = xstruct.create(DOTDOT_DIR_ENTRY) |
dir_entry.signature = [0x2e, 0x2e] |
dir_entry.name = ' ' |
dir_entry.ext = ' ' |
dir_entry.attr = 0x10 |
dir_entry.ctime_fine = 0 # FIXME |
dir_entry.ctime = 0 # FIXME |
dir_entry.cdate = 0 # FIXME |
dir_entry.adate = 0 # FIXME |
dir_entry.mtime = 0 # FIXME |
dir_entry.mdate = 0 # FIXME |
dir_entry.cluster = parent_cluster |
dir_entry.size = 0 |
return dir_entry |
def recursion(head, root, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, parent_cluster): |
"Recursive directory walk" |
directory = [] |
if (not head): |
# Directory cluster preallocation |
empty_cluster = fat.index(0) |
fat[empty_cluster] = 0xffff |
directory.append(create_dot_dirent(empty_cluster)) |
directory.append(create_dotdot_dirent(parent_cluster)) |
else: |
empty_cluster = 0 |
for name in os.listdir(root): |
canon = os.path.join(root, name) |
if (os.path.isfile(canon) and (not name in exclude_names)): |
rv = write_file(canon, outf, cluster_size, data_start, fat, reserved_clusters) |
directory.append(create_dirent(name, False, rv[0], rv[1])) |
if (os.path.isdir(canon) and (not name in exclude_names)): |
rv = recursion(False, canon, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, empty_cluster) |
directory.append(create_dirent(name, True, rv[0], rv[1])) |
if (head): |
outf.seek(root_start) |
for dir_entry in directory: |
outf.write(dir_entry.pack()) |
else: |
return write_directory(directory, outf, cluster_size, data_start, fat, reserved_clusters, dirent_size, empty_cluster) |
BOOT_SECTOR = """little: |
uint8_t jmp[3] /* jump instruction */ |
char oem[8] /* OEM string */ |
uint16_t sector /* bytes per sector */ |
uint8_t cluster /* sectors per cluster */ |
uint16_t reserved /* reserved sectors */ |
uint8_t fats /* number of FATs */ |
uint16_t rootdir /* root directory entries */ |
uint16_t sectors /* total number of sectors */ |
uint8_t descriptor /* media descriptor */ |
uint16_t fat_sectors /* sectors per single FAT */ |
uint16_t track_sectors /* sectors per track */ |
uint16_t heads /* number of heads */ |
uint32_t hidden /* hidden sectors */ |
uint32_t sectors_big /* total number of sectors (if sectors == 0) */ |
/* Extended BIOS Parameter Block */ |
uint8_t drive /* physical drive number */ |
padding[1] /* reserved (current head) */ |
uint8_t extboot_signature /* extended boot signature */ |
uint32_t serial /* serial number */ |
char label[11] /* volume label */ |
char fstype[8] /* filesystem type */ |
padding[448] /* boot code */ |
uint8_t boot_signature[2] /* boot signature */ |
""" |
EMPTY_SECTOR = """little: |
padding[512] /* empty sector data */ |
""" |
FAT_ENTRY = """little: |
uint16_t next /* FAT16 entry */ |
""" |
def usage(prname): |
"Print usage syntax" |
print prname + " <PATH> <IMAGE>" |
def main(): |
if (len(sys.argv) < 3): |
usage(sys.argv[0]) |
return |
path = os.path.abspath(sys.argv[1]) |
if (not os.path.isdir(path)): |
print "<PATH> must be a directory" |
return |
fat16_clusters = 4096 |
sector_size = 512 |
cluster_size = 4096 |
dirent_size = 32 |
fatent_size = 2 |
fat_count = 2 |
reserved_clusters = 2 |
# Make sure the filesystem is large enought for FAT16 |
size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size |
while (size / cluster_size < fat16_clusters): |
if (cluster_size > sector_size): |
cluster_size /= 2 |
size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size |
else: |
size = fat16_clusters * cluster_size + reserved_clusters * cluster_size |
root_size = align_up(root_entries(path) * dirent_size, cluster_size) |
fat_size = align_up(align_up(size, cluster_size) / cluster_size * fatent_size, sector_size) |
sectors = (cluster_size + fat_count * fat_size + root_size + size) / sector_size |
root_start = cluster_size + fat_count * fat_size |
data_start = root_start + root_size |
outf = file(sys.argv[2], "w") |
boot_sector = xstruct.create(BOOT_SECTOR) |
boot_sector.jmp = [0xEB, 0x3C, 0x90] |
boot_sector.oem = "MSDOS5.0" |
boot_sector.sector = sector_size |
boot_sector.cluster = cluster_size / sector_size |
boot_sector.reserved = cluster_size / sector_size |
boot_sector.fats = fat_count |
boot_sector.rootdir = root_size / dirent_size |
if (sectors <= 65535): |
boot_sector.sectors = sectors |
else: |
boot_sector.sectors = 0 |
boot_sector.descriptor = 0xF8 |
boot_sector.fat_sectors = fat_size / sector_size |
boot_sector.track_sectors = 63 |
boot_sector.heads = 6 |
boot_sector.hidden = 0 |
if (sectors > 65535): |
boot_sector.sectors_big = sectors |
else: |
boot_sector.sectors_big = 0 |
boot_sector.drive = 0x80 |
boot_sector.extboot_signature = 0x29 |
boot_sector.serial = random.randint(0, 0x7fffffff) |
boot_sector.label = "HELENOS" |
boot_sector.fstype = "FAT16 " |
boot_sector.boot_signature = [0x55, 0xAA] |
outf.write(boot_sector.pack()) |
empty_sector = xstruct.create(EMPTY_SECTOR) |
# Reserved sectors |
for i in range(1, cluster_size / sector_size): |
outf.write(empty_sector.pack()) |
# FAT tables |
for i in range(0, fat_count): |
for j in range(0, fat_size / sector_size): |
outf.write(empty_sector.pack()) |
# Root directory |
for i in range(0, root_size / sector_size): |
outf.write(empty_sector.pack()) |
# Data |
for i in range(0, size / sector_size): |
outf.write(empty_sector.pack()) |
fat = array.array('L', [0] * (fat_size / fatent_size)) |
fat[0] = 0xfff8 |
fat[1] = 0xffff |
recursion(True, path, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, 0) |
# Store FAT |
fat_entry = xstruct.create(FAT_ENTRY) |
for i in range(0, fat_count): |
outf.seek(cluster_size + i * fat_size) |
for j in range(0, fat_size / fatent_size): |
fat_entry.next = fat[j] |
outf.write(fat_entry.pack()) |
outf.close() |
if __name__ == '__main__': |
main() |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/branches/dd/tools/mkhord.py |
---|
0,0 → 1,104 |
#!/usr/bin/env python |
# |
# Copyright (c) 2008 Martin Decky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - Redistributions in binary form must reproduce the above copyright |
# notice, this list of conditions and the following disclaimer in the |
# documentation and/or other materials provided with the distribution. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
""" |
HORD encapsulator |
""" |
import sys |
import os |
import xstruct |
HEADER = """little: |
char tag[4] /* 'HORD' */ |
uint8_t version /* version */ |
uint8_t encoding /* encoding */ |
uint32_t header_size /* header size */ |
uint64_t payload_size /* payload size */ |
""" |
HORD_LSB = 1 |
def align_up(size, alignment): |
"Align upwards to a given alignment" |
return (((size) + ((alignment) - 1)) & ~((alignment) - 1)) |
def usage(prname): |
"Print usage syntax" |
print prname + " <ALIGNMENT> <FS_IMAGE> <HORD_IMAGE>" |
def main(): |
if (len(sys.argv) < 4): |
usage(sys.argv[0]) |
return |
if (not sys.argv[1].isdigit()): |
print "<ALIGNMENT> must be a number" |
return |
align = int(sys.argv[1], 0) |
if (align <= 0): |
print "<ALIGNMENT> must be positive" |
return |
fs_image = os.path.abspath(sys.argv[2]) |
if (not os.path.isfile(fs_image)): |
print "<FS_IMAGE> must be a file" |
return |
inf = file(fs_image, "rb") |
outf = file(sys.argv[3], "wb") |
header = xstruct.create(HEADER) |
header_size = header.size() |
payload_size = os.path.getsize(fs_image) |
header_size_aligned = align_up(header_size, align) |
payload_size_aligned = align_up(payload_size, align) |
header.tag = "HORD" |
header.version = 1 |
header.encoding = HORD_LSB |
header.header_size = header_size_aligned |
header.payload_size = payload_size_aligned |
outf.write(header.pack()) |
outf.write(xstruct.create("little: padding[%d]" % (header_size_aligned - header_size)).pack()) |
outf.write(inf.read()) |
padding = payload_size_aligned - payload_size |
if (padding > 0): |
outf.write(xstruct.create("little: padding[%d]" % padding).pack()) |
inf.close() |
outf.close() |
if __name__ == '__main__': |
main() |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/branches/dd/tools/config.py |
---|
1,6 → 1,7 |
#!/usr/bin/env python |
# |
# Copyright (c) 2006 Ondrej Palkovsky |
# Copyright (c) 2009 Martin Decky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
27,512 → 28,373 |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
""" |
HelenOS configuration script |
HelenOS configuration system |
""" |
import sys |
import os |
import re |
import commands |
import xtui |
INPUT = sys.argv[1] |
OUTPUT = 'Makefile.config' |
TMPOUTPUT = 'Makefile.config.tmp' |
MAKEFILE = 'Makefile.config' |
MACROS = 'config.h' |
DEFS = 'config.defs' |
class DefaultDialog: |
"Wrapper dialog that tries to return default values" |
def __init__(self, dlg): |
self.dlg = dlg |
def read_defaults(fname, defaults): |
"Read saved values from last configuration run" |
inf = file(fname, 'r') |
for line in inf: |
res = re.match(r'^(?:#!# )?([^#]\w*)\s*=\s*(.*?)\s*$', line) |
if (res): |
defaults[res.group(1)] = res.group(2) |
inf.close() |
def set_title(self,text): |
self.dlg.set_title(text) |
def yesno(self, text, default=None): |
if default is not None: |
return default |
return self.dlg.yesno(text, default) |
def noyes(self, text, default=None): |
if default is not None: |
return default |
return self.dlg.noyes(text, default) |
def choice(self, text, choices, defopt=None): |
if defopt is not None: |
return choices[defopt][0] |
return self.dlg.choice(text, choices, defopt) |
def check_condition(text, defaults, ask_names): |
"Check that the condition specified on input line is True (only CNF and DNF is supported)" |
ctype = 'cnf' |
if ((')|' in text) or ('|(' in text)): |
ctype = 'dnf' |
if (ctype == 'cnf'): |
conds = text.split('&') |
else: |
conds = text.split('|') |
for cond in conds: |
if (cond.startswith('(')) and (cond.endswith(')')): |
cond = cond[1:-1] |
inside = check_inside(cond, defaults, ctype) |
if (ctype == 'cnf') and (not inside): |
return False |
if (ctype == 'dnf') and (inside): |
return True |
if (ctype == 'cnf'): |
return True |
return False |
class NoDialog: |
def __init__(self): |
self.printed = None |
self.title = 'HelenOS Configuration' |
def check_inside(text, defaults, ctype): |
"Check for condition" |
if (ctype == 'cnf'): |
conds = text.split('|') |
else: |
conds = text.split('&') |
for cond in conds: |
res = re.match(r'^(.*?)(!?=)(.*)$', cond) |
if (not res): |
raise RuntimeError("Invalid condition: %s" % cond) |
condname = res.group(1) |
oper = res.group(2) |
condval = res.group(3) |
if (not defaults.has_key(condname)): |
varval = '' |
else: |
varval = defaults[condname] |
if (varval == '*'): |
varval = 'y' |
if (ctype == 'cnf'): |
if (oper == '=') and (condval == varval): |
return True |
if (oper == '!=') and (condval != varval): |
return True |
else: |
if (oper == '=') and (condval != varval): |
return False |
if (oper == '!=') and (condval == varval): |
return False |
if (ctype == 'cnf'): |
return False |
return True |
def print_title(self): |
if not self.printed: |
sys.stdout.write("\n*** %s ***\n" % self.title) |
self.printed = True |
def parse_config(fname, ask_names): |
"Parse configuration file" |
inf = file(fname, 'r') |
name = '' |
choices = [] |
for line in inf: |
if (line.startswith('!')): |
# Ask a question |
res = re.search(r'!\s*(?:\[(.*?)\])?\s*([^\s]+)\s*\((.*)\)\s*$', line) |
if (not res): |
raise RuntimeError("Weird line: %s" % line) |
cond = res.group(1) |
varname = res.group(2) |
vartype = res.group(3) |
ask_names.append((varname, vartype, name, choices, cond)) |
name = '' |
choices = [] |
continue |
if (line.startswith('@')): |
# Add new line into the 'choices' array |
res = re.match(r'@\s*(?:\[(.*?)\])?\s*"(.*?)"\s*(.*)$', line) |
if not res: |
raise RuntimeError("Bad line: %s" % line) |
choices.append((res.group(2), res.group(3))) |
continue |
if (line.startswith('%')): |
# Name of the option |
name = line[1:].strip() |
continue |
if ((line.startswith('#')) or (line == '\n')): |
# Comment or empty line |
continue |
raise RuntimeError("Unknown syntax: %s" % line) |
inf.close() |
def set_title(self, text): |
self.title = text |
self.printed = False |
def noyes(self, text, default=None): |
if not default: |
default = 'n' |
return self.yesno(text, default) |
def yesno(self, text, default=None): |
self.print_title() |
if default != 'n': |
default = 'y' |
while 1: |
sys.stdout.write("%s (y/n)[%s]: " % (text,default)) |
inp = sys.stdin.readline() |
if not inp: |
raise EOFError |
inp = inp.strip().lower() |
if not inp: |
return default |
if inp == 'y': |
return 'y' |
elif inp == 'n': |
return 'n' |
def yes_no(default): |
"Return '*' if yes, ' ' if no" |
if (default == 'y'): |
return '*' |
return ' ' |
def _print_choice(self, text, choices, defopt): |
sys.stdout.write('%s:\n' % text) |
for i,(text,descr) in enumerate(choices): |
if descr is '': |
sys.stdout.write('\t%2d. %s\n' % (i, text)) |
else: |
sys.stdout.write('\t%2d. %s\n' % (i, descr)) |
if defopt is not None: |
sys.stdout.write('Enter choice number[%d]: ' % defopt) |
else: |
sys.stdout.write('Enter choice number: ') |
def subchoice(screen, name, choices, default): |
"Return choice of choices" |
maxkey = 0 |
for key, val in choices: |
length = len(key) |
if (length > maxkey): |
maxkey = length |
options = [] |
position = None |
cnt = 0 |
for key, val in choices: |
if ((default) and (key == default)): |
position = cnt |
options.append(" %-*s %s " % (maxkey, key, val)) |
cnt += 1 |
(button, value) = xtui.choice_window(screen, name, 'Choose value', options, position) |
if (button == 'cancel'): |
return None |
return choices[value][0] |
def menu(self, text, choices, button, defopt=None): |
self.title = 'Main menu' |
menu = [] |
for key, descr in choices: |
txt = key + (45-len(key))*' ' + ': ' + descr |
menu.append((key, txt)) |
return self.choice(text, [button] + menu) |
def choice(self, text, choices, defopt=None): |
self.print_title() |
while 1: |
self._print_choice(text, choices, defopt) |
inp = sys.stdin.readline() |
if not inp: |
raise EOFError |
if not inp.strip(): |
if defopt is not None: |
return choices[defopt][0] |
continue |
try: |
number = int(inp.strip()) |
except ValueError: |
continue |
if number < 0 or number >= len(choices): |
continue |
return choices[number][0] |
def check_choices(defaults, ask_names): |
"Check whether all accessible variables have a default" |
for varname, vartype, name, choices, cond in ask_names: |
if ((cond) and (not check_condition(cond, defaults, ask_names))): |
continue |
if (not defaults.has_key(varname)): |
return False |
return True |
def create_output(mkname, mcname, dfname, defaults, ask_names): |
"Create output configuration" |
revision = commands.getoutput('svnversion . 2> /dev/null') |
timestamp = commands.getoutput('date "+%Y-%m-%d %H:%M:%S"') |
outmk = file(mkname, 'w') |
outmc = file(mcname, 'w') |
outdf = file(dfname, 'w') |
outmk.write('#########################################\n') |
outmk.write('## AUTO-GENERATED FILE, DO NOT EDIT!!! ##\n') |
outmk.write('#########################################\n\n') |
outmc.write('/***************************************\n') |
outmc.write(' * AUTO-GENERATED FILE, DO NOT EDIT!!! *\n') |
outmc.write(' ***************************************/\n\n') |
outdf.write('#########################################\n') |
outdf.write('## AUTO-GENERATED FILE, DO NOT EDIT!!! ##\n') |
outdf.write('#########################################\n\n') |
outdf.write('CONFIG_DEFS =') |
for varname, vartype, name, choices, cond in ask_names: |
if ((cond) and (not check_condition(cond, defaults, ask_names))): |
continue |
if (not defaults.has_key(varname)): |
default = '' |
else: |
default = defaults[varname] |
if (default == '*'): |
default = 'y' |
outmk.write('# %s\n%s = %s\n\n' % (name, varname, default)) |
if ((vartype == "y") or (vartype == "y/n") or (vartype == "n/y")): |
if (default == "y"): |
outmc.write('/* %s */\n#define %s\n\n' % (name, varname)) |
outdf.write(' -D%s' % varname) |
else: |
outmc.write('/* %s */\n#define %s %s\n#define %s_%s\n\n' % (name, varname, default, varname, default)) |
outdf.write(' -D%s=%s -D%s_%s' % (varname, default, varname, default)) |
outmk.write('REVISION = %s\n' % revision) |
outmk.write('TIMESTAMP = %s\n' % timestamp) |
outmc.write('#define REVISION %s\n' % revision) |
outmc.write('#define TIMESTAMP %s\n' % timestamp) |
outdf.write(' "-DREVISION=%s" "-DTIMESTAMP=%s"\n' % (revision, timestamp)) |
outmk.close() |
outmc.close() |
outdf.close() |
def eof_checker(fnc): |
def wrapper(self, *args, **kw): |
try: |
return fnc(self, *args, **kw) |
except EOFError: |
return getattr(self.bckdialog,fnc.func_name)(*args, **kw) |
return wrapper |
class Dialog(NoDialog): |
def __init__(self): |
NoDialog.__init__(self) |
self.dlgcmd = os.environ.get('DIALOG','dialog') |
self.title = '' |
self.backtitle = 'HelenOS Configuration' |
if os.system('%s --print-maxsize >/dev/null 2>&1' % self.dlgcmd) != 0: |
raise NotImplementedError |
self.bckdialog = NoDialog() |
def set_title(self,text): |
self.title = text |
self.bckdialog.set_title(text) |
def calldlg(self,*args,**kw): |
"Wrapper for calling 'dialog' program" |
indesc, outdesc = os.pipe() |
pid = os.fork() |
if not pid: |
os.close(2) |
os.dup(outdesc) |
os.close(indesc) |
dlgargs = [self.dlgcmd,'--title',self.title, |
'--backtitle', self.backtitle] |
for key,val in kw.items(): |
dlgargs.append('--'+key) |
dlgargs.append(val) |
dlgargs += args |
os.execlp(self.dlgcmd,*dlgargs) |
os.close(outdesc) |
try: |
errout = os.fdopen(indesc,'r') |
data = errout.read() |
errout.close() |
pid,status = os.wait() |
except: |
os.system('reset') # Reset terminal |
raise |
if not os.WIFEXITED(status): |
os.system('reset') # Reset terminal |
raise EOFError |
status = os.WEXITSTATUS(status) |
if status == 255: |
raise EOFError |
return status,data |
def yesno(self, text, default=None): |
if text[-1] not in ('?',':'): |
text = text + ':' |
width = '50' |
height = '5' |
if len(text) < 48: |
text = ' '*int(((48-len(text))/2)) + text |
else: |
width = '0' |
height = '0' |
if default == 'n': |
res,data = self.calldlg('--defaultno','--yesno',text,height,width) |
else: |
res,data = self.calldlg('--yesno',text,height,width) |
if res == 0: |
return 'y' |
return 'n' |
yesno = eof_checker(yesno) |
def menu(self, text, choices, button, defopt=None): |
self.title = 'Main menu' |
text = text + ':' |
width = '70' |
height = str(8 + len(choices)) |
args = [] |
for key,val in choices: |
args.append(key) |
args.append(val) |
kw = {} |
if defopt: |
kw['default-item'] = choices[defopt][0] |
res,data = self.calldlg('--ok-label','Change', |
'--extra-label',button[1], |
'--extra-button', |
'--menu',text,height,width, |
str(len(choices)),*args,**kw) |
if res == 3: |
return button[0] |
if res == 1: # Cancel |
sys.exit(1) |
elif res: |
print data |
raise EOFError |
return data |
menu = eof_checker(menu) |
def choice(self, text, choices, defopt=None): |
text = text + ':' |
width = '50' |
height = str(8 + len(choices)) |
args = [] |
for key,val in choices: |
args.append(key) |
args.append(val) |
kw = {} |
if defopt: |
kw['default-item'] = choices[defopt][0] |
res,data = self.calldlg('--nocancel','--menu',text,height,width, |
str(len(choices)),*args, **kw) |
if res: |
print data |
raise EOFError |
return data |
choice = eof_checker(choice) |
def read_defaults(fname,defaults): |
"Read saved values from last configuration run" |
f = file(fname,'r') |
for line in f: |
res = re.match(r'^(?:#!# )?([^#]\w*)\s*=\s*(.*?)\s*$', line) |
if res: |
defaults[res.group(1)] = res.group(2) |
f.close() |
def check_condition(text, defaults, asked_names): |
seen_vars = [ x[0] for x in asked_names ] |
ctype = 'cnf' |
if ')|' in text or '|(' in text: |
ctype = 'dnf' |
if ctype == 'cnf': |
conds = text.split('&') |
else: |
conds = text.split('|') |
for cond in conds: |
if cond.startswith('(') and cond.endswith(')'): |
cond = cond[1:-1] |
inside = check_inside(cond, defaults, ctype, seen_vars) |
if ctype == 'cnf' and not inside: |
return False |
if ctype == 'dnf' and inside: |
return True |
if ctype == 'cnf': |
return True |
return False |
def check_inside(text, defaults, ctype, seen_vars): |
""" |
Check that the condition specified on input line is True |
only CNF is supported |
""" |
if ctype == 'cnf': |
conds = text.split('|') |
else: |
conds = text.split('&') |
for cond in conds: |
res = re.match(r'^(.*?)(!?=)(.*)$', cond) |
if not res: |
raise RuntimeError("Invalid condition: %s" % cond) |
condname = res.group(1) |
oper = res.group(2) |
condval = res.group(3) |
if condname not in seen_vars: |
varval = '' |
## raise RuntimeError("Variable %s not defined before being asked." %\ |
## condname) |
elif not defaults.has_key(condname): |
raise RuntimeError("Condition var %s does not exist: %s" % \ |
(condname,text)) |
else: |
varval = defaults[condname] |
if ctype == 'cnf': |
if oper == '=' and condval == varval: |
return True |
if oper == '!=' and condval != varval: |
return True |
else: |
if oper== '=' and condval != varval: |
return False |
if oper== '!=' and condval == varval: |
return False |
if ctype=='cnf': |
return False |
return True |
def parse_config(input, output, dlg, defaults={}, askonly=None): |
"Parse configuration file and create Makefile.config on the fly" |
def ask_the_question(dialog): |
"Ask question based on the type of variables to ask" |
# This is quite a hack, this thingy is written just to |
# have access to local variables.. |
if vartype == 'y/n': |
return dialog.yesno(comment, default) |
elif vartype == 'n/y': |
return dialog.noyes(comment, default) |
elif vartype == 'choice': |
defopt = None |
if default is not None: |
for i,(key,val) in enumerate(choices): |
if key == default: |
defopt = i |
break |
return dialog.choice(comment, choices, defopt) |
else: |
raise RuntimeError("Bad method: %s" % vartype) |
f = file(input, 'r') |
outf = file(output, 'w') |
outf.write('#########################################\n') |
outf.write('## AUTO-GENERATED FILE, DO NOT EDIT!!! ##\n') |
outf.write('#########################################\n\n') |
asked_names = [] |
comment = '' |
default = None |
choices = [] |
for line in f: |
if line.startswith('%'): |
res = re.match(r'^%\s*(?:\[(.*?)\])?\s*(.*)$', line) |
if not res: |
raise RuntimeError('Invalid command: %s' % line) |
if res.group(1): |
if not check_condition(res.group(1), defaults, |
asked_names): |
continue |
args = res.group(2).strip().split(' ') |
cmd = args[0].lower() |
args = args[1:] |
if cmd == 'saveas': |
outf.write('%s = %s\n' % (args[1],defaults[args[0]])) |
elif cmd == 'shellcmd': |
varname = args[0] |
args = args[1:] |
for i,arg in enumerate(args): |
if arg.startswith('$'): |
args[i] = defaults[arg[1:]] |
data,status = commands.getstatusoutput(' '.join(args)) |
if status: |
raise RuntimeError('Error running: %s' % ' '.join(args)) |
outf.write('%s = %s\n' % (varname,data.strip())) |
continue |
if line.startswith('!'): |
# Ask a question |
res = re.search(r'!\s*(?:\[(.*?)\])?\s*([^\s]+)\s*\((.*)\)\s*$', line) |
if not res: |
raise RuntimeError("Weird line: %s" % line) |
varname = res.group(2) |
vartype = res.group(3) |
default = defaults.get(varname,None) |
if res.group(1): |
if not check_condition(res.group(1), defaults, |
asked_names): |
if default is not None: |
outf.write('#!# %s = %s\n' % (varname, default)) |
# Clear cumulated values |
comment = '' |
default = None |
choices = [] |
continue |
asked_names.append((varname,comment)) |
if default is None or not askonly or askonly == varname: |
default = ask_the_question(dlg) |
else: |
default = ask_the_question(DefaultDialog(dlg)) |
outf.write('%s = %s\n' % (varname, default)) |
# Remeber the selected value |
defaults[varname] = default |
# Clear cumulated values |
comment = '' |
default = None |
choices = [] |
continue |
if line.startswith('@'): |
# Add new line into the 'choice array' |
res = re.match(r'@\s*(?:\[(.*?)\])?\s*"(.*?)"\s*(.*)$', line) |
if not res: |
raise RuntimeError("Bad line: %s" % line) |
if res.group(1): |
if not check_condition(res.group(1),defaults, |
asked_names): |
continue |
choices.append((res.group(2), res.group(3))) |
continue |
# All other things print to output file |
outf.write(line) |
if re.match(r'^#[^#]', line): |
# Last comment before question will be displayed to the user |
comment = line[1:].strip() |
elif line.startswith('## '): |
# Set title of the dialog window |
dlg.set_title(line[2:].strip()) |
outf.write('\n') |
outf.write('REVISION = %s\n' % commands.getoutput('svnversion . 2> /dev/null')) |
outf.write('TIMESTAMP = %s\n' % commands.getoutput('date "+%Y-%m-%d %H:%M:%S"')) |
outf.close() |
f.close() |
return asked_names |
def main(): |
defaults = {} |
try: |
dlg = Dialog() |
except NotImplementedError: |
dlg = NoDialog() |
if len(sys.argv) >= 3 and sys.argv[2]=='default': |
defmode = True |
else: |
defmode = False |
# Default run will update the configuration file |
# with newest options |
if os.path.exists(OUTPUT): |
read_defaults(OUTPUT, defaults) |
# Get ARCH from command line if specified |
if len(sys.argv) >= 4: |
defaults['ARCH'] = sys.argv[3] |
defaults['PLATFORM'] = sys.argv[3] |
defaults = {} |
ask_names = [] |
# Get COMPILER from command line if specified |
if len(sys.argv) >= 5: |
defaults['COMPILER'] = sys.argv[4] |
# Parse configuration file |
parse_config(INPUT, ask_names) |
# Get CONFIG_DEBUG from command line if specified |
if len(sys.argv) >= 6: |
defaults['CONFIG_DEBUG'] = sys.argv[5] |
# Read defaults from previous run |
if os.path.exists(MAKEFILE): |
read_defaults(MAKEFILE, defaults) |
# Get MACHINE/IMAGE from command line if specified |
if len(sys.argv) >= 7: |
defaults['MACHINE'] = sys.argv[6] |
defaults['IMAGE'] = sys.argv[6] |
# Default mode: only check defaults and regenerate configuration |
if ((len(sys.argv) >= 3) and (sys.argv[2] == 'default')): |
if (check_choices(defaults, ask_names)): |
create_output(MAKEFILE, MACROS, DEFS, defaults, ask_names) |
return 0 |
# Check mode: only check defaults |
if ((len(sys.argv) >= 3) and (sys.argv[2] == 'check')): |
if (check_choices(defaults, ask_names)): |
return 0 |
return 1 |
screen = xtui.screen_init() |
try: |
selname = None |
while True: |
# Cancel out all defaults which have to be deduced |
for varname, vartype, name, choices, cond in ask_names: |
if ((vartype == 'y') and (defaults.has_key(varname)) and (defaults[varname] == '*')): |
defaults[varname] = None |
options = [] |
opt2row = {} |
position = None |
cnt = 0 |
for varname, vartype, name, choices, cond in ask_names: |
if ((cond) and (not check_condition(cond, defaults, ask_names))): |
continue |
if (varname == selname): |
position = cnt |
if (not defaults.has_key(varname)): |
default = None |
else: |
default = defaults[varname] |
if (vartype == 'choice'): |
# Check if the default is an acceptable value |
if ((default) and (not default in [choice[0] for choice in choices])): |
default = None |
defaults.pop(varname) |
# If there is just one option, use it |
if (len(choices) == 1): |
defaults[varname] = choices[0][0] |
continue |
if (default == None): |
options.append("? %s --> " % name) |
else: |
options.append(" %s [%s] --> " % (name, default)) |
elif (vartype == 'y'): |
defaults[varname] = '*' |
continue |
elif (vartype == 'y/n'): |
if (default == None): |
default = 'y' |
defaults[varname] = default |
options.append(" <%s> %s " % (yes_no(default), name)) |
elif (vartype == 'n/y'): |
if (default == None): |
default = 'n' |
defaults[varname] = default |
options.append(" <%s> %s " % (yes_no(default), name)) |
else: |
raise RuntimeError("Unknown variable type: %s" % vartype) |
opt2row[cnt] = (varname, vartype, name, choices) |
cnt += 1 |
(button, value) = xtui.choice_window(screen, 'HelenOS configuration', 'Choose configuration option', options, position) |
if (button == 'cancel'): |
return 'Configuration canceled' |
if (not opt2row.has_key(value)): |
raise RuntimeError("Error selecting value: %s" % value) |
(selname, seltype, name, choices) = opt2row[value] |
if (not defaults.has_key(selname)): |
default = None |
else: |
default = defaults[selname] |
if (button == 'done'): |
if (check_choices(defaults, ask_names)): |
break |
else: |
xtui.error_dialog(screen, 'Error', 'Some options have still undefined values. These options are marked with the "?" sign.') |
continue |
if (seltype == 'choice'): |
defaults[selname] = subchoice(screen, name, choices, default) |
elif ((seltype == 'y/n') or (seltype == 'n/y')): |
if (defaults[selname] == 'y'): |
defaults[selname] = 'n' |
else: |
defaults[selname] = 'y' |
finally: |
xtui.screen_done(screen) |
create_output(MAKEFILE, MACROS, DEFS, defaults, ask_names) |
return 0 |
# Dry run only with defaults |
varnames = parse_config(INPUT, TMPOUTPUT, DefaultDialog(dlg), defaults) |
# If not in default mode, present selection of all possibilities |
if not defmode: |
defopt = 0 |
while 1: |
# varnames contains variable names that were in the |
# last question set |
choices = [ (x[1],defaults[x[0]]) for x in varnames ] |
res = dlg.menu('Configuration',choices,('save','Save'),defopt) |
if res == 'save': |
parse_config(INPUT, TMPOUTPUT, DefaultDialog(dlg), defaults) |
break |
# transfer description back to varname |
for i,(vname,descr) in enumerate(varnames): |
if res == descr: |
defopt = i |
break |
# Ask the user a simple question, produce output |
# as if the user answered all the other questions |
# with default answer |
varnames = parse_config(INPUT, TMPOUTPUT, dlg, defaults, |
askonly=varnames[i][0]) |
if os.path.exists(OUTPUT): |
os.unlink(OUTPUT) |
os.rename(TMPOUTPUT, OUTPUT) |
if not defmode and dlg.yesno('Rebuild everything?') == 'y': |
os.execlp('make','make','clean','build') |
if __name__ == '__main__': |
main() |
sys.exit(main()) |