How to get timestamp in Monkey 2 with libc and in C

This morning I got implemented a little code, that can be used to get timestamp based on ANSI C code using Monkey 2 programming language’s libc.

Let’s take first look at the Monkey 2 code:

Namespace myapp

#Import "<std>"
#Import "<libc>"

Using std..
Using libc..

Function Main()

		Local seconds:time_t
		Local p:tm_t Ptr
		Local date:String
		
		libc.time(Varptr seconds)
	
		p = localtime(Varptr seconds)
		
		date = String(p->tm_sec) + "-" + String(p->tm_min) + "-" + String(p->tm_hour) + "-" + String(p->tm_mday) + "-" + String((p->tm_mon)+1) + "-" + String(1900 + p->tm_year)
		
		Print date
	
End

At the moment the output of the program is as follows: 40-31-8-26-10-2018

Year 2018, month 10, day 26, hour 8, min 31, sec 40.

Reversed order might be more useful in practice…

Let’s take a look at the C version:

#include <stdio.h>
#include <time.h>

void Date (char date[10+1]);

void main (void) {

	char datum[10+1];
	
	Date(datum);
	printf("%s",datum);

}


void Date (char date[10+1]) {
	time_t seconds;
	struct tm *p;
	
	time (&seconds);
	p = localtime(&seconds);
	
	sprintf(date, "%02i.%02i.%02i",
		p->tm_mday,
		p->tm_mon + 1,
		p->tm_year+1900);
}

To the year is again added 1900. This gives following output: 26.10.2018

The tm_mon is between 0..11, tm_year between 1900 + 0..n.

That’s it for now, lots of things to do…

 

 

Using C and DLLs in BlitzMax

BlitzMax apps can be made faster by using C. Also using DLLs in BlitzMax is possible, but that isn’t documented in BlitzMax’s documentation at all.

First, an example of using C code in BlitzMax. As an example we generate the Mandlebrot set using C code to determine does the point belong to the set (see my article on my personal blog on generating the Mandelbrot set, whole example code is in BlitzMax).

To compile the example below, you need to have MinGW configured to BlitzMax.

We start with the C code (save it as mandelbrot.c):

int mandelbrot(double dr, double di, double minR, double minI, int x, int y, int maxIter);

int mandelbrot(double dr, double di, double minR, double minI, int x, int y, int maxIter) {

    int iterations = 0;

    double cr,ci,zr,zi,zr_temp,zi_temp;

    cr = minR + x * dr;
    ci = minI + y * di;
    zr = 0.0;   
    zi = 0.0;
    zr_temp = 0.0;
    zi_temp = 0.0;

 while (iterations < maxIter) {

        zr_temp = zr * zr - zi * zi + cr;
       
        zi_temp = 2.0 * zr * zi + ci;
        
        zr = zr_temp;
        zi = zi_temp;       

        iterations++;

        if (zr * zr + zi * zi > 4.0) return iterations;
    
 }

    return 0;
}

Next the BlitzMax code that uses the C code:

Import "mandelbrot.c"

' tell the compiler that there is an external function
Extern
	Function mandelbrot:Int(dr:Double,di:Double,minR:Double,minI:Double,x:Int,y:Int,maxIter:Int)
End Extern

Const maxIter:Int = 40

Graphics 640,480

Local minR:Double = -2.25, maxR:Double = 0.75
Local minI:Double = -1.5, maxI:Double = 1.5

Local dr:Double, di:Double

Local w:Double, h:Double, sW:Double, diff:Double
Local shade:Int

w = maxR - minR
h = maxI - minI
sW = h * (640.0) / (480.0)
diff = sW - w

minR = minR - diff / 2
maxR = maxR + diff / 2

dr = (maxR - minR) / 640
di = (maxI - minI) / 480

For Local y:Int = 0 To 480 - 1
	For Local x:Int = 0 To 640 - 1
		shade = mandelbrot(dr,di,minR,minI,x,y,MAXITER)
		shade = 255 - Double(MAXITER - shade) / MAXITER * 255.0
		SetColor 0,0,shade
		Plot x,y
	Next
Next

Flip
WaitKey
End

Compile and run the code and you’ll see a blue shaded Mandelbrot set that should look like following:

mandelbrot

In the next part of this post we’ll create a DLL in C and call it from BlitzMax.

I’m still mostly using Visual C++ 2008.

The steps to create a DLL:

  • Start Visual C++ and start a new project
  • Select WIN32 console application, name it (in our example Mandelbrot) and press OK
  • Then click ”Next” and select DLL

You’ll get a pre-generated code for a DLL.

The C code for our DLL is following (Mandelbrot.cpp in Visual C++):

#include "stdafx.h"	// this for Visual C++

extern "C"{ 
_declspec(dllexport) int mandelbrot(double dr, double di, double minR, double minI, int x, int y, int maxIter); 
} 
int mandelbrot(double dr, double di, double minR, double minI, int x, int y, int maxIter) {

    int iterations = 0;

	double cr,ci,zr,zi,zr_temp,zi_temp;

    cr = minR + x * dr;
    ci = minI + y * di;
    zr = 0.0;   
    zi = 0.0;
    zr_temp = 0.0;
    zi_temp = 0.0;

	while (iterations < maxIter) {

        zr_temp = zr * zr - zi * zi + cr;
       
        zi_temp = 2.0 * zr * zi + ci;
        
        zr = zr_temp;
        zi = zi_temp;       

        iterations++;

        if (zr * zr + zi * zi > 4.0) return iterations;
    
	}

    return 0;
}

The BlitzMax code using the DLL is as follows:

Extern "win32"
	Function FreeLibrary(hLibrary:Int)
End Extern

Global mandelbrot:Int(dr:Double,di:Double,minR:Double,minI:Double,x:Int,y:Int,MAXITER:Int)"Win32"

Global lib = LoadLibraryA("Mandelbrot.dll")

If lib Then
	mandelbrot = GetProcAddress(lib, "mandelbrot")
Else
	Notify "DLL-file not found!"
	End
EndIf

Global x:Int, y:Int
Const MAXITER:Int = 40

Graphics 640,480

Global minR:Double = -2.25, maxR:Double = 0.75
Global minI:Double = -1.5, maxI:Double = 1.5

Global dr:Double, di:Double

Global w:Double, h:Double, sW:Double, diff:Double
Global shade:Int

w = maxR - minR
h = maxI - minI
sW = h * (640.0) / (480.0)
diff = sW - w

minR = minR - diff / 2
maxR = maxR + diff / 2

dr = (maxR - minR) / 640
di = (maxI - minI) / 480

For y = 0 To 480 - 1
	For x = 0 To 640 - 1
		shade = getShade()
		shade = 255 - Double(MAXITER - shade) / MAXITER * 255.0
		SetColor 0,0,shade
		Plot x,y
	Next
Next

Flip
WaitKey
FreeLibrary(lib)	' free the resources
End

Function getShade:Int()
	Return mandelbrot(dr,di,minR,minI,x,y,MAXITER)
EndFunction

The DLL function is called from a BlitzMax function, because otherwise one would get a EXCEPTION_STACK_OVERFLOW.

When the DLL is called from a function the memory allocated for the DLL-call is local; after returning from the function all the memory allocated for the function call is freed.

As always, this information is free. You may use the codes above in your projects as you wish.

Hex 2 Dec

In many programming languages there is built-in command or function to convert a decimal value to a hex value. But at least in BlitzMax there isn’t a command or function to convert a hex value to a dec value. In this post I present my little function to convert a hex value to dec value in BlitzMax and in C.

The BlitzMax function:

First, put somewhere in the beginning of your program line

Const hexes:String = "0123456789ABCDEF"

The function itself:

Function hex2dec:Int(hexvalue:String)

  Local i:Byte, val10:Int, index:Byte, length:Int
  Local char:String

  length = Len(hexvalue)

  For i = 1 To length

    char = Mid$(hexvalue,i,1)
    index = Instr(hexes,char) - 1
    val10 = val10 + (16 ^ (length - i)) * index

  Next

  Return val10

EndFunction

The C version is a complete program that uses its functions:

#include 
#include 
#include 

int hex2dec(char*);
int indexOfchar(char);

const char hexes[] = "0123456789ABCDEF";

void main (void) {

  char hex[8+1];

  printf("Hex number: ");
  scanf("%s",&hex[0]);
  printf("%s is %d in dec.n",&hex[0],hex2dec(&hex[0]));
}

int hex2dec(char *hex) {
  int i, index, val10, length;
  char chr;

  val10 = 0;

  length = strlen(hex);

  for (i = 0; i < length; i++) {
    chr = hex[i];
    index = indexOfchar(chr);
    val10 = val10 + pow(16,(length - i - 1)) * index;
}
  return val10;
}

int indexOfchar(char chr) {

  int i;

  for (i = 0; i < 16; i++) {
    if (hexes[i] == chr) return i;
  }
}

Be careful with the C version: It doesn’t check if the input is correct. As you can see from the code the letters in the hex number should be given in capital letters. Feel free to use and improve these codes!

How to retrieve the %AppData% folder

AppData folder is used to store data like hiscores, config, etc. of a game (or app). The AppData folder is a special folder that’s location is related to Windows version one is using. This is why AppData folder must be retrieved with the aid of the system.

In Blitz3D retrieving the AppData folder is as simple as this:

AppDataFolder$ = GetEnv$(”AppData”)

In BlitzMax retrieving the AppData folder isn’t this straight forward. The easiest way to get the location of this special folder is to use external module, BAH.Volumes. Once this module is installed for BlitzMax and imported in the beginning of the code, retrieving the AppData folder is as easy as this:

AppDataFolder = GetUserAppDir()

Above is assumed that the variable AppDataFolder is defined as String.

In order to install external modules to BlitzMax, MinGW must be installed and configured for BlitzMax. The BlitzMax product page has a link to forum topic that explains how to set up MinGW for BlitzMax.

Link: BAH.Volumes (from Google Code)

Update!

With good old ANSI C the %AppData% folder can be retrieved as follows:

#include <stdio.h>
#include <stdlib.h>

void main(void) {

	char *appdata;
	appdata = getenv("AppData");
	printf("%s\n",appdata);

}