C fgets_line of arbitrary length This is meant to be a drop in replacement for getline as it's not crossplatform.
I am trying to do as minimal work as possible in here including only calling strlen once at the very end to calculate the size of the final block.
returns -1 for error, 0 for EOF, 1 for success
The way it works it by setting the last two bytes in the array as [0, 1] and if the buffer is filled it will look like [X,0], X being either LF where we are done, or something else meaning we need to realloc and loop again unless we are at eof.
int
fgets_line(char **line, size_t *capacity, size_t *length, FILE *stream) {
  if (!*line &amp;&amp; !(*line = malloc(*capacity = 64)))
    return *capacity = 0, -1;
  (*line)[0] = 0;
  if (length)
    *length = 0;
  char *position = *line;
  while (1) {
    (*line)[*capacity - 1] = 1;
    (*line)[*capacity - 2] = 0;
    if (fgets(position, *line + *capacity - position, stream)) {
      if ((*line)[*capacity - 1] == 0
       &amp;&amp; (*line)[*capacity - 2] != '\n') {
        size_t new_capacity = *capacity * 2;
        char *tmp = realloc(*line, new_capacity);
        if (tmp) {
          position = tmp + *capacity - 1;
          *line = tmp;
          *capacity = new_capacity;
        } else return -1;
      } else goto success;
    } else if (position != *line) {
      if (feof(stream))
        goto success;
      return -1;
    } else return 0;
  }
  success:
  if (length)
    *length = position - *line + strlen(position);
  return 1;
}

usage is similar to getline
int main() {
  char *line = NULL;
  size_t capacity = 0, length = 0;
  int result = 0;
  while ((result = fgets_line(&amp;line, &amp;capacity, &amp;length, stdin)))
    printf(&quot;---Capacity: %-8zuLength: %-8zu---\n%s------\n&quot;, capacity, length, line);
}
Do not put the sentinel characters in every iteration. Set them before the loop, and after a successful reallocation.
Also, (*line)[*capacity - 2] = 0; is redundant. Indeed, if (*line)[*capacity - 1] remains 1 we don't care, and if it turns to 0 then (*line)[*capacity - 2] has been overwritten anyway.

goto is totally unwarranted. break works very well.

Do not handle fgets failures inside the loop. Break immediately.

Using position as an index, rather than the pointer, seems cleaner. Consider
  fgets(*line + position, *capacity - position, stream)

etc.