Amiga Version String für mit SAS/C, VBCC und amiga-gcc compilierte Programme

Amiga Version String Macro www.mbergmann-sh.de

Auf dem Commodore Amiga besitzen gut geschrieben Programme einen Versions-String, der über die Shell mit dem Befehl ‚version <progname> file full‘ abgefragt werden werden kann.

Gerade dann, wenn man als C-Programmierer zu Testzwecken verschiedene C-Compiler verwendet kann es hilfreich sein, ein Template zu schreiben, um einen solchen Versions-String automatisch zu generieren. Man kann ein solches Template z. B. unter ‚S:myHeader.txt‘ ablegen und bei Bedarf einfach in den Texteditor laden.

Um einen Versions-String per Macro mit dem Programmnamen, der Versionsnummer, dem aktuellen Compilerdatum und Informationen zum verwendeten Compiler zu erstellen, geht man so vor:

#define PROGNAME "meinProgramm"
#define VERSIONR "1.0.0"
#define COPYRIGHT "Copyright © 2025 by Micha B."

/* construct version tag */
#if defined(__VBCC__)
 #define PROGDATE __AMIGADATE__
 #define COMPILER "VBCC"
#endif
#if defined(__SASC)
 #define PROGDATE __AMIGADATE__
 #define COMPILER "SAS/C v6.58"
#endif
#if defined(__GNUC__)
 #define PROGDATE __DATE__
 #define COMPILER "GCC"
#endif

/* AmigaOS Version String */
const char *version = "\0$VER: " PROGNAME " " VERSIONR " (" PROGDATE ") - (" COMPILER ") - " COPYRIGHT "\n";

Warum der Aufwand?

Natürlich könnte man den Versions-String auch einfach so schreiben:

const char *version ="\o$VER: meinProgramm ((01. April 2025)) - (SAS/C) - Copyright by IchSelbst\n";

Man müsste dann halt den String jedesmal verändern wenn die Programmversion wechselt oder ein anderer C-Compiler benutzt wird. Da ist es schon komfortabler, wenn man sich ein entsprechenes Makro angelegt hat.

Ich selbst verwende bei der Programmentwicklung grundsätzlich Templates, da mir das viel Arbeit für Kommentare usw. erspart. Für meine mit dem ReBuild GUI Designer entworfenen Projekte sieht mein Standard-Template so aus:

/*********************************************
 * Project:  ReBuild F.A.Q                   *
 * Purpose:  show some ReAction GUI features *
 * File:     meinprogramm.c                  *
 * Version:  1.0 RELEASE                     *
 * Author:   Michael Bergmann                *
 * Date:     2025/04/04                      *
 *                                           *
 * GUI made with ReBuild v1.3 beta           *
 * Tested Compilers:                         *
 *           SAS/C v6.58                     *
 *           VBCC v0.91 pre                  *
 *           amiga-gcc v6.5                  *
 * HINT: Might be linked against             *
 *       amiga.lib and reaction.lib!         *
 *********************************************
 */
/* --- Put INCLUDE-Files HERE: --- *

 
#define myDebug TRUE  /* Debugging Texts TRUE or FALSE */
#ifdef myDebug
  #include <stdio.h>  /* used for puts(), printf() */
  char *str_greet = "Hello Stranger!\n We're ready to DEBUG now!\n\n";
  char *str_bye = "\n\nAll Done!\nThis Demo quits now.\nHope you liked it?";
#endif

/* construct version tag */
#define PROGNAME "meinProgramm"
#define VERSIONR "1.0.0"
#define COPYRIGHT "Copyright © 2025 by Micha B."

#if defined(__VBCC__)
  #define PROGDATE __AMIGADATE__
  #define COMPILER "VBCC"
#endif
#if defined(__SASC)
  #define PROGDATE __AMIGADATE__
  #define COMPILER "SAS/C v6.58"
#endif
#if defined(__GNUC__)
  #define PROGDATE __DATE__
  #define COMPILER "GCC"
#endif

/* AmigaOS Version String */
const char *version = "\0$VER: " PROGNAME " " VERSIONR " (" PROGDATE ") - (" COMPILER ") - " COPYRIGHT "\n";

/* Function Proto Types */
int main(void);
void window_main( void );
int setup( void );
void cleanup( void );
void runWindow( Object *window_object, int window_id, struct Menu *menu_strip, struct Gadget *win_gadgets[] );

/* --- Additional global stuff goes HERE: --------------------------------------------------------------- */

/* --- Menu IDs ----------------------------------------------------------------------------------------- */
enum menus
{
  /* Menu "Project"  */
  MN_ITEM1
};

/* --- Requesters ---------------------------------------------------------------------------------------- */
/* 'No OS 3.2' box */
struct EasyStruct warnreq =
{
  sizeof(struct EasyStruct),
  0,
  "Error",
  "Needs AmigaOS 3.2.x\n\nNo Chance to run this program on your machine!",
  "Ok"
};

/* 'requester.class problem' box */
struct EasyStruct noreqclassreq =
{
  sizeof(struct EasyStruct),
  0,
  "Critical Error",
  " requester.class could not be opened.\nThis App refuses to start!",
  "Ok"
};

/* --- Function: setup() --------------------------------------------------------------------------------- */
/* --- Open libs, gadgets, classes and other ressources -------------------------------------------------- */
int setup( void )
{
  if( !(IntuitionBase = (struct IntuitionBase*) OpenLibrary("intuition.library",0L)) ) return 0;
  if( !(GadToolsBase = (struct Library*) OpenLibrary("gadtools.library",0L) ) ) return 0;
  if( !(WindowBase = (struct Library*) OpenLibrary("window.class",0L) ) ) return 0;
  if( !(IconBase = (struct Library*) OpenLibrary("icon.library",0L) ) ) return 0;
  
  /* --- Check for a sufficient OS! --- */
  if( !(LayoutBase = (struct Library*) OpenLibrary("gadgets/layout.gadget",47) ) )
  {
    if (myDebug)
       puts(" FAIL: layout.gadget");
    EasyRequest(NULL, &warnreq, NULL);    
    return 0;
  }
  /* Additional Stuff: Place HERE! */
  
} /* END Function setup() */

/* --- Function: cleanup() -------------------------------------------------------------------------------- */
/* --- Close used ressources and clean up for shutdown ---------------------------------------------------- */
void cleanup( void )
{
   /* Copy content of Function cleanup() HERE: */
} /* END Function cleanup() */
 

/* --- Function: runWindow() ------------------------------------------------------------------------------ */
/* --- IDCMP Event Handling is done here ------------------------------------------------------------------ */
void runWindow( Object *window_object, int window_id, struct Menu *menu_strip, struct Gadget *win_gadgets[] )
{
  struct Window	*main_window = NULL;  
  struct MenuItem *menuitem = NULL;
  LONG myItem = 0;                  /* GT menu identifier     */
  ULONG selected;                   /* used for Content query */
  ULONG status = 0;                 /* used for Status query  */
  ULONG req_result = 0;
  if ( window_object )
  {
    if ( main_window = (struct Window *) RA_OpenWindow( window_object ))
    {
      WORD Code;
      ULONG wait = 0, signal = 0, result = 0, done = FALSE;
      GetAttr( WINDOW_SigMask, window_object, &signal );
      if ( menu_strip)  SetMenuStrip( main_window, menu_strip );
      
      if(myDebug)
        printf("%s\n", str_greet);
        
      while ( !done)
      {
        wait = Wait( signal | SIGBREAKF_CTRL_C );

        if ( wait & SIGBREAKF_CTRL_C )
          done = TRUE;
        else
          while (( result = RA_HandleInput( window_object, &Code )) != WMHI_LASTMSG)
          {
            switch ( result & WMHI_CLASSMASK )
            {
              /* --- WINDOW -------------------------------------------- */
              case WMHI_CLOSEWINDOW:
                if(myDebug)
                  printf("%s\n", str_bye);
                done = TRUE;
                break;
                
              /* --- MENUS -------------------------------------------- */
              case WMHI_MENUPICK:
                if(myDebug)
                  puts("\nMenu pick!");
                 
                menuitem = ItemAddress(menu_strip, result & WMHI_MENUMASK);
                if(myDebug)
                  printf(" ItemAdress = %ld\n", menuitem); 
                  
                /* Check if menuitem equals to Zero. If Zero, an enforcer hit will occour when */
                /* attempting to examine, so we do not allow switching on menuitem == 0!       */
                if(!(menuitem == 0))
                {
                  /* --- ...get menu entries by using GadTools' GTMENUITEM_USERDATA field macro --- */
                  myItem = ((long)GTMENUITEM_USERDATA(ItemAddress(menu_strip, result & WMHI_MENUMASK)));
                  /* --- Identify selected menu entry */
                  switch(myItem)
                  {
                    case MN_ITEM1:
                      if(myDebug)
                        puts("\n Menu 'Project': <ITEM> was selected.");
                      
                      break;
                  } /* END switch(myItem) */ 
                } /* END if(!(menuitem == 0)) */
                break;  /* END WMHI_MENUPICK */

              /* --- GADGETS ----------------------------------------- */
              case WMHI_GADGETUP:
                switch (result & WMHI_GADGETMASK)
                {
                  /* --- Gadget 1 --- */
                  case 
                    break;          					
          				           
                } /* END switch (result & WMHI_GADGETMASK) */
                break;  /* END case WMHI_GADGETUP */
                
              /* --- ICONIFY ----------------------------------------- */
              case WMHI_ICONIFY:
                if ( RA_Iconify( window_object ) )
                  main_window = NULL;
                break;

              /* --- UNICONIFY --------------------------------------- */
              case WMHI_UNICONIFY:
                main_window = RA_OpenWindow( window_object );
                if ( menu_strip)  SetMenuStrip( main_window, menu_strip );
              break;
            } /* END switch ( result & WMHI_CLASSMASK ) */
          } /* END while (( result = RA_HandleInput( window_object, &Code )) != WMHI_LASTMSG) */
      } /* END while ( !done) */
    } /* END if ( main_window = (struct Window *) RA_OpenWindow( window_object )) */
  } /* END if ( window_object ) */
} /* END Function runWindow() */


/* --- Function: window_main() ----------------------------------- */
/* --- All window-specific setup for main Window is done here. --- */ 
/* ---'runWindow()' is called for message handling afterwards. --- */
void window_main( void )
{
  /* We changed ReBuild's menu struct output in order to obey to GadTools Menu handling! */
  /* Replaced: Last NULL argument by (APTR) <Item identifier>                            */

} /* END Function window_main() */


/* --- Main Function ---------------------------------------------------------------------------------- */
int main(void)
{
  if ( setup() )    /* This will satisfy all needs... */
  {
    window_main();  /* ...and open Application's main Window + implement Event handling by running 'runWindow()' */
  }
  cleanup();        /* Clean up stuff and exit */
} /* END main() */

Du findest dieses Tutorial hilfreich? Dann freue ich mich über einen kleinen Obolus für meine IT-Kasse. Besten Dank!  🙂

[Übersicht]