2

I have a directory with multiple description files and want to store the information in a map to use later to implement a package manager.

Apparently, I read the files correctly, but when I try to filter the information, some things get lost. In most cases, the last line gets cut off, so when the last keyword is %DEPENDS% and it has only one information, I cannot find that file in my dependencies map.

The description files look like the following:

%FILENAME%
zlib-1:1.2.11-4-x86_64.pkg.tar.xz

%NAME%
zlib

%BASE%
zlib

%VERSION%
1:1.2.11-4

%DESC%
Compression library implementing the deflate compression method found in gzip and PKZIP

%CSIZE%
83444

%ISIZE%
341567

%MD5SUM%
954e931d4bb8a1f1f2847b5fa07bf5da

%SHA256SUM%
43a17987d348e0b395cb6e28d2ece65fb3b5a0fe433714762780d18c0451c149

%PGPSIG%
iQEzBAABCAAdFiEEhs/8qRjPOvRxR1iAUeixSKmZnDQFAl3MRDoACgkQUeixSKmZnDTrWwgAjFovNb203v52oTBXrSxDoWFoCn9uEFfDVpXh/WWAsor5aEtqO8cHqeVUW+ttJdX4Zr0ETz9IVykFCuw5AixE6JSuVm7CIzKdR4JzzIwlU4Es0WDEG8gXAe9i+F8tgLuF92PhiCjxNFmBsdKFS5ISz9wAqdCAUoB+N1yWSeraz7NHkM5urdvnpYVReq9/TOrkjZrJzU45g9y1iuw/ZlpMO53LbsXwuiBE4EufQKEHKF5OgcrSBC4DRUliI9aI65jQ+a0unrxFb+bRjZDOIp1lEBbChQg4BIcE8YtNCIRDb6ztAMfoTOirdbJDbnrAjbIjZcPcvAHoz//vBRkkwCSADA==

%URL%
https://www.zlib.net/

%LICENSE%
custom

%ARCH%
x86_64

%BUILDDATE%
1573667866

%PACKAGER%
Evangelos Foutras <evangelos@foutrelis.com>

%DEPENDS%
glibc

I want to store all that information in a map so i have something like this:

std::map<std::string, std::vector<std::string>> data = {
    {"FILENAME", {"zlib-1:1.2.11-4-x86_64.pkg.tar.xz"}},
    {"NAME", {"zlib"}},
    ...,
    {"DEPENDS", {"glibc"}}
}

I have a util class that looks more or less like this:

struct util
{
    std::string path;

    std::map<std::string, std::string> pkg_version;
    std::map<std::string, std::vector<std::string>> pkg_dependencies;
    std::map<std::string, std::vector<std::string>> pkg_virtual;
    std::map<std::string, std::vector<std::string>> pkg_conflicts;

    ...
}

I have two methods to get all the information. One to read all files and store the information line by line in a vector and one method to construct a map from the given vector and store the relevant information in pkg_dependencies. The first one is actually the constructor of my util class.

util::util(std::string path_) :
    path(path_)
{
    for (const auto& dir_entry : std::filesystem::directory_iterator(path_))
    {
        std::string dir_path = dir_entry.path().string();

        for (const auto& file_entry : std::filesystem::directory_iterator(dir_path))
        {
            std::string file_path = file_entry.path().string();
            std::ifstream desc(file_path);

            std::vector<std::string> content;
            std::string line;

            while (getline(desc, line))
            {
                if (line.size())
                {
                    content.push_back(line);
                }
            }

            desc.close();
            parse_desc(content);
        }
    }
}

void util::parse_desc(std::vector<std::string> content)
{
    std::string marker = "%";

    std::map<std::string, std::vector<std::string>> mp;

    std::string key;
    std::vector<std::string> part_lines;

    for (int i = content.size() - 1; i >= 0; --i)
    {
        bool check_front = content[i].substr(0, 1).compare(marker) == 0;
        bool check_back = content[i].substr(content[i].size() - 1, content[i].size()).compare(marker) == 0;
        if (check_front && check_back)
        {
            key = content[i].substr(1, content[i].size() - 2);
            mp.insert(std::make_pair(key, part_lines));
            part_lines.clear();
        }

        else
        {
            part_lines.push_back(content[i]);
        }
        }

    ...

    if (mp.find("DEPENDS") != mp.end() && !(mp.find("DEPENDS")->second).empty())
    {
        pkg_dependencies.insert(std::make_pair(name, mp.find("DEPENDS")->second));
    }

    ...

}

Yet in this example with zlib, it cannot be found in pkg_dependencies. I noticed that zlib has only one dependency because it seems to cut off the last line in every file. After all, there are others with more than one dependency and the last one is always missing.

Currently, I start at the back of the vector and push_back the elements into part_lines until I reach a keyword. Then I insert the keyword with the vector into my map.

I tried iterating over the vector from the beginning. So I find my key first and when I find the next one I first insert my information into the map and then define my new keyword and clear the vector. In case I am at the last element, push_back that element and then insert the information into the map.

Both attempts seem to cut off the last element, so the problem might be somewhere else.

This is the first time asking a question on here, so I do not know if I did a great job at explaining what precisely my problem is, and hope I provided enough information and the relevant code snippets.

Hopefully, someone can help me out.

  • A thought: If there is no or little deviation in the metadata, don't use a `map` Use a structure and give each property its own variable. There may be a little storage waste in the case of unused properties, but the `map` look-up overhead will probably cost more. – user4581301 Jul 19 '21 at 23:54
  • @user4581301 Do you mean in `parse_desc`? Currently I do only want to use `NAME`, `VERSION`, `PROVIDES`, `DEPENDS` and if there are conflicts `CONFLICTS`, but I might want to extend it.. – JacobTwoTwo Jul 20 '21 at 00:03
  • I was thinking more along the lines of `data`. If everything has `DEPENDS`, there's not much point to looking it up. It might be empty, but its always there.. When you need it, you just access the object's `m_depends` member, or whatever you call it. – user4581301 Jul 20 '21 at 00:37
  • @user4581301 Oh ok. As far as I know not every package has `DEPENDS` and sometimes it is not at the end of the description file. So I check if `DEPENDS` is actually present. Then I only check if `DEPENDS` is empty, because what I don't know is whether or not some files have an empty `DEPENDS`. Currently I am just trying to figure out why apparently the last line of the file is missing.. – JacobTwoTwo Jul 20 '21 at 01:23
  • You parse for DEPENDS, and if you find it you add it to `m_depends`. I didn't see why it's dropping the last item. Normally it's misusing `while (!file.eof())`, or the code cut off the for loop one too early. `for (int i = content.size() - 1; i >= 0; --i)` looks good, but consider replacing that with reverse iterators(`for (auto it = content.rbegin(); it != content.rend(); it++)`) just to be sure. Why process backward antyway? – user4581301 Jul 20 '21 at 01:31
  • Have you debugged the program? May set a breakpoint at the line `mp.find("DEPENDS") != mp.end() ` to see the map's contents. – prehistoricpenguin Jul 20 '21 at 01:52
  • I haven't uses the debugging tool that much, since I'm pretty new to C++/Visual Studio, but the map seems to have the correct contents but I get an error later on. `Exception thrown: read access violation.` in `xtree` (not my class). Is there a way to find out what line triggered that? – JacobTwoTwo Jul 20 '21 at 02:33
  • Down in the bottom right (in the default layout) is the callstack. You can use it to find out how the program got wherever it wound up. But note that the crash site often isn't where the bug is. It's a great place to start looking for the bug, but usually the program survives the bug and staggers on mortally wounded for a while after before falling over and dying somewhere innocent. – user4581301 Jul 20 '21 at 04:04

0 Answers0