LINUX.ORG.RU

История изменений

Исправление firkax, (текущая версия) :

По-моему проще весь подобный изврат просто логировать как ошибки, ибо он однозначно вреден в любых необфусцированных исходниках. Все предыдущие случаи могли быть вполне реальными и уместными в коде. Но ладно, задача интересная как просто абстрактная теория. Вот:

/* (c) firk; feel free to use for anything */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

static char * wise_gets(char const * * eoln_type, unsigned long long * p_ln) {
  static char * buf;
  static size_t bs, bp, bl;
  static unsigned long long ln = 1;
  static int eof;
  size_t csz;
  ssize_t rsz;
  
  if(bp) {
    bl -= bp;
    if(bl) bcopy(buf+bp, buf, bl);
    bp = 0;
  }
  if(eof && !bl) return NULL;
  *p_ln = ln;
  while(1) {
    if(!eof) {
      if(bl==bs) {
        bs += 50 + bs/3;
        if(bs<=bl) { fprintf(stderr, "line %llu too long // out of memory\n", ln); exit(-1); }
        if(!buf) buf = malloc(bs); else buf = realloc(buf, bs);
        if(!buf) { fprintf(stderr, "line %llu too long // out of memory\n", ln); exit(-1); }
      }
      csz = bs-bl;
      if(((ssize_t)csz)<=0) csz/=2;
      while((rsz = read(0, buf+bl, csz))<0) if(errno!=EINTR) { fprintf(stderr, "error reading input at line %llu, error %d (%s)\n", ln, errno, strerror(errno)); rsz = 0; break; }
      if(!rsz) eof = 1; else bl += rsz;
    }
    for( ; bp<bl; bp++) {
      if(buf[bp]!='\n') continue;
      ln++;
      if(!bp) { buf[bp++] = 0; *eoln_type = "\n"; return buf; }
      if(buf[bp-1]=='\\') continue;
      if(buf[bp-1]!='\r') { buf[bp++] = 0; *eoln_type = "\n"; return buf; }
      if(bp==1 || buf[bp-2]!='\\') { buf[bp-1] = 0; bp++; *eoln_type = "\r\n"; return buf; }
    }
    if(eof) {
      assert(bl<bs); /* eof results from failed read() so bs-bl>0 */
      buf[bp] = 0; *eoln_type = NULL; return buf;
    }
  }
}

static void handle_line(char *b, char const *eoln, char const *def_eoln, char *pq, unsigned long ln, int warnq);

int main(int argc, char const * const * argv) {
  char q;
  unsigned long long ln;
  int warnq;
  char *b, *p;
  char const *eoln, *def_eoln;
  
  warnq = !(argc>=2 && !strcmp(argv[1],"--multistring"));
  def_eoln = "\n";
  q = 0;
  while(b=wise_gets(&eoln,&ln)) {
    if(eoln) def_eoln = eoln; else eoln = "";
    handle_line(b, eoln, def_eoln, &q, ln, warnq);
  }
  if(q=='/') fprintf(stderr, "warning: unterminated multiline comment at EOF (last line is %lu)\n", ln);
  else if(q) fprintf(stderr, "warning: unterminated quoted (%c) entity at EOF (last line is %lu)\n", q, ln);
  return 0;
}

static char * skip_eolns(char * b) {
  while(*b=='\\') {
    if(b[1]=='\n') { b+=2; continue; }
    if(b[1]=='\r' && b[2]=='\n') { b+=3; continue; }
    break;
  }
  return b;
}

static void handle_line(char *b, char const *eoln, char const *def_eoln, char *pq, unsigned long ln, int warnq) {
  size_t p, plen;
  char c, q;
  char q0;
  char *bb;
  
  for(p=0; (c=b[p])==' ' || c=='\t'; p++);
  plen = p;
  q = q0 = *pq;
  while(c = b[p]) {
    if(q=='/') {
      p++;
      if(c=='*' && *(bb=skip_eolns(b+p))=='/') { p = (bb-b)+1; q = 0; }
      continue;
    }
    if(q) {
      p++;
      if(c==q) q=0;
      else if(c=='\\') { if(b[p]) p++; }
      continue;
    }
    if(c=='\'' || c=='"') { q=c; p++; continue; }
    if(c=='/' && *(bb=skip_eolns(b+p+1))=='*') { q='/'; p=(bb-b)+1; continue; }
    if(c!='/' || *(bb=skip_eolns(b+p+1))!='/') { p++; continue; }
    /* found unquoted // */
    if(q0) {
      if(q0=='/') fprintf(stderr, "warning: can't safely reorder //-comment due to pending multiline-comment at line %lu beginning\n", ln);
      else fprintf(stderr, "warning: can't safely reorder //-comment due to pending quoted (%c) entity at line %lu beginning\n", q, ln);
      break;
    }
    /* here q0==0 && q==0 */
    if(plen) fwrite(b, 1, plen, stdout);
    fputs(b+p, stdout);
    fputs(def_eoln, stdout);
    while(p && (b[p-1]==' ' || b[p-1]=='\t')) p--;
    if(p) { fwrite(b, 1, p, stdout); fputs(eoln, stdout); }
    return;
  }
  /* found EOLN w/o // */
  fputs(b, stdout); fputs(eoln, stdout);
  *pq = q;
  if(warnq && q && q!='/') fprintf(stderr, "warning: unterminated quoted (%c) entity at line %lu\n", q, ln);
}

Поддерживается \, поддерживаются строки любой длины на какую хватит памяти и нормально обрабатываются все errno из чтения. Правда я бы потестировал этот код на всякий случай на всяких разных данных.

А да, ещё проблема - если на входе встретится \0 то строка с ним будет обрезана на выходе.

Исправление firkax, :

По-моему проще весь подобный изврат просто логировать как ошибки, ибо он однозначно вреден в любых необфусцированных исходниках. Все предыдущие случаи могли быть вполне реальными и уместными в коде. Но ладно, задача интересная как просто абстрактная теория. Вот:

/* (c) firk; feel free to use for anything */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

static char * wise_gets(char const * * eoln_type, unsigned long long * p_ln) {
  static char * buf;
  static size_t bs, bp, bl;
  static unsigned long long ln = 1;
  static int eof;
  size_t csz;
  ssize_t rsz;
  
  if(bp) {
    bl -= bp;
    if(bl) bcopy(buf+bp, buf, bl);
    bp = 0;
  }
  if(eof && !bl) return NULL;
  *p_ln = ln;
  while(1) {
    if(!eof) {
      if(bl==bs) {
        bs += 50 + bs/3;
        if(bs<=bl) { fprintf(stderr, "line %llu too long // out of memory\n", ln); exit(-1); }
        if(!buf) buf = malloc(bs); else buf = realloc(buf, bs);
        if(!buf) { fprintf(stderr, "line %llu too long // out of memory\n", ln); exit(-1); }
      }
      csz = bs-bl;
      if(((ssize_t)csz)<=0) csz/=2;
      while((rsz = read(0, buf+bl, csz))<0) if(errno!=EINTR) { fprintf(stderr, "error reading input at line %llu, error %d (%s)\n", ln, errno, strerror(errno)); rsz = 0; break; }
      if(!rsz) eof = 1; else bl += rsz;
    }
    for( ; bp<bl; bp++) {
      if(buf[bp]!='\n') continue;
      ln++;
      if(!bp) { buf[bp++] = 0; *eoln_type = "\n"; return buf; }
      if(buf[bp-1]=='\\') continue;
      if(buf[bp-1]!='\r') { buf[bp++] = 0; *eoln_type = "\n"; return buf; }
      if(bp==1 || buf[bp-2]!='\\') { buf[bp-1] = 0; bp++; *eoln_type = "\r\n"; return buf; }
    }
    if(eof) {
      assert(bl<bs); /* eof results from failed read() so bs-bl>0 */
      buf[bp] = 0; *eoln_type = NULL; return buf;
    }
  }
}

static void handle_line(char *b, char const *eoln, char const *def_eoln, char *pq, unsigned long ln, int warnq);

int main(int argc, char const * const * argv) {
  char q;
  unsigned long long ln;
  int warnq;
  char *b, *p;
  char const *eoln, *def_eoln;
  
  warnq = !(argc>=2 && !strcmp(argv[1],"--multistring"));
  def_eoln = "\n";
  q = 0;
  while(b=wise_gets(&eoln,&ln)) {
    if(eoln) def_eoln = eoln; else eoln = "";
    handle_line(b, eoln, def_eoln, &q, ln, warnq);
  }
  if(q=='/') fprintf(stderr, "warning: unterminated multiline comment at EOF (last line is %lu)\n", ln);
  else if(q) fprintf(stderr, "warning: unterminated quoted (%c) entity at EOF (last line is %lu)\n", q, ln);
  return 0;
}

static char * skip_eolns(char * b) {
  while(*b=='\\') {
    if(b[1]=='\n') { b+=2; continue; }
    if(b[1]=='\r' && b[2]=='\n') { b+=3; continue; }
    break;
  }
  return b;
}

static void handle_line(char *b, char const *eoln, char const *def_eoln, char *pq, unsigned long ln, int warnq) {
  size_t p, plen;
  char c, q;
  char q0;
  char *bb;
  
  for(p=0; (c=b[p])==' ' || c=='\t'; p++);
  plen = p;
  q = q0 = *pq;
  while(c = b[p]) {
    if(q=='/') {
      p++;
      if(c=='*' && *(bb=skip_eolns(b+p))=='/') { p = (bb-b)+1; q = 0; }
      continue;
    }
    if(q) {
      p++;
      if(c==q) q=0;
      else if(c=='\\') { if(b[p]) p++; }
      continue;
    }
    if(c=='\'' || c=='"') { q=c; p++; continue; }
    if(c=='/' && *(bb=skip_eolns(b+p+1))=='*') { q='/'; p=(bb-b)+1; continue; }
    if(c!='/' || *(bb=skip_eolns(b+p+1))!='/') { p++; continue; }
    /* found unquoted // */
    if(q0) {
      if(q0=='/') fprintf(stderr, "warning: can't safely reorder //-comment due to pending multiline-comment at line %lu beginning\n", ln);
      else fprintf(stderr, "warning: can't safely reorder //-comment due to pending quoted (%c) entity at line %lu beginning\n", q, ln);
      break;
    }
    /* here q0==0 && q==0 */
    if(plen) fwrite(b, 1, plen, stdout);
    fputs(b+p, stdout);
    fputs(def_eoln, stdout);
    while(p && (b[p-1]==' ' || b[p-1]=='\t')) p--;
    if(p) { fwrite(b, 1, p, stdout); fputs(eoln, stdout); }
    return;
  }
  /* found EOLN w/o // */
  fputs(b, stdout); fputs(eoln, stdout);
  *pq = q;
  if(warnq && q && q!='/') fprintf(stderr, "warning: unterminated quoted (%c) entity at line %lu\n", q, ln);
}

Поддерживается \, поддерживаются строки любой длины на какую хватит памяти и нормально обрабатываются все errno из чтения. Правда я бы потестировал этот код на всякий случай на всяких разных данных.

Исходная версия firkax, :

По-моему проще весь подобный изврат просто логировать как ошибки, ибо он однозначно вреден в любых необфусцированных исходниках. Все предыдущие случаи могли быть вполне реальными и уместными в коде. Но ладно, задача интересная как просто абстрактная теория. Вот:

/* (c) firk; feel free to use for anything */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

static char * wise_gets(char const * * eoln_type, unsigned long long * p_ln) {
  static char * buf;
  static size_t bs, bp, bl;
  static unsigned long long ln = 1;
  static int eof;
  size_t csz;
  ssize_t rsz;
  
  if(bp) {
    bl -= bp;
    if(bl) bcopy(buf+bp, buf, bl);
    bp = 0;
  }
  if(eof && !bl) return NULL;
  *p_ln = ln;
  while(1) {
    if(!eof) {
      if(bl==bs) {
        bs += 50 + bs/3;
        if(bs<=bl) { fprintf(stderr, "line %llu too long // out of memory\n", ln); exit(-1); }
        if(!buf) buf = malloc(bs); else buf = realloc(buf, bs);
        if(!buf) { fprintf(stderr, "line %llu too long // out of memory\n", ln); exit(-1); }
      }
      csz = bs-bl;
      if(((ssize_t)csz)<=0) csz/=2;
      while((rsz = read(0, buf+bl, csz))<0) if(errno!=EINTR) { fprintf(stderr, "error reading input at line %llu, error %d (%s)\n", ln, errno, strerror(errno)); rsz = 0; break; }
      if(!rsz) eof = 1; else bl += rsz;
    }
    for( ; bp<bl; bp++) {
      if(buf[bp]!='\n') continue;
      ln++;
      if(!bp) { buf[bp++] = 0; *eoln_type = "\n"; return buf; }
      if(buf[bp-1]=='\\') continue;
      if(buf[bp-1]!='\r') { buf[bp++] = 0; *eoln_type = "\n"; return buf; }
      if(bp==1 || buf[bp-2]!='\\') { buf[bp-1] = 0; bp++; *eoln_type = "\r\n"; return buf; }
    }
    if(eof) {
      assert(bl<bs); /* eof results from failed read() so bs-bl>0 */
      buf[bp] = 0; *eoln_type = NULL; return buf;
    }
  }
}

static void handle_line(char *b, char const *eoln, char const *def_eoln, char *pq, unsigned long ln, int warnq);

int main(int argc, char const * const * argv) {
  char q;
  unsigned long long ln;
  int warnq;
  char *b, *p;
  char const *eoln, *def_eoln;
  
  warnq = !(argc>=2 && !strcmp(argv[1],"--multistring"));
  def_eoln = "\n";
  q = 0;
  while(b=wise_gets(&eoln,&ln)) {
    if(eoln) def_eoln = eoln; else eoln = "";
    handle_line(b, eoln, def_eoln, &q, ln, warnq);
  }
  if(q=='/') fprintf(stderr, "warning: unterminated multiline comment at EOF (last line is %lu)\n", ln);
  else if(q) fprintf(stderr, "warning: unterminated quoted (%c) entity at EOF (last line is %lu)\n", q, ln);
  return 0;
}

static char * skip_eolns(char * b) {
  while(*b=='\\') {
    if(b[1]=='\n') { b+=2; continue; }
    if(b[1]=='\r' && b[2]=='\n') { b+=3; continue; }
    break;
  }
  return b;
}

static void handle_line(char *b, char const *eoln, char const *def_eoln, char *pq, unsigned long ln, int warnq) {
  size_t p, plen;
  char c, q;
  char q0;
  char *bb;
  
  for(p=0; (c=b[p])==' ' || c=='\t'; p++);
  plen = p;
  q = q0 = *pq;
  while(c = b[p]) {
    if(q=='/') {
      p++;
      if(c=='*' && *(bb=skip_eolns(b+p))=='/') { p = (bb-b)+1; q = 0; }
      continue;
    }
    if(q) {
      p++;
      if(c==q) q=0;
      else if(c=='\\') { if(b[p]) p++; }
      continue;
    }
    if(c=='\'' || c=='"') { q=c; p++; continue; }
    if(c=='/' && *(bb=skip_eolns(b+p+1))=='*') { q='/'; p=(bb-b)+1; continue; }
    if(c!='/' || *(bb=skip_eolns(b+p+1))!='/') { p++; continue; }
    /* found unquoted // */
    if(q0) {
      if(q0=='/') fprintf(stderr, "warning: can't safely reorder //-comment due to pending multiline-comment at line %lu beginning\n", ln);
      else fprintf(stderr, "warning: can't safely reorder //-comment due to pending quoted (%c) entity at line %lu beginning\n", q, ln);
      break;
    }
    /* here q0==0 && q==0 */
    if(plen) fwrite(b, 1, plen, stdout);
    fputs(b+p, stdout);
    fputs(def_eoln, stdout);
    while(p && (b[p-1]==' ' || b[p-1]=='\t')) p--;
    if(p) { fwrite(b, 1, p, stdout); fputs(eoln, stdout); }
    return;
  }
  /* found EOLN w/o // */
  fputs(b, stdout); fputs(eoln, stdout);
  *pq = q;
  if(warnq && q && q!='/') fprintf(stderr, "warning: unterminated quoted (%c) entity at line %lu\n", q, ln);
}

Поддерживается \, поддерживаются строки любой длины на какую хватит памяти и нормально обрабатываются все errno из чтения. Правда я бы потестировал этот код на всякий случай на всяких разных данных на всякий случай.