#include #include "lesstest.h" extern int verbose; // Return the interior string of a quoted string. static char* parse_qstring(const char** s) { while (*(*s) == ' ') ++(*s); if (*(*s)++ != '"') return NULL; const char* start = *s; while (*(*s) != '"' && *(*s) != '\0') ++(*s); char* ret = strndup(start, (*s)-start); if (*(*s) == '"') ++(*s); return ret; } static int parse_int(const char** s) { return (int) strtol(*s, (char**)s, 0); } // Parse a quoted name and value, // and add them as env vars to the Setup environment. static int parse_env(TestSetup* setup, const char* line, int line_len) { char* name = parse_qstring(&line); char* value = parse_qstring(&line); env_addpair(&setup->env, name, value); free(name); free(value); return 1; } static int parse_command(TestSetup* setup, const char* less, const char* line, int line_len) { setup->argv = (char**) malloc(32*sizeof(const char*)); setup->argc = 1; setup->argv[0] = (char*) less; for (;;) { const char* arg = parse_qstring(&line); setup->argv[setup->argc] = (char*) arg; if (arg == NULL) break; setup->argc++; } return 1; } static int parse_textfile(TestSetup* setup, const char* line, int line_len, FILE* fd) { const char* filename = parse_qstring(&line); if (access(filename, F_OK) == 0) { fprintf(stderr, "%s already exists\n", filename); return 0; } int fsize = parse_int(&line); int len = strlen(filename)+1; setup->textfile = malloc(len); strcpy(setup->textfile, filename); FILE* textfd = fopen(setup->textfile, "w"); if (textfd == NULL) { fprintf(stderr, "cannot create %s\n", setup->textfile); return 0; } int nread = 0; while (nread < fsize) { char buf[4096]; int chunk = fsize - nread; if (chunk > sizeof(buf)) chunk = sizeof(buf); size_t len = fread(buf, 1, chunk, fd); fwrite(buf, 1, len, textfd); nread += len; } fclose(textfd); return 1; } static TestSetup* new_test_setup(void) { TestSetup* setup = (TestSetup*) malloc(sizeof(TestSetup)); setup->textfile = NULL; setup->argv = NULL; setup->argc = 0; env_init(&setup->env); return setup; } void free_test_setup(TestSetup* setup) { if (setup->textfile != NULL) { unlink(setup->textfile); free(setup->textfile); } int i; for (i = 1; i < setup->argc; ++i) free(setup->argv[i]); free((void*)setup->argv); free(setup); } // Read a newline-terminated line from a file and store it // as a null-terminated string without the newline. int read_zline(FILE* fd, char* line, int line_len) { int nread = 0; while (nread < line_len-1) { int ch = fgetc(fd); if (ch == EOF) return -1; if (ch == '\n') break; line[nread++] = (char) ch; } line[nread] = '\0'; return nread; } // Read the header of a .lt file (up to the R line). TestSetup* read_test_setup(FILE* fd, const char* less) { TestSetup* setup = new_test_setup(); int hdr_complete = 0; while (!hdr_complete) { char line[10000]; int line_len = read_zline(fd, line, sizeof(line)); if (line_len < 0) break; if (line_len < 1) continue; switch (line[0]) { case '!': // file header break; case 'T': // test header break; case 'R': // end of test header; start run hdr_complete = 1; break; case 'E': // environment variable if (!parse_env(setup, line+1, line_len-1)) { free_test_setup(setup); return NULL; } break; case 'F': // text file if (!parse_textfile(setup, line+1, line_len-1, fd)) { free_test_setup(setup); return NULL; } break; case 'A': // less cmd line parameters if (!parse_command(setup, less, line+1, line_len-1)) { free_test_setup(setup); return NULL; } break; default: break; } } if (setup->textfile == NULL || setup->argv == NULL) { free_test_setup(setup); return NULL; } if (verbose) { fprintf(stderr, "setup: textfile %s\n", setup->textfile); print_strings("argv:", setup->argv); } return setup; }