c code - spilt string lines for menu

I want to create a menu in c. Can I convert this bash format into c code? Without doing printf on every line.

printf "
Scan Virus
help commands
-------------
virus scan linux files
    p1: -l or --linux
    p2: u   freshclam update      (optional)
    p2: l   low system priority   (optional)
    p2: h   high system priority  (optional)
    p2: s   suspend on end        (optional)
    p2: p   shutdown on end       (optional)
    p2: f   scan folder           (optional)

"           

Internet searches have come up empty.

Thanks.

FYI, I need a new challenge. So, I’v decided to convert the bash code into c.

Untested, but something like this should work:

printf(
"Scan Virus
"
"help commands
"
"-------------
"
"virus scan linux files
"
"    p1: -l or --linux
"
"    p2: u   freshclam update      (optional)
"
"    p2: l   low system priority   (optional)
"
"    p2: h   high system priority  (optional)
"
"    p2: s   suspend on end        (optional)
"
"    p2: p   shutdown on end       (optional)
"
"    p2: f   scan folder           (optional)
"
"
"
);

To explain: If you have several strings (“xyz”) one after another (only separated by whitespace), they get concatenated and result in one long(er) string. (this concatenation doesn’t modify the strings, so you need to add linefeeds explicitly)
Also, C treats newlines as whitespace, so it is possible to split one command about several lines just like this.

I.e. the above would be equivalent to this:

printf("Scan Virus
help commands
-------------
virus scan linux files
    p1: -l or --linux
    p2: u freshclam update (optional)
    p2: l low system priority (optional)
    p2: h high system priority (optional)
    p2: s suspend on end (optional)
    p2: p shutdown on end (optional)
    p2: f scan folder (optional)

");

PS: as you only want to print constant lines of text (and not e.g. formatted numbers), you could also use puts() instead of printf(), which is smaller.

There is a (small) difference though:
puts() automatically adds a newline after printing the text, while printf() does not.
So you’d have to omit the last
when using puts(). :wink:

I tried something like that and it didn’t work. Maybe I missed something. Thanks.

This did work. Thanks to a few hours of web searching. :stuck_out_tongue:

          printf("\
Scan Virus
\
help commands
\
-------------
\
virus scan linux files
\
    p1: -l or --linux
\
    p2: u   freshclam update      (optional)
\
    p2: l   low system priority   (optional)
\
    p2: h   high system priority  (optional)
\
    p2: s   suspend on end        (optional)
\
    p2: p   shutdown on end       (optional)
\
    p2: f   scan folder           (optional)
\

");

Can you show me an example of ‘puts(’?

why not introduce the options (psx: into an array element? So then you only have to iterate over it to create the string and print it? In that way you can re use those values in other parts of your program avoiding duplicated code

The menu called as a function. The menu lines aren’t used outside the menu print.

Split each line of the menu into array elements?

That would be another nice option

Then you probably forgot some of the quotes.

I did try to compile it afterwards, and it does work as intended.

This did work. Thanks to a few hours of web searching. :stuck_out_tongue:

Yes, a \ at the end of a line means that the line ending is being ignored.
Disadvantage: you cannot indent the following lines (as the spaces/tabs would be part of the string), so the source code may become a mess.

Can you show me an example of ‘puts(’?

It’s pretty much the same, just puts instead of printf (and the last newline is removed because puts() adds it anyway):

puts(
"Scan Virus
"
"help commands
"
"-------------
"
"virus scan linux files
"
"    p1: -l or --linux
"
"    p2: u   freshclam update      (optional)
"
"    p2: l   low system priority   (optional)
"
"    p2: h   high system priority  (optional)
"
"    p2: s   suspend on end        (optional)
"
"    p2: p   shutdown on end       (optional)
"
"    p2: f   scan folder           (optional)
"
);

How do you use this with a file stream? I need to write out the config file.

fprintf,fputs

why not make it more generic? Instead of write into a file on the code directly, just redirect the output of the script to a file? command > text.txt
So then you will get the following content into a file, either using put or printf:

Scan Virus
help commands

virus scan linux files
p1: -l or --linux
p2: u freshclam update (optional)
p2: l low system priority (optional)
p2: h high system priority (optional)
p2: s suspend on end (optional)
p2: p shutdown on end (optional)
p2: f scan folder (optional)

Well, the C syntax won’t change depending on which functions you use… :wink:

You’d need to adjust the function calls though, fprintf and fputs take an additional file parameter to depict the stream:

int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);

int puts(const char *s);
int fputs(const char *s, FILE *stream);

I.e. the above would need to be changed to something like this:

fprintf(file,
"Scan Virus
"
"help commands
"
"-------------
"
"virus scan linux files
"
"    p1: -l or --linux
"
"    p2: u   freshclam update      (optional)
"
"    p2: l   low system priority   (optional)
"
"    p2: h   high system priority  (optional)
"
"    p2: s   suspend on end        (optional)
"
"    p2: p   shutdown on end       (optional)
"
"    p2: f   scan folder           (optional)
"
"
"
);

or:

fputs(
"Scan Virus
"
"help commands
"
"-------------
"
"virus scan linux files
"
"    p1: -l or --linux
"
"    p2: u   freshclam update      (optional)
"
"    p2: l   low system priority   (optional)
"
"    p2: h   high system priority  (optional)
"
"    p2: s   suspend on end        (optional)
"
"    p2: p   shutdown on end       (optional)
"
"    p2: f   scan folder           (optional)
"
, file);

You’d also need to open (and close) the file stream of course.

FILE *fopen(const char *pathname, const char *mode);

int fclose(FILE *stream);

For more details, I’d suggest to take a look at the man or info pages, e.g. “man fopen”:

FOPEN(3)                      Linux Programmer's Manual                      FOPEN(3)

NAME
       fopen, fdopen, freopen - stream open functions

SYNOPSIS
       #include <stdio.h>

       FILE *fopen(const char *pathname, const char *mode);

       FILE *fdopen(int fd, const char *mode);

       FILE *freopen(const char *pathname, const char *mode, FILE *stream);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       fdopen(): _POSIX_C_SOURCE

DESCRIPTION
       The  fopen()  function  opens  the file whose name is the string pointed to by
       pathname and associates a stream with it.

       The argument mode points to a string  beginning  with  one  of  the  following
       sequences (possibly followed by additional characters, as described below):

       r      Open  text file for reading.  The stream is positioned at the beginning
              of the file.

       r+     Open for reading and writing.  The stream is positioned at  the  begin-
              ning of the file.

       w      Truncate  file  to  zero  length  or create text file for writing.  The
              stream is positioned at the beginning of the file.

       w+     Open for reading and writing.  The file  is  created  if  it  does  not
              exist,  otherwise  it  is  truncated.   The stream is positioned at the
              beginning of the file.

       a      Open for appending (writing at end of file).  The file is created if it
              does not exist.  The stream is positioned at the end of the file.

       a+     Open  for  reading and appending (writing at end of file).  The file is
              created if it does not exist.  The initial file position for reading is
              at  the beginning of the file, but output is always appended to the end
              of the file.
...

Well, I can just add it as commented out code. The menu as a string array. I have lots of null elements for my own learning. ‘scanvirus’ is well commented and is also meant to help others learn code. :wink:

hmm, I done it in bash. Never seen it done in c code. How?

During this, i’v been writing scanvirusbin code. I’v finished the permissions code. It now creates the needed files and checkpermisions. File username and groupname is for another topic. The code is written out based on the usual gathering of info. There might be problems with it.

I can’t use fprint with the config file. Since, it includes ‘%’ symbol, more maybe added later.

     //create config file if not present
     File_Found= stat(VirusConfig, &file_stats);
     if (File_Found != 0)
     {
          FilePtr=fopen(VirusConfig, "w");
          if (FilePtr != NULL)
          {
fputs("______________________________scanvirus configuration______________________________
", FilePtr);
fputs("date +'%Y-%m-%d %I:%M:%S%P'
", FilePtr);
fputs("TimeStamp= %I:%M:%S%P
", FilePtr);
fputs("DateStamp= %Y-%m-%d
", FilePtr);
fputs("______________________________________________________________________________
", FilePtr);
fputs("ExcludedScanFolders= dev etc kdeinit5__0 proc tmp srv sys var .snapshots
", FilePtr);
fputs("___________________________________________________________________________________
", FilePtr);
fputs("Bash Suspend Command
", FilePtr);
fputs("1= 'systemctl suspend' - openSUSE, Ubuntu, Fedora, Arch, Debian, etc
", FilePtr);
fputs("2= 'pm-suspend' - Void, Gentoo, Devuan etc - pm-utils power management suite
", FilePtr);
fputs("SuspendCommand= 1
", FilePtr);
fputs("___________________________________________________________________________________
", FilePtr);
fputs("Suspend or power-off lock screen - GNOME KDE
", FilePtr);
fputs("LockScreenCommand= 0
", FilePtr);
fputs("___________________________________________________________________________________
", FilePtr);
fputs("MSWIN scan - partition file system types
", FilePtr);
fputs("ScanPartitionFileSystems= ntfs vfat
", FilePtr);
fputs("___________________________________________________________________________________
", FilePtr);
fputs("List users group filter
", FilePtr);
fputs("UserGroupFilter= users
", FilePtr);
fputs("___________________________________________________________________________________
", FilePtr);
fputs("Scan Log Format
", FilePtr);
fputs("%o  OS Type
", FilePtr);
fputs("%s  Virus Status
", FilePtr);
fputs("%f  Scan Folder
", FilePtr);
fputs("%n  Scan Time
", FilePtr);
fputs("%c  Command Options
", FilePtr);
fputs("%t  Time Stamp
", FilePtr);
fputs("%d  Date Stamp
", FilePtr);
fputs("
", FilePtr);
fputs("ScanLogFormat= %o %s %f %n %c %t %d
", FilePtr);
fputs("___________________________________________________________________________________
", FilePtr);                  
         }
          else
          {
               printf("can't write to file
");
               return(-1);
          }
          fclose(FilePtr);


Can I shorten this code?

You can, you’d just need to escape the ‘%’ symbols you want to output, i.e. use ‘%%’.

Or, to put it differently, this will print a % character:

printf("%%");

Can I shorten this code?

I don’t understand that question.

You are just writing lines to a file.
The only way to “shorten” that is to omit some of the lines you are writing. You’d need to know yourself whether that would be ok… :wink:

You could write all lines with a single call to fputs() (like your initial question), but that’s not really shorter.

As it is now, you probably should remove the trailing ’
’ at the end of each line though.
As already mentioned, fputs() does print a newline after outputting your text.
I.e. the code you posted now would generate an empty line between every line of text.

I have it working now. Thanks. :slight_smile:

If I remove the newline character, that makes it all stack on one line and parse the spaces into new lines.

fputs(
"______________________________scanvirus configuration______________________________
"
"date +'%Y-%m-%d %I:%M:%S%P'
"
"TimeStamp= %I:%M:%S%P
"
"DateStamp= %Y-%m-%d
"
"______________________________________________________________________________
"
"ExcludedScanFolders= dev etc kdeinit5__0 proc tmp srv sys var .snapshots
"
"___________________________________________________________________________________
"
"Bash Suspend Command
"
"1= 'systemctl suspend' - openSUSE, Ubuntu, Fedora, Arch, Debian, etc
"
"2= 'pm-suspend' - Void, Gentoo, Devuan etc - pm-utils power management suite
"
"SuspendCommand= 1
"
"___________________________________________________________________________________
"
"Suspend or power-off lock screen - GNOME KDE
"
"LockScreenCommand= 0
"
"___________________________________________________________________________________
"
"MSWIN scan - partition file system types
"
"ScanPartitionFileSystems= ntfs vfat
"
"___________________________________________________________________________________
"
"List users group filter
"
"UserGroupFilter= users
"
"___________________________________________________________________________________
"
"Scan Log Format
"
"%o  OS Type
"
"%s  Virus Status
"
"%f  Scan Folder
"
"%n  Scan Time
"
"%c  Command Options
"
"%t  Time Stamp
"
"%d  Date Stamp
"
"ScanLogFormat= %o %s %f %n %c %t %d
"
"___________________________________________________________________________________
", FilePtr);                  


Now, I need help using getline to split the line into a string array.

Yes, in this case you do need the "
" because fputs() only adds a new line after the whole text you pass to it. (how should it know where you’d want to insert newlines anyway?)

In your previous post, your code called fputs() for every single line though.

Now, I need help using getline to split the line into a string array.

getline() only reads a line (i.e. all input until the next newline) though, it doesn’t split it.

Depending on what you want to do exactly, you could also use e.g. fread(), fscanf(), fgetc() or fgets() to read from a file (or stdin).

You’d need to explain what your goal is though… :wink:

I meant for the next posted message. :wink:

Thanks to all. I have what I need to start the next phase of coding.