A framework written with python, in order to quickly create C shell projects on Linux envinronment.
Note: this package is thought to be used by Linux platforms.
You can install cScell with pip
or pip3
:
$ pip3 install cScell
The package is usually used as a global module. It is possible that a warning will appear during the installation, saying that the location of the package is not on the $PATH
variable. In order to be able to use it from any directory, add that location to the $PATH
variable.
The syntax of the command is:
cScell [app_name] [commands_json_path] [output_dir_path]
The three parameters are:
- app_name: The name of the project. Default:
scell_project
. - commands_json_path: The path to the json file describing the commands of the shell program. Default:
./commands.json
. - output_dir_path: The path where the project directory will be created. Default:
./
.
This example will create in the current folder a project called "myProject":
cScell myProject
This example will create in the parent folder a project called "myProject", with the commands described in "my-commands.json":
cScell myProject ./my-commands.json ../
The module could be actually used also as a local module, here is an example:
from cScell.cScell import generate_scell
APP_NAME = 'myProject'
JSON_COMMANDS = './my-commands.json
OUTPUT_PATH = '../'
generate_scell(APP_NAME, JSON_COMMANDS, OUTPUT_PATH)
You can describe the commands of your c shell program with a json file.
In the commands json file:
- Each root key is the name of a command of the shell. Its value must be an object.
- The special
_arguments
command is the command that could be executed when the user passes command line arguments to the program. - An exception for what was said above is the
promptSymbol
key, that specifies the symbol displayed before each line of the prompt. If not specified, its value will be>>
. - For each command, the
function
property indicates the name of the function that handles that command. - For each command, the
arguments
property indicates the arguments accepted by that command. Its value must be an object. - For each arguments object, every key is the name of an argument and its value must be an object.
- For each argument value, the key
type
is mandatory and describes the variable type of the argument. The possible options are:int
,long
,float
,double
,char
,char*
,array<type>
(wheretype
is one of the precedent types). - For each argument value, the key
alias
is not mandatory and describes an alias (single character) that could be used instead of the extended argument name. - For each argument value, the key
default
is not mandatory. If it is not specified, the argument is mandatory when the command is typed by the user. NB: The bool type is always false as default. The array type can only be "NULL" as default if it is not a required argument. - For each argument value, the key
min
is not mandatory. It can be used with numeric types and indicates that the passed argument value must be bigger or equal than the value of min. - For each argument value, the key
max
is not mandatory. It can be used with numeric types and indicates that the passed argument value must be lower or equal than the value of max. - For each argument value, the key
description
is not mandatory. It is the displayed description for the argument when the command help is executed. - For each command, the key
description
is not mandatory. It is the displayed description for the command when the command help is executed.
An example:
{
"promptSymbol": ">>>",
"_arguments": {
"function": "arguments",
"arguments": {
"thing": {
"type": "int",
"alias": "t",
"default": 1,
"min": 0,
"description": "The thing argument description"
},
"stuff": {
"type": "float",
"alias": "s",
"max": 10,
"description": "The stuff argument description"
},
"ware": {
"type": "array<char*>",
"alias": "w",
"default": "NULL",
"description": "The ware argument description"
}
}
},
"increment": {
"function": "inc",
"arguments": {
"number": {
"type": "int",
"alias": "n",
"description": "The number to increment"
},
"amount": {
"type": "int",
"alias": "a",
"default": 1,
"description": "How much will the number incremented"
}
},
"description": "Increments a number"
},
"add": {
"function": "add",
"arguments": {
"first": {
"type": "int",
"alias": "x",
"description": "The first addend"
},
"second": {
"type": "int",
"alias": "y",
"description": "The second addend"
}
},
"description": "Adds two addends"
},
"concat": {
"function": "concat",
"arguments": {
"strings": {
"type": "array<char*>",
"default": "NULL",
"description": "The strings to concat"
},
"reverse": {
"type": "bool",
"alias": "r",
"description": "If the strings will be in reversed order"
}
},
"description": "Concats an array of strings"
},
"quit": {
"function": "quit",
"description": "closes the program"
}
}
At the end of execution, a project folder called as you specified for the app_name
argument will be created in the output_dir_path
that you specified.
That folder is structured as specified below:
- There will be a
compile.sh
bash script. It is the script to compile the c generated source code. If it is not already executable, you can executesudo chmod +x compile.sh
. - There will be a
[app_name].c
file, named as the name of the project. It will contain the main function of the program, it imports the commands interpreter generated by the module and the commands handlers that you should implement and will run the shell loop. - There will be the
shellutils
folder, containing all thelibraries
that make the shell work. These libraries are:colour
, for a coloured outputconstructs
, containing only header files, aboolean.h
for the boolean enum and ash_state.h
for the state of a command enum.logger
, used by the shell to log errors or warnings.text
, containing all the text functions and the advanced terminal.shell_utils
, used by the shell_commands libraryshell_commands
, the only one that depends on thecommands.json
file passed before creating the project. It will contain the code that parses the shell commands prompted by the user and calls the right function handler
- There will be the
handlers
folder, containing thehandlers.h
andhandlers.c
files. You will edit thehandlers.c
files in order to define the code that will be executed when the user prompts a specific command.
There will be also three variables exported by shell_commands.h
:
char *sh_last_command
: It is the string variable containing the last prompted commandchar *sh_prompt_symbol
: It is the variable whose value is the string that specifies the symbol displayed before each line of the prompt.bool sh_use_advanced_terminal
: It is the boolean variable that determines if the advanced terminal will be used. The advanced terminal makes possible to the user to use the up and down arrows to navigate the commands cronology. Its default value istrue
, but you can change it before thesh_loop();
call in the[app_name].c
file.
To start the program you just need to execute:
cd [your_project_dir]
sudo chmod +x ./compile.sh
./compile.sh
./[your_app_name]
This will compile the c code and start the generate executable program.
You should edit the handlers.c
file to define the behaviour of each command.
Under the hood:
- All arguments containing hyphens in the name will be purged with underscores.
- If the
_arguments
command was defined, if the users passes command line arguments they will be parsed and the corrispondent handler executed. - An infinite loop that listens for the user's commands will be then executed.
- All empty prompted lines will be ignored.
- After a command is prompted, the program will check if the command exists. If not, it will display a proper error message.
- If the command exists, it will be properly parsed.
- If a required argument misses, a value is invalid, a value misses or does not matches provided numerical ranges, an error will be displayed.
- The extended argument names should be preceded by two hyphens
--
while the aliased argument names by a single hyphen-
. - If a value without argument will be passed, a warning will be displayed, but it will not block the command.
- If all checks pass and the command is correctly parsed, the corrispondent handler function is called with the parsed arguments. You can easily edit the
handlers.c
file and implement the handlers, which by default print the command name. - If the
help
command is prompted, the documentation for all the commands will be displayed - If the
help [command]
command is prompted, the documentation for the given command will be displayed
- This framework works only for Linux.
- Only named arguments are allowed. This means that all commands will be like
add -x 1 -y 2
orconcat --strings first second third
but commands likeadd 1 2
will not be allowed. - If a string parameter contains spaces, you can include it inside double apix such as
concat --strings "first string" "second string"