Check-in [b7de7b4c7c]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Initial commit
Timelines: family | ancestors | trunk
Files: files | file ages | folders
SHA1:b7de7b4c7cfeddda59e818fae16ee0b3cb2e5f39
User & Date: mh 2014-08-29 00:08:12
Context
2014-08-29
00:08
Initial commit Leaf check-in: b7de7b4c7c user: mh tags: trunk
2014-08-28
15:08
initial empty check-in check-in: e2f156395e user: machel tags: trunk
Changes

Added BuildRecipes/Makefile.



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
# ### === Machel's MAKEFILE ### ===


# :: File:
#    .. project/file:         Makefile <GNU Make>
#     .
#    .. info:
#     .   Created:            2014-01-12 by "Machel"
#     .   Last modified:      2014-07-12 by "Machel"
#     .   License:            GNU Public License
#     .   (c) Copyright:      "Machel" 2014
#     .
#    .. dependencies:
#         -- GNU Make    - many specific features used
#         -- GCC         - dependency creation feature used
#
# :: Description:
#  . Makefile for Machel's C/C++ projects.
#  . May be used in all Machel's C/C++ projects adhering to certain project
#    layout
#
# :: Functionality:
#   -- sources: auto hunting up source files
#    - inside all src* and lib* directories one level deep
#    - for files with 'c/cxx' suffix (.c/.cxx)
#
#   -- headers: auto determine directories with header files
#    - header files are assumed to exist in source dirs ONLY thus header dirs
#      are the same as source dirs
#
#   -- shell scripts: files with .sh extension auto copied from sh_scripts
#      directory to .bin (extension is removed)
#
#   -- documentation: auto created from files resisting in doc directory and
#      having proper suffix (see targets for docs)
#
#   -- dependencies: auto generates dependency files
#    - depfile is created for each object file, and object file is assumed for
#      each source file
#    - object files depends on corresponding source file and all header files
#      included by this source file
#    - depfile depends on same files to ensure it is recreated each time one
#      of that files is changed (in case included files changed)
#    - depfile lists all dependencies being header files as targets themselves
#      to suppress errors if they do not exist (programmer could remove them
#      from includes in source file and from file system or rename)
#
#   -- separate dirs: files generated by compiler and auxillary files
#      (like depfiles) are placed in separate dirs to not mix them up
#      with source and header files
#    - executables go to '.bin'
#    - object files go to '.build'
#    - depfiles go to '.deps'
#    - GENERAL: temporary files go to dirs begining with dots, except packages
#      which goes to .packages directory
#
#   -- static checks: splint, flawfinder, rats, clang analyzer
#
#   -- debug builds: several levels with different warning flags
#
#   -- cleanup: cleanup project directories
#    - shallow cleans - remove specific files
#    - deep cleans - remove all created dirs and leave project in original state
#    - see clean targets for details
#
# :: Limitations:
#   --- header files are assumed to be only in same dirs as source files
#   --- can't use compiler other then GCC for reason of dependency creation



SHELL := /bin/sh

REQUIRED_FILES := NAME VERSION BuildRecipes/ProjSettings.mk BuildRecipes/mk_hllibs.sh
RES := $(wildcard $(REQUIRED_FILES))
ifneq ($(RES),$(REQUIRED_FILES))
  $(error "One of following files does not exist: $(REQUIRED_FILES)"))
endif




# === USER SETTINGS ===
include BuildRecipes/ProjSettings.mk


# --- BASE SETTINGS ---
PRNAME := $(shell cat NAME)

VERSION := $(patsubst VER%,,$(shell cat VERSION))
VERSION := $(subst \#define ,,$(VERSION))
SPACE_ :=
SPACE_ +=
VERSION := $(subst $(SPACE_),.,$(VERSION))

PACK_NAME := $(PRNAME)-$(VERSION)


ifeq ($(PR_LANG),C)
PROJS_MAIN_DIR := /home/Magazyn/Projects/c
else ifeq ($(PR_LANG),CXX)
PROJS_MAIN_DIR := /home/Magazyn/Projects/cxx
else
$(error "Invalid PR_LANG value")
endif



# --- INSTALL SETTINGS ---
DESTDIR ?=

prefix ?= /usr
confdir ?= /etc
bindir := $(prefix)/bin
libdir := $(prefix)/lib
mandir ?= /usr/share/man

appdatadir ?= /usr/share/$(PRNAME)
vimdatadir := $(appdatadir)/vim/vimfiles
vimdir ?= /usr/share/vim/vimfiles



# --- BUILD LAYOUT SETTINGS ---

# SOURCE FILES
ARCH_BUNDLE := BuildRecipes/arch
DIR_DOCS_SRCS := doc
DIR_SCRIPTS_SRCS := sh_scripts

SOURCES_TESTS_C := $(wildcard src*/*_test.c src*/**/*_test.c)
SOURCES_EXECS_C := $(wildcard src*/*_exec.c src*/**/*_exec.c)
SOURCES_ALL_C := $(wildcard src*/*.c src*/**/*.c lib_*/*.c lib_*/**/*.c)
SOURCES_C := $(filter-out $(SOURCES_TESTS_C),$(SOURCES_ALL_C))
SOURCES_C := $(filter-out $(SOURCES_EXECS_C),$(SOURCES_C))
SOURCES_TESTS_C += $(wildcard tests*/*.c tests*/**/*.c)
SOURCES_EXECS_C += $(wildcard execs*/*.c execs*/**/*.c)

ifeq ($(PR_LANG),CXX)
SOURCES_TESTS_CXX := $(wildcard src*/*_test.cxx src*/**/*_test.cxx)
SOURCES_EXECS_CXX := $(wildcard src*/*_exec.cxx src*/**/*_exec.cxx)
SOURCES_ALL_CXX := $(wildcard src*/*.cxx src*/**/*.cxx lib_*/*.cxx lib_*/**/*.cxx)
SOURCES_CXX := $(filter-out $(SOURCES_TESTS_CXX),$(SOURCES_ALL_CXX))
SOURCES_CXX := $(filter-out $(SOURCES_EXECS_CXX),$(SOURCES_CXX))
SOURCES_TESTS_CXX += $(wildcard tests*/*.cxx tests*/**/*.cxx)
SOURCES_EXECS_CXX += $(wildcard execs*/*.cxx execs*/**/*.cxx)
endif

SOURCES_TESTS := $(SOURCES_TESTS_C) $(SOURCES_TESTS_CXX)
SOURCES_EXECS := $(SOURCES_EXECS_C) $(SOURCES_EXECS_CXX)
SOURCES_ALL := $(SOURCES_ALL_C) $(SOURCES_ALL_CXX)
SOURCES := $(SOURCES_C) $(SOURCES_CXX)

#$(info $(SOURCES_TESTS))
#$(info $(SOURCES_EXECS))
#$(info $(SOURCES_ALL))
#$(info $(SOURCES))

SOURCES_SCRIPTS ?=
SOURCES_SCRIPTS += $(wildcard $(DIR_SCRIPTS_SRCS)/*.sh)
SOURCES_VIM ?=
SOURCES_VIM += $(wildcard vim_*/**/*.vim)
# ex. 'manpage.1.man.t2t' where '1' is section number
SOURCES_DOCS_MANS ?=
SOURCES_DOCS_MANS += $(wildcard $(DIR_DOCS_SRCS)/*.man.t2t)
SOURCES_DOCS_HTMLS ?=
SOURCES_DOCS_HTMLS += $(wildcard $(DIR_DOCS_SRCS)/*.html.t2t)
SOURCES_DOCS_MAINS ?=
SOURCES_DOCS_MAINS += $(wildcard $(DIR_DOCS_SRCS)/*.main.t2t)
SOURCES_DOCS_MDS ?=
SOURCES_DOCS_MDS += $(wildcard $(DIR_DOCS_SRCS)/*.md)

# TARGET FILES
DIR_DOCS := doc
DIR_BIN := .bin
DIR_VIM := .vim
DIR_PACK := .packages
DIR_ANALYSE := .analyse
ANALYZE_OUTPUT_FILE := static_analysis.txt

TAR_TESTS := $(DIR_BIN)/$(PRNAME)_test
TAR_LIBS := $(DIR_BIN)/$(PRNAME).a
TAR_EXECS := $(DIR_BIN)/$(PRNAME)
TAR_SCRIPTS := $(patsubst %.sh,$(DIR_BIN)/%,$(notdir $(SOURCES_SCRIPTS)))

TAR_VIM_FILES := $(notdir $(SOURCES_VIM))
TAR_VIM_DIRS := $(notdir $(patsubst %/,%,$(dir $(SOURCES_VIM))))
TAR_VIM := $(addprefix $(DIR_VIM)/,$(SOURCES_VIM))

DOC_MANS := $(patsubst %.man.t2t,$(DIR_DOCS)/man/%.gz,$(notdir $(SOURCES_DOCS_MANS)))
DOC_HTMLS := $(patsubst %.html.t2t,$(DIR_DOCS)/html/%.html,$(notdir $(SOURCES_DOCS_HTMLS)))
DOC_MAINS := $(patsubst %.main.t2t,$(DIR_DOCS)/mains/%,$(notdir $(SOURCES_DOCS_MAINS)))
DOC_MDS := $(patsubst %.md,$(DIR_DOCS)/md/%.md,$(notdir $(SOURCES_DOCS_MDS)))

DOCS := $(DOC_MANS) $(DOC_HTMLS) $(DOC_MAINS) $(DOC_MDS)


# --- BUILD OPTIONS ---
ifeq ($(PR_LANG),C)
CC = gcc
STD_FLAGS := -std=c99 -pedantic
else ifeq ($(PR_LANG),CXX)
CC = /usr/bin/g++
STD_FLAGS := -std=c++11 -pedantic
endif
COMPILER := $(CC) -pipe #-fdiagnostics-color
CPP_FLAGS :=
ARCH_FLAGS := -march=native -mtune=native
OPTIMIZE_FLAGS := -fstrict-aliasing -Wdisabled-optimization -minline-all-stringops \
   -funroll-loops -momit-leaf-frame-pointer
#<C++>: -fstrict-enums

WARN_FLAGS := -Wall -Wextra -Wshadow -Wwrite-strings -Wpointer-arith -Wcast-qual \
   -Wcast-align -Wswitch-default -Wswitch-enum \
   -Wstrict-overflow=2 -Wredundant-decls \
   -Wlogical-op -Wfloat-equal -Wmissing-include-dirs
   #ev. -Wno-unused-parameter #ev. -Wno-unused-value
WARN2_FLAGS := -Wundef -Wstrict-overflow=5 -Wconversion -Wunsuffixed-float-constants \
   -Wdouble-promotion -Wunused -Wuninitialized -Winit-self -Wfloat-equal \
   -Wbad-function-cast -Wjump-misses-init -Wpadded -Winline -Wformat=2 \
   -Werror-implicit-function-declaration -Wunused-parameter -Wunused
NOWARN_DEPL := -Wno-cast-qual -Wno-pedantic -Wno-unused-parameter

ifeq ($(PR_LANG),C)
WARN_FLAGS += -Wstrict-prototypes -Wnested-externs
else ifeq ($(PR_LANG),CXX)
WARN_FLAGS += -Wctor-dtor-privacy -Wnon-virtual-dtor -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Weffc++
endif

TOOLS_FLAGS := -ggdb3 -pg
DIAGNOSE_FLAGS := -fmem-report -fprofile-report -fstack-usage -ftest-coverage -Q \
   -fdump-translation-unit -fdump-class-hierarchy -save-temps

DBG_COMMON_FLAGS := -DDEBUG -fno-eliminate-unused-debug-types -ftrapv -fstack-check
DBG_FLAGS := -O0 $(DBG_COMMON_FLAGS) $(TOOLS_FLAGS) $(WARN_FLAGS)
DBG2_FLAGS := -O2 $(DBG_COMMON_FLAGS) $(TOOLS_FLAGS) $(WARN2_FLAGS) -DDEBUG2
DBG3_FLAGS := -O3 $(DBG_COMMON_FLAGS) $(TOOLS_FLAGS) $(WARN2_FLAGS) \
   -fmudflap -Wno-nested-externs -fstack-protector-all -lmudflap
# -fmudflap - check arrays/heap bounds		;needs special lib
# -fmudflapth - check arrays/heap bounds for multi-th pr

DEPL_FLAGS := -O3 -DNDEBUG $(WARN_FLAGS) $(NOWARN_DEPL) -fomit-frame-pointer -g
TEST_FLAGS := -O3 -DDEBUG2 $(WARN_FLAGS) $(TOOLS_FLAGS)
#-finline-functions - try inline all simple enough funs

MSGS_FLAGS := -fmessage-length=0 -fmax-errors=10
#<C++>: -fno-pretty-templates




# === TRANSITIONAL FILES ===
DIR_OBJS := .build
DIR_DEPS := .deps

DEPS := $(SOURCES:%.c=$(DIR_DEPS)/%.dep)
DEPS_TESTS := $(SOURCES_TESTS:%.c=$(DIR_DEPS)/%.dep)
DEPS_EXECS := $(SOURCES_EXECS:%.c=$(DIR_DEPS)/%.dep)

OBJECTS := $(patsubst %.c,$(DIR_OBJS)/%.o,$(SOURCES))
OBJECTS_TESTS := $(patsubst %.c,$(DIR_OBJS)/%.o,$(SOURCES_TESTS))
OBJECTS_EXEC := $(patsubst %.c,$(DIR_OBJS)/%.o,$(SOURCES_EXECS))


ifeq ($(PR_LANG),CXX)
DEPS := $(DEPS:%.cxx=$(DIR_DEPS)/%.dep)
DEPS_TESTS := $(DEPS_TESTS:%.cxx=$(DIR_DEPS)/%.dep)
DEPS_EXECS := $(DEPS_EXECS:%.cxx=$(DIR_DEPS)/%.dep)

OBJECTS := $(patsubst %.cxx,$(DIR_OBJS)/%.o,$(OBJECTS))
OBJECTS_TESTS := $(patsubst %.cxx,$(DIR_OBJS)/%.o,$(OBJECTS_TESTS))
OBJECTS_EXEC := $(patsubst %.cxx,$(DIR_OBJS)/%.o,$(OBJECTS_EXECS))
endif

#$(info $(OBJECTS))
#$(info $(OBJECTS_TESTS))
#$(error ABORT)


SOURCES_DOCS := $(wildcard doc*/*.t2t)

DIRS_INCLUDES := . $(wildcard src*) $(filter %/, $(wildcard src*/**/))
DIRS_INCLUDES += $(wildcard include*) $(filter %/, $(wildcard include*/**/))
DIRS_INCLUDES += $(wildcard lib_*) $(filter %/, $(wildcard lib_*/**/))
INCLUDES_OPTS := $(patsubst %,-I%,$(DIRS_INCLUDES))
LIBRARIES := $(wildcard lib/*.a)
LIBRARIES := $(patsubst lib/lib%.a,-l%,$(LIBRARIES))

CPPFLAGS := $(CPP_FLAGS) $(INCLUDES_OPTS)
CFLAGS := $(STD_FLAGS) $(ARCH_FLAGS) $(MSGS_FLAGS) $(OPTIMIZE_FLAGS)
LFLAGS := -L./lib $(LIBRARIES)




DIRS_CONCAT := $(DIR_BIN) $(DIR_OBJS) $(DIR_DEPS) $(DIR_DOCS) $(DIR_PACK) $(DIR_VIM) $(DIR_ANALYSE)




# === TARGETS ===


# --- General targets ---
all:  depl docs

# print help
.PHONY: help
help:
	@echo "make DESTDIR=/dir install  - install to /dir (def. is /usr)"

# createllibs
hllibs:
	@BuildRecipes/mk_hllibs.sh "$(PR_LANG)" "$(PROJS_MAIN_DIR)"




# --- Main targets ---
debug: CFLAGS+=$(DBG_FLAGS)
debug: OUT_REDIRECT := >diagnose.txt 2>&1
debug: prepare $(TAR_TESTS)

debug2: CFLAGS+=$(DBG2_FLAGS)
debug2: prepare $(TAR_TESTS)

debug3: CFLAGS+=$(DBG3_FLAGS)
debug3: prepare $(TAR_TESTS)

diagnose: CFLAGS+=$(DBG_FLAGS) $(DIAGNOSE_FLAGS)
diagnose: prepare $(TAR_TESTS)

depl: CFLAGS+=$(DEPL_FLAGS)
ifeq ($(TYPE),pr)
depl: prepare $(TAR_EXECS) docs scripts vimscripts
else
depl: prepare $(TAR_LIBS)
endif

depl_test: CFLAGS+=$(TEST_FLAGS)
ifeq ($(TYPE),pr)
depl_test: prepare $(TAR_EXECS) docs scripts vimscripts
else
depl_test: prepare $(TAR_LIBS)
endif

docs: prepare $(DOCS)
scripts: prepare $(TAR_SCRIPTS)
vimscripts: prepare $(TAR_VIM)


# --- Build targets ---
.PHONY: prepare
prepare:
	@mkdir -vp $(DIRS_CONCAT)


$(DIR_OBJS)/%.o : %.c
	@echo doing $@
	@mkdir -vp $(@D)
	@mkdir -vp $(@D:$(DIR_OBJS)/%=$(DIR_DEPS)/%)
	$(COMPILER) -c $< -o $@ $(CPPFLAGS) $(CFLAGS)
	@echo -e "...> COMPILED $@\n\n\n"
	@$(COMPILER) -MM -MP -MT'$(@) $(DIR_DEPS)/$*.dep' $(CPPFLAGS) -o $(DIR_DEPS)/$*.dep $<

$(DIR_OBJS)/%.o : %.cxx
	@echo doing $@
	@mkdir -vp $(@D)
	@mkdir -vp $(@D:$(DIR_OBJS)/%=$(DIR_DEPS)/%)
	$(COMPILER) -c $< -o $@ $(CPPFLAGS) $(CFLAGS)
	@echo -e "...> COMPILED $@\n\n\n"
	@$(COMPILER) -MM -MP -MT'$(@) $(DIR_DEPS)/$*.dep' $(CPPFLAGS) -o $(DIR_DEPS)/$*.dep $<
# create object file together with depfile if *.c file changed:
#   . create directories: dirs chain for object file
#      $(@D) - directory part of target object file
#   . create directories: dirs chain for dependency file
#      $(@D:...) - substitute objects dir for deps dir
#   . compile source file that triggered recipe
#      @< - dependency source file that triggered recipe (:right)
#      $@ - target object file (left:)
#   . generate depfiles for created object file
#      $* - part of target that matches pattern (%)  ;only in implicit rules
#    -M:generate dep rule for target (*.o) -MM:same but skip system headers in deps
#    -MP:create phony targets for *.h - prevents errors when headers missing and
#       it is still in old depfile (file will be overriden now with valid deps)
#    -MT:target pattern in rule - current target + current depfile (to make sure
#       its recreation when sources changed - it can mean that #incs changed)

# Other special vars:
#      $^ - all dependencies


-include $(DEPS)
-include $(DEPS_TESTS)
-include $(DEPS_EXECS)
# include depfiles
#    evaluate each depfile and if contains rule to build itself and deps are
#ne      newer it would rebuild itself if we provide implicit rule for thie
#      (and we do not provide as recipe for building .o contains command to
#      generate depfile - .o and .dep have same dependencies)
#    succ: rerun this Makefile
#      + no rebuilding depfiles (timestamp changed)
#      + include redone depfile literally




$(TAR_TESTS): $(OBJECTS) $(OBJECTS_TESTS)
	$(COMPILER) $^ -o $@ $(CFLAGS) $(LFLAGS)
	@echo -e ":::-> LINKED $@\n\n\n"
# /\ create executable with tests:
#    . link object files into target
#
$(TAR_LIBS): $(OBJECTS)
	ar cr $@ $^
	@echo -e ":::-> LIBRARY CREATED $@\n\n\n"
# /\ create library:
#    . archive object files into library
#      $^ - all dependencies
#
$(TAR_EXECS): $(OBJECTS) $(OBJECTS_EXEC)
	$(COMPILER) $^ -o $@ $(CFLAGS) $(LFLAGS)
	@echo -e ":::-> LINKED $@\n\n\n"
# /\ create executable:
#    . link object files into target
#
$(TAR_SCRIPTS): $(DIR_BIN)/% : $(DIR_SCRIPTS_SRCS)/%.sh
	\cp -va $< $@ && \chmod -v a+x $@
#
$(TAR_VIM): $(DIR_VIM)/% : %
	@tar=$@; \
	tar=$(DIR_VIM)/$${tar#$(DIR_VIM)/*/}; \
	mkdir -vp $$(dirname $${tar}); \
	cp -va $< $${tar}


# create DOC_MANS + additional docs not destined for installation in system
#
$(DOC_MANS): $(DIR_DOCS)/man/%.gz : $(DIR_DOCS_SRCS)/%.man.t2t
	@mkdir -vp $(@D) && \
	txt2tags -t man -o $(basename $@) $< && \
	gzip -vf $(basename $@)


T2T_HTML_OPTS := --toc

$(DOC_HTMLS): $(DIR_DOCS)/html/%.html : $(DIR_DOCS_SRCS)/%.html.t2t
	@mkdir -vp $(@D) && \
	txt2tags -t html $(T2T_HTML_OPTS) -o $@ $<

$(DOC_MAINS): $(DIR_DOCS)/mains/% : $(DIR_DOCS_SRCS)/%.main.t2t
	@txt2tags -t txt -o $(notdir $@) $<

$(DOC_MDS): $(SOURCES_DOCS_MDS)
	@mkdir -vp $(@D) && \
	cp -va $< $@






# --- Packaging and Installing targets ---
# create package
.PHONY: pack
pack: $(DOCS)
	@BuildRecipes/pack.sh $(VERSION) $(PACK_NAME) $(DIR_PACK) $(ARCH_BUNDLE) "$(FILES_TO_PACK)"


# install/uninstall package
.PHONY: install
install: depl
	@[[ ! -z "$(DESTDIR)" ]] && mkdir -vp $(DESTDIR) || echo ""
	@mkdir -vp $(DESTDIR)$(bindir)
	@mkdir -vp $(DESTDIR)$(mandir)/man{1,2,3,4,5,6,7,8,9}
	@mkdir -vp $(DESTDIR)$(vimdatadir)/{plugin,syntax}
	@install -vm 0755 $(DIR_BIN)/* $(DESTDIR)$(bindir)
	@for f in $(DOC_MANS); do \
	  section=$${f%.gz}; \
	  section=$${section##*.}; \
 	  install -vm 0644 $${f} $(DESTDIR)$(mandir)/man$${section}/; \
	done;
	@for subdir in plugin syntax; do \
	  install -vm 0644 $(DIR_VIM)/$${subdir}/*.vim $(DESTDIR)$(vimdatadir)/$${subdir}/; \
	done;
	@if [[ -d $(DESTDIR)$(vimdir) ]]; then \
	  for subdir in plugin syntax; do \
	    install -vm 0644 $(DIR_VIM)/$${subdir}/*.vim $(DESTDIR)$(vimdir)/$${subdir}/; \
	  done; \
	else \
	   echo "Unable to find Vim system directory, for Vim support copy following files by hand:"; \
	   echo "  $(DESTDIR)$(vimdatadir)/*/*.vim	to Vim's plugin directory"; \
	fi;

.PHONY: uninstall
uninstall:
	@for f in $(TAR_EXECS); do \
	  rm -vf $(DESTDIR)$(bindir)/$${f#$(DIR_BIN)/}; \
	done;
	@for f in $(TAR_SCRIPTS); do \
	  rm -vf $(DESTDIR)$(bindir)/$${f#$(DIR_BIN)/}; \
	done;
	@for f in $(DOC_MANS); do \
	  section=$${f%.gz}; \
	  section=$${section##*.}; \
	  rm -vf $(DESTDIR)$(mandir)/man$${section}/$$(basename $${f}); \
	done;
	@for f in $(SOURCES_VIM); do \
	  rm -vf $(DESTDIR)$(vimdatadir)/$${f#*/}; \
	done;
	@if [[ -d $(DESTDIR)$(vimdir) ]]; then \
	  rm -vf $(DESTDIR)$(vimdir)/$${f#*/}; \
	fi;

.PHONY: isinstalled
isinstalled:
	@for f in $(TAR_EXECS); do \
	  fname=$(DESTDIR)$(bindir)/$${f#$(DIR_BIN)/}; \
	  [[ -f $${fname} ]] && echo "$${fname} OK" || echo "$${fname} not present"; \
	done;
	@for f in $(TAR_SCRIPTS); do \
	  fname=$(DESTDIR)$(bindir)/$${f#$(DIR_BIN)/}; \
	  [[ -f $${fname} ]] && echo "$${fname} OK" || echo "$${fname} not present"; \
	done;
	@for f in $(DOC_MANS); do \
	  section=$${f%.gz}; \
	  section=$${section##*.}; \
	  fname=$(DESTDIR)$(mandir)/man$${section}/$$(basename $${f}); \
	  [[ -f $${fname} ]] && echo "$${fname} OK" || echo "$${fname} not present"; \
	done;
	@for f in $(SOURCES_VIM); do \
	  fname=$(DESTDIR)$(vimdatadir)/$${f#*/}; \
	  [[ -f $${fname} ]] && echo "$${fname} OK" || echo "$${fname} not present"; \
	done;
	@if [[ -d $(DESTDIR)$(vimdir) ]]; then \
	  fname=$(DESTDIR)$(vimdir)/$${f#*/}; \
	  [[ -f $${fname} ]] && echo "$${fname} OK" || echo "$${fname} not present"; \
	fi;




# --- Auxillary targets ---


# + Run tests +
.PHONY: runt
runt:
	@$(TAR_TESTS)

.PHONY: runt
debugr: debug
	@echo -e ":: Make: running tests now\n\n"
	@$(TAR_TESTS)

.PHONY: vrunt
vrunt:
	@f=$(DIR_ANALYSE)/val_$$(date +%T).txt; \
	valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --num-callers=40 --track-fds=yes --error-limit=yes --log-file=$${f} $(TAR_TESTS); \
	cat $${f};

.PHONY: vrunts
vrunts:
	@f=$(DIR_ANALYSE)/val_$$(date +%T).txt; \
	valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --num-callers=40 --track-fds=yes --error-limit=yes --log-file=$${f} $(TAR_TESTS) s; \
	cat $${f};


# + Fossil info +
.PHONY: fosinf
fosinf:
	@fossil status && \
	 echo -e "\n:: TIMELINE:" && fossil timeline && \
	 echo -e "\n:: INFO:" && fossil info && \
	 echo -en "\n:: BRANCH: " && fossil branch


# + Gcc info +
# see what settings GCC uses
.PHONY: gcc-test
gcc-test:
	@gcc $(CPPFLAGS) $(CFLAGS) -E -v - </dev/null 2>&1

# see options only
.PHONY: gcc-opts
gcc-opts:
	@gcc $(CPPFLAGS) $(CFLAGS) -E -v - </dev/null 2>&1 | grep cc1

# see arch options
.PHONY: gcc-arch
gcc-arch:
	@gcc $(ARCH_FLAGS) -E -v - </dev/null 2>&1 | grep cc1


# --- Code analysis ---
# create cpp files from sources
.PHONY: cpp
cpp:
	@for file in $(SOURCES); do \
	   $(COMPILER) -E -C $${file} -o $${file}.cpp $(CPPFLAGS) $(CFLAGS);\
	done

.PHONY: analyze
analyze:
	@date >> $(ANALYZE_OUTPUT_FILE)
	@echo -e "==============\n\n" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@make dist-clean > /dev/null
	@make debug CC="scan-build gcc" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@echo -e "\n\t--------------\n" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@flawfinder $(SOURCES) >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@echo -e "\n\t--------------\n" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@echo -e "RATS ::" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@rats $(SOURCES) >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@echo -e "\n\t--------------\n" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@splint $(DIRS_INCLUDES) $(SOURCES) >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@echo -e "\n\t--------------\n\n\n" >> $(ANALYZE_OUTPUT_FILE) 2>&1

.PHONY: compile_headers
compile_headers:
	@for dir in $(DIRS_INCLUDES); do \
	  for file in $${dir}/*.h; do \
	    if [ $${file} == "./*.h" ]; then continue; fi; \
	    filec=$${file}.c; \
	    echo "compiling header: $${file}"; \
	    echo "#include \"$${file}\"" > $${filec}; \
	    $(COMPILER) -c $${filec} -o /dev/null $(CPPFLAGS) $(CFLAGS); \
	    \rm -v $${filec}; \
	  done \
	done

.PHONY: headers_tree
headers_tree:
	@for file in $(SOURCES); do \
	  echo -e "\ntree for file: $${file}"; \
	  $(COMPILER) -c -H $${file} $(CPPFLAGS) $(CFLAGS); \
	done


# --- Cleanup targets ---
# remove all not-project files and dirs
.PHONY: dist-clean
dist-clean:	clean-objs clean-tool clean-deps clean-bins clean-dirs
	@\rm -vrf $(ANALYZE_OUTPUT_FILE)

# remove all not-project files
.PHONY: clean
clean:	clean-objs clean-tool clean-deps

# remove object files
.PHONY: clean-objs
clean-objs:
	@\rm -vrf $(TAR_TESTS) $(TAR_LIBS) $(TAR_EXECS) $(TAR_SCRIPTS) $(DOCS) $(DIR_OBJS)/*.o $(DIR_OBJS)/**/*.o

# remove tool files
.PHONY: clean-tool
clean-tool:
	@\rm -vrf $(TAR_TESTS) $(TAR_LIBS) $(TAR_EXECS) $(TAR_SCRIPTS) $(DOCS) $(DIR_OBJS)/{*.gcno,*.su,*.tu} \
	   $(DIR_OBJS)/**/{*.gcno,*.su,*.tu} \
	   src*/*.cpp src*/**/*.cpp \
	   *.i *.s gmon.out

# remove depfiles
.PHONY: clean-deps
clean-deps:
	@\rm -vrf $(DIR_DEPS)/*.dep $(DIR_DEPS)/**/*.dep

# remove executables
.PHONY: clean-bins
clean-bins:
	@\rm -vrf $(DIR_BIN)/*

# remove all not-project dirs with contents
.PHONY: clean-dirs
clean-dirs:
	@\rm -vrf $(DIRS_CONCAT)






### REMAINDERS:
# create implicit rule for creating depfiles
#%.dep : %.c
	#$(MAKEDEPEND)

Added BuildRecipes/ProjSettings.mk.























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
.SUFFIXES: .c .cxx

#PR_LANG := C
PR_LANG := CXX
TYPE := pr
#TYPE := lib


FILES_TO_PACK="src* sh_scripts lib* doc tests vim_* BuildRecipes Makefile ChangeLog INSTALL LICENSE README VERSION NAME"


Added BuildRecipes/mk_hllibs.sh.

























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#! /usr/bin/env bash

# $1 - project's language (C or CXX)
# $2 - project's main dir

libs=(lib*)
[[ "${libs[0]}" == 'lib*' ]] && exit 0

#echo $1
#echo $2
olddir=$PWD

for l in ${libs[@]}; do
  cd ${l}

  lib_dir="$2/a${l:3}"

  srcs=(src*)
  [[ "${srcs[0]}" == 'src*' ]] && { cd -; continue; }
  for s in ${srcs[@]}; do
    cd ${s}
    \ln -v -L ${lib_dir}/${s}/* .
    \rm -vf *_test.c *_test.cxx
    cd -
  done
  cd ${olddir}
done

Added BuildRecipes/pack.sh.

































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/usr/bin/env bash

# $1 - current program version
# $2 - package name (prname-version)
# $3 - dir where store package
# $4 - directory with AUR files (PKGBUILD. *.install etc.)
# $5 - files to pack ex. "file file2 file3"

PKGBUILD_FILE="${4}/PKGBUILD"

# get package version and release
VER=$(\sed -n 's/^pkgver=\(.*\)$/\1/p' ${PKGBUILD_FILE})
REL=$(\sed -n 's/^pkgrel=\(.*\)$/\1/p' ${PKGBUILD_FILE})
if [[ "$VER" != "$1" ]]; then
  # version in PKGBUILD and current pr version are different
  # - reset package release
  REL=1
else
  # are same
  # - increment package release
  ((REL++))
fi

PACK_NAME=${2}    # pr-ver
PACK_DIR=${3}     # .package
TARBALL=${PACK_NAME}-${REL}.tar.gz
AUR_DIR=${4}      # MakeRecipes/arch
AURBALL=${PACK_NAME}-${REL}.src.tar.gz
FILES_TO_PACK=${5}


# create pack-directory tree with files intended to pack
# and tarball pack-directory and create 'current' link
\mkdir -vp ${PACK_DIR}/${PACK_NAME}
\cp -vaf ${FILES_TO_PACK} ${PACK_DIR}/${PACK_NAME}

\cd ${PACK_DIR}
\tar -cvzf ${TARBALL} ${PACK_NAME}
\ln -sf ${TARBALL} current.tar.gz
\cd -

\rm -rf ${PACK_DIR}/${PACK_NAME}
# NOW HAVE: .package / pr-ver.tar.gz, current.tar.gz


# Alter PKGBUID file: checksums, pkg-release
pack_md5sum=$(md5sum ${PACK_DIR}/current.tar.gz)
pack_sha256sum=$(sha256sum ${PACK_DIR}/current.tar.gz)
pack_md5sum="md5sums=('${pack_md5sum%% *}')"
pack_sha256sum="sha256sums=('${pack_sha256sum%% *}')"; \
\sed -i "s/md5sums=(.*)/${pack_md5sum}/" ${PKGBUILD_FILE}; \
\sed -i "s/sha256sums=(.*)/${pack_sha256sum}/" ${PKGBUILD_FILE};

\sed -i "s/^pkgrel=.*$/pkgrel=${REL}/" ${PKGBUILD_FILE}
# NOW HAVE: same + PKGBUILD altered


# make AurBall and create 'current_aur' link
\cp -vaf ${PACK_DIR}/${TARBALL} ${AUR_DIR};     # now PKGBUILD will find tarball in own directory and will not download old version
\cd ${AUR_DIR} && mkaurball -f
\rm ${TARBALL}
\ln -sf ${AURBALL} current_aur.tar.gz
\cd -
\mv -vf ${AUR_DIR}/*.tar.gz ${PACK_DIR}
# NOW HAVE: same + .package / aurball.src.tar.gz , current_aur.tar.gz


fossil rm ${PACK_DIR}/tfman*.tar.gz
fossil add ${PACK_DIR}/${TARBALL}
fossil add ${PACK_DIR}/${AURBALL}


# Note to user
echo "Aurball created, checksums substituted in PKGBUILD"
echo -e "You can now, in this order:\n" \
"\t1.push to repository (to upload new tarball with new sources)\n" \
"\t2.place aurball in AUR (to upload new aurball with new PKGBUILD checksums)"


exit 0

Added Makefile.



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
# ### === Machel's MAKEFILE ### ===


# :: File:
#    .. project/file:         Makefile <GNU Make>
#     .
#    .. info:
#     .   Created:            2014-01-12 by "Machel"
#     .   Last modified:      2014-07-12 by "Machel"
#     .   License:            GNU Public License
#     .   (c) Copyright:      "Machel" 2014
#     .
#    .. dependencies:
#         -- GNU Make    - many specific features used
#         -- GCC         - dependency creation feature used
#
# :: Description:
#  . Makefile for Machel's C/C++ projects.
#  . May be used in all Machel's C/C++ projects adhering to certain project
#    layout
#
# :: Functionality:
#   -- sources: auto hunting up source files
#    - inside all src* and lib* directories one level deep
#    - for files with 'c/cxx' suffix (.c/.cxx)
#
#   -- headers: auto determine directories with header files
#    - header files are assumed to exist in source dirs ONLY thus header dirs
#      are the same as source dirs
#
#   -- shell scripts: files with .sh extension auto copied from sh_scripts
#      directory to .bin (extension is removed)
#
#   -- documentation: auto created from files resisting in doc directory and
#      having proper suffix (see targets for docs)
#
#   -- dependencies: auto generates dependency files
#    - depfile is created for each object file, and object file is assumed for
#      each source file
#    - object files depends on corresponding source file and all header files
#      included by this source file
#    - depfile depends on same files to ensure it is recreated each time one
#      of that files is changed (in case included files changed)
#    - depfile lists all dependencies being header files as targets themselves
#      to suppress errors if they do not exist (programmer could remove them
#      from includes in source file and from file system or rename)
#
#   -- separate dirs: files generated by compiler and auxillary files
#      (like depfiles) are placed in separate dirs to not mix them up
#      with source and header files
#    - executables go to '.bin'
#    - object files go to '.build'
#    - depfiles go to '.deps'
#    - GENERAL: temporary files go to dirs begining with dots, except packages
#      which goes to .packages directory
#
#   -- static checks: splint, flawfinder, rats, clang analyzer
#
#   -- debug builds: several levels with different warning flags
#
#   -- cleanup: cleanup project directories
#    - shallow cleans - remove specific files
#    - deep cleans - remove all created dirs and leave project in original state
#    - see clean targets for details
#
# :: Limitations:
#   --- header files are assumed to be only in same dirs as source files
#   --- can't use compiler other then GCC for reason of dependency creation



SHELL := /bin/sh

REQUIRED_FILES := NAME VERSION BuildRecipes/ProjSettings.mk BuildRecipes/mk_hllibs.sh
RES := $(wildcard $(REQUIRED_FILES))
ifneq ($(RES),$(REQUIRED_FILES))
  $(error "One of following files does not exist: $(REQUIRED_FILES)"))
endif




# === USER SETTINGS ===
include BuildRecipes/ProjSettings.mk


# --- BASE SETTINGS ---
PRNAME := $(shell cat NAME)

VERSION := $(patsubst VER%,,$(shell cat VERSION))
VERSION := $(subst \#define ,,$(VERSION))
SPACE_ :=
SPACE_ +=
VERSION := $(subst $(SPACE_),.,$(VERSION))

PACK_NAME := $(PRNAME)-$(VERSION)


ifeq ($(PR_LANG),C)
PROJS_MAIN_DIR := /home/Magazyn/Projects/c
else ifeq ($(PR_LANG),CXX)
PROJS_MAIN_DIR := /home/Magazyn/Projects/cxx
else
$(error "Invalid PR_LANG value")
endif



# --- INSTALL SETTINGS ---
DESTDIR ?=

prefix ?= /usr
confdir ?= /etc
bindir := $(prefix)/bin
libdir := $(prefix)/lib
mandir ?= /usr/share/man

appdatadir ?= /usr/share/$(PRNAME)
vimdatadir := $(appdatadir)/vim/vimfiles
vimdir ?= /usr/share/vim/vimfiles



# --- BUILD LAYOUT SETTINGS ---

# SOURCE FILES
ARCH_BUNDLE := BuildRecipes/arch
DIR_DOCS_SRCS := doc
DIR_SCRIPTS_SRCS := sh_scripts

SOURCES_TESTS_C := $(wildcard src*/*_test.c src*/**/*_test.c)
SOURCES_EXECS_C := $(wildcard src*/*_exec.c src*/**/*_exec.c)
SOURCES_ALL_C := $(wildcard src*/*.c src*/**/*.c lib_*/*.c lib_*/**/*.c)
SOURCES_C := $(filter-out $(SOURCES_TESTS_C),$(SOURCES_ALL_C))
SOURCES_C := $(filter-out $(SOURCES_EXECS_C),$(SOURCES_C))
SOURCES_TESTS_C += $(wildcard tests*/*.c tests*/**/*.c)
SOURCES_EXECS_C += $(wildcard execs*/*.c execs*/**/*.c)

ifeq ($(PR_LANG),CXX)
SOURCES_TESTS_CXX := $(wildcard src*/*_test.cxx src*/**/*_test.cxx)
SOURCES_EXECS_CXX := $(wildcard src*/*_exec.cxx src*/**/*_exec.cxx)
SOURCES_ALL_CXX := $(wildcard src*/*.cxx src*/**/*.cxx lib_*/*.cxx lib_*/**/*.cxx)
SOURCES_CXX := $(filter-out $(SOURCES_TESTS_CXX),$(SOURCES_ALL_CXX))
SOURCES_CXX := $(filter-out $(SOURCES_EXECS_CXX),$(SOURCES_CXX))
SOURCES_TESTS_CXX += $(wildcard tests*/*.cxx tests*/**/*.cxx)
SOURCES_EXECS_CXX += $(wildcard execs*/*.cxx execs*/**/*.cxx)
endif

SOURCES_TESTS := $(SOURCES_TESTS_C) $(SOURCES_TESTS_CXX)
SOURCES_EXECS := $(SOURCES_EXECS_C) $(SOURCES_EXECS_CXX)
SOURCES_ALL := $(SOURCES_ALL_C) $(SOURCES_ALL_CXX)
SOURCES := $(SOURCES_C) $(SOURCES_CXX)

#$(info $(SOURCES_TESTS))
#$(info $(SOURCES_EXECS))
#$(info $(SOURCES_ALL))
#$(info $(SOURCES))

SOURCES_SCRIPTS ?=
SOURCES_SCRIPTS += $(wildcard $(DIR_SCRIPTS_SRCS)/*.sh)
SOURCES_VIM ?=
SOURCES_VIM += $(wildcard vim_*/**/*.vim)
# ex. 'manpage.1.man.t2t' where '1' is section number
SOURCES_DOCS_MANS ?=
SOURCES_DOCS_MANS += $(wildcard $(DIR_DOCS_SRCS)/*.man.t2t)
SOURCES_DOCS_HTMLS ?=
SOURCES_DOCS_HTMLS += $(wildcard $(DIR_DOCS_SRCS)/*.html.t2t)
SOURCES_DOCS_MAINS ?=
SOURCES_DOCS_MAINS += $(wildcard $(DIR_DOCS_SRCS)/*.main.t2t)
SOURCES_DOCS_MDS ?=
SOURCES_DOCS_MDS += $(wildcard $(DIR_DOCS_SRCS)/*.md)

# TARGET FILES
DIR_DOCS := doc
DIR_BIN := .bin
DIR_VIM := .vim
DIR_PACK := .packages
DIR_ANALYSE := .analyse
ANALYZE_OUTPUT_FILE := static_analysis.txt

TAR_TESTS := $(DIR_BIN)/$(PRNAME)_test
TAR_LIBS := $(DIR_BIN)/$(PRNAME).a
TAR_EXECS := $(DIR_BIN)/$(PRNAME)
TAR_SCRIPTS := $(patsubst %.sh,$(DIR_BIN)/%,$(notdir $(SOURCES_SCRIPTS)))

TAR_VIM_FILES := $(notdir $(SOURCES_VIM))
TAR_VIM_DIRS := $(notdir $(patsubst %/,%,$(dir $(SOURCES_VIM))))
TAR_VIM := $(addprefix $(DIR_VIM)/,$(SOURCES_VIM))

DOC_MANS := $(patsubst %.man.t2t,$(DIR_DOCS)/man/%.gz,$(notdir $(SOURCES_DOCS_MANS)))
DOC_HTMLS := $(patsubst %.html.t2t,$(DIR_DOCS)/html/%.html,$(notdir $(SOURCES_DOCS_HTMLS)))
DOC_MAINS := $(patsubst %.main.t2t,$(DIR_DOCS)/mains/%,$(notdir $(SOURCES_DOCS_MAINS)))
DOC_MDS := $(patsubst %.md,$(DIR_DOCS)/md/%.md,$(notdir $(SOURCES_DOCS_MDS)))

DOCS := $(DOC_MANS) $(DOC_HTMLS) $(DOC_MAINS) $(DOC_MDS)


# --- BUILD OPTIONS ---
ifeq ($(PR_LANG),C)
CC = gcc
STD_FLAGS := -std=c99 -pedantic
else ifeq ($(PR_LANG),CXX)
CC = /usr/bin/g++
STD_FLAGS := -std=c++11 -pedantic
endif
COMPILER := $(CC) -pipe #-fdiagnostics-color
CPP_FLAGS :=
ARCH_FLAGS := -march=native -mtune=native
OPTIMIZE_FLAGS := -fstrict-aliasing -Wdisabled-optimization -minline-all-stringops \
   -funroll-loops -momit-leaf-frame-pointer
#<C++>: -fstrict-enums

WARN_FLAGS := -Wall -Wextra -Wshadow -Wwrite-strings -Wpointer-arith -Wcast-qual \
   -Wcast-align -Wswitch-default -Wswitch-enum \
   -Wstrict-overflow=2 -Wredundant-decls \
   -Wlogical-op -Wfloat-equal -Wmissing-include-dirs
   #ev. -Wno-unused-parameter #ev. -Wno-unused-value
WARN2_FLAGS := -Wundef -Wstrict-overflow=5 -Wconversion -Wunsuffixed-float-constants \
   -Wdouble-promotion -Wunused -Wuninitialized -Winit-self -Wfloat-equal \
   -Wbad-function-cast -Wjump-misses-init -Wpadded -Winline -Wformat=2 \
   -Werror-implicit-function-declaration -Wunused-parameter -Wunused
NOWARN_DEPL := -Wno-cast-qual -Wno-pedantic -Wno-unused-parameter

ifeq ($(PR_LANG),C)
WARN_FLAGS += -Wstrict-prototypes -Wnested-externs
else ifeq ($(PR_LANG),CXX)
WARN_FLAGS += -Wctor-dtor-privacy -Wnon-virtual-dtor -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Weffc++
endif

TOOLS_FLAGS := -ggdb3 -pg
DIAGNOSE_FLAGS := -fmem-report -fprofile-report -fstack-usage -ftest-coverage -Q \
   -fdump-translation-unit -fdump-class-hierarchy -save-temps

DBG_COMMON_FLAGS := -DDEBUG -fno-eliminate-unused-debug-types -ftrapv -fstack-check
DBG_FLAGS := -O0 $(DBG_COMMON_FLAGS) $(TOOLS_FLAGS) $(WARN_FLAGS)
DBG2_FLAGS := -O2 $(DBG_COMMON_FLAGS) $(TOOLS_FLAGS) $(WARN2_FLAGS) -DDEBUG2
DBG3_FLAGS := -O3 $(DBG_COMMON_FLAGS) $(TOOLS_FLAGS) $(WARN2_FLAGS) \
   -fmudflap -Wno-nested-externs -fstack-protector-all -lmudflap
# -fmudflap - check arrays/heap bounds		;needs special lib
# -fmudflapth - check arrays/heap bounds for multi-th pr

DEPL_FLAGS := -O3 -DNDEBUG $(WARN_FLAGS) $(NOWARN_DEPL) -fomit-frame-pointer -g
TEST_FLAGS := -O3 -DDEBUG2 $(WARN_FLAGS) $(TOOLS_FLAGS)
#-finline-functions - try inline all simple enough funs

MSGS_FLAGS := -fmessage-length=0 -fmax-errors=10
#<C++>: -fno-pretty-templates




# === TRANSITIONAL FILES ===
DIR_OBJS := .build
DIR_DEPS := .deps

DEPS := $(SOURCES:%.c=$(DIR_DEPS)/%.dep)
DEPS_TESTS := $(SOURCES_TESTS:%.c=$(DIR_DEPS)/%.dep)
DEPS_EXECS := $(SOURCES_EXECS:%.c=$(DIR_DEPS)/%.dep)

OBJECTS := $(patsubst %.c,$(DIR_OBJS)/%.o,$(SOURCES))
OBJECTS_TESTS := $(patsubst %.c,$(DIR_OBJS)/%.o,$(SOURCES_TESTS))
OBJECTS_EXEC := $(patsubst %.c,$(DIR_OBJS)/%.o,$(SOURCES_EXECS))


ifeq ($(PR_LANG),CXX)
DEPS := $(DEPS:%.cxx=$(DIR_DEPS)/%.dep)
DEPS_TESTS := $(DEPS_TESTS:%.cxx=$(DIR_DEPS)/%.dep)
DEPS_EXECS := $(DEPS_EXECS:%.cxx=$(DIR_DEPS)/%.dep)

OBJECTS := $(patsubst %.cxx,$(DIR_OBJS)/%.o,$(OBJECTS))
OBJECTS_TESTS := $(patsubst %.cxx,$(DIR_OBJS)/%.o,$(OBJECTS_TESTS))
OBJECTS_EXEC := $(patsubst %.cxx,$(DIR_OBJS)/%.o,$(OBJECTS_EXECS))
endif

#$(info $(OBJECTS))
#$(info $(OBJECTS_TESTS))
#$(error ABORT)


SOURCES_DOCS := $(wildcard doc*/*.t2t)

DIRS_INCLUDES := . $(wildcard src*) $(filter %/, $(wildcard src*/**/))
DIRS_INCLUDES += $(wildcard include*) $(filter %/, $(wildcard include*/**/))
DIRS_INCLUDES += $(wildcard lib_*) $(filter %/, $(wildcard lib_*/**/))
INCLUDES_OPTS := $(patsubst %,-I%,$(DIRS_INCLUDES))
LIBRARIES := $(wildcard lib/*.a)
LIBRARIES := $(patsubst lib/lib%.a,-l%,$(LIBRARIES))

CPPFLAGS := $(CPP_FLAGS) $(INCLUDES_OPTS)
CFLAGS := $(STD_FLAGS) $(ARCH_FLAGS) $(MSGS_FLAGS) $(OPTIMIZE_FLAGS)
LFLAGS := -L./lib $(LIBRARIES)




DIRS_CONCAT := $(DIR_BIN) $(DIR_OBJS) $(DIR_DEPS) $(DIR_DOCS) $(DIR_PACK) $(DIR_VIM) $(DIR_ANALYSE)




# === TARGETS ===


# --- General targets ---
all:  depl docs

# print help
.PHONY: help
help:
	@echo "make DESTDIR=/dir install  - install to /dir (def. is /usr)"

# createllibs
hllibs:
	@BuildRecipes/mk_hllibs.sh "$(PR_LANG)" "$(PROJS_MAIN_DIR)"




# --- Main targets ---
debug: CFLAGS+=$(DBG_FLAGS)
debug: OUT_REDIRECT := >diagnose.txt 2>&1
debug: prepare $(TAR_TESTS)

debug2: CFLAGS+=$(DBG2_FLAGS)
debug2: prepare $(TAR_TESTS)

debug3: CFLAGS+=$(DBG3_FLAGS)
debug3: prepare $(TAR_TESTS)

diagnose: CFLAGS+=$(DBG_FLAGS) $(DIAGNOSE_FLAGS)
diagnose: prepare $(TAR_TESTS)

depl: CFLAGS+=$(DEPL_FLAGS)
ifeq ($(TYPE),pr)
depl: prepare $(TAR_EXECS) docs scripts vimscripts
else
depl: prepare $(TAR_LIBS)
endif

depl_test: CFLAGS+=$(TEST_FLAGS)
ifeq ($(TYPE),pr)
depl_test: prepare $(TAR_EXECS) docs scripts vimscripts
else
depl_test: prepare $(TAR_LIBS)
endif

docs: prepare $(DOCS)
scripts: prepare $(TAR_SCRIPTS)
vimscripts: prepare $(TAR_VIM)


# --- Build targets ---
.PHONY: prepare
prepare:
	@mkdir -vp $(DIRS_CONCAT)


$(DIR_OBJS)/%.o : %.c
	@echo doing $@
	@mkdir -vp $(@D)
	@mkdir -vp $(@D:$(DIR_OBJS)/%=$(DIR_DEPS)/%)
	$(COMPILER) -c $< -o $@ $(CPPFLAGS) $(CFLAGS)
	@echo -e "...> COMPILED $@\n\n\n"
	@$(COMPILER) -MM -MP -MT'$(@) $(DIR_DEPS)/$*.dep' $(CPPFLAGS) -o $(DIR_DEPS)/$*.dep $<

$(DIR_OBJS)/%.o : %.cxx
	@echo doing $@
	@mkdir -vp $(@D)
	@mkdir -vp $(@D:$(DIR_OBJS)/%=$(DIR_DEPS)/%)
	$(COMPILER) -c $< -o $@ $(CPPFLAGS) $(CFLAGS)
	@echo -e "...> COMPILED $@\n\n\n"
	@$(COMPILER) -MM -MP -MT'$(@) $(DIR_DEPS)/$*.dep' $(CPPFLAGS) -o $(DIR_DEPS)/$*.dep $<
# create object file together with depfile if *.c file changed:
#   . create directories: dirs chain for object file
#      $(@D) - directory part of target object file
#   . create directories: dirs chain for dependency file
#      $(@D:...) - substitute objects dir for deps dir
#   . compile source file that triggered recipe
#      @< - dependency source file that triggered recipe (:right)
#      $@ - target object file (left:)
#   . generate depfiles for created object file
#      $* - part of target that matches pattern (%)  ;only in implicit rules
#    -M:generate dep rule for target (*.o) -MM:same but skip system headers in deps
#    -MP:create phony targets for *.h - prevents errors when headers missing and
#       it is still in old depfile (file will be overriden now with valid deps)
#    -MT:target pattern in rule - current target + current depfile (to make sure
#       its recreation when sources changed - it can mean that #incs changed)

# Other special vars:
#      $^ - all dependencies


-include $(DEPS)
-include $(DEPS_TESTS)
-include $(DEPS_EXECS)
# include depfiles
#    evaluate each depfile and if contains rule to build itself and deps are
#ne      newer it would rebuild itself if we provide implicit rule for thie
#      (and we do not provide as recipe for building .o contains command to
#      generate depfile - .o and .dep have same dependencies)
#    succ: rerun this Makefile
#      + no rebuilding depfiles (timestamp changed)
#      + include redone depfile literally




$(TAR_TESTS): $(OBJECTS) $(OBJECTS_TESTS)
	$(COMPILER) $^ -o $@ $(CFLAGS) $(LFLAGS)
	@echo -e ":::-> LINKED $@\n\n\n"
# /\ create executable with tests:
#    . link object files into target
#
$(TAR_LIBS): $(OBJECTS)
	ar cr $@ $^
	@echo -e ":::-> LIBRARY CREATED $@\n\n\n"
# /\ create library:
#    . archive object files into library
#      $^ - all dependencies
#
$(TAR_EXECS): $(OBJECTS) $(OBJECTS_EXEC)
	$(COMPILER) $^ -o $@ $(CFLAGS) $(LFLAGS)
	@echo -e ":::-> LINKED $@\n\n\n"
# /\ create executable:
#    . link object files into target
#
$(TAR_SCRIPTS): $(DIR_BIN)/% : $(DIR_SCRIPTS_SRCS)/%.sh
	\cp -va $< $@ && \chmod -v a+x $@
#
$(TAR_VIM): $(DIR_VIM)/% : %
	@tar=$@; \
	tar=$(DIR_VIM)/$${tar#$(DIR_VIM)/*/}; \
	mkdir -vp $$(dirname $${tar}); \
	cp -va $< $${tar}


# create DOC_MANS + additional docs not destined for installation in system
#
$(DOC_MANS): $(DIR_DOCS)/man/%.gz : $(DIR_DOCS_SRCS)/%.man.t2t
	@mkdir -vp $(@D) && \
	txt2tags -t man -o $(basename $@) $< && \
	gzip -vf $(basename $@)


T2T_HTML_OPTS := --toc

$(DOC_HTMLS): $(DIR_DOCS)/html/%.html : $(DIR_DOCS_SRCS)/%.html.t2t
	@mkdir -vp $(@D) && \
	txt2tags -t html $(T2T_HTML_OPTS) -o $@ $<

$(DOC_MAINS): $(DIR_DOCS)/mains/% : $(DIR_DOCS_SRCS)/%.main.t2t
	@txt2tags -t txt -o $(notdir $@) $<

$(DOC_MDS): $(SOURCES_DOCS_MDS)
	@mkdir -vp $(@D) && \
	cp -va $< $@






# --- Packaging and Installing targets ---
# create package
.PHONY: pack
pack: $(DOCS)
	@BuildRecipes/pack.sh $(VERSION) $(PACK_NAME) $(DIR_PACK) $(ARCH_BUNDLE) "$(FILES_TO_PACK)"


# install/uninstall package
.PHONY: install
install: depl
	@[[ ! -z "$(DESTDIR)" ]] && mkdir -vp $(DESTDIR) || echo ""
	@mkdir -vp $(DESTDIR)$(bindir)
	@mkdir -vp $(DESTDIR)$(mandir)/man{1,2,3,4,5,6,7,8,9}
	@mkdir -vp $(DESTDIR)$(vimdatadir)/{plugin,syntax}
	@install -vm 0755 $(DIR_BIN)/* $(DESTDIR)$(bindir)
	@for f in $(DOC_MANS); do \
	  section=$${f%.gz}; \
	  section=$${section##*.}; \
 	  install -vm 0644 $${f} $(DESTDIR)$(mandir)/man$${section}/; \
	done;
	@for subdir in plugin syntax; do \
	  install -vm 0644 $(DIR_VIM)/$${subdir}/*.vim $(DESTDIR)$(vimdatadir)/$${subdir}/; \
	done;
	@if [[ -d $(DESTDIR)$(vimdir) ]]; then \
	  for subdir in plugin syntax; do \
	    install -vm 0644 $(DIR_VIM)/$${subdir}/*.vim $(DESTDIR)$(vimdir)/$${subdir}/; \
	  done; \
	else \
	   echo "Unable to find Vim system directory, for Vim support copy following files by hand:"; \
	   echo "  $(DESTDIR)$(vimdatadir)/*/*.vim	to Vim's plugin directory"; \
	fi;

.PHONY: uninstall
uninstall:
	@for f in $(TAR_EXECS); do \
	  rm -vf $(DESTDIR)$(bindir)/$${f#$(DIR_BIN)/}; \
	done;
	@for f in $(TAR_SCRIPTS); do \
	  rm -vf $(DESTDIR)$(bindir)/$${f#$(DIR_BIN)/}; \
	done;
	@for f in $(DOC_MANS); do \
	  section=$${f%.gz}; \
	  section=$${section##*.}; \
	  rm -vf $(DESTDIR)$(mandir)/man$${section}/$$(basename $${f}); \
	done;
	@for f in $(SOURCES_VIM); do \
	  rm -vf $(DESTDIR)$(vimdatadir)/$${f#*/}; \
	done;
	@if [[ -d $(DESTDIR)$(vimdir) ]]; then \
	  rm -vf $(DESTDIR)$(vimdir)/$${f#*/}; \
	fi;

.PHONY: isinstalled
isinstalled:
	@for f in $(TAR_EXECS); do \
	  fname=$(DESTDIR)$(bindir)/$${f#$(DIR_BIN)/}; \
	  [[ -f $${fname} ]] && echo "$${fname} OK" || echo "$${fname} not present"; \
	done;
	@for f in $(TAR_SCRIPTS); do \
	  fname=$(DESTDIR)$(bindir)/$${f#$(DIR_BIN)/}; \
	  [[ -f $${fname} ]] && echo "$${fname} OK" || echo "$${fname} not present"; \
	done;
	@for f in $(DOC_MANS); do \
	  section=$${f%.gz}; \
	  section=$${section##*.}; \
	  fname=$(DESTDIR)$(mandir)/man$${section}/$$(basename $${f}); \
	  [[ -f $${fname} ]] && echo "$${fname} OK" || echo "$${fname} not present"; \
	done;
	@for f in $(SOURCES_VIM); do \
	  fname=$(DESTDIR)$(vimdatadir)/$${f#*/}; \
	  [[ -f $${fname} ]] && echo "$${fname} OK" || echo "$${fname} not present"; \
	done;
	@if [[ -d $(DESTDIR)$(vimdir) ]]; then \
	  fname=$(DESTDIR)$(vimdir)/$${f#*/}; \
	  [[ -f $${fname} ]] && echo "$${fname} OK" || echo "$${fname} not present"; \
	fi;




# --- Auxillary targets ---


# + Run tests +
.PHONY: runt
runt:
	@$(TAR_TESTS)

.PHONY: runt
debugr: debug
	@echo -e ":: Make: running tests now\n\n"
	@$(TAR_TESTS)

.PHONY: vrunt
vrunt:
	@f=$(DIR_ANALYSE)/val_$$(date +%T).txt; \
	valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --num-callers=40 --track-fds=yes --error-limit=yes --log-file=$${f} $(TAR_TESTS); \
	cat $${f};

.PHONY: vrunts
vrunts:
	@f=$(DIR_ANALYSE)/val_$$(date +%T).txt; \
	valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --num-callers=40 --track-fds=yes --error-limit=yes --log-file=$${f} $(TAR_TESTS) s; \
	cat $${f};


# + Fossil info +
.PHONY: fosinf
fosinf:
	@fossil status && \
	 echo -e "\n:: TIMELINE:" && fossil timeline && \
	 echo -e "\n:: INFO:" && fossil info && \
	 echo -en "\n:: BRANCH: " && fossil branch


# + Gcc info +
# see what settings GCC uses
.PHONY: gcc-test
gcc-test:
	@gcc $(CPPFLAGS) $(CFLAGS) -E -v - </dev/null 2>&1

# see options only
.PHONY: gcc-opts
gcc-opts:
	@gcc $(CPPFLAGS) $(CFLAGS) -E -v - </dev/null 2>&1 | grep cc1

# see arch options
.PHONY: gcc-arch
gcc-arch:
	@gcc $(ARCH_FLAGS) -E -v - </dev/null 2>&1 | grep cc1


# --- Code analysis ---
# create cpp files from sources
.PHONY: cpp
cpp:
	@for file in $(SOURCES); do \
	   $(COMPILER) -E -C $${file} -o $${file}.cpp $(CPPFLAGS) $(CFLAGS);\
	done

.PHONY: analyze
analyze:
	@date >> $(ANALYZE_OUTPUT_FILE)
	@echo -e "==============\n\n" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@make dist-clean > /dev/null
	@make debug CC="scan-build gcc" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@echo -e "\n\t--------------\n" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@flawfinder $(SOURCES) >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@echo -e "\n\t--------------\n" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@echo -e "RATS ::" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@rats $(SOURCES) >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@echo -e "\n\t--------------\n" >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@splint $(DIRS_INCLUDES) $(SOURCES) >> $(ANALYZE_OUTPUT_FILE) 2>&1
	@echo -e "\n\t--------------\n\n\n" >> $(ANALYZE_OUTPUT_FILE) 2>&1

.PHONY: compile_headers
compile_headers:
	@for dir in $(DIRS_INCLUDES); do \
	  for file in $${dir}/*.h; do \
	    if [ $${file} == "./*.h" ]; then continue; fi; \
	    filec=$${file}.c; \
	    echo "compiling header: $${file}"; \
	    echo "#include \"$${file}\"" > $${filec}; \
	    $(COMPILER) -c $${filec} -o /dev/null $(CPPFLAGS) $(CFLAGS); \
	    \rm -v $${filec}; \
	  done \
	done

.PHONY: headers_tree
headers_tree:
	@for file in $(SOURCES); do \
	  echo -e "\ntree for file: $${file}"; \
	  $(COMPILER) -c -H $${file} $(CPPFLAGS) $(CFLAGS); \
	done


# --- Cleanup targets ---
# remove all not-project files and dirs
.PHONY: dist-clean
dist-clean:	clean-objs clean-tool clean-deps clean-bins clean-dirs
	@\rm -vrf $(ANALYZE_OUTPUT_FILE)

# remove all not-project files
.PHONY: clean
clean:	clean-objs clean-tool clean-deps

# remove object files
.PHONY: clean-objs
clean-objs:
	@\rm -vrf $(TAR_TESTS) $(TAR_LIBS) $(TAR_EXECS) $(TAR_SCRIPTS) $(DOCS) $(DIR_OBJS)/*.o $(DIR_OBJS)/**/*.o

# remove tool files
.PHONY: clean-tool
clean-tool:
	@\rm -vrf $(TAR_TESTS) $(TAR_LIBS) $(TAR_EXECS) $(TAR_SCRIPTS) $(DOCS) $(DIR_OBJS)/{*.gcno,*.su,*.tu} \
	   $(DIR_OBJS)/**/{*.gcno,*.su,*.tu} \
	   src*/*.cpp src*/**/*.cpp \
	   *.i *.s gmon.out

# remove depfiles
.PHONY: clean-deps
clean-deps:
	@\rm -vrf $(DIR_DEPS)/*.dep $(DIR_DEPS)/**/*.dep

# remove executables
.PHONY: clean-bins
clean-bins:
	@\rm -vrf $(DIR_BIN)/*

# remove all not-project dirs with contents
.PHONY: clean-dirs
clean-dirs:
	@\rm -vrf $(DIRS_CONCAT)






### REMAINDERS:
# create implicit rule for creating depfiles
#%.dep : %.c
	#$(MAKEDEPEND)

Added NAME.



>
1
manex

Added VERSION.







>
>
>
1
2
3
#define VER_MAJOR 0
#define VER_MINOR 1
#define VER_PATCH 0

Added lib_base/Debug.cxx.





































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*!F::Debugging facilities - main implementation file.
 *
 *  ::Purpose:
 *    Detect and inform about bugs in code. Bugs are considered distinct from
 *    standard errors - they are programmer mistakes, mainly in program logic.
 *    To deal with other errors (system, user etc.) see other facilities.
 *
 *  ::Goals:
 *    - thread-safe, reentrant, portable (POSIX systems)
 *    - buffer/integer overflow safe
 *
 *  ::Properties:
 *    compiler options:   -std=c++11
 *    thread safe
 *
 *  ::Limitations:
 *    - should have type indicating what is the cause: assert, parameter,
 *      sentinel etc.
 *
 *  ::Other:
 *    File:             This file is part of program distributed under GNU General Public License.
 *                      For terms of distribution, warranty and licensing see README file.
 *    Created:          2014-08-12
 *    (c) Copyright:    Maciej Helminiak 2014
 *    License:          GNU General Public License, version 3
 *                      Copy of the license is distributed along with this program
 *                      or can be seen at <http://www.gnu.org/licenses/>
 */




/*
snprintf(), vsnprintf():
  _BSD_SOURCE || _XOPEN_SOURCE >= 500 || _ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L; or cc -std=c99

asctime_r(), ctime_r(), gmtime_r(), localtime_r():
  _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || _POSIX_SOURCE
*/

#define _POSIX_C_SOURCE 200809L




/* current project */

/* mh library */
#include "core.hh"

/* libc */
#include <cstdarg>          // vsnprintf()
#include <ctime>            // time(), localtime() etc.

/* libc++ */

/* current module */
#include "Debug.hh"




/* implementation for classes declared in this namespace: */
using namespace ERRORS_HANDLING;
using namespace ERRORS_HANDLING::__impl__;




/* --------------------------------------------------- st_abort ---- */

/*!:: Construct aborter with given attributes.
 *    Takes information describing place and reason of abort request.
 */
st_abort::st_abort (
  const char* file,   //! file name where abort has been created
  const char* func,   //! function name
  int line,           //! line number
  const char* fmt,    //! reason    ;printf-like format
  ...                 //! reason    ;printf-like data list
)
  : _file{file}, _func{func}, _line{line}, _reason{'\0'}, _time{'\0'}
{
  ___Dassert(file != NULL && file[0] != '\0');
  ___Dassert(func != NULL && func[0] != '\0');
  ___Dassert(line > 0);
  ___Dassert(fmt != NULL);

  /*: Compose reason cstring: */
  va_list ap;
  va_start(ap, fmt);
  vsnprintf(_reason, REASON_MAX_BYTES, fmt, ap);
  va_end(ap);

  /*: Create time cstring: */
  time_t t = time(NULL);    // simple time - since epoch
  struct tm stT;            // broken-down time
  localtime_r(&t, &stT);
  strftime(_time, TIME_MAX_BYTES, "%Y-%m-%d %a %H:%M:%S", &stT);
}

/*!:: Write information about abort request to given file stream. Information
 *    is formatted in consistent and concise manner.
 */
void
st_abort::report_info (
  FILE* fs
){
  ___Dassert(fs != NULL);

  fprintf(fs, ":: ABORT REQUESTED:\n   %s\n   %s : %s() :%d:\n   %s\n",
               _time, _file, _func, _line, _reason);
}
/* --------------------------------------------------- st_abort ---- */

Added lib_base/Debug.hh.



























































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#ifndef MHLIB_BASE_SRCCORE_DEBUG_HH
#define MHLIB_BASE_SRCCORE_DEBUG_HH

/*!F::Debugging facilities - external interface file.
 *
 *  ::Provides class definitions, routines declarations and macro definitions.
 */




#include "core.hh"




namespace ERRORS_HANDLING {
namespace __impl__ {
/* =================================================================== */




/* ----------------------------------------------------- st_abort ---- */
/*!:: Object of this type (called aborter) is intended to be thrown as exception
 *    when program is making abort request (issued by error checking routine or
 *    assertion or in other situations).
 *
 * ::Usage:
 *  . Throw instance as exception, catch it where appropriate
 *  . Outer code is responsible for catching and performing appropriate action.
 *  . Intended to be used by assertion routines.
 *  . see Assertion routines below.
 *
 * ::Note:
 *    All members are public intentionally, subject to change in the future
 */
struct st_abort
{

/*- ...... FUNDAMENTALS ...... -*/
  st_abort (const char* file, const char* func, int line,
      const char* fmt, ...);

  /*- deleted -*/
  st_abort () = delete;


/*- ...... INTERFACE ...... -*/
  void report_info (FILE* fs);


/*- ...... DATA ...... -*/
  static constexpr const uint REASON_MAX_BYTES = 1024;
  static constexpr const uint TIME_MAX_BYTES = 128;

  const char* _file;    //! file name of abort request origin
  const char* _func;    //! function name
  int _line;            //! line number
  char _reason[REASON_MAX_BYTES];  //! reason
  char _time[TIME_MAX_BYTES];      //! time of request
};
/* ----------------------------------------------------- st_abort ---- */




/* =================================================================== */
}
/*- STUFF TO BE USED BY OUTSIDE PARTIES -*/
using __impl__::st_abort;
}




/*!:: Assertion routines.
 *
 * ::1  Assert condition.
 * ::2  Indicate execution of code that should not be reached.
 * ::3  Assert function parameter.
 * ::4  Assert internal function state.
 * ::5  Assert function return expression.
 */
/* =================================================================== */
  #ifdef DEBUG

#define ___Dassert(Cond) do { if(!(Cond)) { throw ERRORS_HANDLING::st_abort(__FILE__, __func__, __LINE__, "assertion failed: '"#Cond"'"); } } while(0)
#define ___Dsentinel(...) do { throw ERRORS_HANDLING::st_abort(__FILE__, __func__, __LINE__, __VA_ARGS__); } while(0)

#define ___Dparam(Cond) do { if(!(Cond)) { throw ERRORS_HANDLING::st_abort(__FILE__, __func__, __LINE__, "'"#Cond"' parameter invalid"); } } while(0)
#define ___Dinter(Cond) do { if(!(Cond)) { throw ERRORS_HANDLING::st_abort(__FILE__, __func__, __LINE__, "'"#Cond"' internal check failed"); } } while(0)
#define ___Dreturn(Cond) do { if(!(Cond)) { throw ERRORS_HANDLING::st_abort(__FILE__, __func__, __LINE__, "'"#Cond"' return expression invalid"); } } while(0)

  #else

#define ___Dassert(...)
#define ___Dsentinel(...)
#define ___Dparam(...)
#define ___Dinter(...)
#define ___Dreturn(...)

  #endif /*- DEBUG -*/
/* =================================================================== */




#endif /*- MHLIB_BASE_SRCCORE_DEBUG_HH -*/

Added lib_base/Exception.cxx.











































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
#include "core.hh"
#include "errors.h"
#include "Debug.hh"
#include "Exception.hh"


#include <cstdio>
#include <cstring>




/*!:: Exception object instance.
 * :: Used by Exception throwing, catching and handling routines.
 *    Created in thread local storage.
 */
__tls__ ERRORS_HANDLING::cl_exception __exc__;




/* implementation for classes declared in this namespace: */
using namespace ERRORS_HANDLING;
using namespace ERRORS_HANDLING::__impl__;




/* ---------------------------------------------------- excnum_en ---- */
constexpr const char* const excnum_en::_Labels[count-ERR_START_NUMBER+1];
constexpr const char* const excnum_en::_Descrs[count-ERR_START_NUMBER+1];


/*- ...... FUNDAMENTALS ...... -*/

/*!:: Construct with enum constant value.
 */
excnum_en::excnum_en (
  val_en val     //! excnum_en constant
)
  : _val{val}
{
  ___Dparam(val >= None && val < count);
}

/*!:: Construct with default value.
 */
excnum_en::excnum_en ()
{
}

/*!:: Construct with 'errno' constant value.
 */
excnum_en::excnum_en (
  int val       //! errno constant
)
  : _val{static_cast<val_en>(val)}
{
  ___Dparam(val >= 0 && val < count);
}

/*!:: Allows cast to 'int' (excnum_en -> int).
 *    Used to convert 'excnum_en' to 'errno' value.
 */
excnum_en::operator int() const
{
  ___Dreturn(_val >= 0 && _val < count);
  return _val;
}

/*!:: Copy-constructor.
 */
excnum_en::excnum_en (
  const excnum_en& obj    //! copied object
)
  : _val{obj._val}
{
}

/*!:: Assignment.
 */
excnum_en& excnum_en::operator= (
  const excnum_en& robj   //! assigned object
){
  _val = robj._val; return *this;
}


/*- ...... INTERFACE ...... -*/

/*!:: Return label of enum constant currently hold.
 */
const char*
excnum_en::label () const
{
  return _label();
}

/*!:: Return description of enum constant currently hold.
 */
const char*
excnum_en::descr () const
{
  return _descr();
}

/*!:: Return label of enum constant given as parameter.
 */
const char*
excnum_en::label (
  const excnum_en& e    //! excnum_en or errno constant
){
  return e._label();
}

/*!:: Return description of enum constant given as parameter.
 */
const char*
excnum_en::descr (
  const excnum_en& e    //! excnum_en or errno constant
){
  return e._descr();
}

/*- ...... INTERNAL ROUTINES ...... -*/
const char*
excnum_en::_label () const
{
   /* error in range of errno values defined in libc */
   if (_val < ERR_START_NUMBER) {
      ___Dinter(_val >= 0);
      return "";
   }
   /* error type defined outside libc */
   else {
      ___Dinter(_val >= None && _val < count);
      return _Labels[_val-ERR_START_NUMBER];
   }
}

const char*
excnum_en::_descr () const
{
   /* error in range of errno values defined in libc */
   if (_val < ERR_START_NUMBER) {
      ___Dinter(_val >= 0);
      return strerror(_val);
   }
   /* error type defined outside libc */
   else {
      ___Dinter(_val >= None && _val < count);
      return _Descrs[_val-ERR_START_NUMBER];
   }
}
/* ---------------------------------------------------- excnum_en ---- */




/* ------------------------------------------------- cl_exc_trace ---- */
/*- ...... INTERFACE ...... -*/

/*!:: Record location of exception origin.
 */
void
cl_exc_trace::origin_stamp (
  const char* file,   //! file where exception occured
  const char* func,   //! function name
  ulong line          //! line number
){
  ___Dparam(file != NULL);
  ___Dparam(func != NULL);

  _Origin._cs_file = file;
  _Origin._cs_func = func;
  _Origin._line = line;
}

/*!:: Record location of 'catch' block passed by exception.
 */
void
cl_exc_trace::app_midway_stamp (
  const char* file,   //! file where exception occured
  const char* func,   //! function name
  ulong line          //! line number
){
  ___Dparam(file != NULL);
  ___Dparam(func != NULL);

  ___Dinter(_used_stamps < STAMPS_MAX_NUM);

  _Stamps[_used_stamps]._cs_file = file;
  _Stamps[_used_stamps]._cs_func = func;
  _Stamps[_used_stamps]._line = line;
  ++_used_stamps;

  ___Dreturn(_used_stamps <= STAMPS_MAX_NUM);
}

/*!:: Record location of last 'catch' block.
 */
void
cl_exc_trace::term_stamp (
  const char* file,   //! file where exception occured
  const char* func,   //! function name
  ulong line          //! line number
){
  ___Dparam(file != NULL);
  ___Dparam(func != NULL);

  _Term._cs_file = file;
  _Term._cs_func = func;
  _Term._line = line;
}

const cl_exc_trace::st_stamp&
cl_exc_trace::ret_origin_stamp () const
{
  return _Origin;
}

const cl_exc_trace::st_stamp&
cl_exc_trace::ret_midway_stamp (
  uint idx            //! index of record of location
)
  const
{
  ___Dparam(idx < _used_stamps);

  return _Stamps[idx];
}

const cl_exc_trace::st_stamp&
cl_exc_trace::ret_term_stamp () const
{
  return _Term;
}

uint
cl_exc_trace::used_stamps () const
{
  return _used_stamps;
}
/* ------------------------------------------------- cl_exc_trace ---- */




/* ------------------------------------------------- cl_exception ---- */
constexpr const char* const cl_exception::FILE_DEF;
constexpr const char* const cl_exception::FUNC_DEF;
constexpr const ulong cl_exception::LINE_DEF;
constexpr const char* const cl_exception::DESCR_DEF;
constexpr const int cl_exception::ARB_VAL_DEF;


/*- ...... FUNDAMENTALS ...... -*/

/*!:: Construct with custom attributes.
 */
cl_exception::cl_exception (
  const char* subj,   //! subject
  excnum_en errnum,   //! error number
  const char* descr,  //! description of error
  const char* file,   //! file where exception occured (location of origin)
  const char* func,   //! function name
  ulong line,         //! line number
  int arb_val         //! arbitrary value for user use
)
  : _arb_val{arb_val},
    _cs_subj{subj}, _errnum{errnum}, _cs_descr{descr}, _C_error{NULL}
{
  ___Dparam(subj != NULL);
  ___Dparam(descr != NULL);
  ___Dparam(file != NULL);
  ___Dparam(func != NULL);

  _Trace.origin_stamp(file, func, line);
}

/*!:: Construct with given custom attributes, remaining attributes are default.
 */
cl_exception::cl_exception (
  const char* subj,   //! subject
  excnum_en errnum,   //! error number
  const char* file,   //! file where exception occured (location of origin)
  const char* func,   //! function name
  ulong line,         //! line number
  int arb_val         //! arbitrary value for user use
)
  : cl_exception(subj, errnum, DESCR_DEF, file, func, line, arb_val)
{
  ___Dparam(subj != NULL);
  ___Dparam(file != NULL);
  ___Dparam(func != NULL);
}

/*!:: Construct with given attributes custom, remaining attributes are default.
 */
cl_exception::cl_exception (
  const char* subj,   //! subject
  excnum_en errnum,   //! error number
  const char* descr,  //! description of error
  const char* file,   //! file where exception occured (location of origin)
  const char* func,   //! function name
  ulong line          //! line number
)
  : cl_exception(subj, errnum, descr, file, func, line, ARB_VAL_DEF)
{
  ___Dparam(subj != NULL);
  ___Dparam(descr != NULL);
  ___Dparam(file != NULL);
  ___Dparam(func != NULL);
}

/*!:: Construct with given attributes custom, remaining attributes are default.
 */
cl_exception::cl_exception (
  const char* subj,   //! subject
  excnum_en errnum,   //! error number
  const char* file,   //! file where exception occured (location of origin)
  const char* func,   //! function name
  ulong line          //! line number
)
  : cl_exception(subj, errnum, DESCR_DEF, file, func, line, ARB_VAL_DEF)
{
  ___Dparam(subj != NULL);
  ___Dparam(file != NULL);
  ___Dparam(func != NULL);
}

/*!:: Construct with default attributes.
 */
cl_exception::cl_exception (
)
  : cl_exception(SUBJ_DEF, excnum_en(), FILE_DEF, FUNC_DEF, LINE_DEF)
{
}

/*!:: Construct with attributes figured from C error.
 */
cl_exception::cl_exception (
  const st_mh_error& c_error
)
  : cl_exception()
{
  setup(c_error);
}

cl_exception::~cl_exception() {}


/*- ...... INTERFACE ...... -*/

/*!:: Set exception attributes.
 */
void
cl_exception::setup (
  const char* subj,   //! subject
  excnum_en errnum,   //! error number
  const char* descr,  //! description of error
  const char* file,   //! file where exception occured (location of origin)
  const char* func,   //! function name
  ulong line,         //! line number
  int arb_val         //! arbitrary value for user use
){
  ___Dparam(subj != NULL);
  ___Dparam(descr != NULL);
  ___Dparam(file != NULL);
  ___Dparam(func != NULL);

  first_stamp(file, func, line);
  _cs_subj = subj;
  _errnum = errnum;
  _cs_descr = descr;
  _arb_val = arb_val;
}

/*!:: Set exception attributes figured from C error.
 */
void
cl_exception::setup (
  const st_mh_error& c_error
){
  setup("C routine", errno, c_error.msg, "", "", 0, static_cast<int>(c_error.aux));
  _C_error = &c_error;
}

/*!:: Record location of origin.
 */
void
cl_exception::first_stamp (
  const char* file,   //! file where exception occured
  const char* func,   //! function name
  ulong line          //! line number
){
  ___Dparam(file != NULL);
  ___Dparam(func != NULL);

  _Trace.origin_stamp(file, func, line);
}

/*!:: Record location of 'catch' block on exception way.
 */
void
cl_exception::app_stamp (
  const char* file,   //! file where exception occured
  const char* func,   //! function name
  ulong line          //! line number
){
  ___Dparam(file != NULL);
  ___Dparam(func != NULL);

  /*: Silently ingore stamp if their max quantity reached: */
  if (_Trace.used_stamps() >= cl_exc_trace::STAMPS_MAX_NUM) { return; }

  /*: Append stamp: */
  _Trace.app_midway_stamp(file, func, line);

  return;
}

/*!:: Record location of last 'catch' block.
 */
void
cl_exception::last_stamp (
  const char* file,   //! file where exception occured
  const char* func,   //! function name
  ulong line          //! line number
){
  ___Dparam(file != NULL);
  ___Dparam(func != NULL);

  _Trace.term_stamp(file, func, line);
}

/*!:: Print information about exception in consistent and concise manner.
 */
void
cl_exception::report_info (
  FILE* fs      //! destination
){
  ___Dparam(fs != NULL);

  const char* sep = STAMPS_SEP;

  /*: Location of origin: */
  if (_C_error == NULL) {
    const cl_exc_trace::st_stamp& StampO = _Trace.ret_origin_stamp();
    fprintf(fs, "TRACE: %s:(%s):%lu", StampO._cs_file, StampO._cs_func, StampO._line);
  } else {
    //: Error originated from C routine:
    fprintf(fs, "TRACE: %s%s%s", _C_error->sig, sep, _C_error->trace);
  }

  /*: Visited 'catch' blocks: */
  for (uint i = 0; i < _Trace.used_stamps(); ++i) {
    const cl_exc_trace::st_stamp& Stamp = _Trace.ret_midway_stamp(i);
    fprintf(fs, "%s%s:(%s):%lu", sep, Stamp._cs_file, Stamp._cs_func, Stamp._line);
  }

  /*: Last 'catch' block: */
  const cl_exc_trace::st_stamp& Stamp = _Trace.ret_term_stamp();
  if (Stamp._line != 0) {
    fprintf(fs, "%s%s:(%s):%lu", sep, Stamp._cs_file, Stamp._cs_func, Stamp._line);
  }

  /*: Other attributes: */
  fprintf(fs, "\nSUBJ: %s\nERROR: %s [%d]\nDESCR: %s\n",
      _cs_subj, _errnum.descr(), static_cast<int>(_errnum), _cs_descr);
}

/*!:: Print information about exception in descriptive way.
 */
void
cl_exception::present_info (
  FILE* fs      //! destination
){
  ___Dparam(fs != NULL);

  const char* sep = STAMPS_SEP;

  /*: Type of error and subject: */
  fprintf(fs, "%s [%d] in %s at ",
      _errnum.descr(), static_cast<int>(_errnum), _cs_subj);

  /*: Location of origin: */
  if (_C_error == NULL) {
    const cl_exc_trace::st_stamp& StampO = _Trace.ret_origin_stamp();
    fprintf(fs, "%s:(%s):%lu", StampO._cs_file, StampO._cs_func, StampO._line);
  } else {
    //: Error originated from C routine:
    fprintf(fs, "%s%s%s", _C_error->sig, sep, _C_error->trace);
  }

  /*: Visited 'catch' blocks: */
  for (uint i = 0; i < _Trace.used_stamps(); ++i) {
    const cl_exc_trace::st_stamp& Stamp = _Trace.ret_midway_stamp(i);
    fprintf(fs, "%s%s:(%s):%lu", sep, Stamp._cs_file, Stamp._cs_func, Stamp._line);
  }

  /*: Last 'catch' block: */
  const cl_exc_trace::st_stamp& Stamp = _Trace.ret_term_stamp();
  if (Stamp._line != 0) {
    fprintf(fs, "%s%s:(%s):%lu", sep, Stamp._cs_file, Stamp._cs_func, Stamp._line);
  }

  /*: Error description: */
  fprintf(fs, "\n%s\n", _cs_descr);
}
/* ------------------------------------------------- cl_exception ---- */
/*


CONCEPTS
---------------------------------------------------


EXCEPTIONS OVERHEAD:
  - modern policy: try-catch: NONE, throw: HIGH (separate table with handling routines) + MORE MEMORY
  - old policy: try-catch: HIGH (pushed onto stack), throw: LOW


FAILURE ORIGIN:
    [System]
    [Pr-Developer]
    [Pr-Client]
    [User]

Fatal, Error, Warn, Info, Debug


FAILURE CATHEGORIES:
  Syntactic Error
          - compiler detects

  Semantic Error
          - prevents fun from succeeding by not:
          . meeting calees precondition (ex. param)
          . achieve own postcondition (ex. valid ret val)
          . reestablish shared maintained invariant
          => exception / assert

    fatal   - external fatal circumstances      ;nomem, thread abort
              can't prevent, can't cleanup
            => exception: fail fast
    external- external retriable circumstances  ;file non-exist, unsufficient perms
              can't prevent, cleanup possible
            => normal flow: retry/inform, continue
    logic   - code design fault                 ;wrong input format
              preventable, cleanup possible
            => exception: fail fast
    bug     - programmer fault                  ;NULL param, bad cast, index overflow, div by 0, > instead of >=
              preventable, cleanup possible
            => assert: abort fast


  Other   - expected outcome: fun succeeded but result means failure
          . no char in str found
          . obj is not type T
          => code/ret_Val/errno etc.


HANDLE WAYS:
  internal  - handled in fun
  other     - report to caller

  abort, exit, retry, ignore


GUARANTEES:
  GUARANT   THAT
  none      - bug
  basic     - pr in valid state: no leaks, invariants preserved, state may be different
  strong    - consistent state: original (operation rolled back) OR target (commited)
  nofail/nothrow  - can't fail, Excepts handled internally      ;destr, dealloc-funs, swap-funs

  + Provide strongest guarantee function can.
  + Guarantee can not penalize code that do not need it.
  + Guarantee can penalize code using fun only if code states that it needs this guarantee.

SPECIAL CASES:
  constructor:    cant create obj =>Except    (obj's lifetime never began)
  destructor / deallocation funs:     except-emmiting code on side and when succeeded modify pr state with non-throwing ops
  operators:      no place for error-params or ret-error, only errno-like approach if no exceptions


ASSURANCES:
  precondition        - condition before fun call (param)
  postcondition       - condition after call (ret val)
  invariant           - state of pr/class/fun that must be true all the time




SYNTAX
---------------------------------------------------

unwinding stack: immediate catch / return+caller catch / propagate further / main() / ev. uncaught:terminate
catch: execute catch code + continue execution after catch {}

try
{
 throw VALUE
}
catch (DERIVED&)
{
  cerr << "Error";
}
catch (BASE&)
{
  cerr << "Error";
}
catch (T& OBJ)
{
  cerr << "Error: " << OBJ;
  throw; == throw OBJ;        //rethrow exception
}
catch (...)
{
  //empty block - ignore exception
}

catch (T& ) { }   ==  catch(T& obj) { throw; }

Fun()
try               //function-try-block
  : a(0)
{ BODY }
catch(...)
{ HANDLE_EXC }

exc specifiers: void Fun() throw(T1,T2) / throw(...) / throw()        //may throw: types / unspecified exc / none

std::exception : bad_alloc / bad_cast / runtime_error ...
{
  what()
};



PROPER USE
---------------------------------------------------

throw obj catch ref&

class Base { virtual void raise() { throw *this; }
class Deriv { virtual void raise() { throw *this; }
void f(Base& e) { e.raise(); }
Deriv e; try { f(e); }    catch (Base& e) { }           //throw polymorphically

try { AQUIRE_RES(var); RELEASE(var); } catch(...) { RELEASE(var); }     //var needs to be in both scopes
ptr = NULL; try { ptr = new K; delete ptr; } catch(...) { delete ptr; } //ptr needs to be in both scopes
try { p = new K; auto_ptr<K> xp(p); } catch(...) { }                    //auto_ptr delete holded ptr when out of scope <memory>
try { K obj; } catch(...) { }                                           //destr called when out of scope
K obj; obj.action(); obj.commit();                                      //commit makes destructor not to undo operation

constr { NO if STATIC INSTANCES   //standard says: cannot catch Exc from static obj
destr { NEVER                     //exc during stack unwinding terminates program

class OwnException {
  OwnException()
  OwnException(string)
  OwnException(string, OwnException)
  ALWAYS COPY-CONSTR



ENHANCEMENTS
---------------------------------------------------

<execinfo.h> <GNU>
exc_constr {
  void* buf[25]; int size = backtrace(buf, 25);       //series of return addresses of frames on stack (active function calls), newest first
  char** symbols = backtrace_symbols(buf, size);      //array of strs describing frame addresses symbolically
  for (0 TO size) { cout << symbols[i]; }             // fun_name + offset into fun + ret addr
  free(symbols);


SCOPE GUARDS

SGImplBase {
  protected:
    mutable bool _dismissed;
  public:
    void Dismiss() { _dismissed = true; }
    SGImplBase() : _dismissed(false) {}
    SGImplBase(const SGImplBase& obj) : _dismissed(obj._dismissed) { obj.Dismiss(); }
    ~SGImplBase() {}
  private:
    operator=
};

template <typename FUN, typename PARM>
class SGImpl1 : public SGImplBase
{
  private:
    FUN _f;
    PARM _p;
  public:
    SGImpl1 (const FUN& f, const PARM& p) : _f(f), _p(p) {}
    ~SGImpl1() { if (!_dismissed) _f(_p);
}

template <typename FUN, typename PARM>
SGImpl1<FUN, PARM>
MakeGuard (const FUN& f, const PARM& p)
{
  return SGImpl1<FUN, PARM>(f, p);
}

typedef const SGImplBase& ScopeGuard;


{
  OPERATION1
  ScopeGuard g1 = MakeObjGuard(obj, &Klasa::reverting_method);    //auto call given meth in destructor on object
  OPERATION2        //throw => obj.reverting_method()
  ScopeGuard g2 = MakeGuard(fun, var);                            //auto call given fun in destructor with variable
  OPERATION3        //throw => fun(var)
  g1.Dismiss();     //disable above
  g2.Dismiss();     //disable above
}

 */

Added lib_base/Exception.hh.















































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
#ifndef MHLIB_BASE_SRCCORE_EXCEPTION_HH
#define MHLIB_BASE_SRCCORE_EXCEPTION_HH




#include "core.hh"
#include "errors.h"
#include <exception>




namespace ERRORS_HANDLING {
namespace __impl__ {
/* =================================================================== */




/* ---------------------------------------------------- excnum_en ---- */
/*!:: Type of error (exception).
 *    Defines error type labels and descriptions too.
 *
 *  ::Note:
 *    Auxillary for exception class. Not intended for stand-alone use.
 */
struct excnum_en
{

/*- ...... SPECIAL ...... -*/
  /* Macros for compile-time creation of eumeration constants and their labels
     and descriptions. Everything in sync. */

  #define MH_ERR_START_NUMBER 4096

  #undef MH_ENUM_CREATE
  #undef MH_ENUM_CREATE_N
  #undef MH_ENUM_CONSTANTS
  #define MH_ENUM_CONSTANTS \
    MH_ENUM_CREATE_N(None, "No error", MH_ERR_START_NUMBER), \
    MH_ENUM_CREATE(OverflowInt, "Integer overflow"), \
    MH_ENUM_CREATE(OverflowBuf, "Buffer overflow"), \
    MH_ENUM_CREATE(StateWrong, "Wrong state"), \
    MH_ENUM_CREATE(BadParam, "Bad parameter"), \
    MH_ENUM_CREATE(LenExc, "Length exceeded"), \
    MH_ENUM_CREATE(Custom, "Custom error"), \
    MH_ENUM_CREATE(All, "All errors"), \
    MH_ENUM_CREATE(Unknown, "Unknown error") \


/*- ...... TYPES ...... -*/
 public:
  enum val_en : int
  {
    #undef MH_ENUM_CREATE
    #undef MH_ENUM_CREATE_N
    #define MH_ENUM_CREATE(CONST, DESCR) CONST
    #define MH_ENUM_CREATE_N(CONST, DESCR, VAL) CONST=VAL
    MH_ENUM_CONSTANTS,
    count
  };


/*- ...... FUNDAMENTALS ...... -*/
 public:
  excnum_en ();
  excnum_en (val_en val);
  excnum_en (int val);

  operator int() const;

  excnum_en (const excnum_en& obj);
  excnum_en& operator= (const excnum_en& robj);

  /*- .. deleted..  -*/
  template<typename T> operator T () const = delete;


/*- ...... INTERFACE ...... -*/
 public:
  const char* label () const;
  const char* descr () const;

  static const char* label (const excnum_en& e);
  static const char* descr (const excnum_en& e);


/*- ...... DATA ...... -*/
 private:
  static const int ERR_START_NUMBER = MH_ERR_START_NUMBER; //! first custom error number
  val_en _val = Unknown;                     //! enum value

  static constexpr const char* const _Labels[count-ERR_START_NUMBER+1] = {
    #undef MH_ENUM_CREATE
    #undef MH_ENUM_CREATE_N
    #define MH_ENUM_CREATE(CONST, DESCR) #CONST
    #define MH_ENUM_CREATE_N(CONST, DESCR, VAL) #CONST
    MH_ENUM_CONSTANTS
  };    //! array of labels of enum constants

  static constexpr const char* const _Descrs[count-ERR_START_NUMBER+1] = {
    #undef MH_ENUM_CREATE
    #undef MH_ENUM_CREATE_N
    #define MH_ENUM_CREATE(CONST, DESCR) DESCR
    #define MH_ENUM_CREATE_N(CONST, DESCR, VAL) DESCR
    MH_ENUM_CONSTANTS
  };    //! array of descriptions of enum constants


/*- ...... INTERNAL ROUTINES ...... -*/
 private:
  const char* _label () const;
  const char* _descr () const;


  friend class errnum_TEST_en;
};
/* ---------------------------------------------------- excnum_en ---- */




/* ------------------------------------------------- cl_exc_trace ---- */
/*!:: Exception trace.
 *    Allows tracking of exception throw location and way through 'catch()'
 *    blocks.
 *
 *  ::Note:
 *    Auxillary for exception class. Not intended for stand-alone use.
 */
class cl_exc_trace
{

/*- ...... TYPES ...... -*/
protected:
  struct st_stamp
  {
    st_stamp () : _cs_file{NULL}, _cs_func{NULL}, _line{0} {}

    const char* _cs_file; //! file name
    const char* _cs_func; //! function name
    ulong _line;          //! line number
  };

/*- ...... INTERFACE ...... -*/
protected:
  void origin_stamp (const char* file, const char* func, ulong line);
  void app_midway_stamp (const char* file, const char* func, ulong line);
  void term_stamp (const char* file, const char* func, ulong line);
  const st_stamp& ret_origin_stamp () const;
  const st_stamp& ret_midway_stamp (uint idx) const;
  const st_stamp& ret_term_stamp () const;
  uint used_stamps () const;

/*- ...... DATA ...... -*/
protected:
  static const uint STAMPS_MAX_NUM = 128;

private:
  st_stamp _Origin = {};            //! first stamp
  st_stamp _Stamps[STAMPS_MAX_NUM]; //! stamps between
  uint _used_stamps = 0;            //! number of stamps used in '_Stamps'
  st_stamp _Term = {};              //! last stamp


/*- ...... Friends ...... -*/
  friend class cl_exception;
  friend class cl_exc_trace_TEST;
};
/* ------------------------------------------------- cl_exc_trace ---- */




/* ------------------------------------------------- cl_exception ---- */
/*!:: Exception.
 *    Create object with specified exception attributes.
 *    Record location of origin and all places where it is caught.
 *    Print exception information.
 */
class cl_exception : public std::exception
{

/*- ...... FUNDAMENTALS ...... -*/
public:
  /* `descr` and `arb_val` are not necessary. */
  cl_exception (const char* subj, excnum_en errnum, const char* descr,
                const char* file, const char* func, ulong line,
                int arb_val);

  cl_exception (const char* subj, excnum_en errnum,
                const char* file, const char* func, ulong line,
                int arb_val);

  cl_exception (const char* subj, excnum_en errnum, const char* descr,
                const char* file, const char* func, ulong line);

  cl_exception (const char* subj, excnum_en errnum,
                const char* file, const char* func, ulong line);

  cl_exception ();

  cl_exception (const st_mh_error& c_error);

  virtual ~cl_exception();

  /*- .. deleted..  -*/
  cl_exception& operator= (const cl_exception&) = delete;


/*- ...... INTERFACE ...... -*/
public:
  virtual void setup (const char* subj, excnum_en errnum, const char* descr,
                const char* file, const char* func, ulong line,
                int arb_val);
  virtual void setup (const st_mh_error& c_error);
  virtual void first_stamp (const char* file, const char* func, ulong line);
  virtual void app_stamp (const char* file, const char* func, ulong line);
  virtual void last_stamp (const char* file, const char* func, ulong line);
  void report_info (FILE* fs);
  void present_info (FILE* fs);


/*- ...... PUBLIC DATA ...... -*/
public:
  int _arb_val;         //! arbitrary value for custom use


/*- ...... DATA ...... -*/
protected:
  /* Default values */
  static constexpr const char* const SUBJ_DEF = "";
  static constexpr const char* const FILE_DEF = "";
  static constexpr const char* const FUNC_DEF = "";
  static constexpr const ulong LINE_DEF = 0;
  static constexpr const char* const DESCR_DEF = "";
  static constexpr const int ARB_VAL_DEF = 0;

  static constexpr const char* STAMPS_SEP = " --> ";  //! separator for locations in trace

  /* Exception data */
  const char* _cs_subj;   //! subject of exception: filename, file system, object name, data etc.
  excnum_en _errnum;      //! errno or excnum_en value denoting error type
  const char* _cs_descr;  //! more elaborate description of error
  cl_exc_trace _Trace = {}; //! Way travelled by exception

  const st_mh_error* _C_error;  //! error taken over from C routines


  friend class cl_exception_TEST;
};
/* ------------------------------------------------- cl_exception ---- */




/* =================================================================== */
}
/*- STUFF TO BE USED BY OUTSIDE PARTIES -*/
using __impl__::excnum_en;
using __impl__::cl_exception;
}




extern __tls__ ERRORS_HANDLING::cl_exception __exc__;




/*!:: Interface macros.
 *    Use them on regular basis instead of raw classes, which should be used
 *    only in special cases. It will make your code consistent.
 */
/* =================================================================== */

#define ExcThrowObject() do { \
  throw __exc__; \
} while(0)

#define ExcArbVal(Val) do { \
  __exc__._arb_val = (Val); \
} while(0)




#define ExcThrow(Subj, Errnum, Descr) do { \
  __exc__.setup((Subj), (Errnum), (Descr), __FILE__, __func__, __LINE__, __exc__._arb_val); \
  ExcThrowObject(); \
} while(0)

#define ExcRethrow() do { \
  ExcThrowObject(); \
} while(0)




#define ExcMidStamp() do { \
  __exc__.app_stamp(__FILE__, __func__, __LINE__); \
} while(0)

#define ExcLastStamp() do { \
  __exc__.last_stamp(__FILE__, __func__, __LINE__); \
} while(0)




/*!:: Macro to handle C routines errors. Counterpart of HandleErr() in C. */
#define HandleCErr() do { \
  if (errno != 0) { \
  __exc__.setup(__err__); \
  __exc__.first_stamp(__FILE__, __func__, __LINE__); \
  ExcThrowObject(); \
  } \
} while(0)

/*!:: Macro to handle C routines errors. Counterpart of ErrorTrigIf() in C. */
#define ExcTrigIf(Cond, Subj, Errnum, Descr) do { \
  if ((Cond)) { \
    ExcThrow((Subj), (Errnum), (Descr)); \
  } \
} while(0)




#define ExcReportInfo(FS) do { \
  __exc__.report_info((FS)); \
} while(0)

#define ExcPresentInfo(FS) do { \
  __exc__.present_info((FS)); \
} while(0)

/* =================================================================== */




/*!:: Standard, common exceptions tracking.
 *    Use them for consistent, standardized exceptions tracking in functions.
 *    Will record location and rethrow exception.
 */
/* =================================================================== */
#define ExcTRACK_BEG try {

#define ExcTRACK_END } \
catch (ERRORS_HANDLING::cl_exception&) { ExcMidStamp(); ExcRethrow(); }
/* =================================================================== */




#endif /*- MHLIB_BASE_SRCCORE_EXCEPTION_HH -*/

Added lib_base/core.hh.





























































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
#ifndef MHLIBS_BASE_SRCCORE_CORE_HH
#define MHLIBS_BASE_SRCCORE_CORE_HH

/*!F::Core declarations and definitions for Machel's C++ projects.
 *
 *  ::Purpose:
 *    Common for every C++ project declarations and definitions:
 *    - headers
 *    - macros
 *    - type definitions and aliases
 *    - common functions nad macro functions
 *    - GNU extensions: attributes
 *
 *  ::Properties:
 *    compiler options:   -std=c++11
 *    thread safe
 *
 *  ::Other:
 *    Created:            2014-06-16
 *    (c) Copyright:      "Machel" 2014
 *    License:            GNU Public License
 */




/* 32/64b */
/* -------------------------------------------------------------------------- */

/* Functions that take 32b parameters (like lseek) wil now take 64b parameters.
 * Thus lseek on 32b system will be transparently replaced by lseek64.
 * Allows 32b systems to use 64b large files and large data.
 */
#define _FILE_OFFSET_BITS 64




/* Common headers */
/* -------------------------------------------------------------------------- */

#include <cerrno>      // errno()
#include <cassert>     // assert()
#include <cstddef>     // NULL, size_t, ptrdiff_t, offsetof


/* Pathname component separator */
#if defined(_WIN32) || defined(_MSC_VER)
# define MH_PNCS '\\'
#else
# define MH_PNCS '/'
#endif




/* Thread local storage. */
/* -------------------------------------------------------------------------- */

/* Thread local storage. Different defines for different compilers.
 * Usage:
 *    extern/static __tls__ int var;
 *
 * !!! C++:
 *    GCC do not allow construct/destruct for '__thread' variables!
 *    use C++'s 'thread_local' (but it is <C++11>)
 */
#ifndef __tls__
#if defined(__cplusplus) && (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
#  define __tls__ thread_local
#elif defined(__GNUC__) || defined(__GNUG__) \
   || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \
   || defined(__ICC) || defined(__INTEL_COMPILER)
#  define __tls__ __thread
#elif defined(_MSC_VER) && defined(__cplusplus)
#  define __tls__ __declspec(thread)
#else
#  define __tls__ TLS_FOR_THIS_COMPILER_NOT_SUPPORTED
#endif
#endif




/* Type definitions. */
/* -------------------------------------------------------------------------- */


#undef NULL
#define NULL nullptr


/* Signed size type. For Windows and for other systems.
 * ssize_t
 */
#if defined(_MSC_VER)
#  include <BaseTsd.h>
   typedef SSIZE_T ssize_t;
#else
#  include <unistd.h>
#endif

/* SIZE_MAX */
#include <climits>        // <C++/Solaris>SIZE_MAX
#if HAVE_STDINT_H
#include <cstdint>        // <C99>SIZE_MAX
#endif

#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)(-1))
#endif


/*!:: Special type that can take three values:
 *       negative (less then 0), neutral (0), positive (greater then 0).
 */
#if !defined(TROOL_DEFINED)
enum trool { tr_neg=-1, tr_less=-1, tr_neut=0, tr_equal=0, tr_pos=1, tr_great=1 };
typedef enum trool trool;
#define TROOL_DEFINED
#endif


/* aliases for built-in types */
typedef unsigned short ushort;
typedef signed short sshort;
typedef unsigned int uint;
typedef signed int sint;
typedef unsigned long ulong;
typedef signed long slong;
typedef int FD;

#include <string>
typedef std::string str;



/* Helper functions. */
/* -------------------------------------------------------------------------- */

/*!:: Stringize macro constant
 */
#define __STR__(x) #x
#define _STR_(x) __STR__(x)

/*!1-3
 * :: Set arrays.
 */
#define ArrSet(ARR,NELS,VAL) for(size_t ii=0; ii<(NELS); ++ii) (ARR)[ii] = (VAL)
#define ArrSetN(ARR,START,NELS,VAL) for(size_t ii=(START); ii<(NELS); ++ii) (ARR)[ii] = (VAL)
#define Arr2DSet(ARR,RELS,CELS,VAL) for(size_t ii=0; ii<(RELS); ++ii) for(size_t jj=0; jj<(CELS); ++jj) (ARR)[ii][jj] = (VAL)

#define SetArr2D(parr, I, J, val) do { \
   for (size_t iii = 0; iii < (I); ++iii) { \
      for (uint jjj = 0; jjj < (J); ++jjj) { \
         (*(parr))[iii][jjj] = (val); \
      } \
   } \
   } while(0)

#ifndef ASK_YN_DEFINED
#include <cstdio>
#include <cstdarg>
static inline
bool
ask_yn (
   const char* yes_chars,  //! any of this chars is 'yes' answer
   const char* fmt,        //! format string conforming to printf specification
   ...                     //! data to print
){
   int ch = '\0';
   if (fmt != NULL) {
      va_list ap;
      va_start(ap, fmt);
      vfprintf(stdout, fmt, ap);
      fflush(stdout);
      va_end(ap);
   }
   ch = getchar();  //==getc(stdin)
   if (ch == '\n') { ch = getchar(); }    //scanf() leaves \n in input buffer
   while (*yes_chars != '\0') {
      if (ch == *yes_chars) { return true; }
      ++yes_chars;
   }
   return false;
}
#define ASK_YN_DEFINED 1
#endif




/* GCC extensions. */
/* -------------------------------------------------------------------------- */

/* Function attributes.
 * Define attribute macros only if compiler is GCC or compatible (particulary
 * Clang), otherwise define empty macros that do nothing.
 */
#if defined(__GNUC__) || defined(__GNUG__)

   // function has no effects, ONLY: ret val, may depend on outside var,
   // not on volatile mem etc.
#  define __attr_pure__ __attribute__((__pure__))

   // function has no effects, ONLY: ret val, may NOT depend on outside var,
   // not on volatile mem etc.
   // examining data pointed by ptr args is depending on outside data!
#  define __attr_const__ __attribute__((__const__))

   // list contains parameter numbers starting from 1 that can not be NULL.
#  define __attr_nonnull__(...) __attribute__((__nonnull__(__VA_ARGS__)))

   // return value can not be NULL
#  define __attr_ret_nonnull__ __attribute__((__returns_nonnull__))

   // return value can not be ignored
#  define __attr_wures__ __attribute__((__warn_unused_result__))

   // num of parameter that specifies size of memory that function will alloc
#  define __attr_alloc_size__(PARAM_NUM) __attribute__((__alloc_size__(PARAM_NUM)))

   // mallo-like function - see documentation
#  define __attr_malloc__ __attribute__((__malloc__))

   // printf-like function - see documentation
#  define __attr_format__(FUN,FMT_NUM,VA_NUM) __attribute__((__format__(FUN,FMT_NUM,VA_NUM)))

   // num of parameter from back starting from 0 that is sentinel in va function
#  define __attr_sentinel__(PARAM_NUM_BACK) __attribute__((__sentinel__(PARAM_NUM_BACK)))

   // attribute can be unused, suppress warnings about it
#  define __attr_unused__ __attribute((__unused__))

#else /*- __GNUC__ -*/

#  define __attribute__(x) /*-nothing-*/
#  define __attr_pure__ /*-nothing-*/
#  define __attr_const__ /*-nothing-*/
#  define __attr_nonnull__(...) /*-nothing-*/
#  define __attr_ret_nonnull__ /*-nothing-*/
#  define __attr_wures__ /*-nothing-*/
#  define __attr_alloc_size__(PARAM_NUM) /*-nothing-*/
#  define __attr_malloc__ /*-nothing-*/
#  define __attr_format__(FUN,FMT_NUM,VA_NUM) /*-nothing-*/
#  define __attr_sentinel__(PARAM_NUM_BACK) /*-nothing-*/
#  define __attr_unused__ /*-nothing-*/
#endif /*- __GNUC__ -*/

// for descriptions of attributes see documentation at:
//    http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Function-Attributes.html




/* REAMINDERS */

/* macros indicating compilers */
#if defined(__GNUC__) || defined(__GNUG__)
   /* <C&C++> <C++> GNU GCC/G++, Clang/LLVM, IBM XL C/C++. ------------------- */
#elif (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
   /* GNU GCC/G++. -----------------------------------only------ */
#elif defined(__clang__)
   /* <C&C++> Clang/LLVM. ---------------------------------------------- */
#elif defined(__IBMC__) || defined(__IBMCPP__)
   /* <C> <C++> IBM XL C/C++. -------------------------------------------- */
#elif defined(__ICC) || defined(__INTEL_COMPILER)
   /* <C&C++> <C&C++> Intel ICC/ICPC. ------------------------------------------ */
#elif defined(__HP_cc) || defined(__HP_aCC)
   /* <C> <C++> Hewlett-Packard C/aC++. ---------------------------------- */
#elif defined(_MSC_VER) && defined(__cplusplus)
   /* <C&C++> <C++> Microsoft Visual Studio. --------------------------------- */
#elif defined(__PGI) && defined(__cplusplus)
   /* <C&C++> <C++> Portland Group PGCC/PGCPP. ------------------------------- */
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
   /* <C> <C++> Oracle Solaris Studio. ----------------------------------- */
#endif

/* macros indicating operating systems */
// __unix__    - any unix-like, NOT Apple-like
//             - HP-UX
// __linux__   - linuxes
// _POSIX*     - linuxes
// BSD         - any BSD or specific: __DragonFly__, __Free/Net/OpenBSD__
//             - OSX, iOS
// __APPLE__ && __MACH__   - OSX, iOS     + TARGET_OS_MAC (OSX), TARGET_OS_IPHONE etc.
// __sun && __SVR4
//
// __hpux      - HP-UX
// _AIX        - Ibm AIX
//
// _WIN64, _WIN32             - WinXP,Vista,7,8
// __CYGWIN__ && !_WIN32      - Cygwin (only 32b version exist)
// __MINGW32/64_              - MinGW

#if defined(__unix__)
#include <sys/param.h>
#if defined(BSD)
   /* BSD (DragonFly BSD, FreeBSD, OpenBSD, NetBSD) ----------- */
#endif
#endif

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <sys/param.h>
#if defined(BSD)
   /* BSD (DragonFly BSD, FreeBSD, OpenBSD, NetBSD) + OSX, iOS, Darwin ----------- */
#endif
#endif

#if defined(__APPLE__) && defined(__MACH__)
   /* Apple OSX and iOS (Darwin). ------------------------------ */
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
   /* iOS in Xcode simulator */
#elif TARGET_OS_IPHONE == 1
   /* iOS on iPhone, iPad, etc. */
#elif TARGET_OS_MAC == 1
   /* OSX */
#endif
#endif

/* UNIX line and POSIX compliant - currently BSD,linux,OSX,Solaris */
#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
   /* UNIX-style OS. ------------------------------------------- */
#include <unistd.h>
#if defined(_POSIX_VERSION)
   /* POSIX compliant */
#endif
#endif




#endif /*- MHLIBS_BASE_SRCCORE_CORE_HH -*/

Added lib_c_base/common_mhlbase.h.













































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#ifndef MHCL_BASE_SRCMAIN_COMMON_MHLBASE_H
#define MHCL_BASE_SRCMAIN_COMMON_MHLBASE_H

/*!F::Common items for this project source files.
 *
 *  ::Purpose:
 *    Provides items common for source files in current project, like its name,
 *    version and the like.
 *
 *  ::Properties:
 *    compiler options:   -std=
 *    thread safe
 *
 *  ::Other:
 *    Created:            2013-12-16
 *    (c) Copyright:      "Machel" 2013
 *    License:            GNU Public License
 */




#define MHLC_BASE_PR_PACK "mhlibs"
#define MHLC_BASE_PR_NAME "baselibs"
#define MHLC_BASE_PR_LONGNAME "base tools"
#define MHLC_BASE_VER_MAJOR 0
#define MHLC_BASE_VER_MINOR 4
#define MHLC_BASE_VER_PATCH 0
#define MHLC_BASE_PR_VER MHLC_BASE_VER_MAJOR.MHLC_BASE_VER_MINOR.MHLC_BASE_VER_PATCH
#define MHLC_BASE_PR_FULLNAME MHLC_BASE_PR_NAME " (" MHLC_BASE_PR_PACK ") " _STR_(MHLC_BASE_PR_VER)


#define LOG_DEF_STREAM stderr




#endif /*- MHCL_BASE_SRCMAIN_COMMON_MHLBASE_H -*/

Added lib_c_base/core.h.



















































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#ifndef MHLIBS_BASE_SRCBASE_CORE_H
#define MHLIBS_BASE_SRCBASE_CORE_H

/*!F::Core declarations and definitions for Machel's C projects.
 *
 *  ::Purpose:
 *    Common for every C project declarations and definitions:
 *    - headers
 *    - macros
 *    - type definitions and aliases
 *    - common functions nad macro functions
 *    - GNU extensions: attributes
 *
 *  ::Properties:
 *    compiler options:   -std=c99
 *    thread safe
 *
 *  ::Other:
 *    Created:            2013-12-16
 *    (c) Copyright:      "Machel" 2013
 *    License:            GNU Public License
 */




/* 32/64b */
/* -------------------------------------------------------------------------- */

/* Functions that take 32b parameters (like lseek) wil now take 64b parameters.
 * Thus lseek on 32b system will be transparently replaced by lseek64.
 * Allows 32b systems to use 64b large files and large data.
 */
#define _FILE_OFFSET_BITS 64




/* Common headers */
/* -------------------------------------------------------------------------- */

#include <assert.h>     // assert()
#include <stddef.h>     // NULL, size_t, ptrdiff_t, offsetof
#include <stdbool.h>    // bool, true, false


/* Pathname component separator */
#define PNCS '/'




/* Thread local storage. */
/* -------------------------------------------------------------------------- */

/* Thread local storage. Different defines for different compilers.
 * Usage:
 *    extern/static __tls__ int var;
 *
 * !!! C++:
 *    GCC do not allow construct/destruct for '__thread' variables!
 *    use C++'s 'thread_local' (but it is <C++11>)
 */
#ifndef __tls__
#if defined(__cplusplus) && (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
#  define __tls__ thread_local
#elif defined(__GNUC__) || defined(__GNUG__) \
   || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \
   || defined(__ICC) || defined(__INTEL_COMPILER)
#  define __tls__ __thread
#elif defined(_MSC_VER) && defined(__cplusplus)
#  define __tls__ __declspec(thread)
#else
#  define __tls__ TLS_FOR_THIS_COMPILER_NOT_SUPPORTED
#endif
#endif




/* Type definitions. */
/* -------------------------------------------------------------------------- */


#if defined(__cplusplus)
#undef NULL
#define NULL nullptr
#endif


/* Signed size type. For Windows and for other systems.
 * ssize_t
 */
#if defined(_MSC_VER)
#  include <BaseTsd.h>
   typedef SSIZE_T ssize_t;
#else
#  include <unistd.h>
#endif

/* SIZE_MAX */
#include <limits.h>        // <C++/Solaris>SIZE_MAX
#if HAVE_STDINT_H
#include <stdint.h>        // <C99>SIZE_MAX
#endif

#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)(-1))
#endif

/*!:: Special type that can take three values:
 *       negative (less then 0), neutral (0), positive (greater then 0).
 */
#if !defined(TROOL_DEFINED)
enum trool { tr_neg=-1, tr_less=-1, tr_neut=0, tr_equal=0, tr_pos=1, tr_great=1 };
typedef enum trool trool;
#define TROOL_DEFINED
#endif


/* aliases for built-in types */
typedef unsigned short ushort;
typedef signed short sshort;
typedef unsigned int uint;
typedef signed int sint;
typedef unsigned long ulong;
typedef signed long slong;
typedef int FD;




/* Helper functions. */
/* -------------------------------------------------------------------------- */

/*!:: Stringize macro constant
 */
#define __STR__(x) #x
#define _STR_(x) __STR__(x)

/*!1-3
 * :: Set arrays.
 */
#define ArrSet(ARR,NELS,VAL) for(size_t ii=0; ii<(NELS); ++ii) (ARR)[ii] = (VAL)
#define ArrSetN(ARR,START,NELS,VAL) for(size_t ii=(START); ii<(NELS); ++ii) (ARR)[ii] = (VAL)
#define Arr2DSet(ARR,RELS,CELS,VAL) for(size_t ii=0; ii<(RELS); ++ii) for(size_t jj=0; jj<(CELS); ++jj) (ARR)[ii][jj] = (VAL)

#define SetArr2D(parr, I, J, val) do { \
   for (size_t iii = 0; iii < (I); ++iii) { \
      for (uint jjj = 0; jjj < (J); ++jjj) { \
         (*(parr))[iii][jjj] = (val); \
      } \
   } \
   } while(0)

#ifndef ASK_YN_DEFINED
#include <stdio.h>
#include <stdarg.h>
static inline
bool
ask_yn (
   const char* yes_chars,  //! any of this chars is 'yes' answer
   const char* fmt,        //! format string conforming to printf specification
   ...                     //! data to print
){
   int ch = '\0';
   if (fmt != NULL) {
      va_list ap;
      va_start(ap, fmt);
      vfprintf(stdout, fmt, ap);
      fflush(stdout);
      va_end(ap);
   }
   ch = getchar();  //==getc(stdin)
   if (ch == '\n') { ch = getchar(); }    //scanf() leaves \n in input buffer
   while (*yes_chars != '\0') {
      if (ch == *yes_chars) { return true; }
      ++yes_chars;
   }
   return false;
}
#define ASK_YN_DEFINED 1
#endif




/* GCC extensions. */
/* -------------------------------------------------------------------------- */

/* Function attributes.
 * Define attribute macros only if compiler is GCC or compatible (particulary
 * Clang), otherwise define empty macros that do nothing.
 */
#if defined(__GNUC__) || defined(__GNUG__)

   // function has no effects, ONLY: ret val, may depend on outside var,
   // not on volatile mem etc.
#  define __attr_pure__ __attribute__((__pure__))

   // function has no effects, ONLY: ret val, may NOT depend on outside var,
   // not on volatile mem etc.
   // examining data pointed by ptr args is depending on outside data!
#  define __attr_const__ __attribute__((__const__))

   // list contains parameter numbers starting from 1 that can not be NULL.
#  define __attr_nonnull__(...) __attribute__((__nonnull__(__VA_ARGS__)))

   // return value can not be NULL
#  define __attr_ret_nonnull__ __attribute__((__returns_nonnull__))

   // return value can not be ignored
#  define __attr_wures__ __attribute__((__warn_unused_result__))

   // num of parameter that specifies size of memory that function will alloc
#  define __attr_alloc_size__(PARAM_NUM) __attribute__((__alloc_size__(PARAM_NUM)))

   // mallo-like function - see documentation
#  define __attr_malloc__ __attribute__((__malloc__))

   // printf-like function - see documentation
#  define __attr_format__(FUN,FMT_NUM,VA_NUM) __attribute__((__format__(FUN,FMT_NUM,VA_NUM)))

   // num of parameter from back starting from 0 that is sentinel in va function
#  define __attr_sentinel__(PARAM_NUM_BACK) __attribute__((__sentinel__(PARAM_NUM_BACK)))

   // attribute can be unused, suppress warnings about it
#  define __attr_unused__ __attribute((__unused__))

#else /*- __GNUC__ -*/

#  define __attribute__(x) /*-nothing-*/
#  define __attr_pure__ /*-nothing-*/
#  define __attr_const__ /*-nothing-*/
#  define __attr_nonnull__(...) /*-nothing-*/
#  define __attr_ret_nonnull__ /*-nothing-*/
#  define __attr_wures__ /*-nothing-*/
#  define __attr_alloc_size__(PARAM_NUM) /*-nothing-*/
#  define __attr_malloc__ /*-nothing-*/
#  define __attr_format__(FUN,FMT_NUM,VA_NUM) /*-nothing-*/
#  define __attr_sentinel__(PARAM_NUM_BACK) /*-nothing-*/
#  define __attr_unused__ /*-nothing-*/
#endif /*- __GNUC__ -*/

// for descriptions of attributes see documentation at:
//    http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Function-Attributes.html




/* REAMINDERS */

/* macros indicating compilers */
#if defined(__GNUC__) || defined(__GNUG__)
   /* <C&C++> <C++> GNU GCC/G++, Clang/LLVM, IBM XL C/C++. ------------------- */
#elif (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER))
   /* GNU GCC/G++. -----------------------------------only------ */
#elif defined(__clang__)
   /* <C&C++> Clang/LLVM. ---------------------------------------------- */
#elif defined(__IBMC__) || defined(__IBMCPP__)
   /* <C> <C++> IBM XL C/C++. -------------------------------------------- */
#elif defined(__ICC) || defined(__INTEL_COMPILER)
   /* <C&C++> <C&C++> Intel ICC/ICPC. ------------------------------------------ */
#elif defined(__HP_cc) || defined(__HP_aCC)
   /* <C> <C++> Hewlett-Packard C/aC++. ---------------------------------- */
#elif defined(_MSC_VER) && defined(__cplusplus)
   /* <C&C++> <C++> Microsoft Visual Studio. --------------------------------- */
#elif defined(__PGI) && defined(__cplusplus)
   /* <C&C++> <C++> Portland Group PGCC/PGCPP. ------------------------------- */
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
   /* <C> <C++> Oracle Solaris Studio. ----------------------------------- */
#endif

/* macros indicating operating systems */
// __unix__    - any unix-like, NOT Apple-like
//             - HP-UX
// __linux__   - linuxes
// _POSIX*     - linuxes
// BSD         - any BSD or specific: __DragonFly__, __Free/Net/OpenBSD__
//             - OSX, iOS
// __APPLE__ && __MACH__   - OSX, iOS     + TARGET_OS_MAC (OSX), TARGET_OS_IPHONE etc.
// __sun && __SVR4
//
// __hpux      - HP-UX
// _AIX        - Ibm AIX
//
// _WIN64, _WIN32             - WinXP,Vista,7,8
// __CYGWIN__ && !_WIN32      - Cygwin (only 32b version exist)
// __MINGW32/64_              - MinGW

#if defined(__unix__)
#include <sys/param.h>
#if defined(BSD)
   /* BSD (DragonFly BSD, FreeBSD, OpenBSD, NetBSD) ----------- */
#endif
#endif

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <sys/param.h>
#if defined(BSD)
   /* BSD (DragonFly BSD, FreeBSD, OpenBSD, NetBSD) + OSX, iOS, Darwin ----------- */
#endif
#endif

#if defined(__APPLE__) && defined(__MACH__)
   /* Apple OSX and iOS (Darwin). ------------------------------ */
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
   /* iOS in Xcode simulator */
#elif TARGET_OS_IPHONE == 1
   /* iOS on iPhone, iPad, etc. */
#elif TARGET_OS_MAC == 1
   /* OSX */
#endif
#endif

/* UNIX line and POSIX compliant - currently BSD,linux,OSX,Solaris */
#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
   /* UNIX-style OS. ------------------------------------------- */
#include <unistd.h>
#if defined(_POSIX_VERSION)
   /* POSIX compliant */
#endif
#endif




#endif /*- MHLIBS_BASE_SRCBASE_CORE_H -*/

Added lib_c_base/debug.c.









































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*!F::Debug procedures - main implementation file.
 *
 *  ::Purpose:
 *    Detect bugs and inform programmer about them.
 *
 *    It is part of error handling facilities which involve error.s, debug.c and
 *    faults.c.
 *    It covers programmers mistakes: bad argument passed, wrong code reached,
 *    bad use of programming facility.
 *    It doesn't cover OS errors (errors.c) and user's errors (faults.c).
 *
 *  ::Goals:
 *    - thread-safe, reentrant, portable (POSIX systems)
 *    - buffer/integer overflow safe
 *    - propagate or handle errors with routines from "errors.h"
 *
 *  ::Functionality:
 *    - log messages
 *    - log messages if condition true
 *    - log variable values
 *
 *  ::Limitations:
 *    - definitely more debug routines can be implemented
 *
 *  ::Properties:
 *    compiler options:   -std=c99
 *    thread safe
 *
 *  ::Other:
 *    File:             This file is part of program distributed under GNU General Public License.
 *                      For terms of distribution, warranty and licensing see README file.
 *    Created:          2013-12-16
 *    (c) Copyright:    Maciej Helminiak 2013
 *    License:          GNU General Public License, version 3
 *                      Copy of the license is distributed along with this program
 *                      or can be seen at <http://www.gnu.org/licenses/>
 */




/* current project */
#include "common_mhlbase.h"

/* mh library */
#include "core.h"
#include "logs.h"

/* libc */

/* current module */
#include "debug.h"

Added lib_c_base/debug.h.

























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#ifndef MHCL_BASE_SRCBASE_DEBUG_H
#define MHCL_BASE_SRCBASE_DEBUG_H

/*!F::Debug procedures - external interface file.
 *
 *  ::Provides function declarations for other modules.
 */




/* current project */
#include "common_mhlbase.h"

/* mh library */
#include "core.h"
#include "logs.h"

/* libc */
#include <stdlib.h>     // abort()
#include <stdio.h>      // printf(), fflush()




#define LogAssert(...) do { log_string(LOG_DEF_STREAM, LOG_PREF_ASSERT, __FILE__, __LINE__, __func__, __VA_ARGS__); } while(0)
#define ___Sentinel(...) do { LogAssert(__VA_ARGS__); } while(0)




/* DEBUG */
/* ========================================================================== */
#ifdef DEBUG


/*!1-6
 * :: Log debug messages.
 * :: Print messages of certain type to 'LOG_DEF_STREAM'. Messages are
 *    consistently formatted with use of adequate prefix, current file name,
 *    line number, function name and additional printf-like string customized
 *    by user.
 * :: Intended for printing various debug messages.
 * :: These macro functions are in effect only if 'DEBUG' macro is defined.
 */
#define DLog(...) do { log_string(LOG_DEF_STREAM, LOG_PREF_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__); } while(0)
#define DLogInfo(...) do { log_string(LOG_DEF_STREAM, LOG_PREF_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__); } while(0)
#define DLogWarn(...) do { log_string(LOG_DEF_STREAM, LOG_PREF_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__); } while(0)
#define DLogError(...) do { log_string(LOG_DEF_STREAM, LOG_PREF_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__); } while(0)
#define DLogTest(...) do { log_string(LOG_DEF_STREAM, LOG_PREF_TEST, __FILE__, __LINE__, __func__, __VA_ARGS__); } while(0)
#define DLogAssert(...) do { log_string(LOG_DEF_STREAM, LOG_PREF_ASSERT, __FILE__, __LINE__, __func__, __VA_ARGS__); } while(0)


/*!1-6
 * :: Checks.
 * :: Check if condition is true and take actions if it is not. Log message or
 *    eventually abort.
 * :: This macro functions are in effect only if 'DEBUG' macro is defined.
 */
#define ___Dcheck(Cond, ...) do { if(!(Cond)) { DLogError(__VA_ARGS__); } } while(0)
#define ___Dassert(Cond, ...) do { if(!(Cond)) { DLogAssert(__VA_ARGS__); abort(); } } while(0)
#define ___Dsentinel(...) do { DLogAssert(__VA_ARGS__); } while(0)

#define ___DParam(Param, Cond) do { if(!((Param) Cond)) { DLogAssert("'"#Param"' parameter invalid"); abort(); } } while(0)
#define ___DInter(Param, Cond) do { if(!((Param) Cond)) { DLogAssert("'"#Param"' internal check failed"); abort(); } } while(0)
#define ___DReturn(Param, Cond) do { if(!((Param) Cond)) { DLogAssert("'"#Param"' return expression invalid"); abort(); } } while(0)

#else
#define DLog(...) ((void)0)
#define DLogInfo(...) ((void)0)
#define DLogWarn(...) ((void)0)
#define DLogError(...) ((void)0)
#define DLogTest(...) ((void)0)
#define DLogAssert(...) ((void)0)
#define ___Dcheck(Cond, ...) ((void)0)
#define ___Dassert(Cond, ...) ((void)0)
#define ___Dsentinel(...) ((void)0)
#define ___DParam(Param, Cond) do { (void)sizeof(Param); } while(0)
#define ___DInter(Param, Cond) do { (void)sizeof(Param); } while(0)
#define ___DReturn(Param, Cond) do { (void)sizeof(Param); } while(0)
#endif /*- DEBUG -*/




/* DEBUG2 */
/* ========================================================================== */
#ifdef DEBUG2


/*!1-4
 * :: Log program state.
 * :: Simply print printf-like formatted message to 'stdout' preceded by
 *    function name and line number, then flush stream.
 * :: Intended for printing state of program during debugging time,
 *    ie. value of variables.
 */
#define ___DPr(...) do { \
   fprintf(stdout, ">> %s:%d: ", __func__, __LINE__); \
   fprintf(stdout, __VA_ARGS__); \
   fflush(stdout); \
} while(0)
#define ___DVs(VAR) do { \
   fprintf(stdout, #VAR"=|%s|", (VAR)); \
   fflush(stdout); \
} while(0)
#define ___DVd(VAR) do { \
   fprintf(stdout, #VAR"=%d", (VAR)); \
   fflush(stdout); \
} while(0)
#define ___DVz(VAR) do { \
   fprintf(stdout, #VAR"=%zu", (VAR)); \
   fflush(stdout); \
} while(0)
#define ___DVp(VAR) do { \
   fprintf(stdout, #VAR"=%p", (VAR)); \
   fflush(stdout); \
} while(0)

#else
#define ___DPr(...)
#define ___DVs(VAR)
#define ___DVd(VAR)
#define ___DVz(VAR)
#define ___DVp(VAR)
#endif /*- DEBUG2 -*/




#ifdef DEBUG
bool debug_all_tests_run (void)
      __attr_wures__
      ;
#endif




#endif /*- MHCL_BASE_SRCBASE_DEBUG_H -*/

Added lib_c_base/errors.c.













































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
/*!F::Errors management - main implementation file.
 *
 *  ::Purpose:
 *    Detecting, propagating and handling of errors in consistent and convenient
 *    way. Thread-safe.
 *    Test for specified conditions and take actions on failing, like jumping to
 *    label.
 *
 *    It is part of error handling facilities which involve error.s, debug.c and
 *    faults.c.
 *    It covers OS errors: access denied, bad permissions, operation not supported,
 *    no memory, quota exceeded etc.
 *    It doesn't cover: programmer's errors (covered by debug.c), user's errors
 *    (covered by faults.c).
 *
 *  ::Goals:
 *    - thread-safe, reentrant, portable (POSIX systems)
 *    - buffer/integer overflow safe
 *
 *  ::Functionality:
 *    - propagate error information from within a function
 *    - set/cancel errors
 *    - handle errors
 *
 *  ::Limitations:
 *    - information is limited to fixed size arrays
 *    - error handling uses labels that must be placed within scope
 *
 *  ::Properties:
 *    compiler options:   -std=c99
 *    thread safe
 *
 *  ::Other:
 *    File:             This file is part of program distributed under GNU General Public License.
 *                      For terms of distribution, warranty and licensing see README file.
 *    Created:          2013-12-16
 *    (c) Copyright:    Maciej Helminiak 2013
 *    License:          GNU General Public License, version 3
 *                      Copy of the license is distributed along with this program
 *                      or can be seen at <http://www.gnu.org/licenses/>
 */




/* snprintf(), vsnprintf():
 *    _BSD_SOURCE || _XOPEN_SOURCE >= 500 || _ISOC99_SOURCE
 *    || _POSIX_C_SOURCE >= 200112L;
 *    or -std=c99
 */
#define _POSIX_C_SOURCE 200112L




/* current project */
#include "common_mhlbase.h"

/* mh library */
#include "core.h"
#include "debug.h"
#include "logs.h"

/* libc */
#include <errno.h>         // errno
#include <stdarg.h>        // va_*
#include <stdio.h>         // printf(), fflush()
#include <string.h>        // strerror()

/* current module */
#include "errors.h"




/* Error structure */
/* -------------------------------------------------------------------------- */

/*!:: Error object instance.
 * :: Used by error setting and handling routines.
 *    Created in thread local storage.
 */
__tls__ st_mh_error __err__;




/* Error codes */
/* -------------------------------------------------------------------------- */

/*!:: Labels for enumeration constants in 'errt_en'.
 * :: Printable, unmodifiable string literals describing each enum constant.
 *    Constant itself minus MH_ET_STARTING_NUMBER can be used as index in this
 *    array.
 */
static const char* const errnum_Labels[errnum_count-MH_ET_STARTING_NUMBER] = {
   "Parameter out of range",
   "Data length exceeded",
   "Integer overflow",
   "Buffer overflow",
   "Output error",
   "Functionality not implemented",
   "State changed during operation",
   "Subject exist",
   "Format is wrong",
   "all types of errors",
   "unknown error"
};




/* Error manipulating routines. */
/* -------------------------------------------------------------------------- */

/*!1-3
 * :: Return cstring with current error's signature, trace, message.
 * ::Preconditions: NONE.
 * ::Errors: NONE.
 */
char*
err_ret_sig (
   void
){
   return &__err__.sig[0];
}

char*
err_ret_trace (
   void
){
   return &__err__.trace[0];
}

char*
err_ret_msg (
   void
){
   return &__err__.msg[0];
}

/*!1-3
 * :: Place formatted in printf-like manner cstring in error's signature, trace,
 *    message.
 * ::Preconditions:
 * ::Errors:
 *    no Errors.
 * ..Note: vsnprintf() returns -1 on output error, but it is ignored as we are
 *    here because of error condition anyway.
 * ::Parameters:
 *    `fmt`: format cstring
 *    `...`: arguments
 */
char*
err_carve_sig (
   const char* fmt,
   ...
){
   va_list ap;
   va_start(ap, fmt);

   vsnprintf(&__err__.sig[0], ERROR_SIGNATURE_BYTES, fmt, ap);

   va_end(ap);

   return &__err__.sig[0];
}

char*
err_carve_trace (
   const char* fmt,
   ...
){
   va_list ap;
   va_start(ap, fmt);

   vsnprintf(&__err__.trace[0], ERROR_TRACE_BYTES, fmt, ap);

   va_end(ap);

   return &__err__.trace[0];
}

char*
err_carve_msg (
   const char* fmt,
   ...
){
   va_list ap;
   va_start(ap, fmt);

   vsnprintf(&__err__.msg[0], ERROR_MESSAGE_BYTES, fmt, ap);

   va_end(ap);

   return &__err__.msg[0];
}

/*!1-2
 * :: Append formatted in printf-like manner cstring to error's trace, message.
 * ::Preconditions:
 * ::Errors:
 *    no Errors.
 * ..Note: vsnprintf() returns -1 on output error, but it is ignored as we are
 *    here because of error condition anyway.
 * ::Parameters:
 *    `fmt`: format cstring
 *    `...`: arguments
 */
char*
err_append_trace (
   const char* fmt,
   ...
){
   va_list ap;
   va_start(ap, fmt);

   const size_t nc = strlen(__err__.trace);
   vsnprintf(&__err__.trace[nc], ERROR_TRACE_BYTES-nc, fmt, ap);

   va_end(ap);

   return &__err__.trace[0];
}

char*
err_append_msg (
   const char* fmt,
   ...
){
   va_list ap;
   va_start(ap, fmt);

   const size_t nc = strlen(__err__.msg);
   vsnprintf(&__err__.msg[nc], ERROR_MESSAGE_BYTES-nc, fmt, ap);

   va_end(ap);

   return &__err__.msg[0];
}

/*!:: Return pointer to string describing given error code.
 * ::Errors:
 */
const char*
err_descr (
   int err     //! error code
){
   /* error in range of errno values defined in libc */
   if (err < MH_ET_STARTING_NUMBER) {
      return strerror(err);
   }
   /* error type defined outside libc */
   else {
      return errnum_Labels[err - MH_ET_STARTING_NUMBER];
   }
}




/* Error handling routines. */
/* -------------------------------------------------------------------------- */


/*!:: Error code must be different from 'NONE' and must be equal to current
 *    code in error or to constant indicating ALL codes.
 * ::Errors:
 */
bool
err_catch_cond_fulfiled (
   errnum_en errnum        //! error code
){
   if (errno == 0) { return false; }
   if ( ((errnum) != E_NONE) && ((uint)errno == (errnum) || (errnum) == E_ALL_TYPES) )
   {
      return true;
   }

   return false;
}

/*!:: Error information is printed accordingly to specified print action.
 * ::Errors:
 */
void
err_catch_print_action (
   errprint_en errpr
){
   switch (errpr)
   {
      case EPR_NONE:
         /*- nothing -*/
      break;
      case EPR_NOTICE:
         LogError("Error: %s\n", ErrDescr());
      break;
      case EPR_MESSAGE:
         LogError("%s\n", ErrMessage());
      break;
      case EPR_DEBUG_INFO:
         LogError("%s\n\ttype: %s\n\toriginated: %s\n\ttrace: %s\n\tmsg: %s",
            "Error encountered:", ErrDescr(), ErrSignat(), ErrTrace(), ErrMessage());
      break;
      case EPR_UNKNOWN:
      case errprint_count:
      default:
         ___Sentinel("Wrong print error action"); abort();
   };
}

Added lib_c_base/errors.h.

























































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
#ifndef MHCL_BASE_SRCBASE_ERRORS_H
#define MHCL_BASE_SRCBASE_ERRORS_H

/*!F::Errors management - external interface file.
 *
 *  ::Provides function declarations for other modules.
 */




/* mh library */
#include "core.h"

/* current project */
#include "common_mhlbase.h"

/* libc */
#include <errno.h>         // errno
#include <stdlib.h>     // abort()
#include <stdio.h>      // printf(), fflush()




/* Error structure */
/* -------------------------------------------------------------------------- */


/* Number of bytes of cstrings representing error's signature, trace, message
   in error structure. */
#define ERROR_SIGNATURE_BYTES 128
#define ERROR_TRACE_BYTES 1024
#define ERROR_MESSAGE_BYTES 1024


typedef struct st_mh_error st_mh_error;
/*!:: Error structure.
 *    Data describing current error. In conjunction with 'errno' provided by
 *    libc makes overall error description.
 */
struct st_mh_error
{
   char sig[ERROR_SIGNATURE_BYTES]; //! signature - where error originated from
   char trace[ERROR_TRACE_BYTES];   //! subsequent places of error propagation
   char msg[ERROR_MESSAGE_BYTES];   //! message used if more elaborate description
                                    //! then provided by 'errno' needed
   bool aux;                        //! for use by error routines
};


extern __tls__ st_mh_error __err__;




/* Error codes and cathegory */
/* -------------------------------------------------------------------------- */


/* Number of first error in 'enum errnum'. It must be greater then highest
   'errno' code.*/
#define MH_ET_STARTING_NUMBER 4096

/*!:: Error codes.
 *    Error codes complementary to those used by 'errno'.
 */
enum errnum_en {
   E_NONE=0,
   E_PARAMOOR=MH_ET_STARTING_NUMBER,   //! parameter has value out of range
   E_DATALENEXC,        //! data is too long
   E_OVERFLOWINT,       //! integer overflow
   E_OVERFLOWBUF,       //! buffer overflow
   E_OUTPUTERR,         //! output to file, screen, network error
   E_FUNC_NOTIMPL,
   E_STATE_CHANGE,      //! state of subject changed during operation
   E_EXIST,             //! file, object, entity exist
   E_FORMAT_WRONG,      //! file, string, user input is in wrong format
   E_ALL_TYPES,         //! all types
   E_UNKNOWN,
   errnum_count };
typedef enum errnum_en errnum_en;


/*!:: Error print action.
 */
enum errprint_en {
   EPR_NONE=0,       //! do not print
   EPR_NOTICE,       //! short notice
   EPR_MESSAGE,      //! informative message
   EPR_DEBUG_INFO,   //! full debug info
   EPR_UNKNOWN,      //! unknown cathegory
   errprint_count };
typedef enum errprint_en errprint_en;




/* Error manipulating routines. */
/* -------------------------------------------------------------------------- */


/*!1-3
 * :: Return error's signature, trace, message.
 */
extern char* err_ret_sig (void)
               __attr_wures__
               ;
extern char* err_ret_trace (void)
               __attr_wures__
               ;
extern char* err_ret_msg (void)
               __attr_wures__
               ;

/*!1-3
 * :: Carve error's signature, trace, message.
 */
extern char* err_carve_sig (const char* format, ...)
               __attr_nonnull__(1)
               __attr_format__(__printf__,1,2)
               ;
extern char* err_carve_trace (const char* format, ...)
               __attr_nonnull__(1)
               __attr_format__(__printf__,1,2)
               ;
extern char* err_carve_msg (const char* format, ...)
               __attr_nonnull__(1)
               __attr_format__(__printf__,1,2)
               ;

/*!1-3
 * :: Append to error's signature, trace, message.
 */
extern char* err_append_trace (const char* format, ...)
               __attr_nonnull__(1)
               __attr_format__(__printf__,1,2)
               ;
extern char* err_append_msg (const char* format, ...)
               __attr_nonnull__(1)
               __attr_format__(__printf__,1,2)
               ;

/*!1:: Return description of error type.
 */
extern const char* err_descr (int errno_val)
                     __attr_wures__
                     ;




/*!1-5
 * :: Error code.
 * :: Set, get, test, clear current error code.
 */
#define SetErr(errnum) do { \
   errno = (errnum); \
} while(0)

#define GetErr() errno

#define IsErr() errno

#define ClrErrCode() do { \
   errno = 0; \
} while(0)

#define ClrErr() do { \
   __err__.sig[0] = '\0'; \
   __err__.trace[0] = '\0'; \
   __err__.msg[0] = '\0'; \
   __err__.aux = false; \
   errno = 0; \
} while(0)




/*!1-5
 * :: Get error parameters.
 * :: Return current error's code, code description, signature, trace, message,
 *    error struct.
 */
#define ErrNum() errno
#define ErrDescr() err_descr(errno)
#define ErrSignat() err_ret_sig()
#define ErrTrace() err_ret_trace()
#define ErrMessage() err_ret_msg()
#define ErrSt() __err__




/* Error triggering routines. */
/* -------------------------------------------------------------------------- */


/*!1-5
 * :: Set error.
 * :: Set error parameters, ev. set custom message, ev. do it conditionally,
 *    ev. do not assign code. Then goto label.
 */
//#define ErrorTrig(errnum, label)
#define ErrorSet(errnum, label) do { \
   if (errno == 0) SetErr(errnum); \
   err_carve_sig("%s:(%s):%d", __FILE__, __func__, __LINE__); \
   goto label; \
} while(0)

//#define ErrorTrig_msg(errnum, label, ...)
#define ErrorSetm(errnum, label, ...) do { \
   if (errno == 0) SetErr(errnum); \
   err_carve_sig("%s:(%s):%d", __FILE__, __func__, __LINE__); \
   err_carve_msg(__VA_ARGS__); \
   goto label; \
} while(0)
   /*err_carve_trace("%s:(%s):%d", __FILE__, __func__, __LINE__); \*/

//#define ErrorTrigIf(Cond, errnum, label)
#define ErrorSetIf(Cond, errnum, label) do { \
   if ((Cond)) { \
      if (errno == 0) SetErr(errnum); \
      err_carve_sig("%s:(%s):%d", __FILE__, __func__, __LINE__); \
      goto label; \
   } \
} while(0)

//#define ErrorIf(Cond, label)
#define ErrorTrigIf(Cond, label) do { \
   if ((Cond)) { \
      err_carve_sig("%s:(%s):%d", __FILE__, __func__, __LINE__); \
      goto label; \
   } \
} while(0)

#define ErrorTrigIfm(Cond, label, ...) do { \
   if ((Cond)) { \
      err_carve_sig("%s:(%s):%d", __FILE__, __func__, __LINE__); \
      err_carve_msg(__VA_ARGS__); \
      goto label; \
   } \
} while(0)




/*!1-2
 * :: Overflows.
 * :: Set error if overflow occured.
 */
#define OverflowIntIf(Cond, label) do { \
   if ((Cond)) { \
      if (errno == 0) SetErr(E_OVERFLOWINT); \
      err_carve_sig("%s:(%s):%d", __FILE__, __func__, __LINE__); \
      goto label; \
   } \
} while(0)

/*!:: If condition is true buffer overflow occured.
 *    Set error approprietely and goto `label`.
 */
#define OverflowBufIf(Cond, label) do { \
   if ((Cond)) { \
      if (errno == 0) SetErr(E_OVERFLOWBUF); \
      err_carve_sig("%s:(%s):%d", __FILE__, __func__, __LINE__); \
      goto label; \
   } \
} while(0)




/* Error handling routines. */
/* -------------------------------------------------------------------------- */


/*!1-2
 * :: Handle (propagate) errors.
 * :: If error is set append trace to parameters and goto label. Eventually
 *    carve custom message.
 */
#define HandleErr(label) do { \
   if (errno != 0) { \
      const char* trace = ErrTrace(); \
      if (trace[0] == '\0') { \
      err_carve_trace("%s:(%s):%d", __FILE__, __func__, __LINE__); \
      } else { \
      err_append_trace(" --> %s:(%s):%d", __FILE__, __func__, __LINE__); \
      } \
      goto label; \
   } \
} while(0)

#define HandleErrm(label, ...) do { \
   if (errno != 0) { \
      const char* trace = ErrTrace(); \
      if (trace[0] == '\0') { \
      err_carve_trace("%s:(%s):%d", __FILE__, __func__, __LINE__); \
      } else { \
      err_append_trace(" --> %s:(%s):%d", __FILE__, __func__, __LINE__); \
      } \
      err_carve_msg(__VA_ARGS__); \
      goto label; \
   } \
} while(0)




/*!:: True if error code in current error is as specified.
 */
extern bool err_catch_cond_fulfiled (errnum_en errnum)
               __attr_wures__
               ;

/*!:: Error information print.
 */
extern void err_catch_print_action (errprint_en errpr)
               ;


/*!1-2
 * :: Catch errors.
 * :: If error is set do any of following actions: print notice, message or
 *    debug info, ignore, continue, retry, exit, abort.
 */
#define CatchError(err_num, err_pr) \
   __err__.aux = err_catch_cond_fulfiled((err_num)); \
   if (__err__.aux == true) { \
      err_append_trace(" --> %s:(%s):%d", __FILE__, __func__, __LINE__); \
      err_catch_print_action((err_pr)); } \
   if (__err__.aux == true)




#ifdef DEBUG
/* Used only by tests in debug mode. */
bool errors_all_tests_run (void)
      __attr_wures__
      ;
#endif




#endif /*- MHCL_BASE_SRCBASE_ERRORS_H -*/

Added lib_c_base/logs.c.





























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*!F::Messages logging - main implementation file.
 *
 *  ::Purpose:
 *    Log messages in consistent manner.
 *
 *  ::Goals:
 *    - thread-safe, reentrant, portable (POSIX systems)
 *    - buffer/integer overflow safe
 *    - propagate or handle errors with routines from "errors.h"
 *
 *  ::Functionality:
 *    - log messages
 *
 *  ::Limitations:
 *
 *  ::Properties:
 *    compiler options:   -std=c99
 *    thread safe
 *
 *  ::Other:
 *    Created:            2013-12-16
 *    (c) Copyright:      "Machel" 2013
 *    License:            GNU Public License
 */




/* current project */
#include "common_mhlbase.h"

/* mh library */
#include "core.h"

/* libc */
#include <stdarg.h>        // va_*
#include <stdio.h>         // printf(), fflush(), FILE*

/* current module */
#include "logs.h"




/*!:: First, fixed part of message is composed from established elements: prefix,
 *    program name, file name, line number and function name. Second part is
 *    customized by user in printf-like manner.
 *    Message is printed to `fs` stream, stream is flushed.
 * :: Intended for logging, debugging and errors printing, wenever message needs
 *    to carry info about file, line and function where event occured.
 *
 * ::Preconditions:
 *  - all parameters except variadic list are required and can't be NULL
 *
 * ::Special preconditions:
 *  - 'MHLC_BASE_PR_NAME' macro should be defined or "UNKNOWN" string will be
 *    used as program name
 *
 * ::Errors: NONE.
 *    printf-like functions return -1 on output error, but it is ignored.
 */
void
log_string (
   FILE* fs,         //! message goes to this stream
   const char* pref, //! prefix, begining of message
   const char* file, //! file where message originated from
   uint line,        //! line in file
   const char* func, //! function where message originated from
   const char* fmt,  //! format string conforming to printf specification
   ...               //! data to print
){
   assert(pref && "'pref' parameter invalid");
   assert(file && "'file' parameter invalid");
   assert(line > 0 && "'line' parameter invalid");
   assert(func && "'func' parameter invalid");
   assert(fmt && "'fmt' parameter invalid");

#ifndef MHLC_BASE_PR_NAME
#  define MHLC_BASE_PR_NAME "UNKNOWN"
#endif

   va_list ap;
   va_start(ap, fmt);

   /*: print custom part */
   vfprintf(fs, fmt, ap);

   /*: print fixed part */
   fprintf(fs, "\nlogged %s at: <%s> %s(): %s:%d\n",
               pref, MHLC_BASE_PR_NAME, func, file, line);
   fflush(fs);

   va_end(ap);
}

Added lib_c_base/logs.h.























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#ifndef MHCL_BASE_SRCBASE_LOGS_H
#define MHCL_BASE_SRCBASE_LOGS_H

/*!F::Messages logging - external interface file.
 *
 *  ::Provides function declarations for other modules.
 */




/* current project */
#include "common_mhlbase.h"

/* mh library */
#include "core.h"

/* libc */
#include <stdarg.h>        // va_*
#include <stdio.h>      // printf(), fflush(), FILE*




/*!1:: Print consistently formatted message to specified file stream.
 */
extern void log_string (FILE* filestream,
   const char* prefix, const char* filename, uint line, const char* funcname,
   const char* format, ...)
      __attr_nonnull__(1,2,3,5,6)
      __attr_format__(__printf__,6,7)
      ;




/*!:: Stream where all debug messages go by default. */
#ifndef LOG_DEF_STREAM
#  define LOG_DEF_STREAM stderr
#endif

/* Prefixes for various types of log messages.
 */
#ifndef LOG_PREF_DEBUG
#define LOG_PREF_DEBUG "   DBG "
#endif
#ifndef LOG_PREF_INFO
#define LOG_PREF_INFO "  INFO "
#endif
#ifndef LOG_PREF_WARN
#define LOG_PREF_WARN " -WARN-"
#endif
#ifndef LOG_PREF_ERROR
#define LOG_PREF_ERROR "=ERROR="
#endif
#ifndef LOG_PREF_TEST
#define LOG_PREF_TEST "test__>"
#endif
#ifndef LOG_PREF_ASSERT
#define LOG_PREF_ASSERT "Assert>"
#endif




/*!:: Print message with error prefix to 'LOG_DEF_STREAM'.
 */
#define LogError(...) do { \
   log_string(LOG_DEF_STREAM, LOG_PREF_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__); \
} while(0)

/*!:: Print message with test prefix to 'LOG_DEF_STREAM'.
 */
#define LogTest(...) do { \
   log_string(LOG_DEF_STREAM, LOG_PREF_TEST, __FILE__, __LINE__, __func__, __VA_ARGS__); \
} while(0)




#ifdef DEBUG
/* Used only by tests in debug mode. */
bool logs_all_tests_run (void)
      __attr_wures__
      ;
#endif




#endif /*- MHCL_BASE_SRCBASE_LOGS_H -*/

Added src_main/ManxController.cxx.





























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/* current project */
//#include "PureConn.hh"

/* mh library */
#include "core.hh"
//#include "sock.h"
#include "Debug.hh"
#include "Exception.hh"

/* libc */
#include <cstdio>       // fgets(), fileno()
#include <cstring>      // strcpy()
#include <unistd.h>     // isatty(), write()

/* current module */
#include "ManxController.hh"




using namespace MANX::GOVERNING;
using namespace MANX::GOVERNING::__impl__;


/* -------------------------------------------------- cl_user_cmd ---- */
constexpr const cl_user_cmd::st_cmd_spec cl_user_cmd::_Cmd_specs[];

void
cl_user_cmd::read_user_cmd (FILE* fs_input)
{
  ___Dparam(fs_input != NULL);

  /*: Print prompt if input is from terminal: */
  int fd_in = fileno(fs_input);
  if (isatty(fd_in)) {
    write(fd_in, PROMPT, strlen(PROMPT));
  } else {
    errno = 0;    //isatty() sets errno on fail
  }

  /*: Read input: */
  char* ret = fgets(_buf_input, INBUF_BYTES, fs_input);
  if (ret == NULL) {
    _buf_input[0] = '\0';
    ExcTrigIf(ferror(fs_input), "Input fs", EIO, "Cannot read user input");
  }

  /*: Get command and arguments: */
  const st_cmd_spec* Spec_curr = NULL;
  size_t ii = 1;
  do
  {
    Spec_curr = &_Cmd_specs[ii++];
    if (strstr(_buf_input, Spec_curr->_cs_keyword) == _buf_input)
    {
      //: Keyword or its abbreviation matches begining of input
      retrieve_args(&_buf_input[0] + strlen(Spec_curr->_cs_keyword));
      break;
    }
    else if (strstr(_buf_input, Spec_curr->_cs_abbr) == _buf_input)
    {
      //: Keyword abbreviation matches begining of input
      retrieve_args(&_buf_input[0] + strlen(Spec_curr->_cs_abbr));
      break;
    }
  }
  while (Spec_curr->_e_kw != keyw_en::Unknown);

  _e_kw = Spec_curr->_e_kw;
}

void
cl_user_cmd::retrieve_args (
  char* input
){
  ___Dparam(input != NULL);

  char* p_n = strrchr(input, '\n');
  if (p_n != NULL) { *p_n = '\0'; }

  printf("|%s|\n", input);

  char* p_beg = input;

  size_t ii = 0;
  while (true)
  {
    while (*p_beg == ' ') { ++p_beg; }

    if (*p_beg == '\0') { break; } //: No more arguments

    char* p_end = p_beg + 1;

    while (*p_end != ' ' && *p_end != '\0') { ++p_end; }
    _cs_args[ii++] = p_beg;
    if (*p_end == ' ')
    {
      *p_end = '\0';
    }
    else
    {
      break;
    }
    p_beg = p_end + 1;
  }

  _cs_args[ii] = NULL;
}
/* -------------------------------------------------- cl_user_cmd ---- */




/* ------------------------------------------------ cl_controller ---- */


/*- ...... FUNDAMENTALS ...... -*/

cl_controller::cl_controller (
  FILE* fs_input,
  FILE* fs_output,
  FILE* fs_logs
)
  : _fs_input{fs_input}, _fs_output{fs_output}, _fs_logs{fs_logs}
{
  ___Dparam(fs_input != NULL);
  ___Dparam(fs_output != NULL);
  ___Dparam(fs_logs != NULL);
}


/*- ...... INTERFACE ...... -*/

void
cl_controller::run ()
{
  while (true)
  {
    _Command.read_user_cmd(_fs_input);

    switch (_Command._e_kw)
    {
      case cl_user_cmd::keyw_en::WorldCreate:
      {
        printf("Creating world, Args:\n");
        size_t ii = 0;
        const char* arg = NULL;
        while ((arg = _Command._cs_args[ii++]) != NULL)
        {
          printf("\t%s\n", arg);
        }
        //spawn(dept_en::World);
        //spawn(dept_en::NetCommunication);
      }
      break;

      case cl_user_cmd::keyw_en::WorldDestroy:
        printf("Destroying world\n");
        return;
        //stow(dept_en::World);
        //stow(dept_en::NetCommunication);
      break;

      case cl_user_cmd::keyw_en::Unknown:
        printf("Not recognized\n");
      break;

      default:
        printf("ERR\n");

    }
  }
}
/* ------------------------------------------------ cl_controller ---- */

Added src_main/ManxController.hh.













































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#ifndef MANEX_SRCMAIN_MANXCONTROLLER_HH
#define MANEX_SRCMAIN_MANXCONTROLLER_HH



#include "core.hh"



namespace MANX {
namespace GOVERNING {
namespace __impl__ {
/* =================================================================== */

class cl_user_cmd
{

/*- ...... TYPES ...... -*/
 private:

  enum class keyw_en
  {
    None = 0,
    WorldCreate,
    WorldDestroy,
    Unknown,
    count
  };

  struct st_cmd_spec
  {
    keyw_en _e_kw;
    const char* const _cs_keyword;
    const char* const _cs_abbr;
  };

  /*- Commands specification -*/
  static constexpr const st_cmd_spec _Cmd_specs[] = {
    { keyw_en::None, "", ""}
   ,{ keyw_en::WorldCreate, "create world", "wc"}
   ,{ keyw_en::WorldDestroy, "destroy world", "wd"}
   ,{ keyw_en::Unknown, "", ""}
  };


/*- ...... FUNDAMENTALS ...... -*/
 private:


/*- ...... INTERFACE ...... -*/
 public:
  void read_user_cmd (FILE* fs_input);


/*- ...... DATA ...... -*/
 private:
  static constexpr const uint MAX_ARGS = 128;
  static constexpr const uint INBUF_BYTES = 4096;

  static constexpr const char* const PROMPT = "> ";

  char _buf_input[INBUF_BYTES];     //! buffer for user input

  keyw_en _e_kw;                    //! command keyword
  const char* _cs_args[MAX_ARGS];   //! each arg points to location in `_buf_input`


/*- ...... INTERNAL ROUTINES ...... -*/
 private:
  void retrieve_args (char* input);



  friend class cl_controller;
};




class cl_controller
{
/*- ...... FUNDAMENTALS ...... -*/
public:
  cl_controller (FILE* fs_input, FILE* fs_output, FILE* fs_logs);

  /*- deleted -*/
  cl_controller () = delete;

public:
/*- ...... INTERFACE ...... -*/
  void run ();

/*- ...... DATA ...... -*/
private:
  FILE* _fs_input = NULL;
  FILE* _fs_output = NULL;
  FILE* _fs_logs = NULL;

  cl_user_cmd _Command = {};

/*- ...... INTERNAL ROUTINES ...... -*/
private:
};




/* =================================================================== */
}
/*- STUFF TO BE USED BY OUTSIDE PARTIES -*/
using __impl__::cl_controller;
}
}




#endif /*- MANEX_SRCMAIN_MANXCONTROLLER_HH */

Added src_network/src_server/ManxServer.cxx.

Added src_network/src_server/ManxServer.hh.









































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#ifndef MANX_NETWORK_SRCSERVER_MANXSERVER_HH
#define MANX_NETWORK_SRCSERVER_MANXSERVER_HH




namespace MANX {
namespace NETWORKING {
namespace __impl__ {
/* =================================================================== */




class cl_server
{
/*- ...... FUNDAMENTALS ...... -*/

/*- ...... INTERFACE ...... -*/

/*- ...... DATA ...... -*/

/*- ...... INTERNAL ROUTINES ...... -*/
};




/* =================================================================== */
}
}
/*- STUFF TO BE USED BY OUTSIDE PARTIES -*/
using __impl__::cl_XXXXX;
}
#include "main_exec.hh"




int main ()
{

  MANX::GOVERNING::cl_controller Ctrl{stdin, stdout, stdout};
  int ret = Ctrl.run();

  return ret;
}




#endif /*- MANX_NETWORK_SRCSERVER_MANXSERVER_HH -*/

Added tests/main_test.cxx.

























>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
#include "ManxController.hh"



int main ()
{

  MANX::GOVERNING::cl_controller Ctrl{stdin, stdout, stdout};
  Ctrl.run();

  return EXIT_SUCCESS;
}