// "http://foo.bar.com/a/b/c.txt?a=b&c=d#lol" => "txt"
// "http://foo.bar.com/index.html" => "html"
// "http://foo.bar.com/a/b/" => ""
std::string getUrlExtension(const std::string& url) {
    std::string url2 = toLowerCase(trim(url));
    int questionMark = stringIndexOf(url2, "?");
    if (questionMark >= 0) {
        url2 = url2.substr(0, questionMark);
    }
    int hash = stringIndexOf(url2, "#");
    if (hash >= 0) {
        url2 = url2.substr(0, hash);
    }
    int slash = stringLastIndexOf(url2, "/");
    if (slash >= 0) {
        url2 = url2.substr(slash + 1);
    }
    int dot = stringLastIndexOf(url2, ".");
    if (dot >= 0) {
        url2 = url2.substr(dot + 1);
    }
    return url2;
}
Exemple #2
0
std::string iurlstream::getUrlFilename(std::string url) const {
    std::string filename = url;
    
    // strip query string, anchor from URL
    int questionmark = stringIndexOf(url, "?");
    if (questionmark >= 0) {
        filename = filename.substr(0, questionmark);
    }
    int hash = stringIndexOf(url, "#");
    if (hash >= 0) {
        filename = filename.substr(0, hash);
    }
    
    filename = getTail(filename);
    if (filename.empty()) {
        filename = "index.tmp";   // for / urls like http://google.com/
    }
    
    return filename;
}
// line = "ZNK6VectorIiE3getEi at vector.h:587"
//         <FUNCTION> at <LINESTR>
void injectAddr2lineInfo(entry& ent, const std::string& line) {
    ent.line     = 0;
    int atIndex = stringIndexOf(line, " at ");
    if (atIndex >= 0) {
        if (ent.function.empty()) {
            ent.function = line.substr(0, atIndex);
        }
        ent.lineStr  = line.substr(atIndex + 4);

        int colonIndex = stringIndexOf(ent.lineStr, ":");
        if (colonIndex >= 0) {
            ent.file = ent.lineStr.substr(0, colonIndex);
            std::string rest = ent.lineStr.substr(colonIndex + 1);
            if (stringIsInteger(rest)) {
                ent.line = stringToInteger(rest);
            }
        }
    } else {
        if (ent.function.empty()) {
            ent.function = line;
        }
    }

    // demangle function name if necessary
    if (startsWith(ent.function, "Z")) {
        ent.function = "_" + ent.function;
    }

    if (startsWith(ent.function, "_Z")) {
        int status;
        char* demangled = abi::__cxa_demangle(ent.function.c_str(), NULL, 0, &status);
        if (status == 0 && demangled) {
            ent.function = demangled;
        }
    }
}
void printStackTrace(std::ostream& out) {
    // constructing the following object jumps into fancy code in call_stack_gcc/windows.cpp
    // to rebuild the stack trace; implementation differs for each operating system
    stacktrace::call_stack trace;
    std::vector<stacktrace::entry> entries = trace.stack;
    
    // get longest line string length to line up stack traces
    void* fakeStackPtr = stacktrace::getFakeCallStackPointer();
    int entriesToShowCount = 0;
    int funcNameLength = 0;
    int lineStrLength = 0;
    for (size_t i = 0; i < entries.size(); ++i) {
        // remove references to std:: namespace
        stringReplaceInPlace(entries[i].function, "std::", "");
        
        // a few substitutions related to predefined types for simplicity
        stringReplaceInPlace(entries[i].function, "basic_ostream", "ostream");
        stringReplaceInPlace(entries[i].function, "basic_istream", "istream");
        stringReplaceInPlace(entries[i].function, "basic_ofstream", "ofstream");
        stringReplaceInPlace(entries[i].function, "basic_ifstream", "ifstream");
        stringReplaceInPlace(entries[i].function, "basic_string", "string");
        
        // remove template arguments
        // TODO: does not work well for nested templates
        int lessThan = stringIndexOf(entries[i].function, "<");
        while (lessThan >= 0) {
            // see if there is a matching > for this <
            int greaterThan = lessThan + 1;
            int count = 1;
            while (greaterThan < (int) entries[i].function.length()) {
                if (entries[i].function[greaterThan] == '<') {
                    count++;
                } else if (entries[i].function[greaterThan] == '>') {
                    count--;
                    if (count == 0) {
                        break;
                    }
                }
                greaterThan++;
            }
            if (count == 0 && lessThan >= 0 && greaterThan > lessThan) {
                entries[i].function.erase(lessThan, greaterThan - lessThan + 1);
            } else {
                // look for the next < in the string, if any, to see if it has a matching >
                lessThan = stringIndexOf(entries[i].function, "<", lessThan + 1);
            }
        }
        
        if (!STACK_TRACE_SHOULD_FILTER || !shouldFilterOutFromStackTrace(entries[i].function)) {
            lineStrLength = std::max(lineStrLength, (int) entries[i].lineStr.length());
            funcNameLength = std::max(funcNameLength, (int) entries[i].function.length());
            entriesToShowCount++;
        }
    }
    
    if (entries.empty() || entriesToShowCount == 0) {
        out << " *** No useful stack trace available." << std::endl;
        out << " ***" << std::endl;
        return;
    }
    
    if (lineStrLength > 0) {
        out << " *** Stack trace (line numbers are approximate):" << std::endl;
        if (STACK_TRACE_SHOW_TOP_BOTTOM_BARS) {
            out << " *** "
                      << std::setw(lineStrLength) << std::left
                      << "file:line" << "  " << "function" << std::endl;
            out << " *** "
                      << std::string(lineStrLength + 2 + funcNameLength, '=') << std::endl;
        }
    } else {
        out << " *** Stack trace:" << std::endl;
    }
    
    for (size_t i = 0; i < entries.size(); ++i) {
        stacktrace::entry entry = entries[i];
        entry.file = getTail(entry.file);
        
        // skip certain entries for clarity
        if (STACK_TRACE_SHOULD_FILTER && shouldFilterOutFromStackTrace(entry.function)) {
            continue;
        }
        
        // show Main() as main() to hide hidden case-change by Stanford C++ lib internals
        if (startsWith(entry.function, "Main(")) {
            entry.function.replace(0, 5, "main(");
        }
        
        std::string lineStr = "";
        if (!entry.lineStr.empty()) {
            lineStr = entry.lineStr;
            if (lineStr == "?? ??:0") {
                lineStr = "(unknown)";
            }
        } else if (entry.line > 0) {
            lineStr = "line " + integerToString(entry.line);
        }


        // JL debugging
//        cout << "entry #" << i << endl;
//        cout << "lineStrLength: " << lineStrLength << endl;
//        cout << "lineStr: " << lineStr << endl;
//        cout << "entry.function: " << entry.function << endl;
        // JL end debugging


        out << " *** " << std::left << std::setw(lineStrLength) << lineStr
                  << "  " << entry.function << std::endl;
        
        // don't show entries beneath the student's main() function, for simplicity
        if (entry.function == "main()") {
            break;
        }
    }
    if (entries.size() == 1 && entries[0].address == fakeStackPtr) {
        out << " *** (partial stack due to crash)" << std::endl;
    }

    if (STACK_TRACE_SHOW_TOP_BOTTOM_BARS && lineStrLength > 0) {
        out << " *** "
                  << std::string(lineStrLength + 2 + funcNameLength, '=') << std::endl;
    }
    
    out << " ***" << std::endl;
    out << " *** NOTE:" << std::endl;
    out << " *** Any line numbers listed above are approximate." << std::endl;
    out << " *** To learn more about why the program crashed, we" << std::endl;
    out << " *** suggest running your program under the debugger." << std::endl;
    
    out << " ***" << std::endl;
}
void printStackTrace(std::ostream& out) {
    // constructing the following object jumps into fancy code in call_stack_gcc/windows.cpp
    // to rebuild the stack trace; implementation differs for each operating system
    stacktrace::call_stack trace;
    std::vector<stacktrace::entry> entries = trace.stack;
    
    // get longest line string length to line up stack traces
    void* fakeStackPtr = stacktrace::getFakeCallStackPointer();
    int entriesToShowCount = 0;
    int funcNameLength = 0;
    int lineStrLength = 0;
    for (size_t i = 0; i < entries.size(); ++i) {
        // remove references to std:: namespace
        stringReplaceInPlace(entries[i].function, "std::", "");
        
        // remove template arguments
        while (stringContains(entries[i].function, "<") && stringContains(entries[i].function, ">")) {
            int lessThan = stringIndexOf(entries[i].function, "<");
            int greaterThan = stringIndexOf(entries[i].function, ">", lessThan);
            if (lessThan >= 0 && greaterThan > lessThan) {
                entries[i].function.erase(lessThan, greaterThan - lessThan + 1);
            }
        }
        
        if (!STACK_TRACE_SHOULD_FILTER || !shouldFilterOutFromStackTrace(entries[i].function)) {
            lineStrLength = std::max(lineStrLength, (int) entries[i].lineStr.length());
            funcNameLength = std::max(funcNameLength, (int) entries[i].function.length());
            entriesToShowCount++;
        }
    }
    
    if (entries.empty() || entriesToShowCount == 0) {
        return;   // couldn't get a stack trace, or had no useful data  :-(
    }
    
    if (lineStrLength > 0) {
        out << " *** Stack trace (line numbers are approximate):" << std::endl;
        if (STACK_TRACE_SHOW_TOP_BOTTOM_BARS) {
            out << " *** "
                      << std::setw(lineStrLength) << std::left
                      << "file:line" << "  " << "function" << std::endl;
            out << " *** "
                      << std::string(lineStrLength + 2 + funcNameLength, '=') << std::endl;
        }
    } else {
        out << " *** Stack trace:" << std::endl;
    }
    
    for (size_t i = 0; i < entries.size(); ++i) {
        stacktrace::entry entry = entries[i];
        entry.file = getTail(entry.file);
        
        // skip certain entries for clarity
        if (STACK_TRACE_SHOULD_FILTER && shouldFilterOutFromStackTrace(entry.function)) {
            continue;
        }
        
        // show Main() as main() to hide hidden case-change by Stanford C++ lib internals
        if (startsWith(entry.function, "Main(")) {
            entry.function.replace(0, 5, "main(");
        }
        
        std::string lineStr = "";
        if (!entry.lineStr.empty()) {
            lineStr = entry.lineStr;
        } else if (entry.line > 0) {
            lineStr = "line " + integerToString(entry.line);
        }
        
        out << " *** " << std::left << std::setw(lineStrLength) << lineStr
                  << "  " << entry.function << std::endl;
        
        // don't show entries beneath the student's main() function, for simplicity
        if (entry.function == "main()") {
            break;
        }
    }
    if (entries.size() == 1 && entries[0].address == fakeStackPtr) {
        out << " *** (partial stack due to crash)" << std::endl;
    }

    if (STACK_TRACE_SHOW_TOP_BOTTOM_BARS && lineStrLength > 0) {
        out << " *** "
                  << std::string(lineStrLength + 2 + funcNameLength, '=') << std::endl;
    }
    
//    out << " ***" << std::endl;
//    out << " *** NOTE:" << std::endl;
//    out << " *** Any line numbers listed above are approximate." << std::endl;
//    out << " *** To learn more about why the program crashed, we" << std::endl;
//    out << " *** suggest running your program under the debugger." << std::endl;
    
    out << " ***" << std::endl;
}