/* WizPPN.C -- scan User IDs from WizTerm log files */ #if defined(__TURBOC__) #include #else #include #endif #include #include #include #include #include #include #include #define PPNFUNC 1 #include "wtppn.h" /**********************/ /* ***** MACROS ***** */ /**********************/ #define WIZPPN #define VERSION "1.00" #define PROG_VERS "WizPPN " VERSION " [09/94] - (C) SirSloth----*" #define MAX_USERS 1000 /********************************/ /* ***** GLOBAL VARIABLES ***** */ /********************************/ int gargc; int gargn; char **gargv; struct ffblk ffblk; /* file control block for findfirst */ int in_flist = 0; /* tells if we are in a file list */ char f_drive[MAXDRIVE]; /* file name components for fnsplit */ char f_dir[MAXDIR]; char f_name[MAXFILE]; char f_ext[MAXEXT]; char f_path[MAXPATH]; cdate file_date, today; t_user user1; t_user *uids_table = NULL; unsigned uids_count; t_user *name_table = NULL; unsigned name_count; unsigned upd_count; unsigned new_count; /*************************/ /* ***** FUNCTIONS ***** */ /*************************/ int first_file(void); int next_file(void); void retire_log(void); /**********************************************/ /* add_tab(): add current user1 to user table */ /**********************************************/ void add_tab(t_user *table, unsigned *tsize, cmpfunc *cmp) { t_user *freepos; /* free location to move item to */ t_user *currpos; /* location from which to move */ freepos = table + *tsize; currpos = freepos - 1; while (freepos > table && (*cmp)(currpos, &user1) > 0) { *freepos-- = *currpos--; } *freepos = user1; (*tsize)++; } /* end add_tab() */ /*****************************************************************/ /* ident_level(): return the level number for given level string */ /* returns 0 to 10 for level or -1 if not found. */ /*****************************************************************/ int ident_level(char *lvl, int *chars) { const struct level_tab { char *desc; int trans; } level_table[] = { { "novice", 0 }, { "warrior", 1 }, { "heroine", 2 }, { "hero", 2 }, { "champion", 3 }, { "superheroine", 4 }, { "superhero", 4 }, { "enchantress", 5 }, { "enchanter", 5 }, { "sorceress", 6 }, { "sorcerer", 6 }, { "necromancess", 7 }, { "necromancer", 7 }, { "legend", 8 }, { "mortal wizard", 9 }, { "mortal witch", 9 }, { "arch-wizard", 10 }, { "arch-witch", 10 }, { "wizard", 9 }, { "witch", 9 }, "" }; const struct level_tab *lp; int level = -1; for (lp=level_table; lp->desc[0]; lp++) { if (!strncmp(lvl, lp->desc, strlen(lp->desc))) { level = lp->trans; *chars = strlen(lp->desc); break; } } /* end for */ return level; } /* end ident_level() */ /* ========================================================= ** next_file(): Get the next file name, from command line ** or from the find_next function. */ int next_file(void) { char nil_drive[MAXDRIVE]; char nil_dir[MAXDIR]; for ( ; ; ) { if (in_flist == 0) { if (gargn >= gargc) return 0; (void) fnsplit(gargv[gargn], f_drive, f_dir, f_name, f_ext); (void) fnmerge(f_path, f_drive, f_dir, f_name, f_ext); if (findfirst(f_path, &ffblk, 0) != 0) { gargn++; } else { in_flist = 1; break; } } else if (in_flist == 1) { if (findnext(&ffblk) == 0) break; in_flist = 0; gargn++; } } /* end for */ (void) fnsplit(ffblk.ff_name, nil_drive, nil_dir, f_name, f_ext); strupr(f_drive); strupr(f_dir); strupr(f_name); strupr(f_ext); (void) fnmerge(f_path, f_drive, f_dir, f_name, f_ext); return 1; } /* end next_file() */ /***********************************************/ /* retire_log(): change log file name to .olg. */ /***********************************************/ void retire_log() { char newname[MAXPATH]; if (strncmp(f_name+2, today, CDATE_LEN) < 0) { fnmerge(newname, f_drive, f_dir, f_name, ".OLG"); if (rename(f_path, newname)) { printf("+++ Error renaming %s\n" " to %s!\n", f_path, newname); } else { printf("Renaming %s\n" " to %s .\n", f_path, newname); } } } /* end retire_log() */ /***************************************************/ /* rjustify(): right justify some text in a field. */ /***************************************************/ void rjustify(char *field, int txtlen, int fldlen, char fill) { char *ps; char *pd; if (fldlen <= txtlen) return; ps = field + txtlen - 1; pd = field + fldlen - 1; fldlen -= txtlen; for (; txtlen; txtlen--) { *pd-- = *ps--; } for (; fldlen; fldlen--) { *pd-- = fill; } } /* end rjustify() */ /***************************************/ /* scan_text(): scan one line of text. */ /***************************************/ int scan_text(char *txt) { const char xtab[] = "0123456789ABCDEF"; const char hcelf[] = " has changed experience level from "; int nchar; int level, level1, level2; int msg_type = 0; int invis = 0; /* data pointers */ char *pn; char *pt; /* ===== scan leading parenthesis (invis) ==== */ invis = 0; if (*txt == '(') { invis = 1; txt++; } /* ===== scan name ===== */ if (! isupper(*txt)) return 0; pn = &user1.name[0]; *pn++ = *txt++; nchar = 1; while (islower(*txt) && nchar < 9) { *pn++ = *txt++; nchar++; } if (invis && *txt == ')') { invis = 0; txt++; } if (*txt != ' ') return 0; while (nchar < NAME_LEN) { *pn++ = ' '; nchar++; } txt++; /* ==== scan 'the ' ==== */ level = 0; if (strncmp(txt, "the ", 4)) goto scn_uid; msg_type |= 1; txt += 4; level = ident_level(txt, &nchar); if (level == -1) return 0; txt += nchar; if (invis && *txt == ')') { invis = 0; txt++; } if (*txt++ != ' ') return 0; /* ==== scan user id ==== */ scn_uid: if (*txt++ != '[') return 0; /* --- part 1: up to 6 digits --- */ nchar = 0; pt = &user1.uid[0]; while (isdigit(*txt) && nchar < UID_LEN1) { *pt++ = *txt++; nchar++; } if (*txt != ',') return 0; /* --- right justify part 1 --- */ rjustify(&user1.uid[0], nchar, UID_LEN1, ' '); /* --- transfer the comma --- */ user1.uid[UID_LEN1] = *txt++; /* --- part 2: Up to 4 digits --- */ nchar = 0; pt = &user1.uid[UID_LEN1+1]; while (isdigit(*txt) && nchar < UID_LEN2) { *pt++ = *txt++; nchar++; } if (*txt++ != ']') return 0; /* --- blank fill part 2 --- */ while (nchar < 4) { *pt++ = ' '; nchar++; } /* --- DON'T right justify part 2 --- */ /*** rjustify(&user1.uid[UID_LEN1+1], nchar, UID_LEN2, '0'); ***/ /* ==== scan ' has changed experience level from ' ===== */ if (*txt == '\n') goto print_id; if (strncmp(txt, hcelf, strlen(hcelf))) return 0; txt += strlen(hcelf); msg_type |= 2; /* ==== scan level 1 ==== */ level1 = ident_level(txt, &nchar); if (level1 == -1) return 0; txt += nchar; /* ==== scan "to " ====== */ if (strncmp(txt, " to ", 4)) return 0; txt += 4; /* ==== scan level 2 ==== */ level2 = ident_level(txt, &nchar); if (level2 == -1) return 0; txt += nchar; if (*txt != '.') return 0; level = max(level1, level2); print_id: user1.mxlv = xtab[level]; /*** printf("(%1X) %-9.9s %c [%11.11s]\n", msg_type, user1.name, user1.mxlv, user1.uid); ***/ return 1; } /* end scan_text() */ /* ========================================================= ** start_file(): Get the first file name, from command line ** or from the find_first function. */ int start_file(void) { gargn = 1; in_flist = 0; return 1; } /* end start_file() */ /*************************************************/ /* upd_file: Update UID master file from tables. */ /*************************************************/ void upd_file(void) { FILE *fp_ppn; long ppn_nrec; FILE *fp_tmp; long tmp_nrec = 0; int stat; t_user *name_ptr = name_table; long ppn_names = 0; t_user *uids_ptr = uids_table; long ppn_uids = 0; t_ppnrec i_rec, new_rec; t_ppnrec *o_rec; int i_empty = 1; int source_sw; /* -1: from table; 0: updated; 1: from file */ int this_update = 0; printf(" %5u names/UIDs found.\n", name_count); strncpy(new_rec.date1, file_date, CDATE_LEN); strncpy(new_rec.date2, file_date, CDATE_LEN); strncpy(new_rec.crlf, "\r\n", 2); /* ==== open existing PPN file ==== */ fp_ppn = fopen(PPNFILENAME, "rb"); if (fp_ppn == NULL) { printf(" No file \"%s\" found; creating new file.\n", PPNFILENAME); ppn_nrec = 0L; } else { stat = fseek(fp_ppn, 0, SEEK_END); assert(stat == 0 /* after fseek to end */); ppn_nrec = ftell(fp_ppn) / sizeof(t_ppnrec); ppn_uids = ppn_nrec / 2; ppn_names = ppn_nrec / 2; rewind(fp_ppn); printf(" %5lu records read in.\n", ppn_nrec); } /* ==== create new temp file ==== */ fp_tmp = fopen(TMPFILENAME, "wb"); if (fp_tmp == NULL) { printf(" Error: File %s can not be created!\n", TMPFILENAME); exit(4); } /* ==== update uids ==== */ if (ppn_uids > 0) { /* --- priming read --- */ stat = fread(&i_rec, sizeof(i_rec), 1, fp_ppn); if (stat != 1) { printf (" Error! Read error, file %s.\n", PPNFILENAME); exit(8); } i_empty = 0; ppn_uids--; } while (uids_count > 0 || !i_empty) { if (uids_count == 0) { source_sw = 1; } else if (i_empty) { source_sw = -1; } else { /* data available from both table and file */ source_sw = cmp_by_uids(uids_ptr, &i_rec); } switch (source_sw) { case 1: /* data from file */ o_rec = &i_rec; i_empty = 1; break; case 0: /* data by update */ this_update = 0; if (strncmp(i_rec.date1, file_date, CDATE_LEN > 0)) { strncpy(i_rec.date1, file_date, CDATE_LEN); this_update = 1; } if (strncmp(i_rec.date2, file_date, CDATE_LEN < 0)) { strncpy(i_rec.date2, file_date, CDATE_LEN); this_update = 1; } if (uids_ptr->mxlv > i_rec.user.mxlv) { i_rec.user.mxlv = uids_ptr->mxlv; this_update = 1; } o_rec = &i_rec; uids_ptr++; uids_count--; i_empty = 1; upd_count+= this_update; break; case -1: /* data from table */ new_rec.user = *uids_ptr++; uids_count--; o_rec = &new_rec; new_count++; break; } /* end switch */ stat = fwrite(o_rec, sizeof(t_ppnrec), 1, fp_tmp); if (stat != 1) { printf (" Error! File %s could not be written.\n", TMPFILENAME); exit(7); } tmp_nrec++; if (i_empty && ppn_uids > 0) { stat = fread(&i_rec, sizeof(i_rec), 1, fp_ppn); if (stat != 1) { printf (" Error! Read error, file %s.\n", PPNFILENAME); exit(8); } i_empty = 0; ppn_uids--; } } /* End while */ /* ==== update names ==== */ if (ppn_names > 0) { /* --- priming read --- */ stat = fread(&i_rec, sizeof(i_rec), 1, fp_ppn); if (stat != 1) { printf (" Error! Read error, file %s.\n", PPNFILENAME); exit(6); } i_empty = 0; ppn_names--; } while (name_count > 0 || !i_empty) { if (name_count == 0) { source_sw = 1; } else if (i_empty) { source_sw = -1; } else { /* data available from both table and file */ source_sw = cmp_by_name(name_ptr, &i_rec); } switch (source_sw) { case 1: /* data from file */ o_rec = &i_rec; i_empty = 1; break; case 0: /* data by update */ if (strncmp(i_rec.date1, file_date, CDATE_LEN > 0)) { strncpy(i_rec.date1, file_date, CDATE_LEN); } if (strncmp(i_rec.date2, file_date, CDATE_LEN < 0)) { strncpy(i_rec.date2, file_date, CDATE_LEN); } if (name_ptr->mxlv > i_rec.user.mxlv) { i_rec.user.mxlv = name_ptr->mxlv; } o_rec = &i_rec; name_ptr++; name_count--; i_empty = 1; break; case -1: /* data from table */ new_rec.user = *name_ptr++; name_count--; o_rec = &new_rec; break; } /* end switch */ stat = fwrite(o_rec, sizeof(t_ppnrec), 1, fp_tmp); if (stat != 1) { printf (" Error! File %s could not be written.\n", TMPFILENAME); exit(5); } tmp_nrec++; if (i_empty && ppn_names > 0) { stat = fread(&i_rec, sizeof(i_rec), 1, fp_ppn); if (stat != 1) { printf (" Error! Read error, file %s.\n", PPNFILENAME); exit(6); } i_empty = 0; ppn_names--; } } /* End while */ fclose(fp_ppn); stat = fclose(fp_tmp); if (stat != 0) { printf (" Error! File %s could not be written.\n", TMPFILENAME); exit(9); } printf(" %5u updates performed.\n", upd_count); printf(" %5u new personas added.\n", new_count); printf(" %5lu records written out.\n", tmp_nrec); unlink(BAKFILENAME); if (fp_ppn != NULL) { if (rename(PPNFILENAME, BAKFILENAME) != 0) { perror(" RENAME error"); exit(10); } } if (rename(TMPFILENAME, PPNFILENAME) != 0) { perror(" RENAME error"); exit(11); } } /* end upd_file() */ /***********************************************/ /* upd_tab(): Update table with new user data. */ /* If name/uid combination already exist, then */ /* update the level, if applicable. If not, */ /* insert the new user record into the table. */ /***********************************************/ void upd_tabs(void) { t_user *olduser; /* ==== try to find current name/uid combination in table ==== */ olduser = bsearch(&user1, uids_table, uids_count, sizeof(t_user), &cmp_by_uids); if (olduser != NULL) { if (user1.mxlv > olduser->mxlv) { olduser->mxlv = user1.mxlv; } } else { add_tab(uids_table, &uids_count, &cmp_by_uids); } /* ==== try to find current name/uid combination in table ==== */ olduser = bsearch(&user1, name_table, name_count, sizeof(t_user), &cmp_by_name); if (olduser != NULL) { if (user1.mxlv > olduser->mxlv) { olduser->mxlv = user1.mxlv; } } else { add_tab(name_table, &name_count, &cmp_by_name); } assert(uids_count == name_count); } /* end upd_tabs() */ /************************/ /* main(): main program */ /************************/ void main(int argc, char *argv[]) { FILE *fp_log; char input_text[160]; struct tm *now; time_t timer; char *default_parms[] = { "", "BL*.LOG", "" }; /* ***** beginning of main program ***** */ printf("%s\n", PROG_VERS); time(&timer); now = localtime(&timer); sprintf(today, "%02u%02u%02u", now->tm_year % 100, now->tm_mon+1, now->tm_mday); /* --- make argc and argv globally available --- */ if (argc > 1) { gargc = argc; gargv = argv; } else { gargc = 2; default_parms[0] = argv[0]; gargv = default_parms; } /* --- allocate space for user id table --- */ uids_table = calloc(MAX_USERS, sizeof(t_user)); name_table = calloc(MAX_USERS, sizeof(t_user)); if (uids_table == NULL || name_table == NULL) { printf("Insufficient memory for user tables\n"); exit(3); } for (start_file(); next_file(); ) { if (strlen(f_name) != 8 || (strncmp(f_name,"BL",2) && strncmp(f_name,"WT",2)) || strcmp(f_ext, ".LOG")) { printf("+++ Not a WizTerm log file: %s\n", f_path); continue; } fp_log = fopen(f_path, "rt"); if (fp_log == NULL) { perror(f_path); exit(2); } strncpy(file_date, f_name+2, CDATE_LEN); file_date[CDATE_LEN] = '\0'; printf(" Scanning file %s\n", f_path); name_count = 0; uids_count = 0; upd_count = 0; new_count = 0; while (! feof(fp_log) && ! ferror(fp_log)) { input_text[0] = '\0'; fgets(input_text, sizeof(input_text), fp_log); if (input_text[0] && scan_text(input_text)) { upd_tabs(); } } /* end while */ fclose(fp_log); upd_file(); retire_log(); } /* end for */ printf("* End WizPPN *\n"); } /* end main() */