Like Adak said, split each of the cases into a separate function instead. Edit: Exactly as Matticus showed.
For example, assume you use this function to calculate a perfect hash of the four character FTP command at the start of the string, save the hash to an int, and return a pointer to the possible arguments following the FTP command. The function will return NULL if there is anything suspicious.
Code:
static inline const char *parse_command(const char *input, int *const cmdptr)
{
int cmd = 0;
/* Nothing to parse? */
if (!input || !*input)
return NULL;
/* Skip leading control and whitespace characters. */
while (*input > 0 && *input <= 32)
input++;
/* Parse the four-character command to cmd.
* input is parsed as a base-40 number, with
* A = 1, .. Z = 26, a = 1, .., z = 26, zero = 28, .., nine = 37.
* AAAA = 65361
* AAAB = 65362
* ZZZZ = 170666
* 0000 = 1837948
* 9999 = 2428717
* While technically the range is 0 .. 2559999,
* only 65361..2428717 are produced by this function.
* (not even all of them, there are holes due to 0, 27, 38, 39 not used)
*/
while (cmd < 64000)
if (*input >= 'A' && *input <= 'Z')
cmd = 40 * cmd + (int)(*(input++) - 'A' + 1);
else
if (*input >= 'a' && *input <= 'z')
cmd = 40 * cmd + (int)(*(input++) - 'a' + 1);
else
if (*input >= '0' && *input <= '9')
cmd = 40 * cmd + (int)(*(input++) - '0' + 28);
else
return NULL;
/* Skip trailing spaces. */
while (*input == ' ')
input++;
/* Save the command number. */
if (cmdptr)
*cmdptr = cmd;
return input;
}
Your command parser function can then utilize the above function to find out the command number, then call the suitable worker function:
Code:
int handle_ftp_command(const char *const input)
{
const char *args; /* Start of arguments in input */
int cmd = -1; /* The command number */
args = parse_command(input, &cmd);
if (!args) {
/* The input line is not a valid command. */
return EINVAL; /* "invalid input" return code. */
}
switch (cmd) {
case 1374618: /* USER */
return ftp_USER(args);
case 1026379: /* PASS */
return ftp_PASS(args);
case 783180: /* LIST */
return ftp_LIST(args);
case 1121980: /* QUIT */
return ftp_QUIT(args);
default:
/* Command cmd is not implemented. */
return ENOSYS;
}
}
The ftp_USER(), ftp_PASS(), ftp_LIST(), and ftp_QUIT() functions all take the string following the command as an argument, and return success (0) or failure (I used errno codes above), just like the handle_ftp_command() function itself.
It is customary to use zero as success and nonzero as error, since you can only have one success type, but multiple error types. (Or you could use negative values for errors, zero for success, and positive values for success with some sort of caveat or comment.)