Implementing an alternative to scanf
Q: How can the algorithm of the function be improved?

A: I'm not sure what you mean by algorithm. There are several things relating to functionality that you should improve on, however:


Make an enum to represent what modes are accepted by your function, and use that instead of taking a char. This will greatly reduce the potential for bugs and makes you less reliant on magic "numbers" (or characters, if you will).
You might want to remove the biggest drawback your function has compared to scanf and friends, which is lack of flexibility. The great strength of scanf is that its format string is extremely variable and can be used to extract data from a vast variety of formats. You approach currently limits you to a single char worth of format specifier, and is thus much more rigid and less adaptable. Depending on what you want from your function, this might be acceptable or even desired, but if you really want to contest with scanf, you should come up with a good idea of two on how to improve flexibility.
Remove the hard limit on length. Why do you arbitrarily only read 20 chars? This is just barely sufficient for 64bit integers, but will quickly prove as too little as soon as you start reading different types of data (especially strings).
Add some error reporting facility to your function. What if you tried to read an int when there was none? You might want to tell your users about this (actually, you absolutely must tell your users about this, or your user interface is quickly going to take a turn into an unpleasant direction).
You state in you question that gets_s is useless for streams different from stdin, but that criticism also applies to your function. Consider taking a stream handle as your first argument and reading from that instead. You can still provide another function which has stdin implied, for convenience's sake.




Q: Don't I need to free() in every case?

A: Yes, you absolutely do. Every buffer that allocated via malloc and friends should be freed at some point, otherwise you've got yourself a memory leak. Actually, you might not even want to allocate things on the heap at all. If all I want to do is read a single integer, I usually don't want to incur the cost of calling out to the OS to reserve some memory for me, when I could just read the value into a local variable. How do you do this? Easy enough, instead of taking care of allocation yourself, hand that task over to the user and just accept a pointer instead, i.e.

void scano(char mode, void* buffer);


This has the added benefit of opening up the return value slot, so now you can actually use that to indicate whether an error occured:

int scano(char mode, void* buffer);


or even better

err_code scano(char mode, void* buffer);


where err_code is an enum containing all the possible error values. This pattern of returning an error indicator is really common throughout the standard library and most C applications in general.



Q: Is it fully safe? If not, how can it be made safe?

A: That depends on your definition of "fully safe". If you mean "has no undefined behavior", then the answer is no, sadly. atoi causes such undefined behavior in the case that the integer it is trying to parse is out of range for the int type. The same is true for atof, so you would need to brace against those cases (by not using those two functions, usually). Another problem is that you don't check for malloc failure - if allocation fails, you get a null pointer and subsequently try to write the result of atoi or atof to it, which also causes undefined behavior. Another point of insecurity is your call to fgets: If reading fails completely, your array remains uninitialized. The subsequent call to strlen is then undefined behavior.



Other things that aren't quite right


You don't need to cast the return value of malloc, or any other function returning void*. In fact, this can lead to subtle bugs when making changes to your code later on.
Don't rely on magic numbers. Instead of typing fgets(sData, 20, stdin), pull that 20 out to its own constant, or, at the very least, do something like fgets(sData, sizeof buf, stdin). That way, you're way less prone to buffer overflow bugs arising from you forgetting to change one of the two 20s when you go back and edit your code.
*(sData + strlen(sData) - 1) = '\0'; //get rid of the '\n' before the '\0' ...and now you've overwritten part of your data! There might not actually be an '\n' there, if the line you are reading from has still 19 or more characters left. Check for those kinds of things before writing into your string!