Skip to content

Instantly share code, notes, and snippets.

@mk2
Created May 14, 2014 13:45
Show Gist options
  • Save mk2/4a427438bfad58b31b2d to your computer and use it in GitHub Desktop.
Save mk2/4a427438bfad58b31b2d to your computer and use it in GitHub Desktop.
/******************************************************************************
Usage : comma [+<n>h][-4] <f1> <f2> ... <file>
: comma -d[4] <string>
Version : Thu Dec 15 13:46:38 JST 2011
******************************************************************************/
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
// for debug
#ifdef DEBUG
#define dbg(...) (printf("%s %u @%s:",__FILE__,__LINE__,__func__), printf(" "__VA_ARGS__))
#else
#define dbg(...)
#endif
typedef enum _opt_type
{
NO_OPT = 0b0000,
H_OPT = 0b0001,
D_OPT = 0b0010,
FOUR_OPT = 0b0100,
} opt_type_t;
typedef struct _line_t
{
int num;
char chars[];
} line_t;
typedef struct _context_t
{
int keta_step;
int cols_len;
int cols[];
} ctx_t;
/**
* Print usage of comma program
* !! This function calls exit with EXIT_FAILURE. !!
*/
static void usage(void);
/**
* Setup context.
* @param {ctx_t *} context
* @param {int} arg array size
* @param {char *} arg chars array
*/
static void setup_context(ctx_t *, int, char *[]);
/**
* Print given file with comma.
* @param {FILE *} file pointer
* @param const {ctx_t *} context
*/
static void print_comma_file(FILE *, const ctx_t *const);
/**
* Print given line chars.
* @param const {char *} line chars
* @param const {ctx_t *} context
*/
static void print_comma_line(const char *const, const ctx_t *const);
/**
* Convert given chars to comma separated chars.
* E.g.
* input chars : 12345678
* output chars : 1234,5678
* @param in_chars {char *} target characters
* @param ctx {ctx_t *} context
* @return {char *} comma separated characters
*/
static char *to_comma_word(const char *const, const ctx_t *const);
int main(int argc, char *argv[])
{
int opt;
extern char *optarg;
extern int optind, opterr;
unsigned int opts = NO_OPT;
while ((opt = getopt(argc, argv, "h4d")) != -1)
{
switch (opt)
{
case 'h':
opts |= H_OPT;
break;
case 'd':
opts |= D_OPT;
break;
case '4':
opts |= FOUR_OPT;
break;
default:
usage();
break;
}
}
// subtract number of options
argc -= optind;
// forward pointer for number of options
argv += optind;
// check remain args, or if there are no args the program will exit
if (argc < 1)
{
usage();
}
dbg("opts = %u\n", opts);
char *comma_word;
int cols_len = 10;
ctx_t *ctx = (ctx_t *) malloc(sizeof(ctx_t) + sizeof(int) * cols_len);
ctx->keta_step = 3;
ctx->cols_len = cols_len;
switch (opts)
{
case (H_OPT | FOUR_OPT):
dbg("### 4 MODE\n");
ctx->keta_step = 4;
case (H_OPT):
dbg("### H MODE\n");
char *filename = argv[argc - 1];
dbg("filename = %s\n", filename);
FILE *f = fopen(filename, "r");
setup_context(ctx, argc, argv);
print_comma_file(f, ctx);
break;
case (D_OPT | FOUR_OPT):
dbg("### 4 MODE\n");
ctx->keta_step = 4;
case (D_OPT):
dbg("### D MODE\n");
comma_word = to_comma_word(argv[0], ctx);
fprintf(stdout, "%s\n", comma_word);
free(comma_word);
break;
case (FOUR_OPT):
dbg("### 4 MODE");
ctx->keta_step = 4;
break;
default:
dbg("### No match mode\n");
usage();
}
exit(EXIT_SUCCESS);
}
static void usage(void)
{
fprintf(stderr, "Usage : comma [+<n>h][-4] <f1> <f2> ... <file>\n");
fprintf(stderr, " : comma -d[4] <string>\n");
fprintf(stderr, "Version : Thu Dec 15 13:46:38 JST 2011\n");
exit(EXIT_FAILURE);
}
static void setup_context(ctx_t *ctx, int argc, char *argv[])
{
int cols_len = argc - 1;
if (cols_len > ctx->cols_len)
{
if (!realloc(ctx, sizeof(ctx_t) + sizeof(int) * cols_len))
{
exit(EXIT_FAILURE);
}
}
ctx->cols_len = cols_len;
for (int i = 0; i < cols_len; i++)
{
ctx->cols[i] = atoi(argv[i]);
dbg("ctx->cols[%d] = %d\n", i, ctx->cols[i]);
}
}
static void print_comma_file(FILE *f, const ctx_t *const ctx)
{
int line_num = 1;
char buf[512];
while (fgets(buf, 512, f))
{
dbg("buf = %s\n", buf);
print_comma_line(buf, ctx);
line_num++;
}
}
static void print_comma_line(const char *const _in_line,
const ctx_t *const ctx)
{
int col_num = 1;
char *in_line = (char *) calloc(strlen(_in_line), sizeof(char));
strcpy(in_line, _in_line);
char *tok = strtok(in_line, " ");
while (tok)
{
dbg("line[%d] = %s\n", col_num, tok);
char *comma_tok = to_comma_word(tok, ctx);
fprintf(stdout, "%s ", comma_tok);
tok = strtok(NULL, " ");
col_num++;
}
}
static char *to_comma_word(const char *const in_chars,
const ctx_t *const ctx)
{
// input chars length
size_t in_chars_length = strlen(in_chars);
// inout chars each keta steps.
// input chars : XYZXYZXYZ : input chars's keta step is 3.
// output chars: XYZ,XYZ,XYZ : output chars's keta step is 4.
int in_chars_keta_step = ctx->keta_step;
int out_chars_keta_step = in_chars_keta_step + 1;
// number of comma in output chars.
// if output chars length is multiple number of the input keta step,
// we must decrement comma count. Because most top comma is not necessary.
// input chars : 1234
// output chars : ,1234
// ^
// This comma is garbage!!
int comma_count = in_chars_length / in_chars_keta_step;
size_t out_chars_length = in_chars_length +
((comma_count * in_chars_keta_step == in_chars_length) ? comma_count - 1 : comma_count);
dbg("in chars keta step = %d\n", in_chars_keta_step);
dbg("out chars keta step = %d\n", out_chars_keta_step);
dbg("input chars length = %ld\n", in_chars_length);
dbg("output chars length = %ld\n", out_chars_length);
char *out_chars = calloc(out_chars_length, sizeof(char));
strncpy(out_chars, in_chars, in_chars_length);
int ii = in_chars_length - 1;
int oi = out_chars_length - 1;
for ( ; ii >= in_chars_keta_step - 1 & oi >= out_chars_keta_step - 1; ii -= in_chars_keta_step, oi -= out_chars_keta_step)
{
dbg("ii = %d\n", ii);
dbg("oi = %d\n", oi);
strncpy(&out_chars[oi - in_chars_keta_step + 1], &in_chars[ii - in_chars_keta_step + 1], in_chars_keta_step);
int comma_index = oi - out_chars_keta_step + 1;
if (comma_index != 0)
out_chars[comma_index] = ',';
}
dbg("in_chars = %s\n", in_chars);
dbg("out_chars = %s\n", out_chars);
return out_chars;
}
@mk2
Copy link
Author

mk2 commented May 14, 2014

サンプルデータファイル

20060201 296030 6710000
20060202 1300100 3130000
20060203 309500 20100
20060204 16300 300100
20060205 41000 210000
20060206 771100 400000

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment