/* * THE GRIM MESSAGE KEEPER * A project for C++ newbies. * Wouldn't be possible without Arvind! * Send comments to: latestringtones2003@yahoo.com * The name's John. * No responsibility whatsoever. Usual stuff. * No copyright restrictions :) * * TODO * - optimise range code * - make non-existent functions existent. * - finish writing help */ #include #include #include #include #include #include #include #include #include #include using namespace std; /* version */ const char* versinfo = "0.0.7c"; void readmsg(int x); void editmsg(char *x); void delmsg(int x); void get_msg_titles(void); void do_all_messages(char *x, char *y); void show_version(void); void show_help(void); void show_about(void); void show_release_dates(void); void show_wenda(void); int msg_filter(const dirent *x); void countmsgs(void); char *get_msg_filename(int x); int main (int argc, char **argv) { if (!argv[1]) /* if no argument is given - i.e. ./grim */ { get_msg_titles(); exit(0); } else { /* check for non-standard arguments */ if (!strcmp(argv[1], "--version")) { show_version(); exit(0); } else if (!strcmp(argv[1], "--help")) { show_help(); exit(0); } else if (!strcmp(argv[1], "--about")) { show_about(); exit(0); } else if (!strcmp(argv[1], "--release-dates")) { show_release_dates(); exit(0); } /* this is an easter egg - it refers to Wenda from "Where's Wally" */ else if (!strcmp(argv[1], "--wenda")) { show_wenda(); exit(0); } } /* normal argument handler - thanks to Arvind */ for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'r': if (argc > i + 1) { /* thanks to Kamran - this range handler is brilliant :) */ char *read_msgs_ = "read"; do_all_messages(argv[i + 1],read_msgs_); i++; } else { get_msg_titles(); } break; case 'w': // cout << "Write message."; break; case 'd': if (argc > i + 1) { char *del_msgs_ = "delete"; do_all_messages(argv[i + 1],del_msgs_); cout << "Message(s) deleted." << endl; i++; } else { cout << "Please enter message number to delete in argument." << endl; exit(0); } break; case 'c': countmsgs(); exit(0); break; case 'e': if (argc > i + 1) { editmsg(argv[i + 1]); i++; } else { cout << "Please enter a message number to edit." << endl; } break; default: cout << "Unknown argument: " << argv[i][1] << endl; break; } } else { cout << "Extra arg: " << argv[i] << endl; } } return (0); } /* functions */ /* read individual message - this is passed to do_all_messages() */ void readmsg(int x) { string mbuffer, mbuffertmp; int mbuffertest, msglinelength; char *themsgfile; themsgfile = get_msg_filename(x); ifstream msgfile(themsgfile); if (! msgfile.is_open()) { cout << "Error opening file.\n"; exit (1); } cout << "\n"; while (! msgfile.eof()) { getline(msgfile,mbuffer,'\n'); mbuffertmp = mbuffer; /* test for blank lines */ mbuffertest = mbuffertmp.empty(); if (mbuffertest == 0) { mbuffertmp = mbuffertmp.erase(1); /* the % occurs more often - used first so no need to check for T or D */ if (mbuffertmp == "%") { msglinelength = mbuffer.length(); if (msglinelength > 1) { mbuffer = mbuffer.substr(2); cout << mbuffer << endl; } else { mbuffer = mbuffer.substr(1); cout << mbuffer << endl; } } else if (mbuffertmp == "T") { mbuffer = mbuffer.substr(7); cout << "-----------------------------------------" << endl; cout << " " << mbuffer << endl; cout << "-----------------------------------------" << endl; } else if (mbuffertmp == "D") { mbuffer = mbuffer.substr(6); long tmpdate; tmpdate = atol(mbuffer.c_str()); cout << "Last Modified: " << ctime(&tmpdate) << "\n"; } } } cout << "\n"; } /* ranges code thanks to Kamran - how cool is it? :D */ /* this function handles the final output (read or delete) of all selected messaages */ void do_all_messages(char *x, char *y) { int range1, range2, range[10], i = 0; string temp, arg(x); /* here's the really messy part. The program first checks whether the argument contains a ','. If yes, it then checks for a '-'. If yes, it handles the argument accordingly. */ while (arg.length() > 0) if (arg.find(",") < arg.length()) if (arg.find("-") < arg.length()) { int loc = arg.find_first_of(",-"); switch (arg[loc]) { case '-': arg.replace(loc, 1, "%"); temp = arg.substr(0, loc); range1 = atoi(temp.c_str()); int nextloc; nextloc = arg.find_first_of("-,"); if (nextloc < arg.length()) { temp = arg.substr(loc + 1, nextloc - loc - 1); arg.erase(0, nextloc + 1); } else { temp = arg.substr(loc + 3); arg.erase(0, loc + 1); } range2 = atoi(temp.c_str()); while (range1 <= range2) range[i++] = range1++; break; case ',': arg.replace(loc, 1, "%"); temp = arg.substr(0, loc); range[i++] = atoi(temp.c_str()); arg.erase(0, loc + 1); break; } } else { int loc = arg.find(","); temp = arg.substr(0, loc); range[i++] = atoi(temp.c_str()); arg.erase(0, loc + 1); } else if (arg.find("-") < arg.length()) { int loc = arg.find("-"); temp = arg.substr(0, loc); range1 = atoi(temp.c_str()); temp = arg.substr(loc + 1, arg.length() - loc - 1); range2 = atoi(temp.c_str()); while (range1 <= range2) range[i++] = range1++; arg.erase(0, loc + 3); } else { range[i++] = atoi(arg.c_str()); break; } //while ends here --i; for(int j = 0; j <= i; j++) { /* read or delete messages ? */ if (y == "read") { readmsg(range[j]); } else if (y == "delete") { delmsg(range[j]); } else { cout << "Didn't want to read or delete, you wanted to " << y << endl; } } } void delmsg(int x) { char *fn2delete; fn2delete = get_msg_filename(x); unlink(fn2delete); } void editmsg(char *x) { /* WORK IN PROGRESS */ int etoint; char *emsgfilename; etoint = atoi(x); emsgfilename = get_msg_filename(etoint); int emsgtmpfilename; /* check for TMPDIR - else use /tmp */ char *tmpdirname = getenv("TMPDIR"); if (tmpdirname!=NULL) { /* use it */ // tmpfn_temp = "/grim_message_tmp_XXXXXX"; } else { tmpdirname = "/tmp"; } char *emsgtmpfilenametemplate; // !! causes segmentation fault !! emsgtmpfilenametemplate = strcat(tmpdirname,tmpfn_temp); // char tmpfntemplate_final[] = emsgtmpfilenametemplate; // emsgtmpfilename = mkstemp(tmpfntemplate_final); // cout << tmpfntemplate_final << endl; // cout << emsgtmpfilename << endl; } /* filter() for scandir */ int msg_filter(const dirent *x) { char *msgindicator = ".message"; char *cmsgindicator; cmsgindicator = strstr(x->d_name,msgindicator); if (cmsgindicator) { return (1); } else { return (0); } } void countmsgs(void) { int num_of_msgs; struct dirent **countedlist; num_of_msgs = scandir(".", &countedlist, msg_filter, versionsort); if (num_of_msgs < 0) { perror("scandir"); } else { cout << "There are " << num_of_msgs << " messages." << endl; while (num_of_msgs--) { free(countedlist[num_of_msgs]); } free(countedlist); } } char *get_msg_filename(int x) { struct dirent **msgarray; int msgarraynum; int filenum; msgarraynum = scandir(".", &msgarray, msg_filter, versionsort); char *fn; filenum = msgarraynum - x; fn = strdup(msgarray[filenum]->d_name); while (msgarraynum--) { free(msgarray[msgarraynum]); } free(msgarray); return (fn); } void get_msg_titles(void) { struct dirent **msgtitlearray; int msgtitlearraynum; msgtitlearraynum = scandir(".", &msgtitlearray, msg_filter, versionsort); string tmbuffer, tmbuffertmp; int tmbuffertest, tmsglinelength, tmsgcount=0; char *tthemsgfile; if (msgtitlearraynum < 0) { perror("scandir"); } else { cout << "\n-----------------------------------------" << endl; cout << " Messages" << endl; cout << "-----------------------------------------" << endl; while(msgtitlearraynum--) { tthemsgfile = strdup(msgtitlearray[msgtitlearraynum]->d_name); ifstream tmsgfile(tthemsgfile); if (! tmsgfile.is_open()) { cout << "Error opening file\n"; exit (1); } while (! tmsgfile.eof()) { getline(tmsgfile,tmbuffer,'\n'); tmbuffertmp = tmbuffer; tmbuffertest = tmbuffertmp.empty(); if (tmbuffertest == 0) { tmbuffertmp = tmbuffertmp.erase(1); if (tmbuffertmp == "T") { tmsgcount++; tmbuffer = tmbuffer.substr(7); cout << tmsgcount << ". "<< tmbuffer << endl; } } } free(msgtitlearray[msgtitlearraynum]); } free(msgtitlearray); } cout << "\n"; } void show_version(void) { cout << "Grim " << versinfo << endl; } void show_help(void) { cout << "Usage: grim [option] [message(s)]\n"; cout << "Manage messages.\n\n"; cout << "OPTIONS:\n\n"; cout << " writing messages\n"; cout << " -w write new message\n"; cout << "\n reading messages\n"; cout << " -r list all message titles\n"; /* have a -r all? */ cout << " -r x read message x\n"; cout << " -r x,y read messages x and y\n"; cout << " -r x-y read all messages from x to y\n"; cout << "\n deleting messages\n"; cout << " -d all delete all messages - BE CAREFUL!\n"; cout << " -d x delete message x\n"; cout << " -d x,y delete messages x and y\n"; cout << " -d x-y delete all messages from x to y\n"; } void show_wenda(void) { cout << "Wenda! Boo Yeh!" << endl; } void show_about(void) { cout << "The Grim Message Keeper is a console-based application that \n"; cout << "stores short reminder messages. It is a project for C/C++ newbies \n"; cout << "that is intended to offer a practical learning experience.\n"; } void show_release_dates(void) { cout << "Release Dates:\n"; cout << "Version 0.0.1 released: Jun 14th 2004\n"; cout << "Version 0.0.2 released: Jun 19th 2004\n"; cout << "Version 0.0.3 released: Jun 20th 2004\n"; cout << "Version 0.0.4 released: Jun 32rd 2004\n"; cout << "Version 0.0.5 released: July 5th 2004\n"; cout << "Version 0.0.5a released: July 5th 2004\n"; cout << "Version 0.0.6 released: July 5th 2004\n"; cout << "Version 0.0.7a released: July 5th 2004\n"; cout << "Version 0.0.7b released: July 6th 2004\n"; cout << "Version 0.0.7c released: July 7th 2004\n"; }