C: Get list of objects in directory
Chris Mahoney (1684) 2100 posts |
I’m trying to get a list of all the files and subdirectories in a directory, and I’m a bit stuck :) First of all, it appears that there is no plain C way of doing this, but please correct me if I’m wrong. From poring over PRM2 I concluded that I should use OS_FSControl 28 to get the number of objects and then feed the result into OS_GBPB 9 to get the actual file details… but I’m not getting past the first step! OS_FSControl 28 is only returning files, not directories. There are some flags to change its behaviour but if I’m reading the docs correctly then there doesn’t seem to be a combination that does what I want. Obviously there must be a way to accomplish this (Filer does it!) but I’m a bit stuck. Any suggestions? |
Rick Murray (539) 13401 posts |
No, a grudge I have with CLib is that one can “unget” a character from a stream and create temp files, but one cannot list files in a directory. Forget OS_FSControl, OS_GBPB will do what you want. |
Rick Murray (539) 13401 posts |
Use OS_GBPB 12 because you need to access the object type.
The object type is 0 (not found, you shouldn’t see this when scanning for entries!), 1 (File), 2 (Directory), or 3 (Image (ie both a directory and a file)). Always check the count (R3) as it is valid to return 0 in the middle of a scan, and don’t make any assumptions about the next value (R4) other than it’ll be -1 when there’s no more. It’s a little more “complicated” these days since the file name can be of an unspecified length, and core developers have an aversion to supplying a means of reading the length limits imposed by the OS; which means you’ll probably have to pick an essentially random size to use here. I’d suggest 232 bytes (to make the entire block 256 bytes) because clearly any larger filename is going to have difficulties being used within the Desktop as it’ll be too big for Wimp messages. Actually, 224 is about the limit as you’d need to leave space for, at least, “SDFS::$.”! :-) |
Chris Mahoney (1684) 2100 posts |
Thanks! I was under the impression that I had to feed the object count into R3 for OS_GBPB, but if I can just put 1 and loop, then that seems that it’ll do the trick :) |
Chris Mahoney (1684) 2100 posts |
I’ve sometimes pondered whether it’d make sense to bring some of the more useful Posix functions into CLib… |
Steve Fryatt (216) 2046 posts |
Be aware that filing system support for OS_GBPB 10, 11 and 12 appears to decrease with increasing reason code. Locate uses 10, despite actually needing the data returned by 12, because several fairly common (image) systems simply refused to support the newer code.
That depends a lot on what you’re doing with it. Allocating a larger buffer and allowing the call to return more than one object at a time can have significant performance benefits, at the expense of having to step through the data in the returned block. This quickly becomes useful if the code is to be used regularly. |
Chris Johns (8262) 242 posts |
IIRC listing the files in a directory isn’t part of the C standard library. |
Steve Fryatt (216) 2046 posts |
Most likely because it would be assuming too much about the target hardware and operating system. The problem was that Acorn provided the standard library plus a fairly shonky way to call SWIs, and then walked away, leaving users to sort out how to access OS calls like OS_GBPB cleanly. OSLib sorts that out, but it was done as a private project and many developers still seem to dislike using it for largely made-up reasons. |
Rick Murray (539) 13401 posts |
Perhaps the Not Another Sodding Library syndrome? I don’t use OSLib. Because by the time it came along, I already had DeskLib and a hotchpotch collection of my own routines. Why add another library to do what I already have? |
Steve Pampling (1551) 7931 posts |
I think many would say that the only useful new library would be one that has all the features of all the other libraries previously in use so that everyone could bin all the others and use just one. |
Richard Walker (2090) 416 posts |
Totally agree. However, in my limited experience, here’s something which irked me trying to use OSLib: I would look at other people’s code, the PRMs, the various documents scattered in the RISC OS source code tree, and the RISC OS headers and sources. Approximately 99% of these resources would not be using OSLib, so I was always having to ask myself what the ‘OSLib equivalent’ would be if I was trying to copy techniques. Sometimes you could guess easily, sometimes it was a quick check of the OSLib StrongHelp, but sometimes I had to delve into the OSLib sources. It would be really really lovely if the PRMs, for example, also contained examples of using each SWI from C with OSLib. I totally appreciate that there is nothing technically stopping me from doing this myself with the ROOL wiki… :). Or is my pipe dream nuts? |
Rick Murray (539) 13401 posts |
There, fixed that for you. :-) |
Steve Fryatt (216) 2046 posts |
Because OSLib doesn’t provide any library functionality: it’s a set of veneers around OS and third-party SWIs, plus structures corresponding to parameter blocks, type definitions and constants, making it much cleaner to call things like OS_GBPB directly. I’m fairly sure that I’ve explained this to you before in a similar context, but thanks for making my point so well… :-) |
Rick Murray (539) 13401 posts |
That rather depends upon what you consider to be “a library”. As far as I’m concerned, it has functions that can be called therefore it is a library (with library functionality). The original author must have agreed, given the Lib in the name. ;-)
Of course, one is obliged to point out that moving to this library means taking all of the existing code and changing it, not just the OS calls but all the structures and such too; and given the type safe aspect, possibly peripheral things that interact with those structure elements. Don’t get me wrong, there’s nothing wrong with OSLib, other than it offering duplication. |
Steve Pampling (1551) 7931 posts |
cough:
Of course, you have to be careful to avoid the MS .Net situation with multiple versions where something written to use .Net 1.0 almost certainly doesn’t work with .Net 2.0 or 3.0 or… so you have to have the whole mountain (it’ far too big to be a monolith) |
Stuart Swales (1481) 351 posts |
Perhaps because of OSLib’s license? Fairly sure that when it was first released it was GPL only. And I don’t know how well JC’s additional exemption for static linking would stand up in court if the FSF came knocking. The source code still looks GPL sans exemption. |
Andrew Rawnsley (492) 1407 posts |
Richard Walker’s point is very well made. I recently helped an experienced programmer, new to Wimp coding, who was using OSlib. Just to be clear, I think this (OSlib) was the right choice, although the learning curve was steep. In the end, most of my reference for assisting him was actually BASIC guides online (eg. one on riscos.com), because they have to call all SWIs directly without the aid of libraries etc. It encouraged a more “fundamental principles” approach, too, which I found helpful. Also, Steve F’s own guides are very handy, although I wish he had the time to expand on them, as they tended to stop at just the points we needed help on! My background is in RISC_OSlib, for which I had source and “Cambridge-mafia” teachers/advisors to guide me. This colours the way I think about wimp programming, because it abstracts at least one level. In many cases, I have to bypass those levels and call things more directly anyway, but I think of things in terms of the RISC_OSlib calls rather than the actual SWI names more closely mirrored by OSlib. Since most of Acorn’s example code was RISC_OSlib or toolbox, and many third party apps similarly, it limits the available reference material for OSlib. As such, I would read the appropriate chapter/section from the BASIC guide, then reference the OSlib headers to translate that into the C functions needed. The only real problems I’ve seen beyond that with [some versions of] OSlib are conflicts of type/function names with other libararies (eg. RISC_OSlib or Toolbox) largely because of the sheer number of types/functions defined in OSlib. Also, some functions have had parameter or type changes over the years, so programs compiled with older OSlib versions don’t necessarily compile against newer versions. Mind you, that seems to affect all libraries (I’ve had issues with DeskLib, and even ROOL’s recent RISC_OSlibs don’t play nice with old ones). Despite that, as Steve said, OSLib is the closest you’ll get to the “metal” of RISC OS, whilst still gaining the order and structure that a proper set of types/functions gives. Being close to the metal means that you’ll avoid potential library-related bugs or “gotchas”, ensuring that your code functions as you’d expect, which is highly desirable. It just badly needs more online documentation/examples and wimp programming guides focussing on C rather than BASIC, just like Steve’s guides, more expanded further. |
Rick Murray (539) 13401 posts |
With DeskLib, or was it the proposed replacement Desk? Desk was a good idea, make things more type safe and rename functions to not clash with other libraries. However this meant revising all existing code, so Desk was mostly ignored and people stuck with what they had.
One of the reasons why I like DeskLib – it has plenty of low level functions in addition to some higher level abstraction such as the Event handler.
Not quite sure what you’re getting at here. You say that OSLib doesn’t suffer from library related gotchas, then you bemoan the lack of documentation, which is arguably a library related gotcha. Also, remaining close to the metal means either bolting on another library, or a lot of wheel reinventing. These days, the most that I expect to have to do is tell my library “when an icon in this window is clicked, call this function”. I do not expect to have to deal with the polling loop mechanics myself. Indeed, something like showing a JPEG in a window…why aren’t we at the stage of being able to say “here’s the window, here’s the JPEG, show it”. |
John Sandgrounder (1650) 574 posts |
That would be a real shame. There are few enough BASIC examples as it is. |
Rick Murray (539) 13401 posts |
That is technically correct, however the Copyright page states: The copyright holder has granted a small relaxation of the conditions of the GNU Public Licence, in that OSLib is itself free software, but applications linked to it need not be. No idea why it wasn’t licenced LGPL in that case… An interesting question is whether this is an acceptable modification of the GPL, given that it gives more freedom to the programmer at the cost of allowing non-GPL use of GPL code. ;-)
…they’d first ask “the hell operating system is this?”. |
Steve Fryatt (216) 2046 posts |
The FSF wouldn’t have any reason to come knocking, because anyone statically linking OSLib to non-GPL code is doing so under a separate licence granted to them to do exactly that. The author of the work can do whatever they like with the code. If they choose to release it under two licences, GPL and something else, that’s their call. The GPL only comes into play when a third-party tries to use the code under the GPL terms.
Which is why I’m fine to use OSLib statically linked to code released under the EUPL or a closed “Freeware” licence, but when I’ve made changes to OSLib components (such as the additions that I made to BindHelp to allow it to build general purpose StrongHelp manuals), they get a GPL licence (in practice, the changes are fed back into the main codebase, and users are pointed there for copies). |
Steve Fryatt (216) 2046 posts |
Most of Acorn’s documentation that I’m aware of – at least that’s publicly available – is for the bare SWIs, so OSLib is usually just a case of reading the PRM, then looking the SWI name up in the OSLib StrongHelp manual and comparing the parameters. The OSLib structs and constants are then just a click or two away in StrongHelp. I have been known for things like flag bits to grep the OSLib headers for the appropriate hex value, but that’s quite rare.
Note that I’m not advocating programming without a higher level library to do the grunt work: I’d be lost without my Wimp libraries for handling all of the messy stuff that Acorn forgot to include. What started this discussion was Rick’s familiar “CLib’s so incomplete” whinge, with the implication that calling OS Heebie-Geebie in C was a pain. My observation was just that OS_GBPB is fine, but calling |
Chris Johnson (125) 819 posts |
OSLib does have its own support library (OSLibSupport), in particular an event driven library. You do not have to deal with low level polling. |
Rick Murray (539) 13401 posts |
Yup. Familiar because you need more than CLib the moment you want to do anything outside of plain text mode or with files somewhere other than the filesystem root (or current directory, if the OS applies working folders). dos.h, conio.h, kernel.h, and so on up to full blown replacement libraries. I suppose, fork() aside, there is some merit to the earlier suggestion of POSIX support.
It’s a bit “involved” due to the many parameters (and PRM error, if StrongHelp is to be believed) but it’s not that big a deal to call it. Or, indeed, use a function written yonks ago that does the job (DeskLib → Filing 1).
I’m pathologically allergic to swix. :-)
You’d have thought, yes. But the question is, how big a buffer to allocate given that you don’t know the length of the longest filename (which can be pretty much anything these days). And, anyway, the size of the filename field is undefined, so you need to manually pick apart where one file description ends and another begins. Far simpler to loop reading one each time and only worry about optimisation if and when the speed becomes an issue. 1 I will confess, I use a mixture of directly calling heebeegeebee or an old function I wrote back in the ‘90s because, yeah, I kind of never noticed that DeskLib had a Filing header file (I probably subconsciously read it as File). At any rate, the only complication with heebeegeebee is that it can return nothing if the underlying FS feels like it, and it’s only really FileCore systems that you can expect to provide entries in alphabetical order (but then this sort of assumption can lead to future pain). |
Richard Walker (2090) 416 posts |
This is what I tried to do, but I kept tripping over. It could just be me being relatively inexperienced with C and all the RISC OS programming tools, but Andrew echoed my point. For what it’s worth, name clashes aside, I wouldn’t object to using multiple libraries. In my day job, it is entirely normal to not re-invent the wheel, and dropping in third-party code to assist with X, Y and Z so I can concentrate on A, B and C. What astonishes me in RISC OS land is the apparent reluctance to do so, and the idea that there is ‘one true library’. Definitely agree that my comment on the PRM examples could have been wider, though! :) |