Adding to the answer of mizo (I'm unable to comment, as I primarily answer on Arduino.SE and EE.SE)
The XC8 compiler also has the feature to determine the appropriate address space at runtime.
So yes, Hi-Tech PICC-18 does this, but is not the only compiler to do so.
Though I could understand if switching compiler might be impossible at the moment.
For that reason, you might want to use the following functions in string.h
/** @name memcpypgm2ram
* The {\bf memcpypgm2ram} function performs a {\bf memcpy} where
* {\bf s1} points to data memory and {\bf s2} points to program
* memory.
* @param s1 pointer to destination in data memory
* @param s2 pointer to source in program memory
* @param n number of characters to copy
*/
void *memcpypgm2ram (auto void *s1, auto const MEM_MODEL rom void *s2, auto sizeram_t n);
/** @name memcpyram2pgm
* The {\bf memcpyram2pgm} function performs a {\bf memcpy} where {\bf s1}
* points to program memory and {\bf s2} point to data memory.
* @param s1 pointer to destination in program memory
* @param s2 pointer to source in data memory
* @param n number of characters to copy
*/
MEM_MODEL rom void *memcpyram2pgm (auto MEM_MODEL rom void *s1, auto const void *s2, auto sizeram_t n);
And you could make your function like:
void YourStringFunction(ramstring);
void YourStringFunctionAccpetingRom(romstring){
YourStringFunction(memcpypgm2ram(romstring));
}
^This isn't actual code, more psuedo code. Also, I'm not sure if it's efficient.