(file) Return to main.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus_unsupported / utils / chlicense

File: [Pegasus] / pegasus_unsupported / utils / chlicense / main.cpp (download)
Revision: 1.5, Mon Apr 30 18:02:14 2007 UTC (17 years, 1 month ago) by mike
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +17 -0 lines
BUG#: 99999
TITLE: chlicense

DESCRIPTION: Added logic for handling WSM licenses.

//%2006////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
// IBM Corp.; EMC Corporation, The Open Group.
// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
// Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
// EMC Corporation; VERITAS Software Corporation; The Open Group.
// Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
// EMC Corporation; Symantec Corporation; The Open Group.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
// ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//%/////////////////////////////////////////////////////////////////////////////

#include <sys/types.h>
#include <regex.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstring>
#include <cstdarg>
#include <string>
#include <vector>
#include <cctype>
#include <fstream>
#include <cstdio>
#include <dirent.h>
#include <fstream>

using namespace std;

static const char* arg0;

//==============================================================================
//
// options:
//
//==============================================================================

bool opt_help = false;
bool opt_verbose = false;

//==============================================================================
//
// regular expressions:
//
//==============================================================================

static const char* start[] =
{
    "^//%[0-9][0-9][0-9][0-9].*",
    "^#//%[0-9][0-9][0-9][0-9].*",
    "^//%{.*",
    "^##%{.*",
#ifdef WSM
    "^\\*\\*====.*$",
    "^##====.*",
#endif
    (char*)0,
};
static size_t start_size = sizeof(start) / sizeof(start[0]);
regex_t start_rx[sizeof(start) / sizeof(start[0])];

static const char* body[] =
{
    "^//.*",
    "^#//.*",
    "^##.*",
#ifdef WSM
    "^\\*\\*.*",
    "^##.*",
#endif
    (char*)0,
};
static size_t body_size = sizeof(body) / sizeof(body[0]);
regex_t body_rx[sizeof(body) / sizeof(body[0])];

static const char* end[] =
{
    "^//%.*",
    "^#//====.*",
    "^//%}.*",
    "^##%}.*",
#ifdef WSM
    "^\\*\\*====.*$",
    "^##====.*",
#endif
    (char*)0,
};
static size_t end_size = sizeof(end) / sizeof(end[0]);
regex_t end_rx[sizeof(end) / sizeof(end[0])];

//==============================================================================
//
// match()
//
//==============================================================================

bool match(const char* text[], regex_t rx[], const char* str)
{
    for (size_t i = 0; text[i]; i++)
    {
        if (regexec(&rx[i], str, 0, NULL, 0) == 0)
            return true;
    }

    return false;
}

//==============================================================================
//
// err()
//
//==============================================================================

void err(const char* format, ...)
{
    fputc('\n', stderr);
    va_list ap;
    fprintf(stderr, "%s: ", arg0);
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);
    fputc('\n', stderr);
    fputc('\n', stderr);
    exit(1);
}

//==============================================================================
//
// warn()
//
//==============================================================================

void warn(const char* format, ...)
{
    va_list ap;
    fprintf(stderr, "%s: warning: ", arg0);
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    fputc('\n', stderr);
    va_end(ap);
}

//==============================================================================
//
// get_opt()
//
//==============================================================================

static char *opt_arg = NULL;
static int opt_ind = 1;
static int opt_err = 1;
static int opt_opt;

static int get_opt(int argc, char** argv, const char* optstring)
{
    for (int i = opt_ind; i < argc; i++)
    {
	char* arg = argv[i];

	if (arg[0] == '-' && arg[1] != '\0')
	{
	    int opt = arg[1];
	    const char* p = strchr(optstring, opt);
	    opt_arg = NULL;

	    if (p == NULL)
	    {
		if (opt_err)
		    fprintf(stderr, "%s: invalid option -- %c\n", argv[0], opt);

		opt_opt = opt;
		opt = '?';
	    }
	    else if (p[1] == ':')
	    {
		if ((opt_arg = argv[i+1]) == NULL)
		{
		    if (opt_err)
		    {
			fprintf(stderr, 
			    "%s: option requires an argument -- %c\n", 
			    argv[0], opt);
		    }

		    opt_opt = opt;

		    if (*optstring == ':')
			opt = ':';
		    else
			opt = '?';
		}
	    }

	    int n = opt_arg ? 2 : 1;

	    memmove(
		argv + opt_ind + n, 
		argv + opt_ind, 
		(i - opt_ind) * sizeof(char*));

	    argv[opt_ind++] = arg;

	    if (opt_arg)
		argv[opt_ind++] = opt_arg;

	    return opt;
	}
    }

    return -1;
}

//==============================================================================
//
// help()
//
//==============================================================================

const char USAGE[] = "\
\n\
Usage: %s [options] license\n\
\n\
Description:\n\
    This utility attempts to replace the license text in all files\n\
    in or below the current directory. The range of lines comprising\n\
    the exiting license have the following form:\n\
\n\
        1 start-line\n\
        0 or more more body-lines\n\
        1 end-line\n\
\n\
    A start-line matches ONE of these regular expressions:\n\
\n\
        ^//%[0-9][0-9][0-9][0-9].*\n\
        ^#//%[0-9][0-9][0-9][0-9].*\n\
        ^//%{.*\n\
        ^##%{.*\n\
\n\
    A body-line matches ONE of these regular expressions:\n\
\n\
        ^//.*\n\
        ^#//.*\n\
        ^##.*\n\
\n\
    An end-line matches ONE of these regular expressions:\n\
\n\
        ^//%.*\n\
        ^#//%.*\n\
        ^//%}.*\n\
        ^##%}.*\n\
\n\
    If the end-line is missing, then the last body-line is used\n\
    as the end-line.\n\
\n\
    The replacement license must NOT contain any comment delimiters.\n\
    Delimiters are added by this utility.\n\
\n\
Options:\n\
    -h             print this help message.\n\
    -v             verbose\n\
\n";

void help()
{
    printf(USAGE, arg0);
    exit(0);
}

//==============================================================================
//
// has_extension()
//
//==============================================================================

bool has_extension(const string& path, const string& ext)
{
    size_t pos = path.find(ext);

    if (pos == string::npos)
        return false;

    return pos + ext.size() == path.size();
}

//==============================================================================
//
// is_text_file()
//
//==============================================================================

bool is_text_file(const string& path)
{
    // These may contain special characters in rare cases.

    if (has_extension(path, ".c") || has_extension(path, ".cpp") ||
        has_extension(path, ".h") || has_extension(path, ".hpp"))
    {
        return true;
    }

    ifstream is(path.c_str());

    if (!is)
        return false;

    char c;

    while (is.get(c))
    {
        if (c < 0)
            return false;
    }

    return true;
}

//==============================================================================
//
// load()
//
//==============================================================================

void load(const string& path, vector<string>& lines)
{
    ifstream is(path.c_str());

    if (!is)
        err("failed to open %s", path.c_str());

    string line;

    while (getline(is, line))
        lines.push_back(line);
}

//==============================================================================
//
// process()
//
//==============================================================================

void process(const string& path, const vector<string>& license)
{
    if (opt_verbose)
        printf("%s\n", path.c_str());

    vector<string>lines;
    load(path, lines);

    size_t start_line = size_t(-1);
    size_t end_line = size_t(-1);

    // Find line range of license:

    for (size_t i = 0; i < lines.size(); i++)
    {
        string line = lines[i];

        if (start_line == size_t(-1))
        {
            if (match(start, start_rx, line.c_str()))
                start_line = i;
        }
        else if (match(end, end_rx, line.c_str()))
        {
            end_line = i;
            break;
        }
        else if (!match(body, body_rx, line.c_str()))
        {
            end_line = i - 1;
            break;
        }
    }

    if (start_line == size_t(-1))
    {
        if (has_extension(path, ".c") || has_extension(path, ".cpp") ||
            has_extension(path, ".h") || has_extension(path, ".hpp") ||
            path == "Makefile")
        {
            warn("%s: start-line not found", path.c_str());
        }
    }
    else
    {
        if (end_line == size_t(-1))
            end_line = lines.size() - 1;

        // Open output file.

        ofstream os(path.c_str());

        if (!os)
            err("failed to open %s", path.c_str());

        // Write lines up to start-line.

        for (size_t i = 0; i < start_line; i++)
            os << lines[i] << endl;

        // Get comment-character.

        char ch = lines[start_line][0];

#ifdef WSM
        if (ch == '*')
            ch = '/';
#endif

        // Write start-line.

        os << ch << ch << '%' << '{';

        for (size_t i = 0; i < 76; i++)
            os << ch;

        os << endl;

        // Write license lines.

        for (size_t i = 0; i < license.size(); i++)
        {
            if (license[i].size())
                os << ch << ch << ' ' << license[i] << endl;
            else
                os << ch << ch << endl;
        }

        // Write end-line.

        os << ch << ch << '%' << '}';

        for (size_t i = 0; i < 76; i++)
            os << ch;

        os << endl;

        // Write lines after end-line.

        for (size_t i = end_line + 1; i < lines.size(); i++)
            os << lines[i] << endl;
    }
}

//==============================================================================
//
// chlicense()
//
//==============================================================================

void chlicense(const string& root, const vector<string>& license)
{
    // Open directory.

    DIR* dir = opendir(root.c_str());

    if (!dir)
        err("opendir() failed: %s", root.c_str());

    // Iterate directory files.

    dirent* ent;
    vector<string> directories;

    while ((ent = readdir(dir)) != NULL)
    {
        // Skip current and parent directories.

        string name = ent->d_name;

        if (name == "." || name == "..")
            continue;

        // Skip CVS directories.

        if (name == "CVS")
            continue;

        // Save and skip directories.

        string path = root + string("/") + name;
        struct stat st;    

        if (stat(path.c_str(), &st) != 0)
            err("failed to stat %s", path.c_str());

        if (S_ISDIR(st.st_mode))
        {
            directories.push_back(path);
            continue;
        }

        // Skip non-text files.

        if (!is_text_file(path))
            continue;

        // Process file.

        process(path, license);
    }

    closedir(dir);

    // Recurse into directories.

    for (size_t i = 0; i < directories.size(); i++)
        chlicense(directories[i], license);
}

//==============================================================================
//
// compile()
//
//==============================================================================

void compile(const char* text[], regex_t rx[])
{
    for (size_t i = 0; text[i]; i++)
    {
        if (regcomp(&rx[i], text[i], REG_NOSUB) != 0)
            err("failed to compile regular expression: %s",text[i]);
    }
}

//==============================================================================
//
// main()
//
//==============================================================================

int main(int argc, char** argv)
{
    arg0 = argv[0];

    // Process options:

    int opt;

    while ((opt = get_opt(argc, argv, "hv")) != -1)
    {
	switch (opt)
	{
	    case 'h':
		opt_help = true;
		break;

	    case 'v':
		opt_verbose = true;
		break;

	    case '?':
	    case ':':
                help();
		exit(1);

	    default:
		err("unexpected");
	}
    }

    argc -= opt_ind;
    argv += opt_ind;

    // Help!

    if (opt_help)
	help();

    // Check arguments (we expect once)

    if (argc != 1)
	err("wrong number of arguments; try -h for help");

    // Compile regular expressions.

    compile(start, start_rx);
    compile(body, body_rx);
    compile(end, end_rx);

    // Load license file.

    vector<string> license;
    load(argv[0], license);

    // Process files.

    chlicense(".", license);

    return 0;
}

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2