//
// tardy - a tar post-processor
// Copyright (C) 1998, 1999, 2002, 2008, 2009, 2011 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

#include <libtardy/ac/assert.h>

#include <libtardy/cannonical.h>


rcstring
cannonicalize(const rcstring &in)
{
        rcstring out;
        rcstring path_text;
        const char *path_pos = in.c_str();
        enum path_token_ty { path_dot, path_slash, path_name, path_end };
        path_token_ty path_token;

        int state = 0;
        while (state >= 0)
        {
                //
                // figure the next token in the path
                //
                switch (*path_pos)
                {
                case 0:
                        path_text = "";
                        path_token = path_end;
                        break;

                case '/':
                        ++path_pos;
                        while (*path_pos == '/')
                                ++path_pos;
                        path_text = "/";
                        path_token = path_slash;
                        break;

                default:
                        const char *cp = path_pos;
                        for (;;)
                        {
                                ++path_pos;
                                if (!*path_pos || *path_pos == '/')
                                        break;
                        }
                        path_text = rcstring(cp, path_pos - cp);
                        static rcstring dot(".");
                        if (path_text == dot)
                                path_token = path_dot;
                        else
                                path_token = path_name;
                        break;
                }

                //
                // do something with the token
                //
                switch (path_token)
                {
                case path_dot:
                        switch (state)
                        {
                        case 0:
                        case 2:
                                ++state;
                                break;

                        default:
                                assert(0);
                                state = -1;
                                break;
                        }
                        break;

                case path_name:
                        switch (state)
                        {
                        case 0:
                                out += path_text;
                                state = 4;
                                break;

                        case 2:
                                out += "/";
                                out += path_text;
                                state = 4;
                                break;

                        default:
                                assert(0);
                                state = -1;
                                break;
                        }
                        break;

                case path_slash:
                        switch (state)
                        {
                        case 0:
                        case 3:
                        case 4:
                                state = 2;
                                break;

                        case 1:
                                state = 0;
                                break;

                        default:
                                assert(0);
                                state = -1;
                                break;
                        }
                        break;

                case path_end:
                        switch (state)
                        {
                        case 0:
                        case 1:
                                out += ".";
                                break;
                        }
                        state = -1;
                        break;
                }
        }
        return out;
}
