-1

I am trying to write a lexer using flex, and want to open and read from a file ending with a particular extension. E.g filename.k. I am only able to do it if I specify the file name as well as the extension.

FILE *myfile = fopen("a.k", "r");
        if (!myfile) {
        cout << "I can't open a.k!" << endl;

Can someone show me the way to open *.k files in C++.

I am running flex on Ubuntu. What I am trying to do is to run a flex program. The above code executes fine. I wanted a way where I can open a file with .k extension irrespective of the file name. Example. ./myprogram a.k or ./myprogram b.k. In the above example I always have to specify the file name in the code itself all the time.

karma
  • 137
  • 3
  • 18
  • 1
    See [filesystem](http://en.cppreference.com/w/cpp/filesystem) and [regex](http://en.cppreference.com/w/cpp/regex) libraries. – eozd May 11 '18 at 07:00
  • You can't. `*.k` could refer to zero, one or many files. How do you expect to be able to open one file given those constraints ? – Sid S May 11 '18 at 07:07
  • "I am only able to do it if I specify the file name as well as the extension." -> The extension is part of the file name. Without the extension you don't have the full file name. Windows might hide the extension from the users, but it's still part of the file name and still required to identify the file. – Cris Luengo May 11 '18 at 07:09
  • @SidS by reading the containing folder – YSC May 11 '18 at 07:09
  • @YSC, That doesn't let you open one file with `fopen()` – Sid S May 11 '18 at 07:10
  • @SidS It lets you list the file(s) you want to open, then do it with the appropriate tool. – YSC May 11 '18 at 07:12
  • @YSC, Well, Duh! That's not what he was asking and it's platform dependent either way – Sid S May 11 '18 at 07:13
  • @SidS No, [it is not](http://en.cppreference.com/w/cpp/filesystem) anymore. – YSC May 11 '18 at 07:26
  • @karma: you actually have two different and unrelated questions: 1) why and when can `fopen` fail? 2) how to get all the files matching some pattern like `*.k` ? At last, you need to mention which C++ standard you care about. – Basile Starynkevitch May 11 '18 at 07:27
  • in the above example `fopen` fails when the file name is not a.k – karma May 11 '18 at 07:34
  • The `#include ` allows you to do `if (filename.size() >= 2 && filename.substr(filename.size()-2) == ".k")` fairly easily. – Eljay May 11 '18 at 12:19

2 Answers2

2

Comment to Basile's anser:

[...] Such as ./myprogram a.k, I wanted a way where I can write any filename instead of a but ending with a .k extension.

While the cited answer technically is correct, I think your true problem is how to get some arbitrary, but specific file path from the command line:

Example: ./myprogram a.k or ./myprogram b.k

The thing is quite easy: you get the command line parameters passed directly to your main function, provided you use the variant accepting them:

int main(int argc, char* argv[]);

First parameter (argv[0]) is always the name of your programme (or an empty string, if not available), so argc will always be at least one. Afterwards the parameters provided follow, so invoking "./myprogram b.k" will result in argc being two and argv pointing to a char* array equivalent to the following:

char* argv[] =
{
    "./myprogram",
    "b.k",
    nullptr // oh, yes, the array is always null terminated...
};

And then, the matter gets easy: Check, if the parameter is given at all: if(argc == 2) or, if you are willing to accept but ignore any additional parameters, if(argc >= 2) or simply if(argv[1]) (as it will be nullptr, if no parameter given, or the first parameter otherwise) and then use it for fopen or, if you prefer a more C++ like way, to open a std::ifstream. You might want to have additional checks, e. g. if the file name really ends with ".k", but that's up to you now...

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
1

Your fopen-ing code is good, but running in conditions (e.g. in some weird working directory, or without sufficient permissions) which make the fopen fail.

I recommend to use errno (perhaps implicitly thru perror) in that failure case to get an idea of the failure reason:

FILE *myfile = fopen("a.k", "r");
if (!myfile) {
     perror("fopen of a.k"); 
     exit(EXIT_FAILURE);
}

See e.g. fopen(3), perror(3), errno(3) (or their documentation for your particular implementation and system).

Notice that file extensions don't really exist in standard C++11 (but C++17 has filesystem). On Linux and POSIX systems, file extensions are just a convention.

Can someone show me the way to open *.k files in C++.

If you need to open all files with a .k extension, you may rely on globbing (on POSIX, run something like yourprog *.k in your shell, which will expand the *.k into a sequence of file names ending with .k before running your program, whose main would get an array of arguments; see glob(7)), or you have to loop explicitly using operating system primitives or functions (perhaps with glob(3), nftw(3), opendir(3), readdir(3), ... on Linux; for Windows, read about FindFirstFile etc...)

Standard C++11 don't provide a way to iterate on all files matching a given pattern. Some framework libraries (Boost, Poco, Qt) do provide such a way. Or you need to use operating system specific functions (e.g. to read the current directory. But directories are not known to C++11 and are an abstraction provided by your operating system). But C++17 has filesystem, but you need a very recent compiler and C++ standard library to get that.

BTW, on Unix or POSIX systems, you could have one single file named *.k. Of course that is very poor taste and should be avoided (but you might run touch '*.k' in your shell to make such a file).

Regarding your edit, for Linux, I recommend running

./myprogram *.k

(then your shell will expand *.k into one or several arguments to myprogram) and code the main of your program myprog appropriately to iterate on arguments. See this.

If you want to run just myprogram without any additional arguments, you need to code the globbing or the expansion inside it. See glob(3), wordexp(3). Or scan directories (with opendir(3), readdir(3), closedir, stat(2) or nftw(3))

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • He wants to open `*.k` – Sid S May 11 '18 at 07:06
  • @SidS: that is not mentioned in his question. What makes you think that? – Basile Starynkevitch May 11 '18 at 07:06
  • Thank you all for the answer. After reading all of your answers, I realized that my question is not framed properly. I am running flex/bison in Ubuntu, I wanted to open a file with particular extension when running an object file. Such as ./myprogram a.k, I wanted a way where I can write any filename instead of a but ending with a .k extension. – karma May 11 '18 at 07:27