feat(cmat): add cmake build for course material

Add a CMakeLists.txt to each exercise directory, included from
cmat/CMakeLists.txt, so every exercise and solution becomes a buildable
target. GUI exercises link the curses-based DOS_Unix implementations on
Unix-like systems; the Windows-specific DOS variants are not compiled.
Exercises without a portable path or with missing dependencies (Boost)
are reported as not available at configure time.

Targets are excluded from the default build and built by name, e.g.
`cmake --build build --target Ex11`, so intentionally buggy exercises
such as Ex21 do not break the default build.

Also fix two portability issues: rename Ex11bug/pole.h to Pole.h for
case-sensitive filesystems and drop the extra Light:: qualification in
SolutionEx71A/Light.h. Document build commands and layout in AGENTS.md.

Co-authored-by: Qwen 3.8 27B <qwen3.8_27b-q3_k_xl@lmstudio.local>
This commit is contained in:
2026-10-05 11:55:00 +02:00
co-authored by Qwen 3.8 27B
parent e8241fd1ff
commit e09540c2b2
701 changed files with 27282 additions and 16 deletions
+11
View File
@@ -0,0 +1,11 @@
# Ex71
cmat_add_exercise(Ex71
SOURCES
CompanyEntry.cpp
CountVisitor.cpp
FindVisitor.cpp
GroupEntry.cpp
main.cpp
PersonEntry.cpp
)
+19
View File
@@ -0,0 +1,19 @@
#include <iomanip>
#include <iostream>
#include "CompanyEntry.h"
#include "EntryVisitor.h"
CompanyEntry::CompanyEntry(std::string name, std::string category, std::string phone)
: Entry(name), _category(category), _phone(phone) {}
void CompanyEntry::print(std::string indent) const {
std::cout << indent << "Company: " << getName() << " <" << _category << "> " << _phone << '\n';
}
std::string CompanyEntry::getPhone() const { return _phone; }
std::string CompanyEntry::getCategory() const { return _category; }
void CompanyEntry::accept(EntryVisitor &v) const { v.visit(*this); }
+22
View File
@@ -0,0 +1,22 @@
#ifndef COMPANYENTRY_H
#define COMPANYENTRY_H
#include "Entry.h"
class CompanyEntry : public Entry {
public:
CompanyEntry(std::string name, std::string category, std::string phone);
void print(std::string indent = "") const;
std::string getPhone() const;
std::string getCategory() const;
void accept(EntryVisitor &) const;
private:
std::string _category;
std::string _phone;
};
#endif
+2
View File
@@ -0,0 +1,2 @@
#include "CountVisitor.h"
#include <iostream>
+7
View File
@@ -0,0 +1,7 @@
#ifndef COUNTVISITOR_H
#define COUNTVISITOR_H
#include "EntryVisitor.h"
class CountVisitor {};
#endif
+5
View File
@@ -0,0 +1,5 @@
// Entry.cpp
#include "Entry.h"
Entry::Entry(std::string name) : _name(name), _phone(phone) {}
+23
View File
@@ -0,0 +1,23 @@
#ifndef ENTRY_H
#define ENTRY_H
#include <string>
class EntryVisitor;
class Entry {
public:
Entry(std::string name) : _name(name) {}
std::string getName() const { return _name; }
virtual void print(std::string indent = "") const = 0;
virtual void accept(EntryVisitor &) const = 0;
private:
std::string _name;
};
#endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef ENTRYVISITOR_H
#define ENTRYVISITOR_H
class PersonEntry;
class CompanyEntry;
class GroupEntry;
class EntryVisitor {
public:
virtual void visit(const PersonEntry &) = 0;
virtual void visit(const CompanyEntry &) = 0;
virtual void visit(const GroupEntry &) = 0;
};
#endif
+21
View File
@@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.21005.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ex71", "Ex71.vcxproj", "{3BE8ED56-4FC0-F86D-B9E1-1EE211AF78DB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3BE8ED56-4FC0-F86D-B9E1-1EE211AF78DB}.Debug|Win32.ActiveCfg = Debug|Win32
{3BE8ED56-4FC0-F86D-B9E1-1EE211AF78DB}.Debug|Win32.Build.0 = Debug|Win32
{3BE8ED56-4FC0-F86D-B9E1-1EE211AF78DB}.Release|Win32.ActiveCfg = Release|Win32
{3BE8ED56-4FC0-F86D-B9E1-1EE211AF78DB}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
Binary file not shown.
+136
View File
@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<ProjectGuid>{3BE8ED56-4FC0-F86D-B9E1-1EE211AF78DB}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>
</PrecompiledHeader>
<PrecompiledHeaderOutputFile>.\Release/Ex71A.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>.\Release/</AssemblerListingLocation>
<ObjectFileName>.\Release/</ObjectFileName>
<ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Release/Ex71A.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ProgramDatabaseFile>.\Release/Ex71A.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
</Link>
<Midl>
<TypeLibraryName>.\Release/Ex71A.tlb</TypeLibraryName>
</Midl>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0809</Culture>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderOutputFile>.\Debug/Ex71A.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
<ObjectFileName>.\Debug/</ObjectFileName>
<ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalIncludeDirectories>C:\course\397\DOS_Unix;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Debug/Ex71.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/Ex71A.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
</Link>
<Midl>
<TypeLibraryName>.\Debug/Ex71A.tlb</TypeLibraryName>
</Midl>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0809</Culture>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="CompanyEntry.cpp" />
<ClCompile Include="CountVisitor.cpp" />
<ClCompile Include="GroupEntry.cpp" />
<ClCompile Include="FindVisitor.cpp" />
<ClCompile Include="PersonEntry.cpp" />
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="CompanyEntry.h" />
<ClInclude Include="CountVisitor.h" />
<ClInclude Include="Entry.h" />
<ClInclude Include="EntryVisitor.h" />
<ClInclude Include="GroupEntry.h" />
<ClInclude Include="FindVisitor.h" />
<ClInclude Include="PersonEntry.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+56
View File
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{a373d85d-0daa-4771-a2af-24735700f4b5}</UniqueIdentifier>
<Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{28280df5-d09d-4335-a70c-dd81eee4485f}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="GroupEntry.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PersonEntry.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CompanyEntry.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FindVisitor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CountVisitor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Entry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EntryVisitor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GroupEntry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PersonEntry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CompanyEntry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FindVisitor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CountVisitor.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
+3
View File
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
+31
View File
@@ -0,0 +1,31 @@
#include <iostream>
#include "CompanyEntry.h"
#include "FindVisitor.h"
#include "GroupEntry.h"
#include "PersonEntry.h"
FindVisitor::FindVisitor(std::string query) : _query(query) {}
const std::vector<const Entry *> &FindVisitor::getFindings() { return findings; }
void FindVisitor::visit(const PersonEntry &s) {
if (s.getName().find(_query) != std::string::npos) {
findings.push_back(&s);
}
}
void FindVisitor::visit(const GroupEntry &g) {
if (g.getName().find(_query) != std::string::npos) {
findings.push_back(&g);
}
}
void FindVisitor::visit(const CompanyEntry &c) {
if (c.getName().find(_query) != std::string::npos || c.getCategory().find(_query) != std::string::npos) {
findings.push_back(&c);
}
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef FINDVISITOR_H
#define FINDVISITOR_H
#include "Entry.h"
#include "EntryVisitor.h"
#include <vector>
class FindVisitor : public EntryVisitor {
std::string _query; // looking for this
std::vector<const Entry *> findings; // finding these entries
public:
FindVisitor(std::string query);
const std::vector<const Entry *> &getFindings();
void visit(const PersonEntry &);
void visit(const CompanyEntry &);
void visit(const GroupEntry &);
};
#endif
+31
View File
@@ -0,0 +1,31 @@
#include <iostream>
#include "EntryVisitor.h"
#include "GroupEntry.h"
#include "PersonEntry.h"
GroupEntry::GroupEntry(std::string name) : Entry(name) {}
void GroupEntry::print(std::string indent) const {
// PART 1 implement print here
// When you call print for the child objects, extend the indent string argument
// with a couple of more space characters.
}
void GroupEntry::addEntry(const Entry &entry) {
// Part 1: Add the entry to this group
_entries.push_back(&entry);
}
void GroupEntry::accept(EntryVisitor &v) const {
v.visit(*this);
// pass visitor to my children
for (auto p : _entries) {
p->accept(v);
}
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef GROUPENTRY_H
#define GROUPENTRY_H
#include <map>
#include <string>
#include <vector>
#include "Entry.h"
#include "PersonEntry.h"
class GroupEntry : public Entry {
public:
GroupEntry(std::string name);
// print the entire group, including its members
// precede the name with the "indent" string
void print(std::string indent = "") const;
// child management
void addEntry(const Entry &);
void accept(EntryVisitor &) const;
private:
std::vector<const Entry *> _entries;
};
#endif
+18
View File
@@ -0,0 +1,18 @@
#include <iomanip>
#include <iostream>
#include "EntryVisitor.h"
#include "PersonEntry.h"
PersonEntry::PersonEntry(std::string name, std::string phone) : Entry(name), _phone(phone) {}
void PersonEntry::print(std::string indent) const {
std::cout << indent << "Person: " << getName() << ' ' << _phone << '\n';
}
std::string PersonEntry::getPhone() const { return _phone; }
void PersonEntry::accept(EntryVisitor &v) const { v.visit(*this); }
+22
View File
@@ -0,0 +1,22 @@
#ifndef PERSONENTRY_H
#define PERSONENTRY_H
#include "Entry.h"
class PersonEntry : public Entry {
public:
PersonEntry(std::string name, std::string phone);
void print(std::string indent = "") const;
std::string getPhone() const;
void accept(EntryVisitor &) const;
private:
std::string _phone;
};
#endif
+68
View File
@@ -0,0 +1,68 @@
#include "CompanyEntry.h"
#include "CountVisitor.h"
#include "FindVisitor.h"
#include "GroupEntry.h"
#include "PersonEntry.h"
#include <iostream>
using namespace std;
int main() {
// declare an address book
GroupEntry addressbook("My addressbook");
// create some entries
PersonEntry Fred("Fred", "555 1234");
PersonEntry Gert("Gert", "555 1235");
PersonEntry Jim("Jim", "999 2445");
PersonEntry Sue("Sue", "456 2951");
PersonEntry Ingar("Ingar", "999 2345");
PersonEntry Lisa("Lisa", "443 4532");
CompanyEntry ShoeWorld("ShoeWorld", "Shoes", "234 4314");
CompanyEntry BestBurgers("BestBurgers", "Food", "456 4651");
CompanyEntry DreamPizza("DreamPizza", "Food", "935 2345");
CompanyEntry BestBooks("BestBooks", "Books", "345 3232");
// add some simple entries
addressbook.addEntry(Fred);
addressbook.addEntry(Gert);
addressbook.addEntry(ShoeWorld);
// make some groups
GroupEntry group1("My Best Food");
group1.addEntry(BestBurgers);
group1.addEntry(DreamPizza);
GroupEntry group2("Coworkers");
group2.addEntry(Jim);
group2.addEntry(Sue);
// make a nested group
GroupEntry group3("Favorites");
group3.addEntry(Ingar);
group3.addEntry(Lisa);
group3.addEntry(BestBooks);
group3.addEntry(group1);
addressbook.addEntry(group2);
addressbook.addEntry(group3);
cout << "*** Print using Composite print operation\n";
addressbook.print();
cout << "*** Find using Visitor\n";
FindVisitor pv("Fred");
addressbook.accept(pv);
for (const Entry *p : pv.getFindings()) {
p->print();
}
// PART 2 Create a CountVisitor and let it visit the address book
// cout << "*** Count objects using Visitor\n";
cout << "*** Test complete\n";
return 0;
}