return to first page linux journal archive
keywordscontents

ICMAKE Part 4

In part 1, Brokken and Kubat explained where the ideas for icmake came from, the basics of the program and where you can get a copy. In Parts 2 and 3 we covered the grammar of icmake source files. In this final part of the article we show examples of the use of icmake.

Frank B. Brokken and K. Kubat ICCE, Department of Education University of Groningen Groningen, the Netherlands

5. Some examples.

Three examples will be given in this final section, completing our discussion of icmake. The first example illustrates a `traditional make script', used with icmake. The example was taken from the `callback utility', developed by Karel (and also available from beatrix.icce.rug.bl). The second example is a simple dos2unix script which may be used to convert DOS textfiles to Unix textfiles: it uses awk to do the hard work. Finally, the attic-move script is presented, implementing a non-destructive remove, by moving files into an `attic.zip'. More examples can be found in the icmake distribution tar.gz file. The examples are annotated by their own comment, and are presented as they are currently used.

5.1. The callback-(ic)make script.

#!/usr/local/bin/icmake -qi

#define CC		"gcc"
#define CFLAGS		"-c -Wall"
#define STRIP		"strip"
#define AR		"ar"
#define ARREPLACE	"rvs"
#define DEBUG		""
#define CALLBACKDIR	"/conf/callback"
#define BINDIR		"/usr/local/bin"
#define VER		"1.05v

int compdir (string dir) 
{
    int
	i,
	ret;
    list
	ofiles,
	cfiles;
    string
	hfile,
	curdir,
	cfile,
	ofile,
	libfile;

    curdir = chdir (".");
    libfile = "lib" + dir + ".a";
    hfile = dir + ".h";

    chdir (dir);
    if (hfile younger libfile)
	cfiles = makelist ("*.c");
    else
	cfiles = makelist ("*.c", younger, libfile);
    for (i = 0; i < sizeof (cfiles); i++)
    {
	cfile = element (i, cfiles);
	ofile = change_ext (cfile, ".o");

	if (! exists (ofile) || ofile older cfile)
	    exec (CC, DEBUG, CFLAGS, cfile);
    }

    if (ofiles = makelist ("*.o"))
    {
	exec (AR, ARREPLACE, libfile, "*.o");
	exec ("rm", "*.o");
	ret = 1;
    }

    chdir (curdir);
    return (ret);
}
void linkprog (string dir)
{
    chdir (dir);
    exec (CC, DEBUG, "-o", dir, "-l" + dir, "-lrss", "-L. -L../rss");
    chdir ("..");
}

void buildprogs ()
{
    int
	cblogin,
	cbstat,
	rss;

    chdir ("src");
    cblogin = compdir ("cblogin");
    cbstat  = compdir ("cbstat");
    rss     = compdir ("rss");

    if (cblogin || rss)
	linkprog ("cblogin");
    if (cbstat || rss)
	linkprog ("cbstat");
    chdir ("..");
}
void instprog (string prog, string destdir)
{
    chdir ("src/" + prog);
    exec (STRIP, prog);
    exec ("chmod", "700", prog);
    exec ("cp", prog, destdir);
    chdir ("../..");
}

void install ()
{
    buildprogs ();
    instprog ("cblogin", CALLBACKDIR);
    instprog ("cbstat",  BINDIR);
}

void cleandir (string dir)
{
    chdir ("src/" + dir);
    exec ("rm", "-f", "*.o lib*.a", dir);
    chdir ("../..");
}

void clean ()
{
    exec ("rm", "-f", "build.bim");
    cleandir ("cblogin");
   cleandir ("cbstat");
    cleandir ("rss");
}

void makedist ()
{
    list
	examples;
    int
	i;
    clean ();
    chdir ("examples");
    examples = makelist ("*");
    for (i = 0; i < sizeof (examples); i++)
	if (exists ("/conf/callback/" + element (i, examples)) &&
	    "/conf/callback/" + element (i, examples) younger
		element (i, examples))
	    exec ("cp", "/conf/callback/" + element (i, examples),
		element (i, examples));
    chdir ("..");
    exec ("rm", "-f", "callback-" + VER + ".tar*");
    exec ("tar", "cvf", "callback-" + VER + ".tar", "*");
    exec ("gzip", "callback-" + VER + ".tar");
    exec ("mv", "callback-" + VER + ".tar.z",
	    "callback-" + VER + ".tar.gz");
}
void main (int argc, list argv)
{
    if (element (1, argv) == "progs")
	buildprogs ();
    else if (element (1, argv) == "install")
	install ();
    else if (element (1, argv) == "clean")
	clean ();
    else if (element (1, argv) == "dist")
	makedist ();
    else
    {
	printf ("\n"
	"Usage: build progs   - builds programs\n"
	"	build install - installs program\n"
	"	build clean   - cleanup .o files etc.\n"
	"\n"
	"	build dist    - makes .tar.gz distrib file\n"
	"\n");
	exit (1);
    }
    exit (0);
}

5.2. The Dos to Unix script.

#!/usr/local/bin/icmake -qi
/*
			    DOS2UNIX
This script is used to change dos textfiles into unix textfiles.
*/
string
    pidfile;

void usage(string prog)
{
    prog = change_ext(get_base(prog), ""); // keep the scriptname
    printf("\n"
	"ICCE ", prog,
	": Dos to Unix textfile conversion.  Version 1.00\n"
	"Copyright (c) ICCE 1993, 1994. All rights reserved\n"
	"\n",
	prog, " by Frank B. Brokken\n"
	"\n"
	"Usage: ", prog, " file(s)\n"		// give help
	"Where:\n"
	"file(s): MS-DOS textfiles to convert to UNIX textfiles\n"
	"\n");
    exit (1);				     // and exit
}
void dos2unix(string file)
{
    if (!exists(file))
	printf("'", file, "' does not exist: skipped\n");
    else
    {
	printf("converting: ", file, "\n");
	exec("/bin/mv", file, pidfile);
	system("/usr/bin/awk 'BEGIN {FS=\"\\r\"}; {print $1}' " +
	       pidfile + " > " + file);
    }
}
void process(list argv)
{
    int
	i;
			       // make general scratchname
    pidfile = "/tmp/dos2unix." + (string)getpid();
    echo(OFF);		       // no echoing of exec-ed progs

    for (i = 1; i < sizeof(argv); i++)
	dos2unix(element(i, argv));	 // convert dos 2 unix
    if (exists(pidfile))
	exec("/bin/rm", pidfile);	// remove final junk
}

int main(int argc, list argv)
{
    if (argc == 1)
	usage(element(0, argv));

    process(argv);		    // process all arguments
    return (0);			   // return when ready
}

5.3. The Attic Move script.

#! /usr/local/bin/icmake -qi
/*

       This script is used to implement a non-destructive rm
*/
#define YEAR	"1993, 1994"
#define VERSION "1.10"
int
    flags_done,
    extract,
    viewmode,
    debug;

string
    home,
    attic,
    cwd,
    progname,
    recurs,
    forced,
    unzipflag;

void kill(string s)
{
    printf(s, "\n\n");
    exit(1);
}

void preamble(list argv, list envp)
{
    int
	index;
    cwd = chdir(".");			    // get cwd
    for (index = 0; home = element(index, envp); index += 2)
    {
	if (home == "HOME")		    // HOME found
	{				    // get it
	    home = element(index + 1, envp);
	    break;			    // and done
	}
    }
if (!home)
	kill("$HOME not found");

    progname = change_ext(element(0, argv), "");
    attic = home + "/attic";	  // set $HOME/attic, change to
}
void check_attic()
{
    if (!exists(attic))		     // attic should exist
    {
	printf(attic, " does not exist. Create it [y/n] ? ");
	if (getch() != "y")	    // not a "y" ?
	    kill("ok.");
	system("mkdir " + attic);   // make the attic subdir
	exec("chmod", 700, attic);  // private use
    }				  // else attic must be dir
    else if (!((int)element(0, stat(attic)) & S_IFDIR))
	kill("'" + attic + "' is not a directory");

    attic += "/attic";		    // append the zip-name
    chdir("/");			   // go to the root
}
void set_flags(string arg)
{
    int
	index;
    string
	flag;

			      // process all arguments
    for (index = 1; flag = element(index, arg); index++)
    {
	if (flag == "r")       // process encountered options
	    recurs = "-r";
	if (flag == "d")
	    debug++;
	else if (flag == "f")
	    forced = "-f";
	else if (flag == "x")
	    extract++;
	else if (flag == "v")
	{
	    extract++;
	    viewmode++;
	    unzipflag = "-l ";
	}
	else
	    kill("Unrecognized flag '-" +
		 flag +
		 "': " +
		 progname +
		 "aborted");
    }
    if (extract && unzipflag == "")
	unzipflag = "-u ";	   // use proper unzip flag
}
list options(int argc, list argv)
{
    int
	index;
    list
	ret;
    string
	arg;

for (index = 0; index < argc; index++)
    {
	arg = element(index, argv); // get next argument
	if (element(0, arg) == "-") // first element is a - ?
	    set_flags(arg);	   // then set flags
	else
	    ret += (list)arg;	  // or add to list to return
    }

    return (ret);		    // returned list
}
void usage()
{
    printf
    (
	"\n"
	"ICCE AM (Attic Move) non-destructive remove. Version "
	VERSION "\n"
	"Copyright (c) ICCE " YEAR ". All Rights Reserved\n"
	"\n"
	"AM by Frank B. Brokken\n"
	"\n"
	"Usage: ", progname, " [options] file(s)\n"
	"Where:\n"
	"   options:\n"
	"      -d: Debug mode: no execution but display of commands\n"
	"      -f: Forced processing of indicated files\n"
	"      -r: Recursive removal of directory contents\n"
	"      -v: View current contents of the attic\n"
	"      -x: Extract files from the attic to their original place\n"
	"	   (i.e., if you are permitted to do so...\n"
	"\n"
	"   file(s): names of files and directories to move to/from
	the attic\n"
	"\n"
	"   ", home, "/attic/attic.zip is used to store the files.\n"
	"\n"
    );
    exit (1);
}
string prefix_path(string file)
{
    string
	el,
	ret;
    int
	index;
    if (element(0, file) != "/")  // if file isn't an absolute path
	file = cwd + file;	 // then make an absolute path
    for (index = 1; el = element(index, file); index++)
	ret += el;	   // remove first char from abs path

    return (ret);		   // return modified string
}
void retrieve(string file)
{
    string
	cmd;
    cmd = "unzip "		    // update only
	+ unzipflag
	+ attic;

if (!viewmode)
	cmd += " "
	     + prefix_path(file);  // and the file (+ path prefix)
    if (debug)
	printf("( cd /; ", cmd, " )\n");  // debug: show command
    else
	system(cmd);			 // else exec cmd
}
void remove(string file)
{
    string
	cmd;
    cmd = "zip -my "	     // remove, remove links as links
	+ forced	     // maybe forced
	+ " "
	+ recurs	     // maybe recursive
	+ " "
	+ attic		     // target zip
	+ " "
	+ prefix_path(file);  // and the file (+ path prefix)
    if (debug)
	printf("( cd /; ", cmd, " )\n");  // debug: show command
    else
	system(cmd);	      // else exec cmd
}
void one_file(string file)
{
    if (extract)		 // either retrieve or remove
	retrieve(file);		  // the file
    else
	remove(file);
}
void process(int argc, list argv)
{
    int
	index;

    for (index = 1; index < argc; index++)

	one_file(element(index, argv));    // process one file
}
int main(int argc, list argv, list envp)
{
    echo (OFF);
    preamble(argv, envp);	// set progname and attic dir.
    argv = options(argc, argv); // get the options
    argc = sizeof(argv);       // determine remaining arguments
    if (argc == 1 && !viewmode) // none left and no viewmode?
	usage();	       // give usage and exit 1
    check_attic();	       // check accessability of attic
    if (viewmode)	       // view contents
	retrieve("");
    else		      // or
	process(argc, argv);	// process remaining arguments
    return (0);		       // done
}