いまやってる仕事は、前にも書いたがNECのEWS4800向けのプログラムのLinuxへの移植である。余談だが、オリジナルソースはSVR4.0がベースの頃のAPI+K&Rな記述+(まえにも書いた通り)へぼいコード+MotifのコードはNECが独自に日本語化した頃の等々、直さないとダメな所が多すぎる(もっとヤバイトコロもあるのだが、それは書かない)。まぁ、これは愚痴なんで今回の話題と関係無い。が、関連しているとも言える。

共有ライブラリがけっこう沢山あるのだが、少ないヤツはソースは1〜3本で普通だ。が、多いのは100本軽く超えている。で、Makefileの書き方が気に入らないので書きなおしていたんだが(って言うか新規に書いていた)か根負けした。あとただでさえ本数が多いソースのティレクトリに、さらに実験用コードやスタブやらドライバやらのソースまであるからグチャグチャ。

って事で、以下の2本のツールをでっち上げた。30分ほど時間を取られたが、あとの作業が楽になったので良かった(雑記書いているよりは有効な時間である(笑))。

  1. オリジナルのMakefileを読んで必要なソースファイルだけコピーする。
  2. カレントディレクトリのソースファイルを調べてMakefileの雛型作成。

2の方は、昔makemakeとかゆーツールを使った事があったんだが、いま使ってる環境に無かったんで作った。本筋じゃないトコロでつい力が入ってしまった(1方向リストライブラリだ)。

以下、そのソース。POSIX準拠な環境+ANSI-Cだったらどれでもコンパイルできると想う。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TOKENSTR " \t\n\\"


int main( int argc, char **argv )
{
  static char  buf[BUFSIZ];
         FILE *fp;
         int   inSRC = 0;


  if ( argc != 3 ) {
    fprintf( stderr, "%s srcdir dstdir\n", argv[0] );
    return EXIT_FAILURE;
  }

  snprintf( buf, BUFSIZ, "%s/makefile", argv[1] );
  fp = fopen( buf, "r" );
  if ( fp == NULL ) {
    fprintf( stderr, "fopen(\"%s\")\n", buf );
    return EXIT_FAILURE;
  }

  while ( fgets(buf,BUFSIZ,fp) ) {
    char *token;

    token = strtok( buf, TOKENSTR );
    while ( token ) {
      if ( inSRC == 1 && strcmp(token,"$(END)") == 0 ) {
        inSRC = 0;
      }

      if ( inSRC == 1 ) {
        static char cmd[BUFSIZ];

        snprintf( cmd, BUFSIZ, "cp %s/%s %s", argv[1], token, argv[2] );
        puts( cmd );
        system( cmd );
      }

      if ( memcmp(token,"SRC",3) == 0 ) {
        inSRC = 1;
      }
      token = strtok( NULL, TOKENSTR );
    }
  }
  fclose( fp );

  return EXIT_SUCCESS;
}


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <dirent.h>

#if 0
#include "list.h"
#else
typedef struct {
    int    max;
    int    cnt;
    int    idx;
    char **lst;
} LIST;

#define SORT_ASC 1
#define SORT_DES 0

void  listInitialize( LIST * );
void  listDelete( LIST * );
int   listAddItem( LIST *, char * );
char *listGetItem( LIST * );
void  listRewind( LIST * );
void  listSort( LIST *, int );
#endif
#define EXTNTSZ 8


static int listExtent( LIST *list )
{
    char **tmp;


    if ( list == NULL ) {
        return EXIT_FAILURE;
    }

    tmp = (char **)calloc( sizeof(char **), list->max + EXTNTSZ );
    if ( tmp == NULL ) {
        return EXIT_FAILURE;
    }

    /* list->cnt == list->max に依存 */
    for ( list->cnt = 0; list->cnt < list->max; list->cnt++ ) {
        tmp[list->cnt] = list->lst[list->cnt];
    }
    if ( list->lst ) {
        free( list->lst );
    }

    list->lst  = tmp;
    list->max += EXTNTSZ;

    return EXIT_SUCCESS;
}

void listInitialize( LIST *list )
{
    if ( list == NULL ) {
        return;
    }
    list->max = 0;
    list->cnt = 0;
    list->idx = 0;
    list->lst = NULL;

    return;
}

void listDelete( LIST *list )
{
    if ( list == NULL ) {
        return;
    }

    for ( list->idx = 0; list->idx < list->cnt; list->idx++ ) {
        free( list->lst[list->idx] );
    }
    free( list->lst );

    list->max = 0;
    list->cnt = 0;
    list->idx = 0;
    list->lst = NULL;
}

int listAddItem( LIST *list, char *item )
{
    if ( list == NULL ) {
        return EXIT_FAILURE;
    }

    if ( list->cnt == list->max ) {
        if ( listExtent(list) == EXIT_FAILURE ) {
            return EXIT_FAILURE;
        }
    }

    list->lst[list->cnt] = strdup( item );
    if ( list->lst[list->cnt] == NULL ) {
        return EXIT_FAILURE;
    }
    list->cnt++;

    return EXIT_SUCCESS;
}

void listRewind( LIST *list )
{
    if ( list == NULL ) {
        return;
    }
    list->idx = 0;
}

char *listGetItem( LIST *list )
{
    if ( list != NULL && list->idx < list->cnt ) {
        return list->lst[list->idx++];
    }
    return NULL;
}

static int listSortAscending( const void *p1, const void *p2 )
{
    return strcmp( *(char **)p1, *(char **)p2 );
}

static int listSortDescending( const void *p2, const void *p1 )
{
    return strcmp( *(char **)p1, *(char **)p2 );
}

void listSort( LIST *list, int dir )
{
    if ( list == NULL ) {
        return;
    }
    if ( dir == SORT_ASC ) {
        qsort( list->lst, list->cnt, sizeof(char*), listSortAscending );
    } else {
        qsort( list->lst, list->cnt, sizeof(char*), listSortDescending );
    }
}

#ifdef UT
int main( int argc, char **argv )
{
    FILE          *ofp = stdout;
    DIR           *dp;
    struct dirent *de;
    LIST           list;
    char          *name;


    listInitialize( &list );

    dp = opendir( "." );
    if ( dp == NULL ) {
      fputs( "opendir.", stderr );
      return EXIT_FAILURE;
    }

    while ( (de = readdir(dp)) != NULL ) {
        char *isDotC;

        isDotC = strrchr( de->d_name, '.' );
        if ( isDotC && strcmp(isDotC,".c") == 0 ) {
            listAddItem( &list, de->d_name );
        }
    }
    closedir( dp );

    listRewind( &list );
    listSort( &list, SORT_ASC );
    name = listGetItem( &list );
    if ( name == NULL ) {
        listDelete( &list );
        fputs( "no source file.", stderr );
        return EXIT_FAILURE;
    }

    fputs( "PRJROOT\t=\t../../../..\n\n", ofp );
    fputs( "CP\t=\t/bin/cp -p\n", ofp );
    fputs( "RM\t=\t/bin/rm -f\n", ofp );
    fputs( "#CC\t=\t\n", ofp );
    fputc( '\n', ofp );

    fprintf( ofp, "SRC\t=\t" );
    do {
        fprintf( ofp, "%s\t\\\n\t\t", name );
        name = listGetItem( &list );
    } while ( name );
    fputs( "$(END)\n\n", ofp );

    listRewind( &list );
    fprintf( ofp, "OBJ\t=\t" );
    while ( (name = listGetItem(&list)) != NULL ) {
        name[strlen(name) - 1] = 'o';
        fprintf( ofp, "%s\t\\\n\t\t", name );
    }
    fputs( "$(END)\n\n", ofp );

    listDelete( &list );

    fputs( "BINDIR\t=\t\n", ofp );
    fputs( "INCDIR\t=\t$(PRJROOT)/foo/inc\n", ofp );
    fputs( "INCDIR2\t=\t$(PRJROOT)/foo/bar/inc\n", ofp );
    fputs( "LIBDIR\t=\t$(PRJROOT)/foo/lib\n", ofp );
    fputc( '\n', ofp );
    fputs( "#CFLAGS\t=\t-g -Wall -DLINUX -DDEBUG\n", ofp );
    fputs( "CFLAGS\t=\t-O -Wall -DLINUX -DRELEASE\n", ofp );
    fputs( "LDFLAGS\t=\t\n", ofp );
    fputc( '\n', ofp );
    if ( argc == 1 ) {
        fputs( "EXEC\t=\tliba.a\n", ofp );
    } else {
        fprintf( ofp, "EXEC\t=\t%s\n", argv[1] );
    }
    fputc( '\n', ofp );
    fputs( "all\t:\t$(EXEC)\n", ofp );
    fputc( '\n', ofp );
    fputs( "$(EXEC)\t:\t$(OBJ)\n", ofp );
    fputs( "\tar rcs $(EXEC) $(OBJ)\n", ofp );
    fputc( '\n', ofp );
    fputs( "tags\t:\t$(SRC)\n", ofp );
    fputs( "\tctags -tw -f tags $(SRC)\n", ofp );
    fputc( '\n', ofp );
    fputs( "install\t:\t$(EXEC)\n", ofp );
    fputs( "\t$(CP) $(EXEC) $(LIBDIR)\n", ofp );
    fputc( '\n', ofp );
    fputs( "clean\t:\n", ofp );
    fputs( "\t$(RM) core $(OBJ) $(EXEC) *~\n", ofp );
    fputc( '\n', ofp );
    fputs( ".c.o\t:\n", ofp );
    fputs( "\t$(CC) $(CFLAGS) -I$(INCDIR) -I$(INCDIR2) -c $<\n", ofp );

    if ( ofp != stdout ) {
        fclose( ofp );
    }

    return EXIT_SUCCESS;
}
#endif

「バータリープログラミング」の参考にするのがよかろう(笑)。

(※ 「バータリープログラミング」とは、場当たり的なプログラミングの事)


っていうか、今日、初めてサンプルじゃないプログラムでキー入力をscanf()でやってるプログラム見たよ。変な値いれたら当然のように永久ループしてたんで、fgets()使って書きなおしておいたけど。でも、入力された値の妥当性チェックはやってない。もともと入ってなかったし仕様書も無いから勝手はできんしな。

あー、あとdouble型変数のゼロクリアでNULL代入している意味不明な個所があったな。ぜんぶ0.0に書き換えといたが。C++ならNULLは0だからエラーにはならんかったかもしれんが、Cでは(void *)0なんでポインタだもんねぇ。

整数型ならwarningで済むんだけど実数型はエラーなんだねぇ>gcc。

まぁ、他にも変な値で初期化してたり初期化してなかったりとかワンサカだけど、マジメに直してたら時間がどれだけかかるか知れたモンじゃないので、コンパイルでwarninngとかfatalになったトコロとcoreの原因になったトコロだけしゅーせーだぁ(またこれが、頻繁にcoreしてくれちゃんだよまったく)。

世の中のCプログラマは偶然動いてる系コード書く事禁止。そのコード通ったときにヒープやスタックがどうなってるか考えて書け。とかエラソーに言っても自分も同罪(笑)。