static VSFileSystem::VSError getProgramSource(const std::string &path, std::vector<std::string> &lines, std::set<std::string> &processed_includes, char *buf, size_t buflen)
{
    std::string dirname = path.substr(0,path.find_last_of('/'));
    
    VSFileSystem::VSFile f;
    VSFileSystem::VSError err = f.OpenReadOnly( path.c_str(), UnknownFile );
    
    const char *include_directive = "#include \"";
    const size_t include_directive_len = 10;
    size_t lineno = 0;
    
    if (err <= Ok) {
        processed_includes.insert(path);
        
        while (Ok == f.ReadLine(buf, buflen)) {
            ++lineno;
            if (strncmp(buf, include_directive, include_directive_len) == 0) {
                // Process include directives
                char *eos = strchr(buf+include_directive_len, '\"');
                if (eos != NULL) {
                    *eos = 0;
                    std::string includepath = dirname + "/" + std::string(buf+include_directive_len);
                    if (processed_includes.count(includepath) == 0) {
                        // Set up line numbers for include file
                        lines.push_back("#line 0\n");
                        
                        VSFileSystem::VSError ierr = getProgramSource(includepath, lines, processed_includes, buf, buflen);
                        if (ierr > Ok) {
                            f.Close();
                            VSFileSystem::vs_fprintf(stderr, "ERROR: included from %s\n", path.c_str());
                            return ierr;
                        } else {
                            // Append a blank line to avoid issues and restore line numbers
                            lines.push_back("\n");
                            snprintf(buf, buflen, "#line %lu\n", lineno);
                            lines.push_back(buf);
                        }
                    } else {
                        // Insert blank line to keep line numbers consistent
                        lines.push_back("\n");
                    }
                } else {
                    VSFileSystem::vs_fprintf(stderr, "WARNING: broken include directive at file %s, line %d - skipping\n",
                        path.c_str(), lineno);
                }
            } else {
                // Append a line to the list
                lines.push_back(buf);
            }
        }
        
        f.Close();
    } else {
        VSFileSystem::vs_fprintf(stderr, "ERROR: at %s\n", path.c_str());
    }
    return err;
}