void free_cond(struct cond *c) { if (c == NULL) return; switch (c->type) { case C_AND: case C_OR: free_cond(c->data.conds.c2); case C_NOT: free_cond(c->data.conds.c1); break; case C_EQ: case C_NEQ: free_expr(c->data.exprs.e1); free_expr(c->data.exprs.e2); break; default: break; } free(c); }
/* * Remove the bang operator from a condition to avoid priority problems. * "!" has different priorities as "test" command argument and in * a tk script. */ static struct condition * remove_bang( struct condition * condition ) { struct condition * conda, * condb, * prev = NULL; for ( conda = condition; conda; conda = conda->next ) { if ( conda->op == op_bang && conda->next && ( condb = conda->next->next ) ) { if ( condb->op == op_eq || condb->op == op_neq ) { condb->op = (condb->op == op_eq) ? op_neq : op_eq; conda->op = op_nuked; if ( prev ) { prev->next = conda->next; } else { condition = conda->next; } conda->next = NULL; free_cond( conda ); conda = condb; } } prev = conda; } return condition; }
/* * Eliminating conditions with ARCH = <not current>. */ static struct condition *eliminate_other_arch( struct condition *list ) { struct condition *cond1a = list, *cond1b = NULL, *cond1c = NULL, *cond1d = NULL; if ( current_arch == NULL ) current_arch = getenv( "ARCH" ); if ( current_arch == NULL ) { fprintf( stderr, "error: ARCH undefined\n" ); exit( 1 ); } if ( cond1a->op == op_variable && ! strcmp( vartable[cond1a->nameindex].name, "ARCH" ) ) { cond1b = cond1a->next; if ( cond1b == NULL ) goto done; cond1c = cond1b->next; if ( cond1c == NULL ) goto done; cond1d = cond1c->next; if ( cond1c->op == op_constant && cond1d == NULL ) { if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch )) || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) ) { /* This is for another architecture */ cond1a->op = op_false; cond1a->next = NULL; free_cond( cond1b ); return cond1a; } else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch )) || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) ) { /* This is for current architecture */ cond1a->op = op_true; cond1a->next = NULL; free_cond( cond1b ); return cond1a; } } else if ( cond1c->op == op_constant && cond1d->op == op_or ) { if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch )) || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) ) { /* This is for another architecture */ cond1b = cond1d->next; cond1d->next = NULL; free_cond( cond1a ); return eliminate_other_arch( cond1b ); } else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch )) || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) ) { /* This is for current architecture */ cond1a->op = op_true; cond1a->next = NULL; free_cond( cond1b ); return cond1a; } } else if ( cond1c->op == op_constant && cond1d->op == op_and ) { if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch )) || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) ) { /* This is for another architecture */ int l_par = 0; for ( cond1c = cond1d->next; cond1c; cond1c = cond1c->next ) { if ( cond1c->op == op_lparen ) l_par++; else if ( cond1c->op == op_rparen ) l_par--; else if ( cond1c->op == op_or && l_par == 0 ) /* Expression too complex - don't touch */ return cond1a; else if ( l_par < 0 ) { fprintf( stderr, "incorrect condition: programming error ?\n" ); exit( 1 ); } } cond1a->op = op_false; cond1a->next = NULL; free_cond( cond1b ); return cond1a; } else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch )) || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) ) { /* This is for current architecture */ cond1b = cond1d->next; cond1d->next = NULL; free_cond( cond1a ); return eliminate_other_arch( cond1b ); } } } if ( cond1a->op == op_variable && ! vartable[cond1a->nameindex].defined ) { cond1b = cond1a->next; if ( cond1b == NULL ) goto done; cond1c = cond1b->next; if ( cond1c == NULL ) goto done; cond1d = cond1c->next; if ( cond1c->op == op_constant && ( cond1d == NULL || cond1d->op == op_and ) ) /*???*/ { if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) ) { cond1a->op = op_false; cond1a->next = NULL; free_cond( cond1b ); return cond1a; } } else if ( cond1c->op == op_constant && cond1d->op == op_or ) { if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) ) { cond1b = cond1d->next; cond1d->next = NULL; free_cond( cond1a ); return eliminate_other_arch( cond1b ); } } } done: return list; }
int32_t main(int32_t argc, char** argv) { FILE* infile = NULL; char* outname = NULL; uintptr_t column_sep = 2; uint32_t flags = 0; int32_t retval = 0; uintptr_t* col_widths = NULL; unsigned char* spacebuf = NULL; unsigned char* rjustify_buf = NULL; uintptr_t col_ct = 0; uint32_t infile_param_idx = 0; char* param_ptr; #ifndef _WIN32 char* cptr; #endif uint32_t param_idx; uint32_t uii; int32_t ii; char cc; if (argc == 1) { goto main_ret_HELP; } for (param_idx = 1; param_idx < (uint32_t)argc; param_idx++) { if ((!strcmp(argv[param_idx], "--help")) || (!strcmp(argv[param_idx], "-help")) || (!strcmp(argv[param_idx], "-?")) || (!strcmp(argv[param_idx], "-h"))) { goto main_ret_HELP; } } if (argc > 10) { fputs("Error: Too many parameters.\n\n", stderr); goto main_ret_INVALID_CMDLINE_2; } for (param_idx = 1; param_idx < (uint32_t)argc; param_idx++) { if (argv[param_idx][0] != '-') { if (!infile_param_idx) { infile_param_idx = param_idx; } else if (!outname) { if (flags & FLAG_INPLACE) { goto main_ret_INVALID_CMDLINE_3; } outname = argv[param_idx]; } else { fputs("Error: Invalid parameter sequence.\n\n", stderr); goto main_ret_INVALID_CMDLINE_2; } continue; } param_ptr = &(argv[param_idx][1]); if (*param_ptr == '-') { // allow both single- and double-dash param_ptr++; } if (!strcmp(param_ptr, "inplace")) { if (outname) { goto main_ret_INVALID_CMDLINE_3; } flags |= FLAG_INPLACE; } else if ((!strcmp(param_ptr, "spacing")) || (!strcmp(param_ptr, "s"))) { if (++param_idx == (uint32_t)argc) { fputs("Error: Missing --spacing parameter.\n", stderr); goto main_ret_INVALID_CMDLINE; } ii = atoi(argv[param_idx]); if (ii < 1) { fprintf(stderr, "Error: Invalid --spacing parameter '%s'.\n", argv[param_idx]); goto main_ret_INVALID_CMDLINE; } column_sep = (uint32_t)ii; } else if (!strcmp(param_ptr, "ralign")) { flags |= FLAG_RJUSTIFY; } else if (!strcmp(param_ptr, "leading")) { flags |= FLAG_SPACES_BEFORE_FIRST; } else if (!strcmp(param_ptr, "extend-short")) { flags |= FLAG_PAD; } else if (!strcmp(param_ptr, "trailing")) { flags |= FLAG_SPACES_AFTER_LAST; } else if (!strcmp(param_ptr, "force-eoln")) { flags |= FLAG_FINAL_EOLN; } else if (!strcmp(param_ptr, "noblank")) { flags |= FLAG_STRIP_BLANK; } else { if ((argv[param_idx][1] != '-') && argv[param_idx][1]) { // permit abbreviated style while (1) { cc = *param_ptr++; if (!cc) { break; } switch (cc) { case 'i': if (outname) { goto main_ret_INVALID_CMDLINE_3; } flags |= FLAG_INPLACE; break; case 'r': flags |= FLAG_RJUSTIFY; break; case 'l': flags |= FLAG_SPACES_BEFORE_FIRST; break; case 'e': flags |= FLAG_PAD; break; case 't': flags |= FLAG_SPACES_AFTER_LAST; break; case 'f': flags |= FLAG_FINAL_EOLN; break; case 'n': flags |= FLAG_STRIP_BLANK; break; default: fprintf(stderr, "Error: Invalid flag '%s'.\n\n", argv[param_idx]); goto main_ret_INVALID_CMDLINE_2; } } } else { fprintf(stderr, "Error: Invalid flag '%s'.\n\n", argv[param_idx]); goto main_ret_INVALID_CMDLINE_2; } } } if (!infile_param_idx) { fputs("Error: No input filename.\n\n", stderr); goto main_ret_INVALID_CMDLINE_2; } if (flags & FLAG_INPLACE) { uii = strlen(argv[infile_param_idx]); outname = (char*)malloc(uii + 11); if (!outname) { goto main_ret_NOMEM; } memcpy(outname, argv[infile_param_idx], uii); memcpy(&(outname[uii]), "-temporary", 11); } else if (outname) { #ifdef _WIN32 uii = GetFullPathName(argv[infile_param_idx], FNAMESIZE, pathbuf, NULL); if ((!uii) || (uii > FNAMESIZE)) #else if (!realpath(argv[infile_param_idx], pathbuf)) #endif { fprintf(stderr, "Error: Failed to open %s.\n", argv[infile_param_idx]); goto main_ret_OPEN_FAIL; } #ifdef _WIN32 uii = GetFullPathName(outname, FNAMESIZE, &(pathbuf[FNAMESIZE + 64]), NULL); if (uii && (uii <= FNAMESIZE) && (!strcmp(pathbuf, &(pathbuf[FNAMESIZE + 64])))) #else cptr = realpath(outname, &(pathbuf[FNAMESIZE + 64])); if (cptr && (!strcmp(pathbuf, &(pathbuf[FNAMESIZE + 64])))) #endif { fputs("Error: Input and output files match. Use --inplace instead.\n", stderr); goto main_ret_INVALID_CMDLINE; } } if (fopen_checked(&infile, argv[infile_param_idx], "rb")) { goto main_ret_OPEN_FAIL; } retval = scan_column_widths(infile, column_sep, &col_widths, &col_ct, &spacebuf, (flags & FLAG_RJUSTIFY)? (&rjustify_buf) : NULL); if (retval) { goto main_ret_1; } retval = pretty_write(infile, outname, flags, column_sep, col_widths, col_ct, spacebuf, rjustify_buf); if (retval) { goto main_ret_1; } fclose_null(&infile); if (flags & FLAG_INPLACE) { unlink(argv[infile_param_idx]); if (rename(outname, argv[infile_param_idx])) { fprintf(stderr, "Error: File rename failed. Output is in %s instead of %s.\n", outname, argv[infile_param_idx]); goto main_ret_OPEN_FAIL; } } while (0) { main_ret_HELP: fputs( "prettify v1.04 (21 Feb 2014) Christopher Chang ([email protected])\n\n" "Takes a tab-and/or-space-delimited text table, and generates a space-delimited\n" "pretty-printed version. Multibyte character encodings are not currently\n" "supported.\n\n" , stdout); disp_usage(stdout); fputs( "\nTo perform the simplest reverse conversion (multiple spaces to one tab), you\n" "can use\n" " cat [input filename] | tr -s ' ' '\\t' > [output filename]\n" "For one-to-one conversion between spaces and tabs instead, omit the \"-s\". And\n" "to strip leading and trailing tabs and spaces, try\n" " cat [in] | sed 's/^[[:space:]]*//g' | sed 's/[[:space:]]*$//g' > [out]\n" , stdout); retval = RET_HELP; break; main_ret_NOMEM: retval = RET_NOMEM; break; main_ret_OPEN_FAIL: retval = RET_OPEN_FAIL; break; main_ret_INVALID_CMDLINE_3: fputs("Error: --inplace cannot be used with an output filename.\n", stderr); retval = RET_INVALID_CMDLINE; break; main_ret_INVALID_CMDLINE_2: disp_usage(stderr); main_ret_INVALID_CMDLINE: retval = RET_INVALID_CMDLINE; break; } main_ret_1: free_cond(col_widths); fclose_cond(infile); dispmsg(retval); return retval; }