/* src.c WJ100 */ #include #include #include #define COL_END "\x1b[33;1m" #define COL_TOKEN "\x1b[0;1m" #define COL_KEYWORD "\x1b[0;1m" #define COL_FUNC "\x1b[0;1m" #define COL_QUOTE "\x1b[0;1m" #define COL_STRING "\x1b[32;1m" #define COL_COMMENT "\x1b[35;1m" #define COL_DIRECTIVE "\x1b[32;1m" #define COL_WEIRDCHAR "\x1b[31;1m" #define COL_HEX "\x1b[31;1m" #define COL_OCTAL "\x1b[35;1m" #define COL_NUMBER "\x1b[36;1m" char *c_keywords[] = { "typedef", "struct", "union", "void", "int", "char", "long", "signed", "unsigned", "const", "volatile", "static", "extern", "if", "else", "while", "for", "switch", "case", "default", "break", "return", NULL }; char *c_funcs[] = { "main", "printf", "fprintf", "sprintf", "vprintf", "vfprintf", "vsprintf", "scanf", "sscanf", "fscanf", "vscanf", "vfscanf", "vsscanf", "malloc", "free", "strcpy", "strdup", "strcat", "strncpy", "strncat", "strcmp", "stricmp", "strcasecmp", "strncmp", "strnicmp", "strncasecmp", "strchr", "strrchr", "index", "rindex", "strstr", "strspn", "strtok", "memcpy", "memset", "bzero", "atoi", "atol", "strtoul", "min", "max", "fopen", "fclose", "fread", "fwrite", "fgets", "fgetc", "fputc", "putc", "getc", "getch", "puts", "gets", "open", "close", "read", "write", "dup", "dup2", "ioctl", "fcntl", "time", "localtime", "gmtime", "ctime", "strftime", "stat", "fstat", "lstat", "socket", "bind", "connect", "listen", "perror", "strerror", /* variables */ "errno", "NULL", /* types */ "size_t", "mode_t", "time_t", "socklen_t", NULL }; int in_comment = 0, in_string = 0, in_quote = 0, in_directive = 0, in_function = 0; void print_color(char *color) { if (in_comment || in_string || in_directive) return; printf("%s", color); } int in_array(char *buf, char **arr) { int i; for(i = 0; arr[i] != NULL; i++) { if (!strcmp(buf, arr[i])) return 1; } return 0; } int is_keyword(char *buf) { return in_array(buf, c_keywords); } int is_func(char *buf) { return in_array(buf, c_funcs); } int is_hexnumber(char *buf) { if (*buf == '0') buf++; else return 0; if (*buf == 'x') buf++; else return 0; if (!*buf) return 0; while(*buf) { if (strchr("0123456789abcdefABCDEF", *buf) == NULL) { if (*buf == 'u' || *buf == 'U') buf++; if (*buf == 'l' || *buf == 'L') buf++; if (!*buf) return 1; return 0; } buf++; } return 1; } int is_octalnumber(char *buf) { if (*buf != '0') return 0; buf++; if (!*buf) return 0; while(*buf) { if (strchr("01234567", *buf) == NULL) { if (*buf == 'u' || *buf == 'U') buf++; if (*buf == 'l' || *buf == 'L') buf++; if (!*buf) return 1; return 0; } buf++; } return 1; } int is_number(char *buf) { if (!*buf || strchr("0123456789", *buf) == NULL) return 0; /* the extensive check for '0' or '0[UL]' is needed for octal numbers... if the number is '0123', it is an octal number */ if (*buf == '0') { buf++; if (!*buf) return 1; else { if (*buf == 'u' || *buf == 'U') { buf++; if (!*buf) return 1; } if (*buf == 'l' || *buf == 'L') { buf++; if (!*buf) return 1; } return 0; } } while(*buf) { if (strchr("0123456789", *buf) == NULL) { if (*buf == 'u' || *buf == 'U') buf++; if (*buf == 'l' || *buf == 'L') buf++; if (!*buf) return 1; return 0; } buf++; } return 1; } char *my_strtok(char *str, char *delim) { while(*str) { if (strchr(delim, *str) != NULL) return str; str++; } return NULL; } void color_src(char *filename) { char buf[256], *p, last_token = 0, *endp, kar; int end_color = 0, was_comment = 0; FILE *f; if ((f = fopen(filename, "r")) == NULL) { fprintf(stderr, "failed to open file '%s'\n", filename); return; } printf("\n" "/*** --8<-- %s --8<-- ***/\n" "\n", filename); while(fgets(buf, 256, f) != NULL) { p = buf; while(*p) { if (!in_comment) { if ((p == buf || strchr(" \t-=~!%^&*()+|{}[]:;<>,.?/", last_token) != NULL) && (endp = my_strtok(p, " \t-=~!%^&*()+|{}[]:;<>,.?/")) != NULL) { kar = *endp; *endp = 0; if (*p) { if (is_keyword(p)) { print_color(COL_KEYWORD); printf("%s", p); print_color(COL_END); *endp = kar; p = endp; continue; } if (is_func(p)) { print_color(COL_FUNC); printf("%s", p); print_color(COL_END); *endp = kar; p = endp; continue; } if (is_number(p)) { print_color(COL_NUMBER); printf("%s", p); print_color(COL_END); *endp = kar; p = endp; continue; } if (is_hexnumber(p)) { print_color(COL_HEX); printf("%s", p); print_color(COL_END); *endp = kar; p = endp; continue; } if (is_octalnumber(p)) { print_color(COL_OCTAL); printf("%s", p); print_color(COL_END); *endp = kar; p = endp; continue; } } *endp = kar; } } switch(*p) { case '\\': printf("%c", *p); p++; break; case '\'': if (in_string || in_comment) break; if (in_quote) { in_quote--; end_color = 1; } else { print_color(COL_QUOTE); in_quote++; } break; case '"': if (in_quote) break; if (in_string) { if (last_token != '\\') { in_string--; end_color = 1; } } else { print_color(COL_STRING); in_string++; } break; case '/': if (!in_string && !in_quote && p[1] == '*') { print_color(COL_COMMENT); in_comment++; } if (!in_comment && was_comment) { was_comment = 0; end_color = 1; } break; case '*': if (!in_string && !in_quote) { if (in_comment) { if (p[1] == '/') { in_comment--; if (!in_comment) was_comment = 1; } } else { print_color(COL_TOKEN); end_color = 1; } } break; case '#': if (!in_string && !in_quote) { print_color(COL_DIRECTIVE); in_directive++; } break; /* case '{': if (!in_string && !in_quote) in_function++; break; case '}': if (!in_string && !in_quote) in_function--; break; */ case '\t': *p = ' '; printf(" "); break; default: if (*p < ' ' && *p != '\r' && *p != '\n' && *p != '\t') { print_color(COL_WEIRDCHAR); printf("[%02x", *p); *p = ']'; end_color = 1; break; } if (in_string || in_quote) break; if (strchr("-=~!%^&*()+|{}[]:;<>,.?/", *p) != NULL) { print_color(COL_TOKEN); end_color = 1; } } last_token = *p; if (*p) { printf("%c", *p); p++; } if (end_color) { print_color(COL_END); end_color = 0; } } if (in_directive && last_token != '\\') { in_directive = 0; print_color(COL_END); } if (in_string && last_token != '\\') { in_string = 0; print_color(COL_END); } if (!in_comment && !in_string && !in_directive) print_color(COL_END); /* --More-- prompt line_num++; if (line_num > 22) { printf("--More--"); fflush(stdout); if (fgets(buf, 4096, stdin) == NULL) break; if (!strcmp(buf, "q") || !strcmp(buf, "Q")) break; line_num = 0; } */ } fclose(f); } int main(int argc, char **argv) { int i; if (argc <= 1) { fprintf(stderr, "usage: src \n" "Example: src hello.c | less -r\n"); return 1; } for(i = 1; i < argc; i++) color_src(argv[i]); return 0; } /* EOB */