/* Copyright (C) 2004 * Andy Goth * * This code is available under the GNU General Public License; see COPYING. */ #include #include #include #define I2H(i) ((i) < 10 ? (i) + '0' - 0x0 : (i) + 'a' - 0xa) #define H2D(c) ((c) >= '0' && (c) <= '9' ? (c) + 0x0 - '0' : \ (c) >= 'a' && (c) <= 'f' ? (c) + 0xa - 'a' : \ (c) >= 'A' && (c) <= 'F' ? (c) + 0xa - 'A' : 0) #define LITERALS ",./':1234567890-=_+|!#$^\n" \ "abcdefghijklmnopqrstuvwxyz" \ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" int main(int argc, char** argv) { int reverse; int i, ret; int state = 0, accum; unsigned char c, buf[4096], prev[3]; /* The world's dumbest option scanner. :^) */ switch (argc) { case 1: reverse = 0; break; case 2: reverse = 1; break; default: fprintf(stderr, "Usage: urlesc [-r]\n"); return EXIT_SUCCESS; } while (1) { ret = read(0, buf, 4096); if (ret == -1) { perror("read"); return EXIT_FAILURE; } else if (ret == 0) { return EXIT_SUCCESS; } else { /* Fall through. */ } for (i = 0; i < ret; ++i) { c = buf[i]; if (reverse) { if (state == 0) { if (c == '%') { prev[0] = '%'; state = 1; accum = 0; } else { write(1, &c, 1); } } else { prev[state] = c; if (isxdigit(c)) { ++state; accum = accum * 16 + H2D(c); if (state == 3) { c = accum; write(1, &c, 1); state = 0; } } else if (c == '%') { write(1, &prev, state); prev[0] = '%'; state = 1; accum = 0; } else { write(1, &prev, state + 1); state = 0; } } } else { if (strchr(LITERALS, c) == NULL) { prev[0] = '%'; prev[1] = I2H(c / 16); prev[2] = I2H(c % 16); write(1, &prev, 3); } else { write(1, &c, 1); } } } } return EXIT_SUCCESS; } /* vim: set ts=4 sts=4 sw=4 tw=80 et: */