Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » Bash or Shell script to create source and header

This thread is locked; no one can reply to it. rss feed Print
Bash or Shell script to create source and header
OnlineCop
Member #7,919
October 2006
avatar

I often find myself writing the same structure for all of my class headers. I want to eliminate repetitive tasks, so I'd like to automate this by making it into a shell script. I'm using a Mac, and I understand there's something called the Automator, but I've never used it before so have no idea what it's for or how to use it, so thought I'd ask a question that people on OTHER platforms might find in the future and be able to use.

I'd like to create a shell script that will perform the following:

  1. Create a filename (case-sensitive) from the supplied argument, plus ".h"

  2. Fill the file with this text:

    #SelectExpand
    1#ifndef $(filename)_h 2#define $(filename)_h 3 4 5class $(filename) 6{ 7public: 8 // Constructor 9 $(filename)(); 10 11 // Destructor 12 virtual ~$(filename)(); 13}; 14 15 16#endif // $(filename)_h

  3. Create the source file (same filename but with a ".cpp" extension)

  4. Fill the file with this text:

    #SelectExpand
    1#include "$(filename).h" 2 3 4// Constructor 5$(filename)::$(filename)() 6{ 7 // Nothing to do 8} 9 10 11// Destructor 12$(filename)::~$(filename)() 13{ 14 // Nothing to do 15}

I'm not exactly certain the format (and the whole "$(filename)" format is borrowed from the makefile style), and I don't know how to supply arguments to shell scripts, so any help is appreciated. Even if the help is in the form of "RTM found at website ___" :-X

kazzmir
Member #1,786
December 2001
avatar

Try this.

#!/bin/sh

if [ "x$1" = "x" ]; then
        echo "Supply an argument"
fi

name=$1

sed template.h -e "s/\$(filename)/${name}/g" > $name.h

Use:

$ ./create foo
$ cat foo.h
#ifndef foo_h
#define foo_h

class foo {
         public:
         // Constructor
         foo();
         // Destructor
         virtual ~foo();
};

#endif // foo_h 

bamccaig
Member #7,536
July 2006
avatar

addclass#SelectExpand
1#!/bin/bash 2 3function do_header 4{ 5 if [ -e "$header_path" ]; then 6 read -p "'$header_path' already exists. Overwrite? (yes/no) "; 7 8 if [ x$REPLY != xyes ]; then 9 return 0; 10 fi 11 fi 12 13 # --- QnD: Header File --- 14 echo "#ifndef $header_guard" > $header_path; 15 echo " #define $header_guard" >> $header_path; 16 echo >> $header_path; 17 18 if [ x$namespace != x ]; then 19 indent=" "; 20 echo "namespace $namespace" >> $header_path; 21 echo "{" >> $header_path; 22 fi 23 24 echo "${indent}class $name" >> $header_path; 25 echo "${indent}{" >> $header_path; 26 echo "${indent}public:" >> $header_path; 27 echo "${indent} ${name}(void);" >> $header_path; 28 echo "${indent} virtual ~${name}(void);" >> $header_path; 29 echo "${indent}};" >> $header_path; 30 31 if [ x$namespace != x ]; then 32 echo "}" >> $header_path; 33 fi 34 35 echo >> $header_path; 36 echo "#endif //${header_guard}" >> $header_path; 37 echo >> $header_path; 38} 39 40function do_source 41{ 42 if [ -e "$source_path" ]; then 43 read -p "'$source_path' already exists. Overwrite? (yes/no) "; 44 45 if [ x$REPLY != xyes ]; then 46 return 0; 47 fi 48 fi 49 50 # QnD --- Source File --- 51 echo "#include <${header_file}>" > $source_path; 52 echo >> $source_path; 53 54 if [ x$namespace != x ]; then 55 indent=" "; 56 echo "namespace $namespace" >> $source_path; 57 echo "{" >> $source_path; 58 fi 59 60 echo "${indent}${name}::${name}(void)" >> $source_path; 61 echo "${indent}{" >> $source_path; 62 echo "${indent} // TODO" >> $source_path; 63 echo "${indent}}" >> $source_path; 64 echo >> $source_path; 65 echo "${indent}${name}::~${name}(void)" >> $source_path; 66 echo "${indent}{" >> $source_path; 67 echo "${indent} // TODO" >> $source_path; 68 echo "${indent}}" >> $source_path; 69 70 if [ x$namespace != x ]; then 71 echo "}" >> $source_path; 72 fi 73 74 echo >> $source_path; 75} 76 77if [ x$1 = x ]; then 78 echo "Usage: $0 NAME [NAMESPACE]"; 79 echo; 80 echo "Where NAME is the name of the file/class and NAMESPACE is the namespace."; 81 82 exit -1; 83fi 84 85name="`echo "$1" | sed -r 's/\s+//g'`"; 86namespace="`echo "$2" | sed -r 's/\s+//g'`"; 87header_guard="`echo "$name" | tr [:lower:] [:upper:]`_HPP"; 88header_file="${name}.hpp"; 89 90if [ -d include ]; then 91 incdir=include/; 92fi 93 94header_path="${incdir}${header_file}"; 95 96do_header; 97 98source_file="${name}.cpp"; 99 100if [ -d src ]; then 101 srcdir=src/; 102fi 103 104source_path="${srcdir}${source_file}"; 105 106do_source;

[bamccaig@sephiroth temp]$ ls -la
total 8
drwxrwxr-x  2 bamccaig bamccaig 4096 2009-07-23 12:09 .
drwxrwxr-x 36 bamccaig bamccaig 4096 2009-07-23 11:10 ..
[bamccaig@sephiroth temp]$ addclass foo
[bamccaig@sephiroth temp]$ ls -la
total 16
drwxrwxr-x  2 bamccaig bamccaig 4096 2009-07-23 12:10 .
drwxrwxr-x 36 bamccaig bamccaig 4096 2009-07-23 11:10 ..
-rw-rw-r--  1 bamccaig bamccaig   85 2009-07-23 12:10 foo.cpp
-rw-rw-r--  1 bamccaig bamccaig  118 2009-07-23 12:10 foo.hpp
[bamccaig@sephiroth temp]$ cat foo.hpp
#ifndef FOO_HPP
    #define FOO_HPP

class foo
{
public:
    foo(void);
    virtual ~foo(void);
};

#endif //FOO_HPP

[bamccaig@sephiroth temp]$ cat foo.cpp
#include <foo.hpp>

foo::foo(void)
{
    // TODO
}

foo::~foo(void)
{
    // TODO
}

[bamccaig@sephiroth temp]$ mkdir include src
[bamccaig@sephiroth temp]$ addclass foo bar
[bamccaig@sephiroth temp]$ ls -Rla
.:
total 24
drwxrwxr-x  4 bamccaig bamccaig 4096 2009-07-23 12:11 .
drwxrwxr-x 36 bamccaig bamccaig 4096 2009-07-23 11:10 ..
-rw-rw-r--  1 bamccaig bamccaig   85 2009-07-23 12:10 foo.cpp
-rw-rw-r--  1 bamccaig bamccaig  118 2009-07-23 12:10 foo.hpp
drwxrwxr-x  2 bamccaig bamccaig 4096 2009-07-23 12:35 include
drwxrwxr-x  2 bamccaig bamccaig 4096 2009-07-23 12:35 src

./include:
total 12
drwxrwxr-x 2 bamccaig bamccaig 4096 2009-07-23 12:35 .
drwxrwxr-x 4 bamccaig bamccaig 4096 2009-07-23 12:11 ..
-rw-rw-r-- 1 bamccaig bamccaig  160 2009-07-23 12:35 foo.hpp

./src:
total 12
drwxrwxr-x 2 bamccaig bamccaig 4096 2009-07-23 12:35 .
drwxrwxr-x 4 bamccaig bamccaig 4096 2009-07-23 12:11 ..
-rw-rw-r-- 1 bamccaig bamccaig  135 2009-07-23 12:35 foo.cpp
[bamccaig@sephiroth temp]$ cat include/foo.hpp
#ifndef FOO_HPP
    #define FOO_HPP

namespace bar
{
    class foo
    {
    public:
        foo(void);
        virtual ~foo(void);
    };
}

#endif //FOO_HPP

[bamccaig@sephiroth temp]$ cat src/foo.cpp
#include <foo.hpp>

namespace bar
{
    foo::foo(void)
    {
        // TODO
    }

    foo::~foo(void)
    {
        // TODO
    }
}

That's actually kind of useful. :D I might just go ahead and try to create a library of bash functions to create file stubs for different types of symbols (enums, structs, classes, functions, main, etc.).

Imagine stubbing out a whole project with just a series of commands... :D

OnlineCop
Member #7,919
October 2006
avatar

bamccaig said:

That's actually kind of useful. I might just go ahead and try to create a library of bash functions to create file stubs for different types of symbols (enums, structs, classes, functions, main, etc.).

When you do, post them here. I'd certainly be interested in them.

I can even see derived classes being handy:

#ifndef FOO_HPP
#define FOO_HPP

#include "bar.hpp"

class foo : public bar
{
public:
    foo();
    virtual ~foo();
};

#endif //FOO_HPP

ixilom
Member #7,167
April 2006
avatar

I did something similar with PHP some time ago.
Just a text input and a submit button, when you submit it creates .cpp and .h file for you both on screen and links so you can save them to your computer :)

___________________________________________
Democracy in Sweden? Not since 2008-Jun-18.
<someone> The lesbians next door bought me a rolex for my birthday.
<someone> I think they misunderstood when I said I wanna watch...

OnlineCop
Member #7,919
October 2006
avatar

I actually hadn't noticed that, with only minor modifications, bamccaig's code already DOES have all the necessary support for inheritance.

Now onto phase 2: the Allegro Timer template. You know the one... it won't exceed a certain FPS under light operation, but will start to dynamically skip frames based on refresh preferences under heavy loads. It also maintains a low CPU usage (around 1%) unless it starts really getting into heavy 3D rendering :o:P

bamccaig
Member #7,536
July 2006
avatar

Updated to include namespace support in header guards and file paths (i.e., namespace foo { class bar; } becomes FOO_BAR_HPP, include/foo/bar.hpp, and src/foo/bar.cpp). Obviously everybody does this a little bit different, but this is how I would do it at this particular point in time. ;)

addclass#SelectExpand
1#!/bin/bash 2 3function do_header 4{ 5 if [ -e "$header_path" ]; then 6 read -p "'$header_path' already exists. Overwrite? (yes/no) "; 7 8 if [ x$REPLY != xyes ]; then 9 return 0; 10 fi 11 fi 12 13 # --- QnD: Header File --- 14 echo "#ifndef $header_guard" > $header_path; 15 echo " #define $header_guard" >> $header_path; 16 echo >> $header_path; 17 18 if [ x$namespace != x ]; then 19 indent=" "; 20 echo "namespace $namespace" >> $header_path; 21 echo "{" >> $header_path; 22 fi 23 24 echo "${indent}class $name" >> $header_path; 25 echo "${indent}{" >> $header_path; 26 echo "${indent}public:" >> $header_path; 27 echo "${indent} ${name}(void);" >> $header_path; 28 echo "${indent} virtual ~${name}(void);" >> $header_path; 29 echo "${indent}};" >> $header_path; 30 31 if [ x$namespace != x ]; then 32 echo "}" >> $header_path; 33 fi 34 35 echo >> $header_path; 36 echo "#endif //${header_guard}" >> $header_path; 37 echo >> $header_path; 38} 39 40function do_source 41{ 42 if [ -e "$source_path" ]; then 43 read -p "'$source_path' already exists. Overwrite? (yes/no) "; 44 45 if [ x$REPLY != xyes ]; then 46 return 0; 47 fi 48 fi 49 50 # QnD --- Source File --- 51 echo "#include <${nsdir}${header_file}>" > $source_path; 52 echo >> $source_path; 53 54 if [ x$namespace != x ]; then 55 indent=" "; 56 echo "namespace $namespace" >> $source_path; 57 echo "{" >> $source_path; 58 fi 59 60 echo "${indent}${name}::${name}(void)" >> $source_path; 61 echo "${indent}{" >> $source_path; 62 echo "${indent} // TODO" >> $source_path; 63 echo "${indent}}" >> $source_path; 64 echo >> $source_path; 65 echo "${indent}${name}::~${name}(void)" >> $source_path; 66 echo "${indent}{" >> $source_path; 67 echo "${indent} // TODO" >> $source_path; 68 echo "${indent}}" >> $source_path; 69 70 if [ x$namespace != x ]; then 71 echo "}" >> $source_path; 72 fi 73 74 echo >> $source_path; 75} 76 77if [ x$1 = x ]; then 78 echo "Usage: $0 NAME [NAMESPACE]"; 79 echo; 80 echo "Where NAME is the name of the file/class and NAMESPACE is the namespace."; 81 82 exit -1; 83fi 84 85name="`echo "$1" | sed -r 's/\s+//g'`"; 86namespace="`echo "$2" | sed -r 's/\s+//g'`"; 87 88if [ x$namespace = x ]; then 89 header_guard="`echo "$name" | tr [:lower:] [:upper:]`_HPP"; 90else 91 header_guard="`echo "\`echo "${namespace}" | sed -r 's/::/_/g'\`_${name}" | tr [:lower:] [:upper:]`_HPP"; 92fi 93 94header_file="${name}.hpp"; 95 96if [ -d include ]; then 97 incdir=include/; 98fi 99 100if [ x$namespace != x ]; then
101 nsdir="`echo "$namespace" | sed -r 's/::/\//g'`/";
102 mkdir -p "${incdir}${nsdir}"; 103fi 104 105header_path="${incdir}${nsdir}${header_file}"; 106 107do_header; 108 109source_file="${name}.cpp"; 110 111if [ -d src ]; then 112 srcdir=src/; 113fi 114 115if [ x$namespace != x ]; then 116 mkdir -p "${srcdir}${nsdir}"; 117fi 118 119source_path="${srcdir}${nsdir}${source_file}"; 120 121do_source;

[bamccaig@sephiroth temp]$ ls -la
total 8
drwxrwxr-x  2 bamccaig bamccaig 4096 2009-07-23 23:48 .
drwxrwxr-x 36 bamccaig bamccaig 4096 2009-07-23 15:28 ..
[bamccaig@sephiroth temp]$ mkdir include src
[bamccaig@sephiroth temp]$ addclass foo bar::baz
[bamccaig@sephiroth temp]$ ls -Rla
.:
total 16
drwxrwxr-x  4 bamccaig bamccaig 4096 2009-07-23 23:48 .
drwxrwxr-x 36 bamccaig bamccaig 4096 2009-07-23 15:28 ..
drwxrwxr-x  3 bamccaig bamccaig 4096 2009-07-23 23:48 include
drwxrwxr-x  3 bamccaig bamccaig 4096 2009-07-23 23:48 src

./include:
total 12
drwxrwxr-x 3 bamccaig bamccaig 4096 2009-07-23 23:48 .
drwxrwxr-x 4 bamccaig bamccaig 4096 2009-07-23 23:48 ..
drwxrwxr-x 3 bamccaig bamccaig 4096 2009-07-23 23:48 bar

./include/bar:
total 12
drwxrwxr-x 3 bamccaig bamccaig 4096 2009-07-23 23:48 .
drwxrwxr-x 3 bamccaig bamccaig 4096 2009-07-23 23:48 ..
drwxrwxr-x 2 bamccaig bamccaig 4096 2009-07-23 23:48 baz

./include/bar/baz:
total 12
drwxrwxr-x 2 bamccaig bamccaig 4096 2009-07-23 23:48 .
drwxrwxr-x 3 bamccaig bamccaig 4096 2009-07-23 23:48 ..
-rw-rw-r-- 1 bamccaig bamccaig  189 2009-07-23 23:48 foo.hpp

./src:
total 12
drwxrwxr-x 3 bamccaig bamccaig 4096 2009-07-23 23:48 .
drwxrwxr-x 4 bamccaig bamccaig 4096 2009-07-23 23:48 ..
drwxrwxr-x 3 bamccaig bamccaig 4096 2009-07-23 23:48 bar

./src/bar:
total 12
drwxrwxr-x 3 bamccaig bamccaig 4096 2009-07-23 23:48 .
drwxrwxr-x 3 bamccaig bamccaig 4096 2009-07-23 23:48 ..
drwxrwxr-x 2 bamccaig bamccaig 4096 2009-07-23 23:48 baz

./src/bar/baz:
total 12
drwxrwxr-x 2 bamccaig bamccaig 4096 2009-07-23 23:48 .
drwxrwxr-x 3 bamccaig bamccaig 4096 2009-07-23 23:48 ..
-rw-rw-r-- 1 bamccaig bamccaig  140 2009-07-23 23:48 foo.cpp
[bamccaig@sephiroth temp]$ cat */*/*/*
#ifndef BAR_BAZ_FOO_HPP
    #define BAR_BAZ_FOO_HPP

namespace bar::baz
{
    class foo
    {
    public:
        foo(void);
        virtual ~foo(void);
    };
}

#endif //BAR_BAZ_FOO_HPP

#include <bar/baz/foo.hpp>

namespace bar::baz
{
    foo::foo(void)
    {
        // TODO
    }

    foo::~foo(void)
    {
        // TODO
    }
}

[bamccaig@sephiroth temp]$ 

I probably find nested namespaces more structurally obvious than qualified ones, but that would require more manipulation of arguments so I just settled for QnD right now. :P

** EDIT **

Note: One of the <code> lines (the highlighted line) apparently lost a backslash in the parsing stage. I think I fixed it by escaping it, but there could be more so I'm going to attach the script to make sure the code is available. :-X

Peter Wang
Member #23
April 2000

Don't forget here documents.

#!/bin/sh

base=$(basename $1 .c)

cat <<EOF

#include "${base}.h"

/* blah blah */

EOF

bamccaig
Member #7,536
July 2006
avatar

I said:
...
namespace bar::baz
{
...

I probably find nested namespaces more structurally obvious than qualified ones, but that would require more manipulation of arguments so I just settled for QnD right now. :P

Hmmm, wait, maybe I'm confusing C# syntax with C++ syntax. Is this legal in C++? ???

namespace bar::baz
{
}

It isn't compiling...

[bamccaig@sephiroth temp]$ g++ -Iinclude src/bar/baz/foo.cpp -c
In file included from src/bar/baz/foo.cpp:2:
include/bar/baz/foo.hpp:4: error: expected `{' before ‘::’ token
include/bar/baz/foo.hpp:4: error: function definition does not declare parameters
src/bar/baz/foo.cpp:3: error: expected `{' before ‘::’ token
src/bar/baz/foo.cpp:3: error: function definition does not declare parameters
src/bar/baz/foo.cpp:14: error: expected `}' at end of input
src/bar/baz/foo.cpp:14: error: expected `}' at end of input
[bamccaig@sephiroth temp]$ 

...and I can't find any tutorials or guides that suggest this syntax is supported. :-X

alethiophile
Member #9,349
December 2007
avatar

The following is me trying to type out from scratch my 'mksfp' (make single-file project) script:

#SelectExpand
1#!/bin/bash 2 3cp ~/.mksfp/Makefile.template ./Makefile 4 5pcmd="'s/EXENAME/"$1"/g;'"; 6 7perl -pie $pcmd Makefile 8 9cat >main.c <<EOF 10#include <stdio.h> 11#include <stdlib.h> 12 13int main(int argc, char **argv) { 14 // insert program here 15} 16 17EOF

The Makefile.template:

EXE= EXENAME
OFILES= main.o

$(EXE): $(OFILES)
        $(CC) -o $@ $(OFILES)

.o.c:
        $(CC) -c -Wall $<

clean:
        -rm *.o $(EXE)

I probably made some mistake or other typing it.

--
Do not meddle in the affairs of dragons, for you are crunchy and taste good with ketchup.
C++: An octopus made by nailing extra legs onto a dog.
I am the Lightning-Struck Penguin of Doom.

Go to: