<commit_before>/*
 * Copyright (c) 2014, 2015 <NAME> <<EMAIL>>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

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

#include <db.h>
#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

/* Point in time. */
typedef struct _timepoint
{
  char loc[49]; /* Name of location. */
  char msg[65]; /* Message. */
  char hts[17]; /* Human readable timestamp of local time at location. */
  char etz[49]; /* Contents of environment variable TZ. */
  char rtz[49]; /* Resulting time zone. */
  int64_t cts; /* Calendar time. Number of seconds since the Epoch. */
} timepoint;

typedef struct _tlentry
{
  timepoint begin;
  timepoint end;
} tlentry;

typedef struct _dottl
{
  char* f_dir;
  char* f_tps;
  char* f_tl;
  DB* tps;
  DB* tl;
} dottl;

void usage(const char* pname)
{
  fprintf(stderr, "Usage:\n");
  fprintf(stderr, " %s init\n", pname);
  fprintf(stderr, " %s timepoint [-l <loc>] [-m <msg>] [-t <ts>]\n", pname);
  fprintf(stderr, " %s pending\n", pname);
  fprintf(stderr, " %s pop-drop\n", pname);
  fprintf(stderr, " %s merge-add\n", pname);
  fprintf(stderr, " %s unlog [-d] <id>\n", pname);
  fprintf(stderr, " %s report\n", pname);
}

/*
 * Initialize time log directory and files.
 * Returns zero on success.
 *
 * The absolute value of a non-zero return value
 * indicates the stage of tl_init where failure occured.
 *
 * On failure, rollback is attempted.  Should rollback fail,
 * the return value is sign-swapped, thus becoming negative.
 */
int tl_init(dottl* cdtl)
{
  int rem = 5; /* Stages remaining */

  if (cdtl->tl != NULL || cdtl->tps != NULL)
  {
    goto rollback_init;
  }
  rem--;

  if (mkdir(cdtl->f_dir, 00755) != 0)
  {
    goto rollback_init;
  }
  rem--;

  if (chdir(cdtl->f_dir) != 0)
  {
    goto rollback_init;
  }
  rem--;

  if ((cdtl->tl = dbopen(cdtl->f_tl, O_CREAT | O_EXCL | O_RDWR | O_EXLOCK,
    00644, DB_RECNO, NULL)) == NULL)
  {
    goto rollback_init;
  }
  rem--;

  if ((cdtl->tps = dbopen(cdtl->f_tps, O_CREAT | O_EXCL | O_RDWR | O_EXLOCK,
    00644, DB_RECNO, NULL)) == NULL)
  {
    goto rollback_init;
  }
  rem--;

  chdir("..");
  return rem;

rollback_init:
  switch (rem)
  {
    case 1:
      cdtl->tl->close(cdtl->tl);
      if (unlink(cdtl->f_tl) != 0)
      {
        return -rem;
      }
      /* FALLTHROUGH */
    case 2:
      /* FALLTHROUGH */
    case 3:
      chdir("..");
      if (rmdir(cdtl->f_dir) != 0)
      {
        return -rem;
      }
      /* FALLTHROUGH */
    case 4:
      /* FALLTHROUGH */
    case 5:
      return rem;
      break;
    default:
      if (rem > 0)
      {
        return -rem;
      }
      return -6;
  }
}

DB* open_tpsdb (dottl* cdtl)
{
  if (cdtl->tps != NULL || chdir(cdtl->f_dir) != 0)
  {
    return NULL;
  }
  if ((cdtl->tps = dbopen(cdtl->f_tps, O_RDWR | O_EXLOCK,
    00644, DB_RECNO, NULL)) == NULL)
  {
    chdir("..");
    return NULL;
  }
  chdir("..");
  return cdtl->tps;
}

DB* open_tldb (dottl* cdtl)
{
  if (cdtl->tl != NULL || chdir(cdtl->f_dir) != 0)
  {
    return NULL;
  }
  if ((cdtl->tl = dbopen(cdtl->f_tl, O_RDWR | O_EXLOCK,
    00644, DB_RECNO, NULL)) == NULL)
  {
    chdir("..");
    return NULL;
  }
  chdir("..");
  return cdtl->tl;
}

/* Initialize a timepoint. */
timepoint* tpt_init (timepoint* tpt,
  const char* loc, const char* msg, const char* ts)
{
  struct tm sts; /* Timestamp. */
  time_t currtime;
  bool docmpts = false; /* Flag used to indicate when ts should be compared. */
  char format[] = "%Y-%m-%dT%H:%M"; /* Fmt of the human readable timestamp. */

  memset(tpt, 0, sizeof(*tpt));

  /* Get current local time, set seconds to 0. */
  (void)time(&currtime);
  (void)localtime_r(&currtime, &sts);
  sts.tm_sec = 0;

  /* If a timestamp was provided, overwrite with user-provided values. */
  if (ts != NULL)
  {
    if (!(strlen(ts) == 5
      && sscanf(ts, "%2d:%2d",
        &(sts.tm_hour), &(sts.tm_min)) == 2
      && sts.tm_hour >= 0 && sts.tm_hour <= 23
      && sts.tm_min >= 0 && sts.tm_hour <= 59))
    {
      if (strlen(ts) == 16
        && sscanf(ts, "%4d-%2d-%2dT%2d:%2d",
          &(sts.tm_year), &(sts.tm_mon), &(sts.tm_mday),
          &(sts.tm_hour), &(sts.tm_min)) == 5)
      {
        /* See ctime(3) */
        sts.tm_year -= 1900;
        sts.tm_mon -= 1;

        docmpts = true;
      }
      else
      {
        return NULL;
      }
    }
  }

  /* If the user provided the date, we check it now. */
  tpt->cts = (int64_t) mktime(&sts);
  if (docmpts)
  {
    (void)strftime(tpt->hts, sizeof(tpt->hts), format,
      localtime((time_t*) &tpt->cts));
    if (strcmp(ts, tpt->hts) != 0)
    {
      return NULL;
    }
  }
  else
  {
    (void)strftime(tpt->hts, sizeof(tpt->hts), format, &sts);
  }

  if (strlcpy(tpt->rtz, sts.tm_zone, sizeof(tpt->rtz)) >= sizeof(tpt->rtz))
  {
    return NULL;
  }

  if (msg != NULL)
  {
    if (strlcpy(tpt->msg, msg, sizeof(tpt->msg)) >= sizeof(tpt->msg))
    {
      return NULL;
    }
  }

  if (loc != NULL)
  {
    if (strlcpy(tpt->loc, loc, sizeof(tpt->loc)) >= sizeof(tpt->loc))
    {
      return NULL;
    }
  }

  return tpt;
}

timepoint* tl_timepoint (dottl* cdtl, timepoint* tpt,
  const char* loc, const char* msg, const char* ts)
{
  struct stat st_tps;
  recno_t kval;
  DBT key;
  DBT data;

  if (open_tpsdb(cdtl) == NULL)
  {
    return NULL;
  }

  if (fstat(cdtl->tps->fd(cdtl->tps), &st_tps) != 0
    || (tpt = tpt_init(tpt, loc, msg, ts)) == NULL)
  {
    cdtl->tps->close(cdtl->tps);
    return NULL;<commit_msg>Combine some consecutive if statements.<commit_after>/*
 * Copyright (c) 2014, 2015 <NAME> <<EMAIL>>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

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

#include <db.h>
#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

/* Point in time. */
typedef struct _timepoint
{
  char loc[49]; /* Name of location. */
  char msg[65]; /* Message. */
  char hts[17]; /* Human readable timestamp of local time at location. */
  char etz[49]; /* Contents of environment variable TZ. */
  char rtz[49]; /* Resulting time zone. */
  int64_t cts; /* Calendar time. Number of seconds since the Epoch. */
} timepoint;

typedef struct _tlentry
{
  timepoint begin;
  timepoint end;
} tlentry;

typedef struct _dottl
{
  char* f_dir;
  char* f_tps;
  char* f_tl;
  DB* tps;
  DB* tl;
} dottl;

void usage(const char* pname)
{
  fprintf(stderr, "Usage:\n");
  fprintf(stderr, " %s init\n", pname);
  fprintf(stderr, " %s timepoint [-l <loc>] [-m <msg>] [-t <ts>]\n", pname);
  fprintf(stderr, " %s pending\n", pname);
  fprintf(stderr, " %s pop-drop\n", pname);
  fprintf(stderr, " %s merge-add\n", pname);
  fprintf(stderr, " %s unlog [-d] <id>\n", pname);
  fprintf(stderr, " %s report\n", pname);
}

/*
 * Initialize time log directory and files.
 * Returns zero on success.
 *
 * The absolute value of a non-zero return value
 * indicates the stage of tl_init where failure occured.
 *
 * On failure, rollback is attempted.  Should rollback fail,
 * the return value is sign-swapped, thus becoming negative.
 */
int tl_init(dottl* cdtl)
{
  int rem = 5; /* Stages remaining */

  if (cdtl->tl != NULL || cdtl->tps != NULL)
  {
    goto rollback_init;
  }
  rem--;

  if (mkdir(cdtl->f_dir, 00755) != 0)
  {
    goto rollback_init;
  }
  rem--;

  if (chdir(cdtl->f_dir) != 0)
  {
    goto rollback_init;
  }
  rem--;

  if ((cdtl->tl = dbopen(cdtl->f_tl, O_CREAT | O_EXCL | O_RDWR | O_EXLOCK,
    00644, DB_RECNO, NULL)) == NULL)
  {
    goto rollback_init;
  }
  rem--;

  if ((cdtl->tps = dbopen(cdtl->f_tps, O_CREAT | O_EXCL | O_RDWR | O_EXLOCK,
    00644, DB_RECNO, NULL)) == NULL)
  {
    goto rollback_init;
  }
  rem--;

  chdir("..");
  return rem;

rollback_init:
  switch (rem)
  {
    case 1:
      cdtl->tl->close(cdtl->tl);
      if (unlink(cdtl->f_tl) != 0)
      {
        return -rem;
      }
      /* FALLTHROUGH */
    case 2:
      /* FALLTHROUGH */
    case 3:
      chdir("..");
      if (rmdir(cdtl->f_dir) != 0)
      {
        return -rem;
      }
      /* FALLTHROUGH */
    case 4:
      /* FALLTHROUGH */
    case 5:
      return rem;
      break;
    default:
      if (rem > 0)
      {
        return -rem;
      }
      return -6;
  }
}

DB* open_tpsdb (dottl* cdtl)
{
  if (cdtl->tps != NULL || chdir(cdtl->f_dir) != 0)
  {
    return NULL;
  }
  if ((cdtl->tps = dbopen(cdtl->f_tps, O_RDWR | O_EXLOCK,
    00644, DB_RECNO, NULL)) == NULL)
  {
    chdir("..");
    return NULL;
  }
  chdir("..");
  return cdtl->tps;
}

DB* open_tldb (dottl* cdtl)
{
  if (cdtl->tl != NULL || chdir(cdtl->f_dir) != 0)
  {
    return NULL;
  }
  if ((cdtl->tl = dbopen(cdtl->f_tl, O_RDWR | O_EXLOCK,
    00644, DB_RECNO, NULL)) == NULL)
  {
    chdir("..");
    return NULL;
  }
  chdir("..");
  return cdtl->tl;
}

/* Initialize a timepoint. */
timepoint* tpt_init (timepoint* tpt,
  const char* loc, const char* msg, const char* ts)
{
  struct tm sts; /* Timestamp. */
  time_t currtime;
  bool docmpts = false; /* Flag used to indicate when ts should be compared. */
  char format[] = "%Y-%m-%dT%H:%M"; /* Fmt of the human readable timestamp. */

  memset(tpt, 0, sizeof(*tpt));

  /* Get current local time, set seconds to 0. */
  (void)time(&currtime);
  (void)localtime_r(&currtime, &sts);
  sts.tm_sec = 0;

  /* If a timestamp was provided, overwrite with user-provided values. */
  if (ts != NULL)
  {
    if (!(strlen(ts) == 5
      && sscanf(ts, "%2d:%2d",
        &(sts.tm_hour), &(sts.tm_min)) == 2
      && sts.tm_hour >= 0 && sts.tm_hour <= 23
      && sts.tm_min >= 0 && sts.tm_hour <= 59))
    {
      if (strlen(ts) == 16
        && sscanf(ts, "%4d-%2d-%2dT%2d:%2d",
          &(sts.tm_year), &(sts.tm_mon), &(sts.tm_mday),
          &(sts.tm_hour), &(sts.tm_min)) == 5)
      {
        /* See ctime(3) */
        sts.tm_year -= 1900;
        sts.tm_mon -= 1;

        docmpts = true;
      }
      else
      {
        return NULL;
      }
    }
  }

  /* If the user provided the date, we check it now. */
  tpt->cts = (int64_t) mktime(&sts);
  if (docmpts)
  {
    (void)strftime(tpt->hts, sizeof(tpt->hts), format,
      localtime((time_t*) &tpt->cts));
    if (strcmp(ts, tpt->hts) != 0)
    {
      return NULL;
    }
  }
  else
  {
    (void)strftime(tpt->hts, sizeof(tpt->hts), format, &sts);
  }

  if (strlcpy(tpt->rtz, sts.tm_zone, sizeof(tpt->rtz)) >= sizeof(tpt->rtz)
    || (msg != NULL
      && strlcpy(tpt->msg, msg, sizeof(tpt->msg)) >= sizeof(tpt->msg))
    || (loc != NULL
      && strlcpy(tpt->loc, loc, sizeof(tpt->loc)) >= sizeof(tpt->loc)))
  {
    return NULL;
  }

  return tpt;
}

timepoint* tl_timepoint (dottl* cdtl, timepoint* tpt,
  const char* loc, const char* msg, const char* ts)
{
  struct stat st_tps;
  recno_t kval;
  DBT key;
  DBT data;

  if (open_tpsdb(cdtl) == NULL)
  {
    return NULL;
  }

  if (fstat(cdtl->tps->fd(cdtl->tps), &st_tps) != 0
    || (tpt = tpt_init(tpt, loc, msg, ts)) == NULL)
  {
    cdtl->tps->close(cdtl->tps);
    return NULL;
{'fraction_non_alphanumeric': 0.16406125378848302, 'fraction_numerical': 0.014356356675705855, 'mean_word_length': 2.6010913268236644, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 141, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5031590', 'n_tokens_mistral': 5116, 'n_tokens_neox': 4886, 'n_words': 1307}