#! /usr/bin/gawk -f # Last edited on 2003-10-12 12:30:42 by stolfi BEGIN { abort = -1; usage = ( "compare-grades \\\n" \ " [-v ignoreOld='M1,M2,...'] [-v ignoreNew='N1,N2...'] \\\n" \ " OLDFILE.iso NEWFILE.iso \\\n" \ " > medias-cook.iso" ); split("", igOld); # Indexed [1..nigOld] split("", igNew); # Indexed [1..nigNew] fileOld = ARGV[1]; fileNew = ARGV[2]; nigOld = parse_ignore_option(ignoreOld, igOld); nigNew = parse_ignore_option(ignoreNew, igNew); split("", nrOld); # Line number, indexed [ra] split("", nrNew); # Line number, indexed [ra] split("", nfOld); # Field count, indexed [ra] split("", nfNew); # Field count, indexed [ra] split("", fldOld); # Indexed [ra,1..nfOld[ra]] split("", fldNew); # Indexed [ra,1..nfNew[ra]] done = 0; nals = 58; read_grades(fileOld,nals, fldOld,nfOld,nrOld, nigOld,igOld); read_grades(fileNew,nals, fldNew,nfNew,nrNew, nigNew,igNew); for (ra in nrNew) { if (! (ra in nrOld)) { data_error(fileNew, nrNew[ra], ("extra new student " ra)); } } for (ra in nrOld) { if (! (ra in nrNew)) { data_error(fileOld, nrOld[ra], ("extra old student " ra)); } } for (ra in nrOld) { if (nfOld[ra] != nfNew[ra]) { data_error(fileOld, nrOld, ("inconsistent field count = " nfOld[ra])); data_error(fileNew, nrNew, ("inconsistent field count = " nfNew[ra])); } compare_fields(ra,nfOld[ra], nrOld,fldOld, nrNew,fldNew); } } function parse_ignore_option(string,ifld, nig,i,j,t) { # Parses a comma-separated list of field indices, puts result in `ifld', # and returns number of indices. nig = split(string, ifld, ","); for(i = 1; i < nig; i++) { for(j = i+1; j <= nig; j++) { if (ig[i] > ig[j]) { t = ig[i]; ig[i] = ig[j]; ig[j] = t; } } } return nig; } function read_grades(file,nals, fld,nf,nr, nig,ig, nlin,k,i,m,f,lin,nstuds) { # Reads lines from `file'. For each student with number `ra', stores # the line number in `nr[ra]', returns its fields in `fld[ra,k]', # and the field count in `nf[ra]'. Removes selected fields; the # indices of fields to ignore are `ig[1..nig]', in increasing order. nlin = 0; nstuds = 0; printf "reading %s...", file > "/dev/stderr"; while (getline lin < file) { if (ERRNO != "0") { break; } nlin++; if (abort >= 0) { exit abort; } if (lin ~ /^[ ]*([#]|$)/) { lin = ""; } if (lin != "") { nstuds++; m = split(lin, f); for (k = nig; k > 0; k--) { i = ig[k]; if ((i < 1) || (i > m)) { data_error(file, nlin, "bad ignore index"); } for (j = i; j < m; j++) { f[j] = f[j+1]; } m--; } ra = f[2]; nr[ra] = nlin; for(i = 1; i <= m; i++) { fld[ra,i] = f[i]; } nf[ra] = m; } } if (ERRNO != "0") { data_error(file, nlin, (": " ERRNO)); } close (file); printf "done (%d students)\n", nstuds > "/dev/stderr"; if (nlin == 0) { arg_error(("file \"" file "\" empty or missing")); } } function compare_fields(ra,nf, nrOld,fldOld,nrNew,fldNew, i,dif) { dif = 0; for (i = 1; i <= nf; i++) { if (fldOld[ra,i] != fldNew[ra,i]) { printf "%s: field %s = «%s» -> «%s»\n", ra, i, fldOld[ra,i], fldNew[ra,i] > "/dev/stderr"; dif = 1; } } if (dif) { dump_line(ra, fileOld, nrOld[ra], "<", nf,fldOld); dump_line(ra, fileNew, nrNew[ra], ">", nf,fldNew); printf "\n" > "/dev/stderr"; } } function dump_line(ra,file,nr,tag,nf,fld, i) { printf "%s %s", ra, tag > "/dev/stderr"; for(i = 1; i <= nf; i++) { printf " %s", fld[ra,i] > "/dev/stderr"; } printf "\n" > "/dev/stderr"; } function data_error(file, nlin, msg) { printf "%s:%d: ** %s\n", file, nlin, msg > "/dev/stderr"; abort = 1; exit abort; } function arg_error(msg) { printf "** %s\n", msg > "/dev/stderr"; printf "usage: %s\n", usage > "/dev/stderr"; abort = 1; exit abort; }