#!/usr/local/bin/icmake -qt /tmp/xuser
/*                              build

   A C++ makefile generated by C++ for xuser.cc

*/

string                                      // contain options for
    libxxxa,				    // expanded lib-name
    libs,	                            // extra libs, e.g., "-lrss -licce"
    libpath;			   	    // extra lib-paths, eg, "-L../rss"

int
    relink;                                 // internally used: != 0 to relink

string
    copt,				// extra C-options
    lopt,				// extra link-options
    sources,				// sources to be used
    wild,                               // wildcard of extension
    current;                            // contains name of current dir.

/*
                                O B J F I L E S . I M
*/

list objfiles(list files)
{
    string
        file,
        objfile;
    int
        i;

    for (i = 0; i < sizeof(files); i++)
    {
        file = element(i, files);           // determine element of the list
        objfile = change_ext(file, "o");    // make obj-filename
        if (objfile younger file)           // objfile is younger
        {
            files -= (list)file;            // remove the file from the list
            i--;                            // reduce i to test the next
        }
    }
    return (files);
}
/*
                                A L T E R E D . I M
*/

list altered(list files, string target)
{
    int
        i;
    string
        file;

    for (i = 0; i < sizeof(files); i++)     // try all elements of the list
    {
        file = element(i, files);           // use element i of the list

        if (file older target)              // a file is older than the target
        {
            files -= (list)file;            // remove the file from the list
            i--;                            // reduce i to inspect the next
        }                                   // file of the list
    }
    return (files);                         // return the new list
}
/*
                            F I L E L I S T . I M
*/

list file_list(string type, string library)
{
    list
        files;

    files = makelist(type);                 // make all files of certain type
    files = altered(files, library);        // keep all files newer than lib.
    files = objfiles(files);                // remove if younger .obj exist

    return (files);
}
/*
                        L I N K . I M
*/

void link(string library, string exe)
{
    if
    (
        relink                           // new library, new main.obj
        ||
        !exists(exe)                     // final program doesn't exist
    )
    {
        printf("\n");
        exec("gcc", "-o", exe, "-l" + library, libs, "-L.", libpath, lopt);
        printf("ok: ", exe, "\n");
    }
}
/*
                            C C O M P I L E . I M
*/

void c_compile(list cfiles)
{
	string
		nextfile;
	int
		i;

	if (sizeof(cfiles))			// files to compile ?
	{
	        printf("\ncompiling: ", current, "\n\n");
						// compile all files separately
		for (i = 0; nextfile = element(i, cfiles); i++)
			exec("gcc",
				"-c -m486 -Wall -funsigned-char " +
				copt + " " + nextfile);
        	relink = 1;
		printf("\n");
	}
	printf("ok: ", current, "\n");
}
/*
                            U P D A T E L I . I M
*/

void updatelib(string library)
{
    list
	arlist,
        objlist;
    string
        to,
        from;

    objlist = makelist("*.o");

    if (!sizeof(objlist))
        return;

    printf("\n");
    relink = 1;

    exec("ar", "rvs", library, "*.o");
    exec("rm", "*.o");

    printf("\n");
}
/*
                                S T D C P P . I M
*/

void std_cpp(string library)
{
    list
        cfiles;

    cfiles = file_list(wild, library);      // make list of all cpp-files

    c_compile(cfiles);                      // compile cpp-files
}

void prefix_class(string class_id)
{
    list
	o_files;
    string
	o_file;
    int
	i;

    o_files = makelist("*.o");

    for (i = 0; o_file = element(i, o_files); i++)
	exec("mv", o_file, class_id + o_file);
}

/*
                                C P P M A K E . C

    CPP files are processed by stdmake.

    Arguments of CPPMAKE:

    cpp_make(
        string mainfile,    : name of the main .cpp file, or "" for library
                              maintenance
        string library,     : name of the local library to use/create
				(without lib prefix, .a suffix
				 if main is given here, libmain.a is created)

	[
	        string scratchlib,  : "" or the FULL path of a scratch-update area for
        	                      the library
                	              (e.g., RAMDRIVE + "\\dump\\mylib.lib")
	]

        string exe,         : (path) name of the exe file to create

	[
	        string exep,        : "" or the FULL path of the exepacked exe file
	        string mm,          : "S", "M", "C", or "L": memory model to use
	]

        list classes        : list of subdirectories containing class
                              implementations
        )

    Both mainfile and library MUST be in the current directory


    If mainfile == "", then  exe is not interpreted.

The linker is automatically linking libraries to the main object
file. 


    Global variables:
        string
            lopt            for special linker options required
            copt            for special compiler options required
	    sources	    wildcard-definition  of sources to use
			    (defaults to  "*.cc" if left unaltered)

    may be set before calling std_make to specify, respectively,
    extra .o files to be linked with mainfile,
    a names of libraries to be used with linking (as one string),
    special linker options,
    special compiler options.

*/

void cpp_make(string mainfile, string library, string exe, list classes)
{
    int
        index;

    wild = sources;
					    // make library name
    libxxxa = chdir(".") + "lib" + library + ".a";

                                            // first process all classes
    for (index = 0; index < sizeof(classes); index++)
    {
        current = element(index, classes);  // next class to process
        chdir(current);                     // change to directory

        current = "subdir " + current;
        std_cpp (libxxxa);                // compile all files
        chdir( "..");                     // go back to parent dir
    }


    current = "auxiliary " + wild + " files";
    std_cpp (libxxxa);                    // compile all files in current dir

    for (index = 0; index < sizeof(classes); index++)
    {
        current = element(index, classes);  // determine class name
        chdir( current);                  // chdir to a class directory.
	prefix_class((string)index);	  // prefix class-number for .o files
        updatelib(libxxxa);
        chdir( "..");                     // go back to parent dir
    }

    current = "";                           // no class anymore

    updatelib(libxxxa);			    // update lib in current dir

    if (mainfile != "")                     // mainfile -> do link
    {
        link(library, exe);
        printf
	(
	    "\nProgram construction completed.\n"
	    "\n"
	);
    }
}

void main()
{
    list
        dirlist;                   // see below

// Comment the next statement out if you don't want to see the
// executed  commands:
    echo(ON);

    sources = "*.cc";

//  Uncomment and edit the next two statements if extra libraries are needed
// Specify libs from the most specific to the most general one
// To include xform-libraries (from /usr/lib)
// the following is suggested:
	   libs = "-lshadow -lforms -lX11 -lm";

//    libs    = "-l";		// extra libraries (no lib, .a)
//    libpath = "-L";		// extra library path specification

//  COMPILATION options: Uncomment and edit the next statement for extra options:
//  (e.g., -g for gdb-compilation, -O2 for optimzation),
//         -Wall, -i486 and -funsigned-char are already used by 'build'
//    copt = "";

//  LINK options: Edit the next statement for extra options:
//  (e.g., "-s" for strip (*not* with copt == "-g" !)):
    lopt = "-s";                     // strip

// For library maintenance/construction, set the 'program source'
// and the 'binary program' arguments to ""

    dirlist =
        (list)"aux" +
        (list)"passwd" +
        (list)"user" +
        (list)"shadow" +
        (list)"forms" +
        (list)"callback" +
        (list)"groupbrowse" +
        (list)"set" +
        (list)"uidbrowse" +
        (list)"shellbrowse" +
        (list)"errorbrowse" +
        (list)"makehome" +
        (list)"test" +
        (list)"screen" +
        (list)"namebrowse" +
        (list)"rmrf" +
        (list)"sort" +
        (list)"linefun";

/* +
                 + (list)"uidbrowser"
                + (list)"shellbrowser" +  + (list)"actual";
*/

    cpp_make
    (
        "xuser.cc",          // program source
        "xuser",                    // program library
        "xuser",                    // binary program
        dirlist                        // list of classes
    );
/*
    Expand 'dirlist' BEFORE calling cpp_make()  when classes are
    used.
    E.g.,

        dirlist = (list)"class1" + (list)"class2"
        cpp_make(.... (etc))

    NOTE: objectfiles will be prefixed by their class-order numbers
    before they are entered into the library.
    Therefore, classes should not be removed from the dirlist
    and the dirlist should not be reordered.
    If reordering or removing classes is necessary, the compilation
    should start again from scratch.
*/
}
