473,699 Members | 2,693 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Duration Conversion

[C application running on TRU64 Unix]

Hello All

I have a simple task that is driving me crazy. A string representing a
duration in the following format is passed to my application, a
function is dedicated to convert this duration to seconds;

[H]H:MM:SS

e.g. 0:00:00 or 00:12:45

The original function used atoi as part of the conversion process and
it produced some scary conversions 0:00:10 converted to 956 seconds
etc.

The function was rewritten to make use of strtol because of its better
error handling functionality but it now core dumps! Do someone have a
bullet proof idea to do this conversion assuming that anything might
be passed into this function;

e.g. A:00:00 or :0:45 etc

Reproducted below is the offending function the lines where it
currently dumps is marked with a @.

Any help would be much appreciated.

Thank you,

B

void secondDurations ()
{
long hr, min, sec, sec_duration = 0;
char tm[10];
int ch = ':';
char *end_ptr = NULL;
char duration[41];

char *pfirst;
char *plast;

// 00:00:00
// 0:00:00
// 01234567
strcpy(duration , "00:00:34") ;

//String should at leat be 7 characters long
if (strlen(duratio n) >= 7)
{
pfirst = strchr(duration , ch);
plast = strrchr(duratio n, ch);

//Test duration format 00:00:00
if((pfirst != NULL || plast != NULL) && (pfirst != plast))
{
errno = 0;

//Get hour portion
strcpy(tm, strtok(duration ,":"));

//Convert
hr = strtol(tm, &end_ptr, 10);

//Test
if (hr INT_MAX || hr < INT_MIN)
{
//Reject;
return;
}
else if (end_ptr == tm || *end_ptr != '\0')
{
//Reject
return;
}
else
{
errno = 0;

@ strcpy(tm, strtok(NULL,":" ));

min = strtol(tm, &end_ptr, 10);

if (min INT_MAX || min < INT_MIN || min 59)
{
//Reject;
return;
}
else if (end_ptr == tm || *end_ptr != '\0')
{
//Reject
return;
}
else
{
errno = 0;

@ strcpy(tm, strtok(NULL,":" ));

sec = strtol(tm, &end_ptr, 10);

if (sec INT_MAX || sec < INT_MIN || sec 59)
{
//Reject;
return;
}
else if (end_ptr == tm || *end_ptr != '\0')
{
//Reject
return;
}
else
{
sec_duration = hr * 3600 + min * 60 + sec;
printf("duratio n in seconds=%d\n",( int)sec_duratio n);
}
}
}
}
}

Sep 13 '07
15 2045
Keith Thompson <ks***@mib.orgw rote:
Bart van Ingen Schenau <ba**@ingen.ddn s.infowrites:
bcpkh wrote:
I have a simple task that is driving me crazy. A string representing a
duration in the following format is passed to my application, a
function is dedicated to convert this duration to seconds;

[H]H:MM:SS

e.g. 0:00:00 or 00:12:45
As the format is rather strict in what you can accept, I would use
sscanf() for this task.

void secondDurations ()
{
int hr, min, sec, num_matches, num_chars;
[...]
/* The trailing %n causes the number of characters consumed to be
recorded. This should be the entire length of the string */
num_matches = sscanf(duration , "%d:%d:%d%n ", &hr, &min, &sec,
&num_chars);

If the string you're scanning contains a syntactically valid integer
value that can't be stored in an int, then sscanf with the "%d" format
invokes undefined behavior. This is true for all the numeric
conversion formats for the *scanf() functions.

If you want safety, you'll need to check for the number of digits
before invoking sscanf, or you'll need to use some other method (like
strtol).
That's why his function carefully checks that the length of the _whole_
string is less than 7. Since INT_MAX can be 32767, that still isn't
careful enough, but it's some way towards the right amount of care.
Using longs instead of ints would solve the problem.

Richard
Sep 14 '07 #11
"Old Wolf" <ol*****@inspir e.net.nza écrit dans le message de news:
11************* *********@19g20 00...legro ups.com...
On Sep 14, 3:25 am, bcpkh <vanheerden.br. ..@gmail.comwro te:
[...]
> //Get hour portion
strcpy(tm, strtok(duration ,":"));

strtok would return NULL if the stirng contains no colon.
As posted, this can't happen, but what if somebody changes
the 'ch' variable but does not update the strtok calls?
You should use the same variable for both.

Also, if the duration string contains a lot of characters
between the colons, you cause a buffer overflow when copying
into tm.

What is the purpose of this "tm" ? You could have
written:
hr = strtol( strtok(NULL, ":"), &end_ptr, 10 );

although in either case I would prefer that the result
of strtok be stored in an intermediate variable and
checked that it is not NULL.
Do not use strtok: it is non reentrant. It used a private global state
variable. It is error prone even in single threaded programs. A reentrant
version strtok_r is available on POSIX systems, but you hardly need
something to heavy for a simple parsing task such as this one. Here is a
program that performs the needed conversion, feel free to copy the relevant
function.

#include <stdio.h>
#include <ctype.h>

/* Convert a timestamp to a number of seconds:
* format is H:MM:SS or HH:MM:SS
* hour must be in range [0..23]
* minutes and seconds must be in range [0..59]
* return -1 in case of NULL pointer or invalid format
*/
long convert_time(co nst char *str) {
int hour, min, sec;

if (!str || !isdigit(*str))
return -1;
hour = *str++ - '0';
if (isdigit(*str))
hour = hour * 10 + (*str++ - '0');
if (*str != ':' || !isdigit(str[1]) || !isdigit(str[2]))
return -1;
min = (str[1] - '0') * 10 + (str[2] - '0');
str += 3;
if (*str != ':' || !isdigit(str[1]) || !isdigit(str[2]))
return -1;
sec = (str[1] - '0') * 10 + (str[2] - '0');
str += 3;
/* here you can relax the check on what can follow the time stamp */
if (*str != '\0')
return -1;
/* here you can customize the checks on timestamp validity */
if (hour 23 || min 59 || sec 59)
return -1;
return hour * 3600L + min * 60 + sec;
}

int main(int argc, char **argv) {
int i;
for (i = 1; i < argc; i++) {
printf("\"%s\" -%ld\n", argv[i], convert_time(ar gv[i]));
}
return 0;
}
--
Chqrlie.
Sep 14 '07 #12
CBFalconer <cb********@yah oo.comwrites:
Old Wolf wrote:
>>
... snip ...
>>
It is hard to follow. IMHO, much clearer is:
if ( !A )
return;
if ( B )
return;
if ( C )
return;
if ( D )
return;
if ( E )
return;
/* dozens of lines */
/* print results */

I would prefer:

if (!(!A || B || C || D || E)) {
/* dozens of lines */
/* print results */
}
return;
much clearer is

if (B || ... || (!A))
return

dozens of lines.
>
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home .att.net>
Sep 14 '07 #13
Richard <rg****@gmail.c omwrote:
CBFalconer <cb********@yah oo.comwrites:
I would prefer:

if (!(!A || B || C || D || E)) {
/* dozens of lines */
/* print results */
}
return;

much clearer is

if (B || ... || (!A))
return
That may be, but it doesn't have the same semantics, because || is a
short-circuiting operator.

Richard
Sep 14 '07 #14
jaysome wrote:
CBFalconer <cb********@yah oo.comwrote:
.... snip long coded sample ...
>
> if (!(!A || B || C || D || E)) {
/* dozens of lines */
/* print results */
}
return;

Applying De Morgan's Theorem to your expression I get:

if ( A && !B && !C && !D && !E )
{
/* dozens of lines */
/* print results */
}

This is clearer to me, and it ostensibly takes advantage of C's
short-circuit evaluation of conditions to determine the value of
the expression. It's unclear to me whether your expression takes
advantage of C's short-circuit evaluation of conditions, given that
everything in the inner-most parenthesis is surrounded by a '!'.
While true enough, also consider the effort of evaluating the
conditional (although many optimizers will eliminate the
difference). With my statement, the decision to print is reached
after chacking a minimum number of components, while your 'reduced'
version requires all components to be checked. Of course the
reverse applies if optimizing for the 'skip it all' case.

(and yes, the short circuit operation functions in both)

At any rate my point was to eliminate the long confusing barrage of
lines in the original.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home .att.net>

--
Posted via a free Usenet account from http://www.teranews.com

Sep 14 '07 #15
Keith Thompson <ks***@mib.orgw rites:
Bart van Ingen Schenau <ba**@ingen.ddn s.infowrites:
>bcpkh wrote:
>>[C application running on TRU64 Unix]
I have a simple task that is driving me crazy. A string representing a
duration in the following format is passed to my application, a
function is dedicated to convert this duration to seconds;

[H]H:MM:SS

e.g. 0:00:00 or 00:12:45

The original function used atoi as part of the conversion process and
it produced some scary conversions 0:00:10 converted to 956 seconds
etc.
[...]
>From reading your code, these invalid time strings should be rejected.
As the format is rather strict in what you can accept, I would use
sscanf() for this task.

void secondDurations ()
{
int hr, min, sec, num_matches, num_chars;
[...]
> /* The trailing %n causes the number of characters consumed to be
recorded. This should be the entire length of the string */
num_matches = sscanf(duration , "%d:%d:%d%n ", &hr, &min, &sec,
&num_chars);
[...]

If the string you're scanning contains a syntactically valid integer
value that can't be stored in an int, then sscanf with the "%d" format
invokes undefined behavior. This is true for all the numeric
conversion formats for the *scanf() functions.

If you want safety, you'll need to check for the number of digits
before invoking sscanf, or you'll need to use some other method (like
strtol).
There is another option. One can limit the number of digits read.
Also, the OP can use a trick to ensure the last number is no more than
two digits long:

sscanf(duration , "%2d:%2d:%2d%c" , &hr, &min, &sec, &end) == 3

means the data is valid. The test is for three not four conversions
because the final one failing indicates that the string ends after no
more that a two-digit number. I think this is safe from undefined
behaviour.

If the string might not end after the last digit one can do:

nc = sscanf(duration , "%2d:%2d:%2d%c" , &hr, &min, &sec, %end);
if (nc == 3 || nc == 4 && !isdigit(end)) /* data OK */

(I think 'unsigned char end;' is the best type for this kind of thing.)

--
Ben.
Sep 14 '07 #16

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
2461
by: Louis | last post by:
Hi, Does anyone know of a script that will give "weighted job duration"? I want to use it, to identify which jobs are hogging the CPU. That is for a given server, list the sql agent jobs ordered by: (avg job duration in minutes) times (avg num of times job runs in a given day).
1
2238
by: Dave | last post by:
Greetings, I am trying to create a duration field in a query. I have a field with a start time and a field with an end time. They are both in military time, and are formatted as hours:minutes. I am trying to create a duration field by subtracting the start time from the end time. This is working. However, some end times do not happen until the following day, and this is screwing up the results. If the start time is 04:30 and the
4
5702
by: Stephen Young | last post by:
Hello Have a bit of a problem, im trying to get the total number of hours:minutes for all actions over the month in a query, have tried two methods to no luck... Duration This Month: Format(Sum(.-.),"hh:nn") displays the total hours but rolls over anything over 1 day and starts
2
2168
by: CJ | last post by:
If I set the outputcache like this.. <%@ OutputCache Duration="900" VaryByParam="none" %> on a server on the east coast. Will someone who hits the site on the west coast get three hours added to the cache expiration? it mentions at msdn that Response.Cache.SetExpires should follow UTC and any HTTP1.1 docs that you read on w3c will say that UTC is the only accepted format.
0
1423
by: kbodily | last post by:
Hi, I have this code in a dragdrop routine for a listview to get the duration of an mp3, where fPath is the path to the file that gets dropped Dim fname As String = Chr(34) + Trim(fPath) + Chr(34) mciSendString("open " & fname & " alias song", 0, 0, 0) Dim totalTime As String = Space(128) mciSendString("status song length", totalTime, 128, 0&) .Duration = totalTime
5
2056
by: Ivan Novick | last post by:
Is the string below automatic storage duration? #include <iostream> #include <string> int main(int argc, char** argv) { std::cout << std::string().size() << std::endl; return 0; }
3
2317
by: Keith Wilby | last post by:
Here's something I thought I'd know how to do ... I have an Appointments table and want to add a duration (integer representing hours) to a start time (Date/Time field, "Short Time" format) to give a finish time. I want to do this in a query but if I do + I get a date returned. I've tried using the Format function to no avail. What forehead slappingly obvious trick am I missing?
0
1275
by: Yew12 | last post by:
I'm trying to use PL/SQL to create a trigger that will stop bookings. Based on a duration field and a start time. I have had a go at trying to do this but I'm sure that im well off from where I need to be. Create or Replace Trigger multiple_appointments Before insert on appointment Begin IF (NEW.toNumber(ADATE) between toNumber(ADATE + "Duration(Min)" from Appointmenmt)
1
3757
by: Giacomo Catenazzi | last post by:
Hello, To learn the details of C, I've build the following example, could you check if it is correct and if it miss some important cases? Are there some useful (real cases) examples of: - "function prototype scope" for structures and unions? - "extern" for internal linkage ?
0
8615
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9173
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
8911
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8882
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7748
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6533
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4375
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4627
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2345
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.