C Source Code

"Life would be so much easier if we only had the source code."
On this page:

Introduction

Here are some snippets of C code that I hacked for specific purposes. I believe them to be useful and since it was developed while I was paid by the (Italian/French/US) government, you might consider it like your tax money at work. All this code is ANSI C and should work on any 32 bit compiler. I have tested them on LabWindows/CVI on Windows and Linux.

Since 2019, most of the code is available on my gitlab page.



Statistics

LabWindows/CVI has some great libraries for math/signal stuff. The problem is that most of it works on arrays. What if you have on the fly data and want temporary results ? Here's a standard statistics module I wrote that enables you to keep feeding data to it while getting results. Note that you can compile it for FLOAT or DOUBLE precision. Two structures and two sets of functions: for single and double variables.

	CStat S;
	StatReset(&S);
	StatAdd(&S, 10);
	StatAdd(&S, 0);
	StatAdd(&S, 50);
	A=StatAvr(&S);	// will return 20
	// S.N  =3
	// S.Min=0
	// S.Max=50
Category:
ANSI C (Windows, Unix...), LabWindows/CVI Function Panel
1994
First C++ version
1995
Lowered to C version
2019/06/11
Published on gitlab (find the Statistics source code there).

Color scaling

When you have a graph with a series of plots, it makes sense to display the plots in a range of colors, like a rainbow. Problem is, the rainbow is not very visible (all the colors have the same luminance), and how do you scale between two colors anyway ? Use my ColorScaleHSL function. This module also gives you conversion functions between RGB colors and HSL color definitions and macros to get darker colors.

See the examples below for different scales of RGB and HSL between 2 colors, or here for examples with 3 colors. If you don't want to bother with the source but want to do some color stuff, check out my color palette generator freeware.

	COLORREF Color;
	for (RG=0; RG<NbRG; RG++) {
		if (Int[RG]<Min) Min=Int[RG];
		if (Int[RG]>Max) Max=Int[RG];
	}
	if (Max==Min) MaxInt++;		// Avoid divide by 0
	for (RG=0; RG<NbRG; RG++) {
		Color=ColorScaleHSL(VAL_WHITE, VAL_BLACK, (Int[RG]-Min)/(Max-Min));
		...
		SetCtrlAttribute (PnlFax, Cnvs , ATTR_PEN_COLOR, Color);
		CanvasDrawLine (PnlFax, Cnvs, P1, P2);
	}
Category:
ANSI C (Windows, Unix...), LabWindows/CVI Function Panel
1998
First version
2001
Added ability to scale between 3 colors
2001/09/10
Added inverted steps for more readable maps
2019/06/11
Published on gitlab (find the ColorScale source code there).

[ScaleRGB.png]
Examples of scaling using RGB or HSL, Linear or with 8 steps

The images on the left show examples of scalings between various colors (black, white, primaries [RGB] and secondaries [CMY]) using linear RGB and linear HSL. Pass the mouse over the following lines (requires JavaScript):

RGB HSL
Linear 1 2
8 steps 3 4
Examples of linear scaling using HSL Examples of scaling using RGB with 8 inverted steps Examples of scaling using HSL with 8 inverted steps

Extended time formatting

The strftime function from the ANSI C library is nice, but it lacks a lot of things before being really useful in a scientific environment. My StrfTime() function adds many formatting codes, like the number of minutes since the start of the year and things like that. And it stays compatible with the standard C strftime() function.

In addition to the two StrfTime source files for the library, there's also a documentation file, a LabWindows/CVI function panel and also 5 utility programs and scripts to compile independently:

TimeFormat.exe
uses StrfTime.exe to format a time string from the command line)
TimeDiffFormat.exe
similar but formats the difference between two times
TimeJump.exe
returns the previous or next time/date given a date in [YY]YY[MM[DD[HH[MM[SS]]]]] format
JulianDate.exe
Julian date to YYMMDD conversions
LengthOfYearMonth.exe
return the number of days in a given month or year
TimeLoop.sh
Shell script that loops between two dates, giving you plenty of local time variables to customize your own scripts
Makefile
Makefile to compile all the programs. Just type make

Note 1: this code uses both two and four digits years, and is Y2K compliant within 1970 ~ 2026.

Note 2: 'Julian day' refers here to a day of the year expressed as a number from 1 to 366, not to the true Julian calendar established by Julius Cesar and now superseded by the Gregorian calendar (our calendar). Julian days DDD are equivalent to Month/Days MMDD, but you need to know if the year is a leap year to provide a conversion. Source code included for all programs.

Category:
ANSI C (Windows, Unix...), LabWindows/CVI Function Panel
1997
First version
2001
PreviousTime.exe and TimeFormat.exe for automated shell scripts
2001/8/3
StrfTimeDiff function for formatting a time difference
2001/11/8
Julian day conversions.
2001/11/14
Added TimeDiffFormat and LengthOfYearMonth programs.
2002/01/15
Renamed FormatTime to TimeFormat and FormatDiffTime to TimeDiffFormat.
TimeJump.exe now supersedes PreviousTime.exe
2002/06/13
Added a YYYY or YY option for years
2005/06/02
Corrected bug when using seconds.
2005/11/14
Corrected bugs when converting Julian dates from YYYYMMDD format and length of year.
2019/06/11
Published on gitlab (find the StrfTime source code there).

Example of Use in Unix: running through a sequence of dates (I also provide a script that does exactly that, with plenty of extras):

#! /bin/ksh
Start=950101	# Start date YYMMDD - included
Stop=$(FormatTime.exe NOW "%y%m%d")		# End date YYMMDD - excluded
YYMMDD=$Start
while [ $YYMMDD != $Stop ]
do
	FormatTime.exe $YYMMDD "%d %B %Y"
	# Skip to next day
	YYMMDD=$(TimeJump.exe $YYMMDD +1)
done

Parameter Parsing

When writing scientific programs, one of the first problem you run into is: how do you want to control the program parameters (input values, default directories...). Asking the user each time is not a good idea because you cannot run the program in a batch and most of the options are probably always the same; hard coding the values inside the program is fine until you need to change them (get the same compiler, same compiling options...); saving in the registry is non portable, complex and allows for only one set of data.

No the usual solution is to put the values inside a file. But then you need a parser to read it properly. Here's one. Note that this is for reading only, you cannot modify the parameter values inside the file. Also this code works but is not optimized for speed.

	char DirSfcBin[MAX_PATHNAME_LEN];
	int MaxLat, DoLegend, ColorZero, ColorNan, ColorCurve;
	float MaxScale;
	ParseParamString("Param.txt", DirSfcBin);
	ParseParamInt("Param.txt", MaxLat);
	ParseParamFloat("Param.txt", MaxScale);
	ParseParamBool("Param.txt", DoLegend);
	ParseParamHex("Param.txt", ColorZero);
	ParseParamHex("Param.txt", ColorNan);
 	ParseParamHex("Param.txt", ColorCurve);
Will parse the following Param.txt file:
; This is the parameter file
; Comments are preceded by ; # or !
; You can use blank lines too
; Parameters can be in any order in the file, in case of duplicates, only the first one is read.

DirSfcBin="/raid/data/SfcRain/"		; Use double quotes around strings
NAN=-9999.			; float, ignored value
MaxLat = 40			; integer
ColorZero=	0xC0C0C0	; hex value
ColorNan =	FFFFFF		; optional 0x
ColorCuve=	0x101040		; Syntax error
MaxScale=10.		; leading/trailing spaces are ignored
DoLegend=Y		; Bool can be T, F, Y, N, True, False, Yes, No, 0, 1...
Category:
ANSI C (Windows, Unix...), parser.
2001
First version
2019/06/11
Published on gitlab (find the ParseParam source code there).

Graphic Filter


[Filters.png]
User interface of the FilterPopup module

You want to lighten up a bitmap or turn it to a negative image ? That's a simple graphic filter (here the function Filter1x1()).
You want to sharpen up a bitmap or enhance the edges or emboss it ? That can be done with a 3x3 graphic filter (here the function Filter3x3()).
You want to change a color bitmap to greyscale or switch the colors ? That can be done with an interchannel graphic filter (here the function Filter1C()).
This sample source code does all of that (plus 5x5 filters) and works in the same way than the user defined filters of applications like Buy at Amazon.comPhotoShop or Buy at Amazon.comPaint Shop Pro.

Some sample filters are included, but if you want to define your own, here's how for a 3x3 filter: define a 3x3 matrix with the coefficients of the surrounding pixels, a divider and a bias. For instance {{1,0,0},{0,5,0},{0,0,1}} will apply to a pixel the sum of the upper left pixel, the lower right pixel and 5 times the central pixel. Then it is divided by div and we add a bias. The result is truncated to fit between 0 (black) and 255 (white). This applies separately to the different channels Red, Green and Blue. There is no way to combine the channels with a normal 1x1, 3x3 or 5x5 filter, but you can do it with an interchannel filter. It works on greyscale images, 24 bits RGB or 32 bits images with alpha channel (the filter is applied to the alpha channel, which may not be a desired result).

Two source files and some specific LabWindows/CVI code to do a custom filter popup (one UIR file CustomFilter.uir, and one C file FilterPopup.c with their respective headers). I did not bother creating a function panel for LabWindows/CVI. Example of use:

	Png_ReadBitmapFromFile(NULL, &Bits, &RowBytes, &PixDepth, &Width, &Height, SourcePathName); // Reads a PNG file
	Filter3x3(Bits, RowBytes, PixDepth, Width, Height, FilterSharpen); // Apply sharpen filter
	Jpg_SaveBitmapToFile(Bits, RowBytes, PixDepth, Width, Height, DestPathName, Compression));	// Saves to a JPEG file
Category:
ANSI C (Windows, Unix...) for the filters only, graphics.
2001/08/15
First version
2002/03/15
Added simple pixel filters, 5x5 filters and interchannel color filters.
Added popups for custom filters (LabWindows/CVI only).
2019/06/11
Published on gitlab (find the GraphicFilter source code there).

Simple logging facility

There are many ways to log error messages out of a program, but I couldn't find one that matched my requirements, so I wrote a simple logging facility. The requirements:

// print all messages to stderr, no time stamp
SimpleLog_Setup(NULL, NULL, 0, 1, 0, " ");
// Avoid repeating the last message
SimpleLog_Setup("Msg.log", "%H:%M ", 1, 0, 0, ", ");
// Among the last 10 different messages, avoid repeating them at most 20 times
SimpleLog_Setup("Msg.log", "%Y%m%d-%H%M%S ", 10, 20, 0, "\t");
// Among the last 100 different messages, avoid repeating them but print them at least once per minute
SimpleLog_Setup(NULL, "%Y%m%d-%H%M%S ", 100, 0, 60, " ");

// Display everything except debug messages
SimpleLog_FilterLevel(SL_NOTICE);

SLOG(SWRN, "Fubar has a value of %d", fubar);
// This won't be printed with the above filter level
SLOG(SDBG, "Expected value was %d", tarfu);

// Optional before quitting the program, to get pending messages
SimpleLog_Flush();
Category:
ANSI C (Windows, Unix...)
2009/02/23
First version
2019/01/17
Fixed a memory leak
2019/06/11
Published on gitlab (find the SimpleLog source code there).

Simple binary to ascii converting function

Note: I have 2 executables that do more advanced binary to ascii conversions. This is just a simple C function. Requirement:

2 source files: Bin2ascii.h, Bin2ascii.c. Example of use:

printf("Buffer: %s\n", Bin2ascii(Str, sizeof(Str), 0, 1, 0, 0))
Category:
ANSI C (Windows, Unix...), text processing, function
2009/02/23
First version
2019/06/11
Published on gitlab (find the Bin2ascii source code there).

Support my site: make a donation, buy images, use associate services

Numerical and boolean evaluation

There's sometimes a need to give a user the possibility to input formulas inside a program without recompiling the whole thing, but it's not possible to do this simply in C (there's no magical 'eval' function). So this is a simple postfix evaluator that can use double and booleans present in the program with various formulas. The requirements:

double A=2, B=3, C=4;
tPE_Variable VarList[10];
tPE_Val Val;
char *Formula="AA BB / sin CC + sqrt";
int NV=0;
VarList[NV].Name="AA";	VarList[NV].pVal=&A;	VarList[NV++].Type=VAL_DOUBLE;
VarList[NV].Name="BB";	VarList[NV].pVal=&B;	VarList[NV++].Type=VAL_DOUBLE;
VarList[NV].Name="CC";	VarList[NV].pVal=&C;	VarList[NV++].Type=VAL_DOUBLE;
Val=PostfixEval_Compute(Formula, VarList, NV, NULL, NULL)
switch (Val.Type) {
	case VAL_ERROR: printf("\n%s gave error %s", Formula, PostfixEval_ErrMsg(Val.Err, NULL)); break;
	case VAL_BOOL:  printf("\n%s is %s", Formula, Val.B?"TRUE":"FALSE");  break;
	case VAL_DOUBLE:printf("\n%s = %f",  Formula, Val.D); break;
	default:		printf("\nError, invalid result type %d", Val.Type); break;
}
Category:
ANSI C (Windows, Unix...)
2009/02/23
First version
2019/06/11
Published on gitlab (find the PostfixEval source code there).