File:  [Isaki's NoNo m68k/m88k emulator] / nono / util / sramedit / sramedit.cpp
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:04:55 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, v026, v025, v024, v023, v022, v021, v020, v019, v018, v017, v016, v015, v014, v013, v012, v011, HEAD
nono 0.2.0

//
// nono
// Copyright (C) 2021 nono project
// Licensed under nono-license.txt
//

//
// X680x0 SRAM.DAT エディタ
//

#include "sramedit.h"
#include <err.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

[[noreturn]] static void usage();
static void calc_width();
static void show();
static void edit(int ac, char *av[]);

static int width;
int debug;
uint8 *sram;

int
main(int ac, char *av[])
{
	const char *filename;
	int c;
	int fd;
	int mode;
	int prot;
	size_t maplen;

	calc_width();

	while ((c = getopt(ac, av, "dh")) != -1) {
		switch (c) {
		 case 'd':
			debug++;
			break;
		 case 'h':
		 default:
			usage();
			break;
		}
	}
	ac -= optind;
	av += optind;

	if (ac == 0) {
		usage();
	}

	filename = av[0];
	ac--;
	av++;

	if (ac == 0) {
		// show
		mode = O_RDONLY;
		prot = PROT_READ;
	} else {
		// edit
		mode = O_RDWR;
		prot = PROT_READ | PROT_WRITE;
	}

	fd = open(filename, mode);
	if (fd < 0) {
		err(1, "%s: open", filename);
	}
	maplen = 0x100;
	int flag = MAP_FILE | MAP_SHARED;
	void *m = mmap(NULL, maplen, prot, flag, fd, 0);
	if (m == MAP_FAILED) {
		err(1, "%s: mmap", filename);
	}
	sram = (uint8 *)m;

	if (ac == 0) {
		show();
	} else {
		edit(ac, av);
	}

	munmap(m, maplen);
	close(fd);
	return 0;
}

static void
usage()
{
	fprintf(stderr, "usage: %s <SRAM.DAT>             .. show all\n",
		getprogname());
	fprintf(stderr, "       %s <SRAM.DAT> <key=value> .. set\n",
		getprogname());
	exit(1);
}

// グローバル変数 width に代入する
static void
calc_width()
{
	width = 0;

	for (const auto& si : sraminfo) {
		if (si.reader == NULL) {
			continue;
		}

		width = std::max(width, (int)strlen(si.name));
	}
}

static void
show1(const sraminfo_t& si)
{
	std::string val = si.reader(si);
	printf("$%02x: %-*s = %s\n", si.offset, width, si.name, val.c_str());
}

static void
show()
{
	for (const auto& si : sraminfo) {
		if (si.reader) {
			show1(si);
		}
	}
}

static void
edit(int ac, char *av[])
{
	int updated = 0;

	for (int i = 0; i < ac; i++) {
		const char *s;
		const char *e;
		std::string key;
		std::string val;

		s = av[i];
		e = strchr(s, '=');
		if (e) {
			key = std::string(s, (e - s));
			val = std::string(e + 1);
		} else {
			key = std::string(s);
		}

		if (key.empty()) {
			warnx("%s: key must be specified", av[i]);
			return;
		}

		bool found = false;
		for (const auto& si : sraminfo) {
			if (strcasecmp(key.c_str(), si.name) != 0) {
				continue;
			}

			if (val.empty()) {
				// key のみなら、現在値と書式ヘルプを表示
				printf("current value:\n\t");
				show1(si);

				if (si.help != NULL) {
					const std::string msg0 = si.help(si);
					// 行頭にタブを追加
					std::string msg = "\t";
					for (auto c : msg0) {
						msg += c;
						if (c == '\n') {
							msg += '\t';
						}
					}
					printf("syntax:\n");
					printf("%s\n", msg.c_str());
				}
				return;
			} else {
				// key=val なら更新
				int result = (si.writer)(si, val);
				if (result == -1) {
					// エラーは向こうで表示済み
					return;
				}
				show1(si);
				// エラーでなければ更新件数を返している
				updated += result;
				found = true;
				break;
			}
		}
		if (!found) {
			warnx("%s: key not found", av[i]);
			return;
		}
	}

	if (updated == 0) {
		printf("Nothing was updated\n");
	} else {
		printf("%d updated\n", updated);
	}
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.