htmlspecialchars() equivalent in C
You shouldn't pass a char* as buffer end but a size_t size corresponding to the size of the allocated buffer. So your available length will be size - 2 ("zero-indexed" and "trailing '\0'").
You return either 1 or 0, why don't using bool as return type? (Or maybe a size_t corresponding to the final string length, but, that's a design decision).
Variables where value doesn't change in your function (as locales or parameters) should be marked const. That's not faster but it show your intends.
You can maybe use strcpy, strncpy or  memcpy to ... copy the replacements string into destination (and replace multiple incrementation by a single add-assign).
For non-special chars sequences, you can maybe get them in chunk by chunk (between two special chars) with strcspn or strpbrk. (and after, copying them with same functions than former)




Edit

This is a raw try using theses functions.

I think it is safe, with no overflow, but maybe not the optimal implement.
Don't be scared about the size, there is a lot of comments :)

I outed two functions from source (strlenand replace_chrstr), 'cause I think they are reusable somewhere.

#include &lt;string.h&gt;

// Get the position of the c char in the str string.
// -&gt; str: a null-terminated string where to lookup
// -&gt; needle: char to find 
// Return: Position of the char `c` or 1 past the end (strlen + 1)
size_t strpos(const char* const str, const char c)
{
    char* p = strchr(str, c);
    return p ? (p - str) : strlen(str) + 1;
}

// Scan `in_str` and replace all char occurrences from `search` 
// by corresponding string from `replace`, then place the result in `out_str`.
// -&gt; search: A null-terminated string with all char to fiend
// -&gt; replace: An array of null-terminated strings with index based replacement from `search`
// -&gt; out_str: a buffer to put the result, at least as big than max_size
// -&gt; in_str: a null-terminated string where to process replacements
// Return: length of resulting string, or length+1 in case of overflow
size_t replace_chrstr(const char* const search, const char* const* const replace,
                      char *const out_str, const char* const in_str, const size_t max_size)
{
    size_t in_offset = 0;
    size_t out_offset = 0;
    size_t index;
    size_t length;
    const size_t index_max = strlen(search);
    const size_t length_max = strlen(in_str);

    while (max_size &gt; out_offset) {
        length = strcspn(in_str + in_offset, search);
        // buffer overflow detected, here we truncate the input string
        // we add `\0` and return max_size (equivalent to strlen + 1)
        // but maybe you want another handling
        if (max_size &lt;= out_offset + length) {
            strncpy(out_str + out_offset, in_str + in_offset, max_size-out_offset-1);
            out_str[max_size-1] = '\0';
            return max_size;
        }
        strncpy(out_str + out_offset, in_str + in_offset, length);
        in_offset += length + 1;
        out_offset += length;
        // normal end of input string
        // add a `\0`, then return out_offset (equivalent to strlen)
        if (in_str[in_offset-1] == '\0') {
            out_str[out_offset] = '\0';
            return out_offset;
        }
        index = strpos(search, in_str[in_offset-1]);
        length = strlen(replace[index]);
        // buffer overflow detected, here we truncate the replacement string
        // we add `\0` and return max_size (equivalent to strlen + 1)
        // but maybe you want another handling        
        if (max_size &lt;= out_offset + length) {
            strncpy(out_str + out_offset, replace[index], max_size-out_offset-1);
            out_str[max_size-1] = '\0';            
            return max_size;
        }
        strcpy(out_str + out_offset, replace[index]);
        out_offset += length;
    }
    // we never reach here, normally
    return 0;
}

size_t www_specialchars_html(char* const dest, const char* const source, size_t max_size)
{
    const char search[] = "&amp;\"'&lt;&gt;";
    const char * replace[] = {"&amp;amp;","&amp;quot;","&amp;#039;","&amp;lt;","&amp;gt;"}; 
    return replace_chrstr(search, replace, dest, source, max_size);
}