#
#  Makefile - p50emu, a Westinghouse Prodac-50 emulator
#
# Copyright (c) 2026 Large Scale Systems Museum
# By Dave McGuire <mcguire@lssmuseum.org>
#
#
# Targets:
#   all (default)  build the emulator, src/p50emu, and its man page,
#                  docs/p50emu.1 (from docs/p50emu.1.in, with the version
#                  number filled in from src/version.h)
#   examples       assemble the example .p50tap tapes from their .p50
#                  sources (requires p50asm, a companion project, on
#                  $PATH; the tapes aren't stored in the repository)
#   test           build, then run the test suite in tests/
#   install        install the emulator into $(PREFIX)/bin, its man page
#                  into $(PREFIX)/share/man/man1, and its manual, license,
#                  and sample config into $(PREFIX)/share/doc/<progname>;
#                  PREFIX defaults to
#                  /usr/local, and DESTDIR is honored for staged installs
#   clangd         build under bear to generate compile_commands.json
#   dist           create <progname>-<version>.tar.bz2, with the name and
#                  version taken from src/version.h, containing
#                  everything needed to build, test, and use the
#                  emulator (and nothing from Subversion)
#   clean          remove everything the other targets build
#

CC = cc
CFLAGS = -Wall -Wextra -std=c99 -O2 -D_POSIX_C_SOURCE=200809L
LDFLAGS =
LDLIBS = -lncursesw

# MacOS X hides everything beyond strict POSIX (INADDR_LOOPBACK,
# TCP_NODELAY, the faster B<N> baud constants, ...) when _POSIX_C_SOURCE
# is defined, unless _DARWIN_C_SOURCE is also defined. Its system ncurses
# is already the wide-character build, and is named plain libncurses.
ifeq ($(shell uname -s),Darwin)
CFLAGS += -D_DARWIN_C_SOURCE
LDLIBS = -lncurses
endif
P50ASM = p50asm
PYTHON = python3
INSTALL = install

PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
MANDIR = $(PREFIX)/share/man/man1
DOCINSTDIR = $(PREFIX)/share/doc/$(PROGNAME)

SRCDIR = src
EXDIR = examples
TESTDIR = tests
DOCDIR = docs

PROGNAME := $(shell sed -n 's/^#define P50EMU_PROGNAME[ \t]*"\(.*\)".*/\1/p' $(SRCDIR)/version.h)
VERSION  := $(shell sed -n 's/^#define P50EMU_VERSION[ \t]*"\(.*\)".*/\1/p' $(SRCDIR)/version.h)
DISTDIR  = $(PROGNAME)-$(VERSION)

PROG = $(SRCDIR)/p50emu
SRCS = $(SRCDIR)/p50core.c $(SRCDIR)/p50tty.c $(SRCDIR)/p50file.c \
       $(SRCDIR)/p50throttle.c $(SRCDIR)/p50cli.c $(SRCDIR)/p50panel.c \
       $(SRCDIR)/main.c
HDRS = $(SRCDIR)/p50core.h $(SRCDIR)/p50tty.h $(SRCDIR)/p50file.h \
       $(SRCDIR)/p50throttle.h \
       $(SRCDIR)/p50ui.h $(SRCDIR)/version.h
OBJS = $(SRCS:.c=.o)
MANPAGE = $(DOCDIR)/$(PROGNAME).1

# Each example's entry point (octal), passed to p50asm as --entry.
ENTRY_add_demo = 200
ENTRY_manual_examples_demo = 300
ENTRY_teletype_ascii_sweep = 200
ENTRY_teletype_echo = 200

TAPES = $(EXDIR)/add_demo.p50tap $(EXDIR)/manual_examples_demo.p50tap \
        $(EXDIR)/teletype_ascii_sweep.p50tap $(EXDIR)/teletype_echo.p50tap

# Everything that goes into the distribution, beyond $(SRCS) and $(HDRS).
# These are explicit lists rather than wildcards so that editor backups,
# build products, and local scratch files can't end up in a release.
DOCS = README.md
DOC_FILES = $(DOCDIR)/MANUAL.md $(DOCDIR)/LICENSE.md $(DOCDIR)/p50.cfg-sample
EXAMPLE_FILES = $(TAPES:.p50tap=.p50) $(TAPES:.p50tap=.cfg) \
                $(EXDIR)/add_demo_gen.py $(EXDIR)/manual_examples_demo_gen.py \
                $(EXDIR)/teletype_echo_gen.py
TEST_FILES = $(TESTDIR)/README.md $(TESTDIR)/test_command_execute.py \
             $(TESTDIR)/command_execute_data.py $(TESTDIR)/p50_harness.py \
             $(TESTDIR)/command_execute_test.cfg $(TESTDIR)/test_panel.py $(TESTDIR)/test_function_switch.py

all: $(PROG) $(MANPAGE)

$(PROG): $(OBJS)
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

$(MANPAGE): $(MANPAGE).in $(SRCDIR)/version.h
	sed 's/@VERSION@/$(VERSION)/g' $(MANPAGE).in > $@

$(SRCDIR)/%.o: $(SRCDIR)/%.c
	$(CC) $(CFLAGS) -c $< -o $@

$(SRCDIR)/p50core.o: $(SRCDIR)/p50core.h $(SRCDIR)/version.h
$(SRCDIR)/p50tty.o: $(SRCDIR)/p50tty.h $(SRCDIR)/version.h
$(SRCDIR)/p50file.o: $(SRCDIR)/p50file.h $(SRCDIR)/version.h
$(SRCDIR)/p50throttle.o: $(SRCDIR)/p50throttle.h $(SRCDIR)/p50core.h
$(SRCDIR)/p50cli.o: $(SRCDIR)/p50throttle.h $(SRCDIR)/p50core.h $(SRCDIR)/p50ui.h $(SRCDIR)/p50tty.h $(SRCDIR)/p50file.h \
                  $(SRCDIR)/version.h
$(SRCDIR)/p50panel.o: $(SRCDIR)/p50throttle.h $(SRCDIR)/p50core.h $(SRCDIR)/p50ui.h $(SRCDIR)/p50tty.h $(SRCDIR)/p50file.h \
                    $(SRCDIR)/version.h
$(SRCDIR)/main.o: $(SRCDIR)/p50core.h $(SRCDIR)/p50ui.h $(SRCDIR)/p50tty.h $(SRCDIR)/p50file.h \
                  $(SRCDIR)/version.h

examples: $(TAPES)

$(EXDIR)/%.p50tap: $(EXDIR)/%.p50
	cd $(EXDIR) && $(P50ASM) --output=$*.p50tap --entry=$(ENTRY_$*) $*.p50

test: all
	cd $(TESTDIR) && $(PYTHON) -m unittest discover -s . -p "test_*.py" -v

install: all
	$(INSTALL) -d $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR) $(DESTDIR)$(DOCINSTDIR)
	$(INSTALL) -m 755 $(PROG) $(DESTDIR)$(BINDIR)
	$(INSTALL) -m 644 $(MANPAGE) $(DESTDIR)$(MANDIR)
	$(INSTALL) -m 644 $(DOC_FILES) $(DESTDIR)$(DOCINSTDIR)

clangd:
	bear -- make

dist:
	@rm -rf $(DISTDIR)
	@rm -f $(DISTDIR).tar.bz2
	@mkdir -p $(DISTDIR)/$(SRCDIR) $(DISTDIR)/$(EXDIR) $(DISTDIR)/$(TESTDIR) \
		$(DISTDIR)/$(DOCDIR)
	@cp Makefile $(DOCS) $(DISTDIR)
	@cp $(SRCS) $(HDRS) $(DISTDIR)/$(SRCDIR)
	@cp $(EXAMPLE_FILES) $(DISTDIR)/$(EXDIR)
	@cp $(TEST_FILES) $(DISTDIR)/$(TESTDIR)
	@cp $(DOC_FILES) $(MANPAGE).in $(DISTDIR)/$(DOCDIR)
	@tar -cjf $(DISTDIR).tar.bz2 $(DISTDIR)
	@rm -rf $(DISTDIR)
	@echo Distribution file $(DISTDIR).tar.bz2 created.

clean:
	rm -f $(PROG) $(OBJS) $(MANPAGE) $(TAPES) $(EXDIR)/*.lst
	rm -rf $(TESTDIR)/__pycache__

.PHONY: all examples test install clangd dist clean
