(1) Start "Visual Studio Command Prompt (2010)":
===============================================
Start menu [icon]
--> "All Programs" [link]
--> "Microsoft Visual Studio 2010 Express" [folder]
--> "Visual Studio Command Prompt (2010)" [icon]
===============================================
(2) Within the Visual Studio command prompt, change
directory to the "freetype2-demos-master" folder:
===============================================
cd [path of "freetype_build_test" folder]
cd freetype2-demos-master
===============================================
(3) Within the Visual Studio command prompt, use GNU Make
application to build the FreeType 2 demo programs.
Start "make.exe" without any parameters.
===============================================
[...]\make-3.81-bin\bin\make.exe
===============================================
BUILDING FREETYPE 2 DEMO PROGRAMS : PROBLEMS AND WORKAROUNDS
Following the procedure described in the previous section
("BUILDING FREETYPE 2 DEMO PROGRAMS : PROCEDURE")
initially failed to build all demo programs for my software environment.
After finding a solution to the first encountered problem, and following the
procedure again, I encountered a second problem. In total, I encountered
six different problems before successfully building all demo programs.
The following subsections describe each problem I encountered,
along with its solution.
PROBLEM #1
(1) Follow the procedure described in the section
"BUILDING FREETYPE 2 DEMO PROGRAMS : PROCEDURE".
Result:
===============================================
src\output.c(295) : error C2220: warning treated as error [...]
src\output.c(295) : warning C4333: '>>' : right shift by too large amount, data
loss
src\output.c(296) : warning C4333: '>>' : right shift by too large amount, data
loss
===============================================
CAUTION! Although the compiler is "merely" issuing a warning,
in fact this is a clue of an actual logical bug in this code!
Note that freetype_build_test\freetype2\include\freetype\fttypes.h
defines the following:
===============================================
typedef unsigned char FT_Byte;
===============================================
Also, sizeof(unsigned char)==1 for all platforms, even 64-bit Linux;
i.e., "unsigned char" is a byte (8-bit unsigned integer; an octet).
Now look at freetype_build_test\freetype2-demos-master\src\output.c
Specifically, look at the function "put_unicode_be16_string".
It has a parameter, "FT_Byte* string".
It declares the following variable: "FT_Int ch = 0;".
In a loop, it sets the variable "ch":
===============================================
ch = ( string[i] << 8 ) | string[i + 1];
===============================================
A UTC-16BE character from the byte array is put in to
the lowest 16 bits of the integer "ch".
(QUESTION: Is the string *actually* big-endian? I did not
study the code enough to guess the intent.)
If the output format is not UTF-8, then it seems like the
intent of the code is to render UTC-16 code points at or
beyond 0x80 as escape sequences of the form "\u####".
The problem is in the following block of code:
===============================================
{
*out++ = '\\';
*out++ = 'U';
*out++ = '+';
*out++ = hexdigit[( string[i] >> 12 ) & 0xF]; /* <<<BAD!!! */
*out++ = hexdigit[( string[i] >> 8 ) & 0xF]; /* <<<BAD!!! */
*out++ = hexdigit[( string[i] >> 4 ) & 0xF]; /* ALSO WRONG! */
*out++ = hexdigit[ string[i] & 0xF]; /* ALSO WRONG! */
}
===============================================
The specific problem is that "string" refers to bytes,
and the ">> 12" and ">> 8" bit shifting would always
result in values of zero.
Clearly, what was intended was to extract the four
4-bit nibbles of the UTC-16 code point value.
(2) SOLUTION: Modify the code to read as follows:
===============================================
{
*out++ = '\\';
*out++ = 'U';
*out++ = '+';
*out++ = hexdigit[( ch >> 12 ) & 0xF]; /* <<<FIXED */
*out++ = hexdigit[( ch >> 8 ) & 0xF]; /* <<<FIXED */
*out++ = hexdigit[( ch >> 4 ) & 0xF]; /* <<<FIXED */
*out++ = hexdigit[ ch & 0xF]; /* <<<FIXED */
}
===============================================
This code does what was clearly intended.
PROBLEM #2
(1) Follow the procedure described in the section
"BUILDING FREETYPE 2 DEMO PROGRAMS : PROCEDURE".
Result:
===============================================
src\ttdebug.c(1336) : error C2220: warning treated as error [...]
src\ttdebug.c(1336) : warning C4013: 'getch' undefined; assuming extern
returning int
src\ttdebug.c(1935) : warning C4013: 'snprintf' undefined; assuming extern
returning int
===============================================
CAUTION! I am using VC++ 2010 and its associated C Runtime Library
(CRT). This problem might not occur for later versions of
VC++ (with their associated CRT files).
(2) SOLUTION:
I am using VC++ 2010, which has its C Runtime Library
(CRT) "include" files in the following folder:
===============================================
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include
===============================================
The "conio.h" file defines "_getch", but not "getch".
The "stdio.h" file defines "_snprintf", but not "snprintf".
CAUTION! Later versions of the VC++ CRT might define the
non-underscore symbols, reversing a long-time decision;
I don't know.
Consider the following block of code starting at
line #44:
===============================================
#ifndef UNIX
#include <conio.h>
#else
#define getch getchar
#endif
===============================================
Proposed workaround:
===============================================
#ifndef UNIX
#include <conio.h>
/* ====== BEGIN ====== */
#ifdef _MSC_VER
#if _MSC_VER <= 1600
#define getch _getch
#define snprintf _snprintf
#endif
#endif
/* ====== END ====== */
#else
#define getch getchar
#endif
===============================================
Explanation:
I think this problem affects, at the very least, VC++ 2010
and earlier versions.
The VC++ compiler version can be determined at compile time
by the compiler-defined preprocessor variable "_MSC_VER",
which has the following values:
(Source: https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B )
===============================================
MSVC++ 4.x _MSC_VER == 1000
MSVC++ 5.0 _MSC_VER == 1100
MSVC++ 6.0 _MSC_VER == 1200
MSVC++ 7.0 _MSC_VER == 1300
MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio 2003)
MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005)
MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008)
MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017)
===============================================
So, we can limit the fix to VC++ compilers by first
testing whether "_MSC_VER" is defined at all.
Then, we can further limit to VC++ 2010 and earlier
by testing for "_MSC_VER <= 1600".
If the CRT for VC++ for later versions of VC++
also do not define "getch" and/or "snprintf", then
the version number test proposed here can be
modified accordingly. I can only say that this
problem likely includes versions up to and including
VC++ 2010 (i.e., internal version number 1600).
PROBLEM #3
(1) Follow the procedure described in the section
"BUILDING FREETYPE 2 DEMO PROGRAMS : PROCEDURE".
Result:
===============================================
freetype_build_test\freetype2-demos-master\graph\gblbgra.h(2) :
error C2143: syntax error : missing ';' before 'type'
freetype_build_test\freetype2-demos-master\graph\gblbgra.h(3) :
error C2143: syntax error : missing ';' before 'const'
freetype_build_test\freetype2-demos-master\graph\gblbgra.h(4) :
error C2143: syntax error : missing ';' before 'type'
freetype_build_test\freetype2-demos-master\graph\gblbgra.h(10) :
error C2065: 'src_line' : undeclared identifier
[ . . and many more errors . . . ]
===============================================
The contents of "gblbrga.h" is actually intended to be put in to
a body of a function declared in the file:
freetype_build_test\freetype2-demos-master\graph\gblany.h
===============================================
static void
GCONCAT( _gblender_blit_bgra_, GDST_TYPE )( GBlenderBlit blit,
GBlenderPixel color )
{
GBlender blender = blit->blender;
(void)color; /* unused */
#include "gblbgra.h"
}
===============================================
The problem seems to be that VC++ 2010 (and possibly/probably
earlier versions of VC++) compile this C source file with
old C language expectations, where variable declarations
in the body of a function are all before any other kinds
of statements, and the statement "(void)color;", which is
clearly intended to bypass a compiler warning for some
other compiler (e.g., GCC), hilariously/ironically causes
the problem for VC++.
(2) SOLUTION:
The fix is actually really easy! Simply put the dummy
access to "color" *AFTER* the #include statement!
===============================================
static void
GCONCAT( _gblender_blit_bgra_, GDST_TYPE )( GBlenderBlit blit,
GBlenderPixel color )
{
GBlender blender = blit->blender;
#include "gblbgra.h"
/* CAUTION: (void)color; should happen AFTER #include'd code. */
(void)color; /* unused */
}
===============================================
PROBLEM #4
(1) Follow the procedure described in the section
"BUILDING FREETYPE 2 DEMO PROGRAMS : PROCEDURE".
Result:
===============================================
ar -r obj\graph.lib obj\gblblit.obj obj\gblender.obj
obj\grblit.obj obj\grdevice.obj obj\grfill.obj
obj\grfont.obj obj\grinit.obj obj\grobjs.obj
obj\grswizzle.obj
process_begin: CreateProcess(NULL, ar -r obj\graph.lib
obj\gblblit.obj obj\gblender.obj obj\grblit.obj
obj\grdevice.obj obj\grfill.obj obj\grfont.obj
obj\grinit.obj obj\grobjs.obj obj\grswizzle.obj, ...) failed.
===============================================
The ultimate cause of this problem was tricky to find!
First, recall that the procedure for building the
FreeType 2 library began by "make setup visualc".
This created the file "freetype_build_test\freetype2\config.mk",
which, for "visualc" configuration, includes
"freetype_build_test\freetype2\builds\windows\win32-def.mk".
That "win32-def.mk" file contains the following statement:
===============================================
PLATFORM := windows
===============================================
Meanwhile, for the FreeType 2 demo programs build process,
the "freetype_build_test\freetype2-demos-master\Makefile"
has the following statement:
===============================================
include $(GRAPH_DIR)/rules.mk
===============================================
Which causes the following file to be included:
===============================================
freetype_build_test\freetype2-demos-master\graph\rules.mk
===============================================
But, that file includes yet more files, by the following statement:
===============================================
include $(wildcard $(TOP_DIR_2)/graph/*/rules.mk)
===============================================
Among the many files included by that wildcard statement
is the following:
===============================================
freetype_build_test\freetype2-demos-master\graph\win32\rules.mk
===============================================
And this Windows-specific rule file contains the following
(selected extract):
===============================================
ifeq ($(PLATFORM),win32)
. . .
ifeq ($(findstring $(CC),cl icl), $(CC)) # test for Visual C++ & Intel C++
COMPILE_GRAPH_LIB = lib /nologo /out:$(subst /,$(COMPILER_SEP),$(GRAPH_LIB) $(GRAPH_OBJS))
LINK = cl /nologo /MD /Fe$(subst /,$(COMPILER_SEP),$@ $< $(FTLIB))
GRAPH_LINK += user32.lib gdi32.lib
endif
. . .
endif
===============================================
The crucial thing to observe is that the statements in
the body of this file will only be processed if $(PLATFORM)
is "win32".
However, as mentioned above, the "win32-def.mk" file
set PLATFORM to "windows" (and not "win32")!!
The result is that "graph\win32\rules.mk" won't override
the definition of the "COMPILE_GRAPH_LIB" with the correct
command (i.e., "lib", in this case).
This causes "graph\rules.mk" to use its default choice
for COMPILE_GRAPH_LIB, which, if LIBTOOL is not defined,
will be the UNIX/Linux "ar" (archive) command, and hence
the error described above.
(2) SOLUTION:
The solution is trivial!
In the file "graph\win32\rules.mk", change "win32"
to "windows" in the very first statement, resulting
in the following line:
===============================================
ifeq ($(PLATFORM),windows)
===============================================
PROBLEM #5
(1) Follow the procedure described in the section
"BUILDING FREETYPE 2 DEMO PROGRAMS : PROCEDURE".
Result:
===============================================
src\ftgrid.c(1350) : error C2220: warning treated as error [...]
src\ftgrid.c(1350) : warning C4244: '*=' : conversion from
'double' to 'FT_F26Dot6', possible loss of data
===============================================
The following is a relevant fragment of "src\ftgrid.c":
===============================================
static void
event_grid_zoom( double zoom )
{
FT_F26Dot6 scale_old = status.scale;
status.scale *= zoom;
===============================================
Note that "FT_F26Dot6" is defined in the file
"freetype_build_test\freetype2\include\freetype\fttypes.h":
===============================================
typedef signed long FT_F26Dot6;
===============================================
This type is described as a "signed 26.6 fixed-point
type".
Also, note that the top of the "src\ftgrid.c" source
file declares "status" as a "GridStatusRec" structure,
which has "FT_F26Dot6 scale;" as a field.
So, the problematic statement:
===============================================
status.scale *= zoom;
===============================================
is effectively doing "FT_F26Dot6 *= double", or
"signed long *= double".
The problem is that the multiplication implicitly
promotes the signed long to double, but the
subsequent assignment of the product (a double)
back to the signed long would lose precision.
Clearly, the loss of precision is acceptable here,
given the way this value is used. So...
(2) SOLUTION:
At line #1350 of "src\ftgrid.c", replace:
===============================================
status.scale *= zoom;
===============================================
with:
===============================================
status.scale = (FT_F26Dot6)((double)status.scale * zoom);
===============================================
PROBLEM #6:
(1) Follow the procedure described in the section
"BUILDING FREETYPE 2 DEMO PROGRAMS : PROCEDURE".
Result:
===============================================
src\ftstring.c(41) : error C2220: warning treated as error [...]
src\ftstring.c(41) : warning C4566: character represented by
universal-character-name '\u039F' cannot be represented in
the current code page (1252)
src\ftstring.c(41) : warning C4566: character represented by
universal-character-name '\u03BA' cannot be represented in
the current code page (1252)
src\ftstring.c(41) : warning C4566: character represented by
universal-character-name '\u03B1' cannot be represented in
the current code page (1252)
src\ftstring.c(41) : warning C4566: character represented by
universal-character-name '\u03BB' cannot be represented in
the current code page (1252)
[ . . . and MANY more warnings like this . . . ]
===============================================
The file "freetype_build_test\freetype2-demos-master\src\ftstring.c"
contains the following:
(The following is a simplified extract showing
a relevant example of the problem.)
===============================================
static const char* Sample[] =
{
/* . . . */
"\u5929\u5730\u7384\u9EC3\uFF0C\u5B87[...]"
/* . . . */
};
===============================================
For C/C++, sizeof(char)==1 for ALL platforms, including 64-bit Linux.
I think it's rather unclear what *should* happen to
2-byte "\u####" Unicode code points for a "char" string
literal. Encode as UTF-8, UTF-16LE, or UTF-16BE ?
It seems like some kind of hint would be required for
the compiler to decide how to put bytes in to the
"char" string.
Testing indicates that this demo apparently relies on
each "char" string in the array to be encoded as UTF-8.
(2) SOLUTION:
Convert the original Unicode text (in the comment
appearing above each string literal) to UTF-8
where each byte is expressed in an escape sequence
of the form "\x##".
For example, each Unicode text string could be
converted to UTF-8 (with "\x##" byte format)
using the following online converter:
===============================================
https://www.branah.com/unicode-converter
===============================================
Resulting modified portion of the file
"freetype_build_test\freetype2-demos-master\src\ftstring.c":
===============================================
static const char* Sample[] =
{
"The quick brown fox jumps over the lazy dog",
/* [ . . . Portuguese text . . . ] */
"\x4c\x75\xc3\xad\x73 \x61\x72\x67\xc3\xbc\x69\x61 \xc3\xa0 "
"\x4a\xc3\xba\x6c\x69\x61 \x71\x75\x65 "
"\xc2\xab\x62\x72\x61\xc3\xa7\xc3\xb5\x65\x73\x2c "
"\x66\xc3\xa9\x2c \x63\x68\xc3\xa1\x2c \xc3\xb3\x78\x69\x64\x6f\x2c "
"\x70\xc3\xb4\x72\x2c \x7a\xc3\xa2\x6e\x67\xc3\xa3\x6f\xc2\xbb "
"\x65\x72\x61\x6d \x70\x61\x6c\x61\x76\x72\x61\x73 "
"\x64\x6f \x70\x6f\x72\x74\x75\x67\x75\xc3\xaa\x73",
/* [ . . . Greek text . . . ] */
"\xce\x9f \xce\xba\xce\xb1\xce\xbb\xcf\x8d\xce\xbc\xce\xbd\xce\xb9\xce\xbf\xcf\x82 "
"\xcf\x83\xcf\x86\xce\xbf\xcf\x85\xce\xb3\xce\xb3\xce\xb1\xcf\x81\xce\xac\xcf\x82 "
"\xcf\x88\xce\xb9\xce\xb8\xcf\x8d\xcf\x81\xce\xb9\xcf\x83\xce\xb5 "
"\xcf\x80\xcf\x89\xcf\x82 \xce\xb8\xce\xb1 "
"\xce\xb2\xce\xbf\xcf\x85\xcf\x84\xce\xae\xce\xbe\xce\xb5\xce\xb9 "
"\xcf\x87\xcf\x89\xcf\x81\xce\xaf\xcf\x82 \xce\xbd\xce\xb1 "
"\xce\xb4\xce\xb9\xcf\x83\xcf\x84\xce\xac\xce\xb6\xce\xb5\xce\xb9",
/* [ . . . Russian text . . . ] */
"\xd0\xa1\xd1\x8a\xd0\xb5\xd1\x88\xd1\x8c \xd0\xb5\xd1\x89\xd1\x91 "
"\xd1\x8d\xd1\x82\xd0\xb8\xd1\x85 "
"\xd0\xbc\xd1\x8f\xd0\xb3\xd0\xba\xd0\xb8\xd1\x85 "
"\xd1\x84\xd1\x80\xd0\xb0\xd0\xbd\xd1\x86\xd1\x83\xd0\xb7\xd1\x81\xd0\xba\xd0\xb8\xd1\x85 "
"\xd0\xb1\xd1\x83\xd0\xbb\xd0\xbe\xd0\xba \xd0\xb4\xd0\xb0 "
"\xd0\xb2\xd1\x8b\xd0\xbf\xd0\xb5\xd0\xb9 \xd0\xb6\xd0\xb5 "
"\xd1\x87\xd0\xb0\xd1\x8e",
/* [ . . . Chinese text . . . ] */
"\xe5\xa4\xa9\xe5\x9c\xb0\xe7\x8e\x84\xe9\xbb\x83\xef\xbc\x8c"
"\xe5\xae\x87\xe5\xae\x99\xe6\xb4\xaa\xe8\x8d\x92\xe3\x80\x82"
"\xe6\x97\xa5\xe6\x9c\x88\xe7\x9b\x88\xe6\x98\x83\xef\xbc\x8c"
"\xe8\xbe\xb0\xe5\xae\xbf\xe5\x88\x97\xe5\xbc\xb5\xe3\x80\x82"
"\xe5\xaf\x92\xe4\xbe\x86\xe6\x9a\x91\xe5\xbe\x80\xef\xbc\x8c"
"\xe7\xa7\x8b\xe6\x94\xb6\xe5\x86\xac\xe8\x97\x8f\xe3\x80\x82",
/* [ . . . Japanese text . . . ] */
"\xe3\x81\x84\xe3\x82\x8d\xe3\x81\xaf\xe3\x81\xab\xe3\x81\xbb\xe3\x81\xb8\xe3\x81\xa8 "
"\xe3\x81\xa1\xe3\x82\x8a\xe3\x81\xac\xe3\x82\x8b\xe3\x82\x92 "
"\xe3\x82\x8f\xe3\x81\x8b\xe3\x82\x88\xe3\x81\x9f\xe3\x82\x8c\xe3\x81\x9d "
"\xe3\x81\xa4\xe3\x81\xad\xe3\x81\xaa\xe3\x82\x89\xe3\x82\x80 "
"\xe3\x81\x86\xe3\x82\x90\xe3\x81\xae\xe3\x81\x8a\xe3\x81\x8f\xe3\x82\x84\xe3\x81\xbe "
"\xe3\x81\x91\xe3\x81\xb5\xe3\x81\x93\xe3\x81\x88\xe3\x81\xa6 "
"\xe3\x81\x82\xe3\x81\x95\xe3\x81\x8d\xe3\x82\x86\xe3\x82\x81\xe3\x81\xbf\xe3\x81\x97 "
"\xe3\x82\x91\xe3\x81\xb2\xe3\x82\x82\xe3\x81\x9b\xe3\x81\x99",
/* [ . . . Korean text . . . ] */
"\xed\x82\xa4\xec\x8a\xa4\xec\x9d\x98 "
"\xea\xb3\xa0\xec\x9c\xa0\xec\xa1\xb0\xea\xb1\xb4\xec\x9d\x80 "
"\xec\x9e\x85\xec\x88\xa0\xeb\x81\xbc\xeb\xa6\xac "
"\xeb\xa7\x8c\xeb\x82\x98\xec\x95\xbc "
"\xed\x95\x98\xea\xb3\xa0 \xed\x8a\xb9\xeb\xb3\x84\xed\x95\x9c "
"\xea\xb8\xb0\xec\x88\xa0\xec\x9d\x80 "
"\xed\x95\x84\xec\x9a\x94\xec\xb9\x98 \xec\x95\x8a\xeb\x8b\xa4"
};
===============================================
This is rather messy, but it fixes the problem for VC++ 2010.
I suppose GCC, and maybe later versions of VC++, would
encounter "\u####", and note that the destination is
a "char" (byte) string, and assume that UTF-8 should be
used. (Whereas, if the destination were a "wchar_t" string,
then the Unicode value might be stored as UTF-16LE or
UTF-16BE, depending on architecture.)
TESTING
FTSTRING.EXE :
(1) Start regular Windows command prompt window:
===============================================
Start menu [icon]
--> "All Programs" [link]
--> "Accessories" [folder]
--> "Command Prompt" [icon]
===============================================
(2) Within the Windows command prompt window, change
directory to the "freetype2-demos-master" folder:
===============================================
cd [path of "freetype_build_test" folder]
cd freetype2-demos-master
===============================================
(3) Within the Windows command prompt window, start
the FTSTRING.EXE demo program:
===============================================
ftstring.exe -w 1000 -h 1000 20 C:\Windows\Fonts\arialuni.ttf
===============================================
(4) Click the demo program window to ensure it has
input focus, and then press the TAB key repeatedly
to cycle through the example Unicode strings.
Result: All strings (English, Portuguese, Greek,
Russian, Chinese, Japanese, Korean) look identical
to the commented text in the "ftstring.c" source file.
FTGRID.EXE :
(1) Start regular Windows command prompt window:
===============================================
Start menu [icon]
--> "All Programs" [link]
--> "Accessories" [folder]
--> "Command Prompt" [icon]
===============================================
(2) Within the Windows command prompt window, change
directory to the "freetype2-demos-master" folder:
===============================================
cd [path of "freetype_build_test" folder]
cd freetype2-demos-master
===============================================
(3) Within the Windows command prompt window, start
the FTGRID.EXE demo program:
===============================================
ftgrid.exe -w 1000 -h 1000 20 C:\Windows\Fonts\arialuni.ttf
===============================================
(4) Click the demo program window to ensure it has
input focus, and then press the RIGHT ARROW key
repeatedly to advance through the glyphs defined by
the font. LEFT ARROW key to go to a previous glyph.
PAGE UP to magnify the grid. PAGE DOWN to reduce
the grid. "I":Move grid upward; "K":Move grid downward.
"J":Move grid leftward; "L":Move grid rightward.
Result: Demo program appears to be working
correctly!
FTVIEW.EXE :
(1) Start regular Windows command prompt window:
===============================================
Start menu [icon]
--> "All Programs" [link]
--> "Accessories" [folder]
--> "Command Prompt" [icon]
===============================================
(2) Within the Windows command prompt window, change
directory to the "freetype2-demos-master" folder:
===============================================
cd [path of "freetype_build_test" folder]
cd freetype2-demos-master
===============================================
(3) Within the Windows command prompt window, start
the FTVIEW.EXE demo program:
===============================================
ftview.exe -w 1000 -h 1000 20 C:\Windows\Fonts\arialuni.ttf
===============================================
(4) Click the demo program window to ensure it has
input focus, and then press:
PAGE UP to magnify the grid. PAGE DOWN to reduce
the grid.
"L" : Cycle through rendering options
(monochrome, normal AA, light AA, LCD...)
Result: Demo program appears to be working
correctly!